Making the NPC characters walk around the rooms.

Started by Professor Plum, Sat 10/10/2009 18:02:12

Previous topic - Next topic

RickJ

Quote
Rick, you slap the cats ass.
@Snake:  Thanks for the compliment but my cat, she says for you not to give me any crazy ideas like that or else she is gonna come over there and scratch you 5 or  6 times.  She is so fast that you won't even feel it until after she's done.

Quote
Edit: Upon further inspection of the above function, I think it's supposed to be like this, but Rick may need to verify:
@Monkey:  Thanks monkey for helping out.  I forgot to set them equal to the input parameters as you figured out.  That's what I get for being up too late.

Quote
Here's what I'm getting when I attempt to run.
@Professor: Hmm, I've had errors like this under different circumstances and they were always weird problems.   I wonder if extender functions can't be used in the global script or something?  Try making the call in a room script just for laughs.  Also try calling a non-existent function like cPlum.DontHaveOne() to see what kind of error you get.  I'll have to think one it to see what else I can think of.

monkey0506

#21
An unresolved import error means that you're:

1. Defining an import of a function in a script header.
2. Never defining the actual function anywhere.
3. Calling the function.

Check spelling, capitalization, parameter lists, etc. and make sure the function being imported (that you're calling) is actually getting properly defined.

You can absolutely use extenders just fine in the global script so long as they're properly set up.

Edit: Found it! The import (in the header) as well as the function call both reference "SetSuspectLocation". However if you look closely at your script, you'll see the function is labeled improperly (in the global script) as "SuspectSetLocation". Switch the names so they both match (either order, just so long as they all match) and it should resolve this issue. ;)

Professor Plum

#22
How about I show you what I have (not including the edits monkey gave which I used after taking this picture):


Here's my global script.



Here's my script header.


So far, my game runs with these written into the scripts. Is there anything off?

monkey0506

Just so you don't miss it since you replied with these images, I edited my last post:

Quote from: monkey_05_06 on Tue 13/10/2009 00:28:40Edit: Found it! The import (in the header) as well as the function call both reference "SetSuspectLocation". However if you look closely at your script, you'll see the function is labeled improperly (in the global script) as "SuspectSetLocation". Switch the names so they both match (either order, just so long as they all match) and it should resolve this issue. ;)

Professor Plum

Okay, I fixed it, as well as fixed SuspectsMove to MoveSuspects.

Here's my next encountered error:

Script link failed: Runtime error: unresolved inport Character::SuspectSetLocation

RickJ

Hey Professor,  sorry that I changed the naming scheme and then not tell anyone.   I was thinking that it would be better to have everything start with Suspect so that you would know they were all part of the same mechanism and that it would make better use of the editor's auto completion feature.  Anyway you can form the names anyway you like but they need to be consistent everywhere.

Also note that SuspectMove() and SuspectInitialize() are supposed to be called from the Global Script so it's not necessary to have an import statement in the Script header.   I was thinking the same would be true for SuspectSetLocation() but it seems that since it is an extender function it needs to have the import statement in the header.



Professor Plum

Alright, alright. I understand. Oh an I realized I was making a mistake earlier. I was putting the final bit with the individual characters and their movements under Global Scripts rather than Event Handler Functions.

Now my next issue is getting rid of the error message that says Undefined token: SuspectInitialize.

I thought it was defined in the Global Script here?

Code: ags
// This function initializes the Suspect array with default values
function SuspectInitialize() {
   int i;
   int j; /code]



RickJ

#27
Use the search or find button in the editor to make sure you have used the same spelling everywhere.  Also remove the import statements from the Script header, except for the SuspectSetLocation() one, which seems to be required.  Does it give you the line where this error occurs?

Code: ags

*** Global Script ***

// 1.  There should only be two references to SuspectInitialize() and they should 
//      be in the global script.  Remove any import or other // statements from the 
//      Script header or Room scripts that contain "SuspectInitialize".  
//
// 2.  The function SuspectInitialize() should be defined first in the global script 
//
//  3.  Then it should be called from the game_start() event handler function
//
//  4.  Make sure it is spelled the same in both places 

function SuspectInitialize() {
}

function start_game() {
   SuspectInitialize();
}

Professor Plum

Alright thanks, I think I've fixed the definitions issue, but I'm still getting the Unresolved import: SuspectSetLocation issue.

It's an error that pops up in a box, doesn't show up in the errors dialog below.


RickJ

Quote
It's an error that pops up in a box, doesn't show up in the errors dialog below.
[/quote
Yeah, I've had one of those a long time ago and they are really screwy.  It ended up being about something other than what the message seems to be complaining about.   What happens if you comment out the stuff in the game_start() function where it is used?  If the error goes away then what happens if you try to use .SuspectSetLocation() in a room script?


monkey0506

Again, if you're getting an unresolved import it is only because you're importing and using a function which is never defined. Check your definitions and imports again.

Quote from: monkey_05_06 on Tue 13/10/2009 00:28:40An unresolved import error means that you're:

1. Defining an import of a function in a script header.
2. Never defining the actual function anywhere.
3. Calling the function.

Check spelling, capitalization, parameter lists, etc. and make sure the function being imported (that you're calling) is actually getting properly defined.

RickJ

Monkey, I think he's getting a runtime error.  I had one like this before when making a module.  The definitions the message complained about were correct but there was another error (can't remember what exactly) that caused the problem.  If there was a mismatch between the function definition, it's usage, or it's import statement the compiler would generate an error at compile time. 

I don't have a working AGS development system at the moment else I would offer to  hack on a copy until I found out what's wrong.  IMHO, the way to find this problem is to clip stuff out (comment out)  untril the problem goes away and then slowly add everything back in until it reappears.

monkey0506

#32
Quote from: RickJ on Wed 14/10/2009 02:43:39If there was a mismatch between the function definition, it's usage, or it's import statement the compiler would generate an error at compile time.

No it wouldn't. Unresolved import errors mean exactly what I said they mean. And the error is generated at run-time, not compile-time. Trust me on this one. I've encountered them enough with some of the things (hacks) I've tried to pull off in AGS.

Example:

Code: ags
// unresolvedimport.ash

import function SomeFunctionA(this Character*);



Code: ags
// unresolvedimport.asc

function SomeFunctionB(this Character*) {
  // BLAH!
}

function game_start() {
  player.SomeFunctionA();
  player.SomeFunctionB();
}



Build -> Build EXE:

Quote---------------------------
Adventure Game Studio
---------------------------
Compile successful!
---------------------------
OK   
---------------------------

Build -> Run:

Quote---------------------------
Adventure Game Studio
---------------------------
Script link failed: Runtime error: unresolved import 'Character::SomeFunctionA'

---------------------------
OK   
---------------------------

Steps to resolution:

A) Comment/delete the first line of game_start:

Code: ags
  //player.SomeFunctionA();


OR

B)
  i. Comment/delete the second line of game_start:

Code: ags
  //player.SomeFunctionB();


  ii. Then change the name of the function in the main script file to "SomeFunctionA":

Code: ags
function SomeFunctionA(this Character*) {
  // BLAH!
}


OR

C) Add the function "SomeFunctionA" (before game_start):

Code: ags
function SomeFunctionA(this Character*) {
  // BLAH!
}


Unresolved import errors are only generated in the circumstances I described. It would give a compile-time error if the function call did not match the import, or if there was no import given and the function call did not match the function definition, or if there was a function call but no import or function definition given, or if both the import and the function definition were given but the function call was placed before the function definition. All of these would generate compile-time errors. But if there is an import given but no function definition, there will only be a run-time error, and then only if the function is actually called.

Also there's no possibility that the function call is just happening before the function definition because then the error would say "Already referenced name as import." So I do know what unresolved import means.

RickJ

Quote
But if there is an import given but no function definition, there will only be a run-time error, and then only if the function is actually called.
Thanks for the research and the explanation.  When this happened to me I couldn't figure out what was happening and it has always bugged me.   I vaguely remember  changing something in a struct definition in  a Module Header that ended up resolving the error.  But I never really knew exactly what I did or understood why the error was occurring or not occurring.       

I couold have sworn that I had checked all the names using the editor search function.  I wonder if in my case there could have been something wrong with something declared just before my function that made it not defined or not defined correctly?  At this point I suppose I'll never know but thanks to your post I'll definitely know what to look for next time.  Thanks.

So monkey is it the case here, that the function call and the import statement match each other but not the function definition?

Professor Plum

Unfortunately, this is starting to get out of my know-how. I've very new to AGS and this sort of thing was definately going to be a challenge for myself right from the start. For the moment though, I think it's best I get more comfortable with the basics. Thank you for the help that was provided and special thanks to you Rick for going through the trouble to create a script that apparently has not been used before on AGS.

Sadly, I find the effort is not working out on my end, and I've decided to tackle the problem with different method. It's just I got to move on for now and possibly come back to this later.  

By all means, this thread can be used for if any of you wish to post moderation to the scripts given if they will prove to be more successful in the testing stage for anybody else who wishes to do something like this in their game.


tzachs

Have you read the manual of the character control module (which Mr Matti suggested)?
What you're trying to do can be done relatively easily with this module, just do something like:

Code: ags

CharacterControl.CreateChain(1, "ROOM:1,0,50; WALK:50,50; WALK:70,70, SAY:|I'll just stay here for a while|;  ANIMATE:4,1,0,20; WALK:0,0, ROOM:2,0,50; WAIT:200; GOTO:1");

CharacterControl.StartExecuting(cMustard, 1);


This will make colonel mustard change to room 1, walk a little, speak, animate something, walk out of the room, change to room 2 and wait... and then the chain will start all over again...

monkey0506

#36
Sorry if I might've come across a bit stand-offish. Reading back through it, it seems like I may have...

Quote from: RickJ on Wed 14/10/2009 04:58:40So monkey is it the case here, that the function call and the import statement match each other but not the function definition?

That's right. Either 1) the function isn't defined at all OR 2) the function is defined with the wrong name.

Probably the easiest way of tracking this problem down would be:

1) Comment all the imports in the script header.
2) Comment/remove any calls to these functions in OTHER scripts (not the script you're defining the functions in).
3) Build.

You should get a compile-time error then telling you that the function you're calling doesn't exist. Then you have to find where the appropriate function is and correct the names. Once this compiles correctly, uncomment the imports and any function calls in other scripts. It should then be running correctly.

Edit: I appear to have gotten it working on my system with a few changes, though none of them involved function names at this point... ::)

Code: ags
// script header

// Define the max number of locations a NPC can be in
#define MAX_LOCATIONS 10

// Define the max number of suspects 
#define MAX_SUSPECTS   10

import function InitializeSuspect(this Character*, int idx);
import function SetSuspectLocation(this Character*, int dwell_time, int room, int x, int y);
import function MoveSuspect(this Character*, bool sequential);

// script body

// Define the info needed for each suspect (npc) and their possible locations 
struct suspect {
   Character *Ptr;                              // Pointer to character
   int Location;                                   // Current location index  
   int DwellCount;                              // Time in current location  
   int DwellTime[MAX_LOCATIONS];   // Time to stay in each location
   int Rm[MAX_LOCATIONS];          // Room number for each location
   int X[MAX_LOCATIONS];                 //  X coordniate for each location
   int Y[MAX_LOCATIONS];                 //  Y coordniate for each location
};

// Create an array of suspects, one for each character.
suspect Suspect[MAX_SUSPECTS];

// Create some functions that use or manipulate the suspect info

// This function returns the index of specified suspect character 
int chridx(Character *ptr) {
   int i, idx;

   idx = -1;   // Return -1 if not found
   i = 0;
   while (i<MAX_SUSPECTS) {
      if (Suspect[i].Ptr==ptr) {
         idx = i;                        // return the index of found character
         i = MAX_SUSPECTS;    // Break loop
      }
      i++;
   }
   return idx;
}

// This function initializes each of the suspect characters
function InitializeSuspect(this Character*, int idx) {
   int i;

   if ((idx<0)||(idx>=MAX_SUSPECTS)) {
      Display("*** Error-InitializeSuspect, idx must be in the range 0 - %d", MAX_SUSPECTS-1);
   }
   else {
      Suspect[idx].Ptr = this;
      Suspect[idx].Location = 0;
      Suspect[idx].DwellCount = 0;
 
      i = 0;
      while (i<MAX_LOCATIONS) {
         Suspect[idx].DwellTime[i] = 0;
         Suspect[idx].Rm[i] = -1;
         Suspect[idx].X[i] = 0;
         Suspect[idx].Y[i] = 0;
         i++;
      }
   } 
}

// This function sets up a suspect character location 
function SetSuspectLocation(this Character*, int dwell_time, int room, int x, int y) {
  int idx;  
  int location;

  // Find the character 
  idx = chridx(this);
  if (idx<0) {
    Display("*** Error-SetSuspectLocation, idx must be in the range 0 - %d", MAX_SUSPECTS-1);
  }
  else if (Suspect[idx].Location<0) {
    Display("*** Error-SetSuspectLocation, not initialized, call InitializeSuspect(() befor calling this function");
  }
  else if (Suspect[idx].Location>=MAX_LOCATIONS) {
    Display("*** Error-SetSuspectLocation, max number of locations, %d,  exceeded", MAX_LOCATIONS-1);
  }
  else {
    Suspect[idx].Ptr = this;
    Suspect[idx].DwellCount = 0;
    Suspect[idx].DwellTime[Suspect[idx].Location] = dwell_time;
    Suspect[idx].Rm[Suspect[idx].Location] = room;
    Suspect[idx].X[Suspect[idx].Location] = x;
    Suspect[idx].Y[Suspect[idx].Location] = y;
    Suspect[idx].Location++;
  }
}

