NPC Doing...

I know I've seen this on one of the forum questions, but I can't seem to find it.
Maybe I'm using an old library as well.

I've just set up an NPC, and at the bottom it says; 'Doing NPC...'
I think I read somewhere that Pixie put this in as a check to see what the NPC was doing, but how do I get rid of the message.
Is there a checkbox I can use or some coding that goes into the start script.

Any help is appreciated.


I thought I had then, rereading the documentation, it mentions game.npcdebug and setting it to either true or false. The information to help you debug what the npc is doing is displayed in blue.

This is something else. Arghhh


Looks like I left in a line I was using for debugging. Open the library up in a text editor, and delete line 96:

          msg("Doing " + o.name)

Found it. Thanks Pixie.
Also, didn't realise there was a new version of 'NpcLib'. So updated that too.
Is it still beta testing? Will the tutorial notes be updated too, or are they now included in the library on the various tabs?


One further question.

I want my NPC character to patrol a route, starting from position A to B to C, then B and back to A and repeat.

I thought I'd found the answer by inserting this.deletefromlist = false into the script at the bottom, but it doesn't appear to be working.

What am I doing wrong.


Io

Way I'd do this is have the attribute NPC.RoomID as an Integer. So if say, A to B to C, then back to B, then to A, it goes something like this. And pardon my psuedocode:

Switch based on NPC.RoomID:
case(1): Move NPC to A, set NPC.RoomID=2
case(2): Move NPC to B, set NPC.RoomID=3
case(3): Move NPC to C, set NPC.RoomID=4
case(4): Move NPC to B, set NPC.RoomID=1

Let me clarify:

There is a tab called NPC Actions, I've put into the box at the top, 'List of actions to perform',

GoTo:RoomA
GoTo:RoomB
GoTo:RoomC
GoTo:RoomB
GoTo:RoomA

Then there is a box on the same tab at the bottom, 'NPC script (run with Npc Script)', where I have then inserted the code
this.deletefromlist = false, not sure what I've done wrong, but the NPC character is not repeating the list of actions.


Further to my previous issue regarding having the NPC character repeat a pattern. I have come across another problem.

Ask/Tell NPC to follow.

The NPC says okay, and looks at you expectantly. When I then move to a new location, I'm hit with the error message;
Error running script: Object reference not set to an instance of an object.

Asking the NPC to sit or stand or crouch is ok, but asking the NPC to follow results in this message. Do I need to set up an attribute on the NPC.

Any help with this question, and the previous one, will be greatly appreciated.


K.V.

