Spherical forums

Sphere Development => Sphere Support => Script Support => Topic started by: Vakinox on July 07, 2013, 11:51:17 pm

Title: Question about API and Obstructions
Post by: Vakinox on July 07, 2013, 11:51:17 pm
[Question:] Is there an existing function or way to set a person as "obstructed" through the API?

I noticed we have:

Quote

      IsPersonObstructed(name, x, y)
      // returns true if person 'name' would be obstructed at (x, y)

      GetObstructingTile(name, x, y)
      // returns -1 if name isn't obstructed by a tile at x, y,
       - returns the tile index of the tile if name is obstructed at x, y

      GetObstructingPerson(name, x, y)
      // returns "" if name isn't obstructed by person at x, y,
       - returns the name of the person if name is obstructed at x, y

      IgnorePersonObstructions(person, ignore)
       - Sets whether 'person' should ignore other spriteset bases

      IsIgnoringPersonObstructions(person)
       - Returns true if 'person' is ignoring person obstructions, else false
      
      IgnoreTileObstructions(person, ignore)
       - Sets whether 'person' should ignore tile obstructions

      IsIgnoringTileObstructions(person)
       - Returns true if 'person' is ignoring tile obstructions, else false


But don't see anything about setting a person to obstructed.

Should I instead write something like (pseudo-code):

Code: (javascript) [Select]

if (GetTileName(Next_tile) == "obstruct_nw" && direction == "south")
{
QueuePersonCommand(Player, COMMAND_FACE_SOUTH, true);
SetPersonFrame(GetInputPerson(),1);
UpdateMapEngine();
}


Will that work?

. . .

[Edit:] Scratch that, doesn't work.
He skips across the tile like a long jumper. Any ideas?

Tried adding:

Code: [Select]
 QueuePersonCommand(Player, COMMAND_WAIT, true); 


also, but that didn't work either.

Script is attached in case anyone needs to see it.

. . .

[Edit:] Tried a little something else:

Code: (javascript) [Select]

function SetPersonObstructed(name, command)
{
  switch(command) {
  case North: Move(name, 16, South, Face_north); break;
  case South: Move(name, -16, North, Face_south); break;
  case East: Move(name, -16, West, Face_east);  break;
  case West: Move(name, 16, East, Face_west);  break;
  break;
}
}

. . .

if (GetTileName(Ntile) == "obstruct_n" && direction == "south")
{
SetPersonObstructed(GetInputPerson(), South)
SetPersonFrame(GetInputPerson(),0);
UpdateMapEngine();
}

. . .

function Move(Name, Tiles, Direction, Face)
{

if (Direction == North) {QueuePersonCommand(Name, Face_north, false);}  //Makes sprite face its proper direction.
if (Direction == South) {QueuePersonCommand(Name, Face_south, false);}
if (Direction == East)  {QueuePersonCommand(Name, Face_east, false);}
if (Direction == West)  {QueuePersonCommand(Name, Face_west, false);}

if (Direction != Wait) {QueuePersonCommand(Name, Face, false);}   //If Direction commands sprite to Wait. It simply faces



for (var j = 0; j < Tiles; ++j) //For as long as "j" is less than Tiles, +1 is added to variable "j."
{ //The "j" variable will get us to reach our Tile Number. Once Tiles starts to become than "j" we no longer move.

   for (var i = 0; i < 16; ++i) {  QueuePersonCommand(Name, Direction, false);  }
   SetPersonFrame(Name, 0);  //When Tile for-loop is finished, we reset the sprite's frame of currection direction to "0"
}



//Now we set the sprite's facing direction.

if (Face == undefined)   //Checks Face for undefined.
{     //If undefined, sprite faces towards the direction it's commanded to go in.
   if (Direction == North) {Face = North;}
   if (Direction == South) {Face = South;}
   if (Direction == East)  {Face = East;}
   if (Direction == West)  {Face = West;}
}

if (Face == North) {QueuePersonCommand(Name, Face_north, false);}  //Makes sprite face its proper direction.
if (Face == South) {QueuePersonCommand(Name, Face_south, false);}
if (Face == East)  {QueuePersonCommand(Name, Face_east, false);}
if (Face == West)  {QueuePersonCommand(Name, Face_west, false);}


}
   

