Adventure Game Studio

AGS Support => Advanced Technical Forum => Topic started by: LostTrainDude on Fri 17/08/2018 09:31:12

Title: [SOLVED] Routine stops working after a random number of cycles
Post by: LostTrainDude on Fri 17/08/2018 09:31:12
In my space trading game prototype I have also NPCs who run errands in such way:

The problem I have is that this "routine" does not seem to happen "endlessly" as it should. It randomly lasts an average 3 to - maybe - 5 cycles, then the NPC will get a new mission, with new coords, and just sit there, although they are flagged as being "on mission".

I have double checked and the coords are always within the bounds and "real", so I'm not sure what I'm getting wrong. Maybe someone here can provide some feedback?

Here comes the code in the order in which it is compiled:
Code (ags) Select
// Movement uses a pretty basic algorithm.
// Manhattan distance to calculate the distance between the NPC and its target

function Person::Move(int toX, int toY)
{
   int x1 = this.X;
   int y1 = this.Y;
   
   int x2 = toX;
   int y2 = toY;
   
   float tx = IntToFloat(x2 - x1);
   float ty = IntToFloat(y2 - y1);
   
   int dist = GetDistance(this.X, this.Y, x2, y2);
   
   if (dist > 0)
   {
      tx = tx/IntToFloat(dist);
      ty = ty/IntToFloat(dist);
      this.X += FloatToInt(Maths.Ceil(tx));
      this.Y += FloatToInt(Maths.Ceil(ty));
   }
}

Code (ags) Select
/// Move People who are flagged as being on mission towards their destination

function MovePerson(int who)
{
   // The ID of the mission an NPC is on (always 0 in this test)
   int mission_id = People[who].MissionID;
   
   // The ID of the target planet
   int target_planet = Missions[mission_id].TargetPlanet;
   
   // The current X/Y coords of the NPC
   int pX = People[who].X;
   int pY = People[who].Y;
   
   // The X/Y coords of the target planet
   int toX = planetarySystem[target_planet].X;
   int toY = planetarySystem[target_planet].Y;

   // If the NPC is on the target planet
   if (pX == toX && pY == toY)
   {
      // Then is not on mission anymore
      People[who].IsOnMission = false;
     
      // Former target planet becomes new starting position
      People[who].Where = Missions[mission_id].TargetPlanet;
   }     
   else
   {
      // Move towards the target planet
      People[who].Move(toX, toY);
   }
}

Code (ags) Select
// This is the main function who controls the routine

function NextTurn(int turns)
{
   for (int t = 0; t < turns; t++)
   {
      // If NPC (always 0 in this test) is flagged as being on mission
      if (People[0].IsOnMission)
      {
         // Then move NPC (always 0 in this test)
         MovePerson(0);
      }
      else
      {
         // Check that this code is actually being executed
         Display("New Mission!");
         int person = 0; // Always 0 in this test
       
         // Select a random type of mission
         int type = Random(MISSION_TYPES-1);
         
         // Select the starting planet to be the same as the one the NPC is sitting on
         int startPlanet = People[person].Where;
         
         // Select a random target planet
         int targetPlanet = Random(TOTAL_SYSTEMS-1);
         
         // Repeat if start and target planets are the same
         if ((targetPlanet == startPlanet))
         {
            do
            {
               targetPlanet = Random(TOTAL_SYSTEMS-1);
            } while ((targetPlanet == startPlanet));
         }
         
         Missions[0].AssignedTo = 0; // The ID of the NPC to which this mission is assigned
         Missions[0].ID = 0; // The ID of the mission
         Missions[0].OriginPlanet = startPlanet;
         Missions[0].TargetPlanet = targetPlanet;
         Missions[0].Type = type;
         
         People[0].MissionID = 0; // The same as Mission[0].ID
         People[0].IsOnMission = true;
      }
      // Draw the pixels on the screen!
      map.DrawPixelPeople();
   }
}


Code (ags) Select
// This is the debug function I'm using to test the whole thing

function on_key_press(eKeyCode keycode)
{
   if (keycode == eKey1)
   {
      for (int i = 0; i < 1500; i++)
      {
         NextTurn(1);
         Wait(1); // I want to see it moving on the screen!
      }
   }
}


Thanks in advance and I hope I have made everything clear!

EDIT:

The issue is apparently solved by changing Math.Ceil() to Math.Round() in the Person::Move() function.
vga256 suggested me to go deeper with the debug and I just did that. I'm not sure why the calculation caused the problem, but now it seems to be working as intended!
Title: Re: [SOLVED] Routine stops working after a random number of cycles
Post by: eri0o on Fri 17/08/2018 16:10:20
Hey, you forgot to show the function GetDistance.
Title: Re: [SOLVED] Routine stops working after a random number of cycles
Post by: LostTrainDude on Fri 17/08/2018 16:13:33
Quote from: eri0o on Fri 17/08/2018 16:10:20
Hey, you forgot to show the function GetDistance.

You're right!
Here it is:

Code (ags) Select
int GetDistance(int x1, int y1, int x2, int y2)
{   
float x1f = IntToFloat(x1);
float x2f = IntToFloat(x2);
float y1f = IntToFloat(y1);
float y2f = IntToFloat(y2);

float a = Maths.RaiseToPower((x2f - x1f), 2.0);
float b = Maths.RaiseToPower((y2f - y1f), 2.0);

float d = Maths.Sqrt(a + b);
int dist = FloatToInt(d);

return dist;
}