// This function moves the suspect character from location to location
function MoveSuspect(this Character*, bool sequential) { 
  int idx;  
  int next_location;

  // Find the character 
  idx = chridx(this);
  if (idx<0) {
    Display("*** Error-MoveSuspectLocation, idx must be in the range 0 - %d", MAX_SUSPECTS-1);
  }
  else if (Suspect[idx].DwellCount>=0) {
    Suspect[idx].DwellCount--;
  }
  else {
    // Go to next location either sequentially or randomly
    if (sequential) {
      Suspect[idx].Location++;
      if (Suspect[idx].Location>=MAX_LOCATIONS) Suspect[idx].Location = 0;
      if (Suspect[idx].Rm[Suspect[idx].Location] == -1) Suspect[idx].Location = 0;
    }
    else {
      Suspect[idx].Location = Random(MAX_LOCATIONS-1);
      int i = 0;
      while ((Suspect[idx].Rm[Suspect[idx].Location] == -1) && (i < 150000)) {
        Suspect[idx].Location = Random(MAX_LOCATIONS-1);
        i++;
      }
      if (i > 150000) {
        Display("*** Error-MoveSuspectLocation, no valid locations found.");
        Suspect[idx].Location = 0;
      }
    }
    // Setup the dwell timer for the new location
    Suspect[idx].DwellCount = Suspect[idx].DwellTime[Suspect[idx].Location]; 

    if ((Suspect[idx].Ptr.Room==player.Room) || (Suspect[idx].Rm[Suspect[idx].Location]==player.Room)) {
      // Don't allow suspects to vanish from room where player character is
      // Also don't allow suspects to materialize in same room as player character
      Suspect[idx].Ptr.Walk(Suspect[idx].X[Suspect[idx].Location], Suspect[idx].Y[Suspect[idx].Location]);
    }
    else {
      // Setup the character's room and position for the new location
      Suspect[idx].Ptr.ChangeRoom(Suspect[idx].Rm[Suspect[idx].Location], Suspect[idx].X[Suspect[idx].Location], Suspect[idx].Y[Suspect[idx].Location]);
    }
  }
}

function game_start() {
  cMustard.InitializeSuspect(0);
  cMustard.SetSuspectLocation(200, 1, 100, 100);  // dwell_time, room, x, y 
  cMustard.SetSuspectLocation(200, 2, 100, 100);
  cMustard.SetSuspectLocation(200, 3, 100, 100);
  cMustard.SetSuspectLocation(200, 4, 100, 100);
  cMustard.SetSuspectLocation(200, 5, 100, 100);
  cMustard.SetSuspectLocation(200, 6, 100, 100);

  cPlum.InitializeSuspect(1);
  cPlum.SetSuspectLocation(200, 1, 100, 100);  // dwell_time, room, x, y
  cPlum.SetSuspectLocation(200, 2, 100, 100);
  cPlum.SetSuspectLocation(200, 3, 100, 100);
  cPlum.SetSuspectLocation(200, 4, 100, 100);
  cPlum.SetSuspectLocation(200, 5, 100, 100);
  cPlum.SetSuspectLocation(200, 6, 100, 100);
}

function repeatedly_execute() {
  cMustard.MoveSuspect(false);   // Move him randomly
  cPlum.MoveSuspect(true);         // Move him sequentially
}



Changes (to code presently in Rick's post):

  • In function "MoveSuspect" under the final else clause, you attempt to directly modify Character.Room which is read-only. Changed that to use Character.ChangeRoom instead.
  • Function "SetSuspectLocation" was using Suspect.Location as an index for adding a location but was resetting it every time. Removed line "Suspect[idx].Location = 0;" to resolve this.
  • Added check in function "MoveSuspect" to make sure we're only working with valid locations (added as loop for randomized locations, otherwise resets location to 0).
  • Added call to Character.Walk to actually make the character move to the specified location. Without this they don't move at all (i.e., if they have more than one location in the same room)! (May possibly want to use eWalkAnywhere? I didn't specify)
  • Corrected some uses of MAX_SUSPECTS instead of MAX_LOCATIONS and changed Suspect.Room to Suspect.Rm so AGS would stop detecting collisions (as mentioned previously).
  • A couple of other typos such as "in" instead of "int", "furnction" instead of "function" were corrected.

    Hopefully this should get you where you need to be.

RickJ

Quote
Sorry if I might've come across a bit stand-offish. Reading back through it, it seems like I may have...
I didn't take it that way at all.   I appreciate the effort because as I said I had a similar error that drove me crazy and it went away without  me coming to understand what was really going on.  I also appreciate your taking the time to debug the code in my post.  Hopefully I'll get my workstation up this week.

SMF spam blocked by CleanTalk