But that failed also. Still skips across the tile,
but now he stops and turns around and then stays stuck.

Still working on it.

Title: Re: Question about API and Obstructions
Post by: DaVince on July 08, 2013, 06:26:34 am
Quote
[Question:] Is there an existing function or way to set a person as "obstructed" through the API?

A person is *always* obstructed. Rules:

- A person isn't obstructed with people it's ignoring.
- A person isn't obstructed with people on another layer.
- Make sure your obstruction base in the rss file looks like it should.
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 08, 2013, 06:36:25 pm
Apologies, I'm approaching and wording it all wrong.
Lack of sleep, delirium, last night kept me from making the right decisions.

Turns out, what I'm really wanting to do:
Is make a tile obstruct a character, but in different ways.
For example, if the character enters the tile in one certain direction, it'll be obstructed by the tile on the other side of it.
If the character attempts to enter the tile from the other side, then it's obstructed by the original tile.

[Visual Translation:]
Quote

--> []
Trying to enter the tile from the West causes obstruction

Quote

[][<--
Entering the tile from the East causes obstruction against the tile next to it (from the west).

Quote

[][^
. . |
You would also be free to move North, or South, inside the tile, alongside the tile next to it.
As long as you don't move West, which will cause obstruction.


What I should be doing is editing the TileMovement() script to check the Tiles that come next.
And then switch between Command_Wait or Command_Direction depending on the direction of travel and the specified tile.

To do this, I'll need to use functions: IgnoreTileObstructions(person, ignore); GetTileName(Next_Tile); and such.
Does this make sense? And is correct for what I want to achieve?

. . .

Problem, for some reason when sphere starts up, the Sprite is given the placement value of (0, 0).
I'm having to collect the placement values for the player to predict the Next Tile in front of their chosen direction.
So if something collides with the player during TileMovement, from the point of startup, one of the values will register -1.
Thus, throwing/returning an error. (Because there is no existence of a tile in (-1, 0) or (0, -1)).

How do I change the values from point of start?

I tried this:

Quote

QueuePersonScript("Player", 'Txy("Player", 19, 12)', true);


But it doesn't work. It places "Player" at values (19, 12) but it registers as (0, 0) still.
Is this a problem with sphere?

Title: Re: Question about API and Obstructions
Post by: Vakinox on July 08, 2013, 08:25:50 pm
There's another problem,
this function:

Code: (javascript) [Select]

// To get the tile in front of the player.
function GetTileInFront()
{
  var direction = GetPersonDirection(GetInputPerson());
  if (direction == "north") return GetTile(NowTileX/16,NowTileY/16-1,0);
  if (direction == "south") return GetTile(NowTileX/16,NowTileY/16+1,0);
  if (direction == "west") return GetTile(NowTileX/16-1,NowTileY/16,0);
  if (direction == "east") return GetTile(NowTileX/16+1,NowTileY/16,0);
}


is returning some crazy numbers.
For example, it returns a Y-value of 44, when it should be 14.
As seen here:

(http://i.imgur.com/hats5Zf.png)


For reference: The NowTile variables only collect the pixel coordinates of the tiles.
Code: (javascript) [Select]

if (IsKeyPressed(KEY_DOWN))
{
  if (IsPersonObstructed(Player, GetPersonX(Player), GetPersonY(Player)+16) == false) Counter++;
  Direction = COMMAND_MOVE_SOUTH;

  QueuePersonCommand(Player, COMMAND_FACE_SOUTH, true);
  if (IsPersonObstructed(Player, GetPersonX(Player), GetPersonY(Player)+16) == false) LastTileY = GetPersonY(Player);
  if (IsPersonObstructed(Player, GetPersonX(Player), GetPersonY(Player)+16) == false) NowTileY = GetPersonY(Player) + 16;
}


Anybody have any ideas?

. . . .

[Edit:] Alright, I figured this part out!

The function GetTile() doesn't return coordinate values,
it returns the Tile's numeral identity count within the tileset used for the map.
In otherwords, the tile in the front is the 44th tile in the tileset of the map.
So it is returning the correct number, not an arbitrary one like I thought it was.

Still have more from the previous comment to solve.
Feel free to add in whenever possible.
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 08, 2013, 10:01:41 pm
Solved it! Well, sort of.
Everything begins to work, the sprite pauses in the correct location, however he keeps moving afterwards.
I need him to stop completely. Shouldn't the for-loop keep him waiting as long as KEY_UP is pressed?

Code: (javascript) [Select]

if (IsKeyPressed(KEY_UP))
{
  //Adds count to total number of steps
  if (IsPersonObstructed(Player, GetPersonX(Player), GetPersonY(Player)-16) == false) Counter++;  

  //Gets the next tile, if it's "obstruct_n" it ignores it for the time being
  if (GetTileName(Next_Tile) == "obstruct_n") IgnoreTileObstructions(Player, true);   

  if (GetTileName(GetTile(NowTileX/16, NowTileY/16, 0)) == "obstruct_nw") Direction = COMMAND_WAIT;
  if (GetTileName(GetTile(NowTileX/16, NowTileY/16, 0)) == "obstruct_ne") Direction = COMMAND_WAIT;

  //Until here, where the sprite is suppose to Wait as long as KEY_UP is pressed
  if (GetTileName(GetTile(NowTileX/16, NowTileY/16, 0)) == "obstruct_n")  Direction = COMMAND_WAIT;
 
  //Anywhere else or any other tile on the map, it can move North, except "obstruct_n"
  else { Direction = COMMAND_MOVE_NORTH; }                                                                                     


  QueuePersonCommand(Player, COMMAND_FACE_NORTH, true);
  if (IsPersonObstructed(Player, GetPersonX(Player), GetPersonY(Player)-16) == false) LastTileY = GetPersonY(Player);          //Gets previous Tile location in pixel-value
  if (IsPersonObstructed(Player, GetPersonX(Player), GetPersonY(Player)-16) == false) NowTileY = GetPersonY(Player) - 16;  //Gets present Tile location in pixel-value
  }



The GetTileInFront() function is the same, only thing that's changed is the definition for the Key commands.

[Question:] How do I keep him from moving, other than using only COMMAND_WAIT?

. . .

[Edit:] Tried running it through a for-loop:

Code: [Select]
 for (var j = 1; j > 0; ++j){Direction = COMMAND_WAIT;} 


But that didn't work either. He did stop completely, however he remained there and was stuck without hope of getting out.

. . .

[Edit:] He's still getting stuck, but should this work?

Code: (javascript) [Select]

//Reads: If Next Tile is "obstruct_n" AND Player is going North, then ignore tile obstruction.

if (GetTileName(Next_Tile) == "obstruct_n" && GetPersonDirection(Player) == "north") IgnoreTileObstructions(Player, true);

//Reads: UNLESS If the current tile is "obstruct_n", do not Obstruct (because that would get us stuck inside the tile)

else if (GetTileName(GetTile(NowTileX/16,NowTileY/16,0)) !== "obstruct_n") IgnoreTileObstructions(Player, false);

Title: Re: Question about API and Obstructions
Post by: Radnen on July 09, 2013, 12:16:41 am
To make him stop try using ClearCommandQueue(name);

Also this line of code:
for (var j = 1; j > 0; ++j){Direction = COMMAND_WAIT;}

Just sets Direction to COMMAND_WAIT forever without pause. This is an infinite loop!
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 09, 2013, 12:56:18 am
Sphere throws a "ClearCommandQueue(Player); is not defined"

Did you mean: ClearPersonCommands(name);

That doesn't work either, it does the same as the problem before.
Where he pauses for a quick bit, then keeps on walking.

. . .

To break the loop with a key, could I do this?

Code: [Select]

for (var j = 1; j > 0; ++j){
Direction = COMMAND_WAIT;
if ( IsKeyPressed(KEY_UP) == false) j = -1;}


Would that be if anything other than KEY_UP is pressed, then j registers a value as -1, thus breaking the loop?

. . .

Also, working getting the third part of the previous comment working.
If I get this working, I'll just need to keep the character from continuing walking North after the tile obstruction is ignored.

This is what I'm referring to:
Quote from: javascript

if (GetTileName(Next_Tile) == "obstruct_n" && GetPersonDirection(Player) == "north") IgnoreTileObstructions(Player, true);

else if (GetTileName(GetTile(NowTileX/16,NowTileY/16,0)) !== "obstruct_n") IgnoreTileObstructions(Player, false);


The problem is the character keeps getting stuck inside of the tile, for some reason the second part (else if) isn't working correctly.
Doesn't "!==" mean comparing to see if they're NOT equal?

Title: Re: Question about API and Obstructions
Post by: Radnen on July 09, 2013, 01:20:19 am
!== is a strict not equals which checks type and value. You were using it correctly there. :) You usually only use != tho.

Try:
Code: (javascript) [Select]

if (GetTileName(Next_Tile) == "obstruct_n")) IgnoreTileObstructions(Player, GetPersonDirection(Player) == "north");


What that will do is disable tile obstructions going north only if the next tiles name is 'obstruct_n'.
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 09, 2013, 09:30:23 am
Mind blown, as it's very creative. Just realized what was done.
The true or false part of IgnoreTileObstructions() is chosen according to what the GetPersonDirection() registers as in the comparison.
Which is also a true or false statement.

However, doesn't work.
For some reason the character is freely able to move South across the tile, when it should be obstructed.
Being that the direction isn't north.
Title: Re: Question about API and Obstructions
Post by: Radnen on July 09, 2013, 02:08:28 pm
So, the idea is: when you move north you can't move through obstruct_n tiles, and when you move any other direction you can move through them, right?
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 09, 2013, 02:12:46 pm
Sorta, but not quite.

1.) When you move north, you can enter the tile, but you can't pass through it.
2.) You can totally pass through it if you're moving east or west.
3.) However, when you're moving south, you're entirely obstructed by the tile, except when already inside of it.