The stuff I see in the library which concerns following (ignoring the "stop following" bits):

  <command name="go">
    <pattern type="string"><![CDATA[^go to (?<exit>.*)$|^go (?<exit>.*)$|^(?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$]]></pattern>
    <unresolved>[UnresolvedLocation]</unresolved>
    <script>
      old = game.pov.parent
      if (exit.visible) {
        if (ExitCheck(exit)) {
          // nothing
        }
        else if (exit.locked) {
          msg (exit.lockmessage)
        }
        else if (exit.runscript) {
          StandUp
          if (HasScript(exit, "script")) {
            do (exit, "script")
          }
        }
        else if (exit.lookonly) {
          msg ([UnresolvedLocation])
        }
        else {
          StandUp
          if (HasString(exit, "message")) {
            if (not exit.message = "") {
              if (game.clearscreenonroomenter) {
                game.currentexitmessage = exit.message
              }
              else {
                msg (exit.message)
              }
            }
          }
          game.pov.parent = exit.to
        }
      }
      else {
        msg ([UnresolvedLocation])
      }

THE BIT WHICH INVOLVES FOLLOWING:

      if (not old = game.pov.parent) {
        foreach (npc, FilterByAttribute(AllObjects(), "following", game.pov)) {
          do (npc, "followplayer")
        }
      }
    </script>
</command>

NOTE: I don't see followplayer anywhere else in the code in this library.

Perhaps that is the missing script attribute?

...or maybe that snippet should be:

      if (not old = game.pov.parent) {
        foreach (npc, FilterByAttribute(AllObjects(), "following", game.pov)) {
          NpcFollow (npc, npc.following)
        }
      }

This is untested.


The rest of this is just the other related code snippets (with no notes from me):

  <command name="cmd_tell_to_follow">
    <pattern type="string"><![CDATA[^((tell|ask) (?<objectnpc>.*) to|(?<objectnpc>.*),) (follow me|follow)$]]></pattern>
    <script>
      if (not DoesInherit(objectnpc, "NpcType")) {
        msg(DynamicTemplate("PosturesNotNpc", objectnpc))
      }
      else {
        do (objectnpc, "requestfollow")
      }        
    </script>
</command>

    <requestfollow type="script">
      do (this, "checkagreement", QuickParams("command", "follow"))
      if (this.complies) {
        if (this.following = game.pov) {
          msg ("'I am!' says " + GetDefiniteName(this) + ".")
        }
        else {
          msg ("'" + this.yesmsg + "' says " + GetDefiniteName(this) + ", looking expectantly at you.")
          this.following = game.pov
        }
      }
</requestfollow>


  <function name="NpcFollow" parameters="npc, obj" type="boolean">
    if (not npc.parent = obj.parent) {
      NpcGoTo(npc, obj.parent)
    }
    else if (HasAttribute(npc, "followidle")) {
      msg(PickOneString(npc.followidle))
    }
    return (false)
</function>


That seems to work KV, but now the NPC won't stop following you, even when you tell it to stop following you, wait, desist or all other manner of obscenities, the NPC wont leave you alone.


K.V.

Curses!

Hrmm... I'm not around a PC, but maybe...

It's probably wise to avoid changing too much code, so, instead of changing that code to call the NpcFollow function, perhaps adding a followplayer script attribute to each NPC (a script which calls the NpcFollow function) would alter the outcome?

Hrmm...

I'll have access to a PC this afternoon, and I'll see what I can deduce if no one has posted a solution by then.


I tried altering 'requestwait' attribute of the NPC, changing the last else statement from

msg ("'" + this.yesmsg + "' says " + GetDefiniteName(this) + ", tapping " + this.possessive + " foot.")
this.following = game.pov

to

msg ("'" + this.yesmsg + "' says " + GetDefiniteName(this) + ", tapping " + this.possessive + " foot.")
this.following = null

and that seems to have done the trick.

But I also noted something else as I was messing about, trying different commands.
When asking the NPC to sit, lie down, etc, the NPC does it. Then ask the NPC to follow, move to the next room, the NPC follows you to the next room, still sitting, lying down, etc.


Also, just noted something else.

If the NPC, has a list of actions, and as it passes you(i.e. is in the same room as you, on it's way to complete its list of actions), you tell the NPC to follow, it carries on with its list of actions, then it follows you, (always the number of uncompleted actions behind, when you asked the NPC to follow), stalking you as it were, until you double back and are in the same room again.


Thought I was onto something then: I've modified the npc_type requestfollow script as follows

do (this, "checkagreement", QuickParams("command", "follow"))
if (this.complies) {
  if (this.following = game.pov) {
    msg ("'I am!' says " + GetDefiniteName(this) + ".")
  }
  else {
    msg ("'" + this.yesmsg + "' says " + GetDefiniteName(this) + ", looking expectantly at you.")
    this.following = game.pov
  }
}
// Checks to see if "actions" has been set up (meaning at least on action has been added) to avoid errors.
if (HasAttribute(this, "actions")) {
  if (ListCount(this.actions) > 0) {
    foreach (s, this.actions) {
      list remove (this.actions, s)
      PrintIfDebug (this, "Deleted")
    }
  }
}

The NPC's list of actions is deleted, but now I get the error message
'Collection was modified; enumeration operation may not execute.'

Rethink!!!


'Collection was modified; enumeration operation may not execute.'

You can't modify a list inside a foreach loop.

Your code:

    foreach (s, this.actions) {
      list remove (this.actions, s)
      PrintIfDebug (this, "Deleted")
    }

could be updated to:

    foreach (s, ListExclude (this.actions, "")) {
      list remove (this.actions, s)
      PrintIfDebug (this, "Deleted")
    }

forcing the foreach to apply to a copy of the list, allowing you to remove each one from the original list.

Or you could use a much quicker way to remove all elements from a list:

this.actions = NewList()

(or NewObjectList or NewStringList if appropriate)

(the remainder of this post is me going off at a tangent; but might be helpful to anyone having the same error in slightly different circumstances. Or might be something useful for you to know in future)

If you want to print a message for each item removed, or if a future modification might require you to do something with each one before removing it, you could do:

while (ListCount (this.actions) > 0) {
  s = ListItem (this.actions, 0)
  list remove (this.actions, s)
  PrintIfDebug (this, "Deleted "+ToString(s))
}

(and I'm completely digressing now, but a useful paradigm if you want to test and remove some elements from a list would be:

i = 0;
while (ListCount (this.actions) > i) {
  s = ListItem (this.actions, i)
  if (IsUrgentAction (s)) {
    i = i + 1
    PrintIfDebug (this, "Didn't delete "+ToString(s))
  }
  else {
    list remove (this.actions, s)
    PrintIfDebug (this, "Deleted "+ToString(s))
  }
}

(this might be useful if some actions are "urgent". For example, an NPC who is on fire might still want to put himself out before following you, but forget all other queued actions. The variable i is only incremented if an item remains in the list, because if you remove item 0 from the list then the next item is now in slot 0. I know it's a silly example, but the "remove an item or increment the list counter" loop is a useful trick to know)


Thanks mrangel, your first code

foreach (s, ListExclude (this.actions, null)) {
      list remove (this.actions, s)
      PrintIfDebug (this, "Deleted")
    }

produced an error, too ambiguous, but the second code

while (ListCount (this.actions) > 0) {
  s = ListItem (this.actions, 0)
  list remove (this.actions, s)
  PrintIfDebug (this, "Deleted "+ToString(s))
}

seems to work, now to put it into the other bits of code it might affect, and alter the fact that the NPC can follow you while their lying down, and WAHEY!!!

Anyone got any ideas on how I can have a list of actions repeat, as I posted a bit further up the page.
I get myself side-tracked with little bits of coding.


Sorry to harp on about this thing, but once I get something into my head, sometimes I can't let go.

If you tell an NPC character to 'follow you', then change your mind and tell them to 'sit down' or whatever, then move in any direction, would you expect that character to follow you?

At the moment they follow you, still in the posture you have just given them.

But, I was thinking, maybe they should still be stuck there, until you again ask/tell that NPC character to 'follow you.

Any thoughts...


Io

I would indeed expect them to just sit in one place until you tell them to again follow you. The description you gave gives me the impression of someone sitting on air, sliding along the ground after you like a bad flash animation.


Yes, If there is, lets say a bed in the room, you tell the NPC to get on the bed, displayed in the 'Places and Objects' box, will be
NPC (reclining on bed)
tell NPC to follow, Okay. You then move and the NPC follows you, but it still says 'NPC (reclining on bed)'.
If you tell them to get of the bed, your met with the message, 'I can't see that (bed)'


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums