function FindGridPath(%bot, %destination)
{
   $openlist = new SimGroup();
   $closedlist = new SimGroup();
   
   // get the grid name
   
   %grid = $currentgrid;
   
   echo("raw destination " @ %destination);
   
   // get the origin tile
   
   %OriginTile = %grid.PickTile(%bot.GetPosition());   

   // get the destination tile
   
   echo("dest " @ %destination);
   
   %DestTile = %grid.PickTile(%destination);   
   %x = getWord(%DestTile, 0);
   %y = getWord(%DestTile, 1);
   
   // if they click on a block square then return
   
   if(CheckAstarBlock(%grid, %x, %y) $= true && $combat $= false)
   {
      echo("Clicked on blocked square in astar");
      return -1;
   }
   
   // add the parent node to the open list
   
   %parentnode = new ScriptObject();
   %parentnode.tile = %OriginTile;
   %parentnode.h = 0;
   %parentnode.g = 0;
   %parentnode.f = 0;   
         
   %tilex = getWord(%OriginTile, 0);
   %tiley = getWord(%OriginTile, 1);

   $closedlist.Add(%parentnode);
   
   %closed[%tilex, %tiley] = true;
      
   for(%j=1;%j<100;%j++)
   {
      if(CheckAstarBlock(%grid, %tilex+1, %tiley) $= false)
      {
         if(%closed[%tilex+1, %tiley] !$= true) 
         {
            %node = new ScriptObject();
            
            %node.tile = %tilex+1 SPC %tiley;
            %node.parentnode = %parentnode;      
            $openlist.add(%node);
            
            %node.h = GenerateHeuristic(%tilex+1 SPC %tiley, %DestTile);
            %node.g = %parentnode.g+10;
            %node.f = %node.h+%node.g;
            %closed[%tilex+1, %tiley] = true;
         }
      }

      if(CheckAstarBlock(%grid, %tilex-1, %tiley) $= false)
      {
         if(%closed[%tilex-1, %tiley] !$= true) 
         {
            %node = new ScriptObject();
            
            %node.tile = %tilex-1 SPC %tiley;
            %node.parentnode = %parentnode;      
            $openlist.add(%node);
            
            %node.h = GenerateHeuristic(%tilex-1 SPC %tiley, %DestTile);
            %node.g = %parentnode.g+10;
            %node.f = %node.h+%node.g;
            %closed[%tilex-1, %tiley] = true;
         }
      }
      
      if(CheckAstarBlock(%grid, %tilex, %tiley+1) $= false)
      {
         if(%closed[%tilex, %tiley+1] !$= true) 
         {
            %node = new ScriptObject();
            
            %node.tile = %tilex SPC %tiley+1;
            %node.parentnode = %parentnode;      
            $openlist.add(%node);
            
            %node.h = GenerateHeuristic(%tilex SPC %tiley+1, %DestTile);
            %node.g = %parentnode.g+10;
            %node.f = %node.h+%node.g;
            %closed[%tilex, %tiley+1] = true;
         }
      }

      if(CheckAstarBlock(%grid, %tilex, %tiley-1) $= false)
      {
         if(%closed[%tilex, %tiley-1] !$= true) 
         {
            %node = new ScriptObject();
            
            %node.tile = %tilex SPC %tiley-1;
            %node.parentnode = %parentnode;      
            $openlist.add(%node);
            
            %node.h = GenerateHeuristic(%tilex SPC %tiley-1, %DestTile);
            %node.g = %parentnode.g+10;
            %node.f = %node.h+%node.g;
            %closed[%tilex, %tiley-1] = true;
         }
      }

      if(CheckAstarBlock(%grid, %tilex+1, %tiley-1) $= false)
      {
         if(%closed[%tilex+1, %tiley-1] !$= true) 
         {
            %node = new ScriptObject();
            
            %node.tile = %tilex+1 SPC %tiley-1;
            %node.parentnode = %parentnode;      
            $openlist.add(%node);
            
            %node.h = GenerateHeuristic(%tilex+1 SPC %tiley-1, %DestTile);
            %node.g = %parentnode.g+14;
            %node.f = %node.h+%node.g;
            %closed[%tilex+1, %tiley-1] = true;
         }
      }
      
      if(CheckAstarBlock(%grid, %tilex-1, %tiley-1) $= false)
      {
         if(%closed[%tilex-1, %tiley-1] !$= true) 
         {
            %node = new ScriptObject();
            
            %node.tile = %tilex-1 SPC %tiley-1;
            %node.parentnode = %parentnode;      
            $openlist.add(%node);
            
            %node.h = GenerateHeuristic(%tilex-1 SPC %tiley-1, %DestTile);
            %node.g = %parentnode.g+14;
            %node.f = %node.h+%node.g;
            %closed[%tilex-1, %tiley-1] = true;
         }
      }

      if(CheckAstarBlock(%grid, %tilex-1, %tiley+1) $= false)
      {
         if(%closed[%tilex-1, %tiley+1] !$= true) 
         {
            %node = new ScriptObject();
            
            %node.tile = %tilex-1 SPC %tiley+1;
            %node.parentnode = %parentnode;      
            $openlist.add(%node);
            
            %node.h = GenerateHeuristic(%tilex-1 SPC %tiley+1, %DestTile);
            %node.g = %parentnode.g+14;
            %node.f = %node.h+%node.g;
            %closed[%tilex-1, %tiley+1] = true;
         }
      }

      if(CheckAstarBlock(%grid, %tilex+1, %tiley+1) $= false)
      {
         if(%closed[%tilex+1, %tiley+1] !$= true) 
         {
            %node = new ScriptObject();
            
            %node.tile = %tilex+1 SPC %tiley+1;
            %node.parentnode = %parentnode;      
            $openlist.add(%node);
            
            %node.h = GenerateHeuristic(%tilex+1 SPC %tiley+1, %DestTile);
            %node.g = %parentnode.g+14;
            %node.f = %node.h+%node.g;
            %closed[%tilex+1, %tiley+1] = true;
         }
      }

      // find the node with the lowest score
      
      %lowestscore = 10000;

      %count = $openlist.GetCount();

      for(%i=0;%i<%count;%i++)
      {
         %node = $openlist.GetObject(%i);
         
         if(%node.f < %lowestscore)
         {
            %index = %i;
            %lowestscore = %node.f; 
         }
      }
      
      // make this the new parent square
            
      %parentnode = $openlist.GetObject(%index);
      
      // drop the parent square into the closed list

      $openlist.Remove(%parentnode);        
      $closedlist.Add(%parentnode);
      
      // update tilex and tiley
      
      %tilex = getWord(%parentnode.tile, 0);
      %tiley = getWord(%parentnode.tile, 1);
            
      %tile = %tilex SPC %tiley;
      
      if(%tile $= %DestTile)
      {
         $currentgrid = %grid;
         
         GeneratePath(%bot, %parentnode);
            
         return;
      }
   }
   
   // no path found
   
   echo("PATH NOT FOUND");
   return -1;
}