. . .

[Edit:] Just realized during explanation, I should probably be putting this through a
Code: [Select]
 switch(Direction){ 
case north: //rules
case east:  //exception
case west:  //exception
case south: //rules
}

Right?
Title: Re: Question about API and Obstructions
Post by: Radnen on July 09, 2013, 03:33:07 pm
Yeah, a switch is a good start. When programming you look at the rules and exceptions, ask yourself what needs to be true or false for those to work and then implement them.

You will also need to figure out two things: what is the tile in front of you., and what is the tile you are currently on. Then I'm sure you can do the rest.
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 09, 2013, 09:31:14 pm
[Update:]

Alright, just attempted to run it through the for-loop which deals with the player's tile movements.
However, that doesn't work. Meaning I'll have to code into each individual Key's input,
rather than handling it within the for-loop with a switch(Direction); operator.

Code: (javascript) [Select]
 
if (Direction != null && !IsObstructed(Player, Direction)) {
for (var i = 0; i < 16; ++i) {
QueuePersonCommand(Player, Direction, false);
switch (Direction){

  case COMMAND_MOVE_NORTH:
  if (GetTileName(Next_Tile) == "obstruct_n") IgnoreTileObstructions(Player, true);
  //if (GetTileName(GetTile(NowTileX/16,NowTileY/16,0)) != "obstruct_n") IgnoreTileObstructions(Player, false);
break;
  case East:
break;
  case West:
break;
  case South:
break;}
}
}


