Game Development Community

AI not recognizing functions?

by Nathan Kent · in Technical Issues · 03/07/2008 (3:40 pm) · 9 replies

My AI aren't doing their functions. I keep getting that nodeScan, findNodes, and CorrectPath don't exist for AIPlayers. I'm not getting it:

function AIPlayer::nodeScan(%this) {
   InitContainerRadiusSearch(%this.getPosition(), 2, $TypeMasks::PlayerObjectType);

   while ((%targetObject = containerSearchNext()) != 0)
   {
      error("Someone coming close -- I'm " @ %this @ "and they're " @ %targetObject);
      if (%targetObject.rank < %this.rank)
         %this.assignNodes(%targetObject);
   }
   
   schedule(2000,'nodeScan', %this);
}

function AIPlayer::assignNodes(%this, %them) {
   %curNode = %them.path.getObject(%them.currentNode);
   %theirDist = VectorDist(%them.getPosition(), %curNode.getPosition());
   %theyReq = %curNode.pathsNum == 1;
   
   %curNode = %this.path.getObject(%this.currentNode);
   %myDist = VectorDist(%this.getPosition(), %curNode.getPosition());
   %meReq = %curNode.pathsNum == 1;
   
   switch (%myDist < %theirDist) {
      case 1:
         if (%meReq && %theyReq) 
            %this.waitForNode();
         else if(%meReq)
            %them.correctPath();
         else
            %them.correctPath();
      
      case 0:
         if (%meReq && %theyReq) 
            %them.waitForNode();
         else if(%theyReq)
            %this.correctPath();
         else
            %them.correctPath();
   }
}

function AIPlayer::findNodeNum(%this) {
   %nodeStart = %this.path.getObject(%this.oldNode);
   %nodecountStart = %nodeStart.pathsNum;
   
   %nodeEnd = %them.path.getObject(%them.currentNode);
   %nodecountEnd = %nodeEnd.pathsNum;
   
   for (%i = 0; %i < %nodecountStart; %i++) {
      %a = getWord(%nodeStart.paths, %i);
      
      for (%y = 0; %y < %nodecountEnd; %y++) {
         %b = getWord(%nodeEnd.paths, %y);
         
         if(%b $= %y)
            break;
      }
      
      if(%a $= %y)
         break;
   }
   
   return %a;
}

function AIPlayer::correctPath(%this) {
   %new = %this.findNodeNum();
   
   while(%new $= %this.currentNode) {
      %new = %this.findNodeNum();
   }
   
   %this.moveToNode(%new);
}

function AIPlayer::spawnPeasent(%name, %path, %node, %gender) {
   %peasent = AIPlayer::spawnOnPath(%name, %path, %node, "PeasantAvatar", %gender);
   schedule(2000, 'nodeScan', %peasent);
   %peasent.setMoveSpeed(.15);
   return %peasent;
}


//-----------------------------------------------------------------------------
// AIPlayer static functions
//-----------------------------------------------------------------------------

function AIPlayer::spawn(%name,%spawnPoint,%datablock)
{
   // Create the demo player object
   %player = new AiPlayer() {
      dataBlock = %datablock;
      path = "";
      rank = $AIPlayer::count;
   };
   MissionCleanup.add(%player);
   %player.setShapeName(%name);
   %player.setTransform(%spawnPoint);
   $AIPlayer::count++;
   return %player;
}

function AIPlayer::spawnOnPath(%name, %path, %node,%datablock)
{
   // Spawn a player and place him on the first node of the path
   if (!isObject(%path))
      return;
   %node = %path.getObject(%node-1);

   return AIPlayer::spawn(%name, %node.getTransform(),%datablock);
}

#1
03/07/2008 (7:58 pm)
Hmm, could you copy/paste the exact error message, and the corresponding line in your script that generated it?
#2
03/08/2008 (4:12 am)
Errors:
schedule() not working
Function [functionHere] not found for AIPlayer
#3
03/08/2008 (1:12 pm)
I've had considerable issues trying to create new functions in namespaces in script--exactly like what you've got. I solved it by simply removing it from the namespace, as in, changing AIPlayer::spawnOnPath to plain old spawnOnPath and then calling it appropriately.
#4
03/08/2008 (1:58 pm)
I as well, Lee, especially with schedules. Sometimes you just have to change the order for some ungodly reason. The "%this" parameter is just too useful to totally throw out using namespaces.
#5
03/09/2008 (5:24 am)
I tried that, but the scedule still won't call.
#6
03/09/2008 (6:31 am)
Your syntax isn't quite right. Try something like:

schedule(2000,0,'nodeScan', %this);

You need the field where the 0 is. I think this is supposed to be an object the schedule is dependent on, but I haven't seen that work, yet. Zero will be fine for testing purposes.
#7
03/09/2008 (7:30 am)
Perhaps its my programming ignorance speaking here, but does including the namespace itself in a function call ever work? There seems to be some major problems with the syntax of your entire block of code.

In my experience, creating a function based on a namespace should look like this:
function playerClass::executeAttack(%this, %param1, %param2)
{
}
When you call the above function, it would look like this:
player.executeAttack("swing", 15);
Obviously, %param1 is a string and %param2 is an integer. Notice however that since "executeAttack" has a namespace, you say %object.executeAttack(. . . ) instead of passing in an object in the parameters.

Whenever you use a namespace to define a function, you should include %this as the first parameter, and any object to call the function should treat it like a "built-in" function.

Thus you can reference the object that calls the function as %this no matter what.

As far as scheduling goes:

If you are calling a function that has a namespace, use this scheduling method:
%object.schedule([%time integer], [%functionName string], [%arg1 . . . %argN]);
%peasent.schedule(2000, "nodeScan");
Note that any function with a namespace will automactically receive the object that calls a schedule, in the above fashion, as %this.

What Lee is thinking of is scheduling global functions such as quit() or activateKeyboard():
schedule([%time integer], [%referenceObject integerID OR 0 for a GLOBAL function], [%functionName string], [%arg1 . . . %argN]);

schedule(2000, %peasent, "nodeScan");
schedule(2000, 0, "quit");

After writing all of this, I realized that this wasn't in the TGB forums. Well, the above is what works in TGB %100 of the time.
#8
03/09/2008 (8:19 am)
"schedule(2000,'nodeScan', %this);" isn't dealing with the namespace. It's trying to call the function "nodeScan" which doesn't exist. Without calling schedule on the AIPlayer, you would need to do:
schedule(2000, 0, "AIPlayer::nodeScan", %this);
I'm pretty sure you could do that and have it work, but try doing this first:
%this.schedule(2000, "nodeScan");
#9
03/10/2008 (4:49 am)
I figured out the problem, I was using 'nodeScan' when it should've been "nodeScan". I hate stupid typos like that, mess up your programming, but to small to get an error from it.