// for some reason on some interiors when clicking outside the room it finds a path
// if a parentnode is a -1 return a failure even though it's trying to generate a path

function GeneratePath(%bot, %endnode)
{
   echo("NEW PATH");
   
   deleteVariables("$gridpath*");
   
   %i = 1;
   
   %x = getWord(%endnode.tile, 0);
   %y = getWord(%endnode.tile, 1);
   %dest = getTileCenter($currentgrid, %x, %y);  

   $gridpath[%i] = %dest;
   
   %i++;
   
   // give %parentnode a value to start the while loop
   
   %parentnode = %endnode;
      
   while(%parentnode !$= "")
   {
      %parentnode = %parentnode.parentnode;   
      
      if(%parentnode $= -1)
      {
         echo("Final path not found");
         return -1;
      }
      
      if(%parentnode !$= "")
      {
         %x = getWord(%parentnode.tile, 0);
         %y = getWord(%parentnode.tile, 1);
         %dest = getTileCenter($currentgrid, %x, %y);  

         $gridpath[%i] = %dest;         
                  
         %i++;
      }
   }   
   
   $pathlength = %i-2;
   
   return true;
}


// generate the H factor
// currtile is the origin tile

function GenerateHeuristic(%CurrTile, %DestTile)
{
   %destx = getWord(%DestTile, 0);
   %desty = getWord(%DestTile, 1);
   
   %CurrX = getWord(%CurrTile, 0);
   %CurrY = getWord(%CurrTile, 1);
   
   // handle x first
   // either add or subtract from the origin tile to get to the destination
      
   if(%DestX < %CurrX)
   {
      while(%currX !$= %destX)
      {
         %CurrX--;
         %xcount++;         
      }
   }
   else
   {
      while(%currX !$= %destx)
      {
         %CurrX++;
         %xcount++;         
      }
   }

   // handle y first
   // add or subtract to get to the y destination
   
   if(%DestY < %CurrY)
   {
      while(%currY !$= %destY)
      {
         %CurrY--;
         %ycount++;         
      }
   }
   else
   {
      while(%currY !$= %destY)
      {
         %CurrY++;
         %ycount++;         
      }
   }
   
   %totalsquares = %xcount + %ycount;
   
   return %totalsquares*10;
}