Instead of working, it doesn't ignore the tile's obstruction, and instantly blocks the player upon contact.
So now I'm back to handling it inside of the input key's defining.

. . .

FINALLY! Got it working correctly though.
This is the code:

Code: (javascript) [Select]
 
if (IsKeyPressed(KEY_UP))
{
if (IsPersonObstructed(Player, GetPersonX(Player), GetPersonY(Player)-7) == false) Counter++;

if (GetTileName(Next_Tile) == "obstruct_n" && GetPersonDirection(Player) == "north") IgnoreTileObstructions(Player, true), Direction = COMMAND_MOVE_NORTH;
if (GetTileName(GetTile(NowTileX/16,NowTileY/16,0)) == "obstruct_n") IgnoreTileObstructions(Player, false), Direction = COMMAND_WAIT;
else Direction = COMMAND_MOVE_NORTH;

QueuePersonCommand(Player, COMMAND_FACE_NORTH, true);
if (IsPersonObstructed(Player, GetPersonX(Player), GetPersonY(Player)-16) == false) LastTileY = GetPersonY(Player);
if (IsPersonObstructed(Player, GetPersonX(Player), GetPersonY(Player)-16) == false) NowTileY = GetPersonY(Player) - 16;
}


And then added a:

Code: [Select]
 if (GetTileName(GetTile(NowTileX/16-7,NowTileY/16-7,0)) == "obstruct_n") IgnoreTileObstructions(Player, true), Direction = COMMAND_MOVE_SOUTH; 


