NPC states - The Old and The New

NPC states - The Old and The New

Postby Batlin on Fri Dec 31, 2010 9:10 am

I was working on decoding and understanding more of the NPC AI and I suddenly stumbled upon an uncalled function inside the EXE. I documented the function and named it "FUNC_GetNPCstateString". This is a screenshot of the function:
FUNC_GetNPCstateString.png
FUNC_GetNPCstateString.png (95.25 KiB) Viewed 51 times
This is the C version of the same function:
Code: Select all
const char *GetNPCstateString(int NPCstate)
{
  const char *result;

  switch(NPCstate)
  {
    case 0x00:
      result = "Seek Food";
      break;
    case 0x01:
      result = "Seek Shelter";
      break;
    case 0x02:
      result = "Purse Shelter";
      break;
    case 0x03:
      result = "Seek Desires";
      break;
    case 0x04:
      result = "Purse Desires";
      break;
    case 0x05:
      result = "Eat Food";
      break;
    case 0x06:
      result = "Loiter";
      break;
    case 0x07:
      result = "Runaway";
      break;
    case 0x08:
      result = "Talking";
      break;
    case 0x09:
      result = "Attack Target";
      break;
    case 0x0A:
      result = "Idle";
      break;
    case 0x0B:
      result = "Wander";
      break;
    case 0x0C:
      result = "Sleep";
      break;
    case 0x0D:
      result = "Following";
      break;
    default:
      result = "Unknown State";
  }
  return result;
}


In the past I had already found an unused function that would SuperBark the current state of the NPC. However, that function did not match the actual states being used inside the core and scripts. Here's a screenshot of that function:
FUNC_SuperBarkNPCstate__OLD.png
FUNC_SuperBarkNPCstate__OLD.png (96.88 KiB) Viewed 51 times
Again, the C version:
Code: Select all
void FUNC_SuperBarkNPCstate__OLD(NPC *NPCobject)
{
  const char *result;
  char TempStringBuffer[512];

  switch(NPCobject->CurrentState)
  {
    case 0x00:
      result = "Wander";
      break;
    case 0x01:
      result = "Pursue";
      break;
    case 0x02:
      result = "Runaway";
      break;
    case 0x03:
      result = "Combat";
      break;
    case 0x04:
      result = "Following";
      break;
    case 0x05:
      result = "Talking";
      break;
    case 0x06:
      result = "Loiter";
      break;
    case 0x07:
      result = "Sleep";
      break;
    case 0x0A:
      result = "Idle";
      break;
    default:
      result = "Bad State";
  }

  // Format the state into nice output
  sprintf(TempStringBuffer, "myState: %d  (%s)", NPCobject->CurrentState, result);

  // Bark the nicely formatted state
  NPCobject->SuperBark(TempStringBuffer, -1, -1, -1);
}
If you look closely you will see I added the tag __OLD to the function because it dates most probably from an older period in OSI's UO development.

How did I know which state function is the correct one? Well, the biggest clue is the sleep-state. In the first function I posted that equals state 0x0C, in the other one it is 0x07. There is a script command "goSleep". Let's take a look at that one:
COMMAND_GoSleep.png
COMMAND_GoSleep.png (33.58 KiB) Viewed 51 times
For most people, the C version:
Code: Select all
int COMMAND_goSleep(int NPCserial, int SleepTimeInTicks, int PostSleepState)
{
  int result;

  // Validate the PostSleepState
  if(PostSleepState >= 0 && PostSleepState < 14)
  {
    // Ensure the given NPC is really a NPC object
    NPC NPCobject = ConvertObjectBySerialToNPCobject(NPCserial, "setNPCState");
    if(NPCobject != NULL)
    {
      // Go set the actual sleep state
      NPCobject->GoSleep(SleepTimeInTicks, PostSleepState);
      result = 1;
    }
    else
      result = 0;
  }
  else
    result = 0;

  return result;
}
The most important thing we learn from this function is the range check of the PostSleepState. This range equals the switch/case-statement in the top function. Next, let's look at the actual NPC class function GoSleep:
FUNC_NPCobject_GoSleep.png
FUNC_NPCobject_GoSleep.png (33.52 KiB) Viewed 51 times
At 0x004AB8D6 you see "push 0x0C", this is the NewState being set when the NPC goes into sleep state. Perfect match with that first function.

Thank you OSI for leaving those 2 functions in there, it's gonna be a whole lot easier to understand the NPC AI now and it gives a glimp from your old AI. More to come, but that's going to be for the new year, old year is today. Happy holidays to you all!
<Derrick> RunUO AI is kind of a functional prototype, which i have hacked into something resembling OSI behavior, but only by complitcating everything
Batlin
Site Admin
 
Posts: 306
Joined: Wed Apr 08, 2009 6:35 am


Re: NPC states - The Old and The New

Postby Derrick on Fri Dec 31, 2010 6:21 pm

Nice thanks Batlin, and OSi :)
Hapy New Year!
Derrick
Site Admin
 
Posts: 250
Joined: Tue Jun 17, 2008 2:33 pm



Return to UO Demo

Who is online

Users browsing this forum: No registered users and 1 guest