// give this a layer and a tile position and it will return world coordidates 
// for the center of the square

function getTileCenter(%layer, %tileX, %tileY)
{
   //get the world coordinates of the tileLayer
   %LayerPosX = %Layer.getPositionX();
   %LayerPosY = %Layer.getPositionY();

   // get tile width and height
   
   %tilesize = %layer.GetTileSize();
   %tilewidth = getWord(%tilesize, 0);
   %tileheight = getWord(%tilesize, 1);
   
   // get the upper left X and Y

   %width = %layer.GetWidth();
   %height = %layer.GetHeight();
   %x = %layerPosX - (%width / 2); 
   %y = %layerPosY - (%height / 2);

   // get what half the tile is
   
   %halfx = %tilewidth / 2;
   %halfy = %tileheight / 2;
   
   // get the final position

   %xcoord = %tilex * %tilewidth + %halfx;
   %ycoord = %tiley * %tileheight + %halfy;
   
   %x = %x + %xcoord;
   %y = %y + %ycoord;

   return %x SPC %y;
}

// get a free square next to a target in combat
// %attackbot and %defendbot are the actual model id's

function GetAdjSquare(%attackbot, %defendbot)
{
   %destTile = $currentgrid.PickTile(%defendbot.GetPosition());
   %currTile = $currentgrid.PickTile(%attackbot.GetPosition());

   %grid = $currentgrid;

   %tilex = getWord(%destTile, 0);
   %tiley = getWord(%destTile, 1);

   %i=0;
   
   // find all the free squares next to this one
      
   if(CheckAstarBlock(%grid, %tilex+1, %tiley) !$= true)
   {
      %i++;
      %array[%i] = %tilex+1 SPC %tiley;
   }
   if(CheckAStarBlock(%grid, %tilex-1, %tiley) !$= true)
   {
      %i++;
      %array[%i] = %tilex-1 SPC %tiley;
   }
   if(CheckAStarBlock(%grid, %tilex, %tiley+1) !$= true)
   {
      %i++;
      %array[%i] = %tilex SPC %tiley+1;
   }
   if(CheckAStarBlock(%grid, %tilex, %tiley-1) !$= true)
   {
      %i++;
      %array[%i] = %tilex SPC %tiley-1;
   }
   if(CheckAStarBlock(%grid, %tilex+1, %tiley-1) !$= true)
   {
      %i++;
      %array[%i] = %tilex+1 SPC %tiley-1;
   }
   if(CheckAStarBlock(%grid, %tilex-1, %tiley-1) !$= true)
   {
      %i++;
      %array[%i] = %tilex-1 SPC %tiley-1;
   }
   if(CheckAStarBlock(%grid, %tilex-1, %tiley+1) !$= true)
   {
      %i++;
      %array[%i] = %tilex-1 SPC %tiley+1;
   }
   if(CheckAStarBlock(%grid, %tilex+1, %tiley+1) !$= true)
   {
      %i++;
      %array[%i] = %tilex+1 SPC %tiley+1;
   }

   // if there are no free tiles return
   
   if(%i == 0)
      return -1;
   
   // find the closest one - we can use the hueristic function
   
   %lowest = 1000;
   
   for(%j=1;%j<=%i;%j++)
   {
      %position = getTileCenter($currentgrid, getWord(%currtile, 0), getWord(%currtile, 1));
      %destination = getTileCenter($currentgrid, getWord(%array[%j], 0), getWord(%array[%j], 1)); 

      %dist = VectorDist(%position, %destination);
      
      if(%dist <= %lowest)
      {
         %index = %j;      
         %lowest = %dist;
      }
   }
   
   return %array[%index];
   
}

// when moving, either combat or non-combat, this will check the square to see if it's occupied

function CheckAstarBlock(%grid, %tilex, %tiley)
{
   if($peoplebattle $= "")
   {
      %tilecenter = getTileCenter(%grid, %tilex, %tiley);
      
      %x = getWord(%tilecenter, 0);
      %y = getWord(%tilecenter, 1);
      
      %startx = %x-1;
      %starty = %y-1;
      %endx = %x+1;
      %endy = %y+1;
            
      %objects = sg.PickRect(%startx SPC %starty, %endx SPC %endy);
      
      %count = getWordCount(%objects);
      
      for(%i=0;%i<%count;%i++)
      {
         %obj = getWord(%objects, %i);
               
         if(%obj.block == 1)
            return true;
      }
      
      return false;   
   }
   else
   {
      %block = %grid.GetTileCustomData(%tilex, %tiley);
      
      if(%block $= 10)
         return true;      
   }
}