to the KEY_DOWN's definitions.
Took the whole day to figure it out, but finally got it.

Turns out that there was a similar problem with my step counter, in which the correct tiles weren't registering.
So had to correct the math a bit, add a (-7) and done. Works.
Title: Re: Question about API and Obstructions
Post by: Radnen on July 09, 2013, 09:57:01 pm
Yeah, I noticed the -7 helps, you can also do a bit shift: GetTileWidth() >> 1;

It'll divide it in half and round. The reason for the 7 is that the width is 0..15 and 15/2 = 7.5, rounded down it's 7. Just stuff to look out for.
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 09, 2013, 10:05:17 pm
Thanks for the advice man, will take it.

Though while you're here, one last problem that was posted I forgot to fix. It's now messing with my corrections.

For reference, it's this one:
Quote

For some reason when sphere starts up, the Sprite is given the placement value of (0, 0).
I'm having to collect the placement values for the player to predict the Next Tile in front of their chosen direction.
So if something collides with the player during TileMovement, from the point of startup, one of the values will register -1.
Thus, throwing/returning an error. (Because there is no existence of a tile in (-1, 0) or (0, -1)).

How do I change the values from point of start?

I tried this:
Code: (javascript) [Select]
 QueuePersonScript("Player", 'Txy("Player", 19, 12)', true); 


But it doesn't work. It places "Player" at values (19, 12) but it registers as (0, 0) still.
Is this a problem with sphere?


Still can't figure it out. Can you help?
Title: Re: Question about API and Obstructions
Post by: Radnen on July 09, 2013, 10:42:01 pm
I dunno... I'll need more info such as how you get the (0, 0). It doesn't help me when you post working code! :P
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 09, 2013, 11:04:10 pm
Lol, that's the weird thing. It should work, but doesn't.

I'm guessing the values come from the global variables LastTile and NowTile, but even if I change the values from 0 nothing happens.
I'm also thinking Sphere automatically assigns the placement value (0,0) until input is given, which is part of the reason why it's returning negative tile numbers.

Attached the script to browse through.
Ask questions if something seems confusing,
I will clear things up as quickly and much I'm able to.

Conflict occurs between Lines:
*153-156  (Key_up, check Now Tile)
*168         (Key_down, check Now Tile)
* 13-17    (last and now Tile, global variables)

. . .

[Edit:] Just attempted to wrap the part I think that's the source of conflict "NowTileY/16-7" in Math.abs(); to get an absolute value. however it's still returning a negative number.
Although, it's now a -1 instead of a -6. Always look on the bright side of life I guess.
Title: Re: Question about API and Obstructions
Post by: Radnen on July 10, 2013, 12:38:23 am

Lol, that's the weird thing. It should work, but doesn't.


No it works I can see that it's not thinking on it's own. I ask, where are you getting the (0, 0) from?

All you need to do is use GetPersonX("name"), and GetPersonY("name"). If you want to get the pixel coords. There's a distinction between pixel and tile coords.

Realtime X/Y coords in tiles:
Code: (javascript) [Select]

var name = GetInputPerson();
var x = Math.floor(GetPersonX(name) / 16);
var y = Math.floor(GetPersonY(name) / 16);

var position = "(" + x + ", " + y + ")";


That's how you get the coordinates of the player. You shouldn't have the Txy(17, 8) = (0, 0) problem by calculating where the player is at when you draw the location string.
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 10, 2013, 12:57:12 am
[Update:] Removed all NowTile variables from conflicting lines in the movement script,
and replaced it with GetPersonX(GetInputPerson())/16, GetPersonY(GetInputPerson())/16 according to the script.

So it removed the error, which turned out to be a fault with I'm guessing using NowTile as a global variable,
which retains the placement values (0,0) at startup and using that in the math.
(note: odd it still didn't change from 0,0 when I changed the values in the globals)

Though, now I'm back to square one with getting stuck inside the obstructing tile.
Think the problem has now been simplified to a mistake in calculations somewhere.

Title: Re: Question about API and Obstructions
Post by: Radnen on July 10, 2013, 05:20:57 pm
Movement:
Code: [Select]

function Movement()
{
var Player = GetInputPerson();
if (!IsCommandQueueEmpty(Player)) return;

var x = Math.floor(GetPersonX(Player) / 16);
var y = Math.floor(GetPersonY(Player) / 16);
if (x < 0 || y < 0) return;

TileName = GetTileName(GetTile(x, y, 0));
NextTileName = GetTileName(GetTileInFront());
var Command = null;

//Start defining keys here
if (IsKeyPressed(KEY_UP)   ) { Command = North; QueuePersonCommand(Player, FaceNorth, true); }
if (IsKeyPressed(KEY_DOWN) ) { Command = South; QueuePersonCommand(Player, FaceSouth, true); }
if (IsKeyPressed(KEY_RIGHT)) { Command = East ; QueuePersonCommand(Player, FaceEast, true) ; }
if (IsKeyPressed(KEY_LEFT) ) { Command = West ; QueuePersonCommand(Player, FaceWest, true) ; }

IgnoreTileObstructions(Player, false);

if (NextTileName == "obstruct_n" || NextTileName == "obstruct_nw" || NextTileName == "obstruct_ne" ||
TileName == "obstruct_n" || TileName == "obstruct_nw" || TileName == "obstruct_ne") {
IgnoreTileObstructions(Player, true);
}

if (Command == North && (TileName == "obstruct_n" || TileName == "obstruct_nw" || TileName == "obstruct_ne")) {
Command = null;
}

if (Command != null && !IsObstructed(Player, Command)) {
for (var i = 0; i < 16; ++i) { QueuePersonCommand(Player, Command, false); }
}
}
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 10, 2013, 05:56:48 pm
That is a godsend my friend.
Thank you, bro. Appreciate it.
Title: Re: Question about API and Obstructions
Post by: Radnen on July 10, 2013, 06:26:06 pm
It actually too me quite a bit of time to try and debug that. :P Anyways I think it does what you wanted it to do.
Title: Re: Question about API and Obstructions
Post by: Vakinox on July 10, 2013, 06:45:06 pm
It's closer than I was ever going to be.

Still got a few kinks to work out that I can handle, but it's definitely does exactly what I needed it to.