Npc - Repeat Actions

Hi All.

I'm still having problems with this issue.

I have an NPC that I want to patrol between a series of rooms, then repeat.
So in the 'List of actions to perform I have:

GoTo:room5
GoTo:room1

In the 'NPC script' box at the bottom of the screen I have:

this.deletefromlist = false

For some reason this is not working, and I don't know what I'm doing wrong.

Any help is greatly appreciated. Thanks.


for this example:

IMPORTANT: for the way I got the code design, the npc can't start in the first room of the order of destination rooms (so for this example, npc can't start in room1)

the npc changes its location when the player changes his/her location (if you want it to happen differently, and need help, let me know)

the order of destinations is the order of added rooms to the 'npc.destination_objectlist_attribute', which is then looped ( the increment and looping is done by the npc.changedparent's scripting/code-line of: this.iterator_integer_attribute = (this.iterator_integer_attribute + 1) % this.destination_quantity_integer_attribute ):

room1 -> room2 -> room3 -> room4 -> room5 -> room1

(if you want control or randomness, this requires a bit more and different coding required to handle it, well, the randomness isn't that much of a difference nor much code work, but the control is quite different and much more code work)

when the npc's location changes, it's iterator is incremented, which causes it to be set for going to its next destination, for when the next time its destination change occurs

room1: objectlist index 0: npc.iterator_integer_attribute = 0: modulus operation of 0 % 5 = 0 (and 5 % 5 = 0 ---> this is the looping of the destination: room5 -> room1)

room2: objectlist index 1: npc.iterator_integer_attribute = 1: modulus operation of 1 % 5 = 1

room3: objectlist index 2: npc.iterator_integer_attribute = 2: modulus operation of 2 % 5 = 2

room4: objectlist index 3: npc.iterator_integer_attribute = 3: modulus operation of 3 % 5 = 3

room5: objectlist index 4: npc.iterator_integer_attribute = 4: modulus operation of 4 % 5 = 4


for an example:

initial/starting locations:

player: room0
npc: room0
(player and npc ARE in the same room)

let's say the player goes/moves to room1
which causes npc to be moved to room1
(player and npc ARE in the same room)

let's say the player goes/moves to room5
which causes npc to be moved to room2
(player and npc are NOT in the same room)

let's say the player goes/moves to room3
which causes the npc to be moved to room3
(player and npc ARE in the same room)

let's say the player goes/moves to room2
which causes the npc to be moved to room4
(player and npc are NOT in the same room)

let's say the player goes/moves to room4
which causes the npc to be moved to room5
(player and npc are NOT in the same room)

let's say the player goes/moves to room1
which causes the npc to be moved to room1
(player and npc ARE in the same room)


<object name="player">

  <inherit name="editor_object" />
  <inherit name="editor_player" />

  <attr name="parent" type="object">room0</attr>

  <attr name="changedparent" type="script">

    npc.parent = ObjectListItem (npc.destination_objectlist_attribute, npc.iterator_integer_attribute)

  </attr>

</object>

<object name="npc">

  <inherit name="editor_object" />

  <attr name="parent" type="object">room0</attr>

  <attr name="iterator_integer_attribute" type="int">0</attr>

  <attr name="destination_quantity_integer_attribute" type="int">5</attr>

  <attr name="changedparent" type="script">

    this.iterator_integer_attribute = (this.iterator_integer_attribute + 1) % this.destination_quantity_integer_attribute

  </attr>

  <destination_objectlist_attribute type="objectlist">

    <value>room1</value>
    <value>room2</value>
    <value>room3</value>
    <value>room4</value>
    <value>room5</value>

  </destination_objectlist_attribute>

</object>

<object name="room0">

  <inherit name="editor_room" />

</object>

<object name="room1">

  <inherit name="editor_room" />

</object>

<object name="room2">

  <inherit name="editor_room" />

</object>

<object name="room3">

  <inherit name="editor_room" />

</object>

<object name="room4">

  <inherit name="editor_room" />

</object>

<object name="room5">

  <inherit name="editor_room" />

</object>

the modulus operation (modulus operator: %) is division, except it gets the REMAINDER value, which makes it great for cyclic handling (and also odd/even of a number and factors/divisibilities of a number):

for understanding division vs modulus:

0 / 5 = Quotient:0 and Remainder:0
0 % 5 = Remainder:0

1 / 5 = Quotient:0 and Remainder:1
1 % 5 = Remainder:1

2 / 5 = Quotient:0 and Remainder:2
2 % 5 = Remainder:2

3 / 5 = Quotient:0 and Remainder:3
3 % 5 = Remainder:3

4 / 5 = Quotient:0 and Remainder:4
4 % 5 = Remainder:4

5 / 5 = Quotient:1 and Remainder:0
0 % 5 = Remainder:0

6 / 5 = Quotient:1 and Remainder:1
6 % 5 = Remainder:1

7 / 5 = Quotient:1 and Remainder:2
7 % 5 = Remainder:2

8 / 5 = Quotient:1 and Remainder:3
8 % 5 = Remainder:3

9 / 5 = Quotient:1 and Remainder:4
9 % 5 = Remainder:4

10 / 5 = Quotient:2 and Remainder:0
10 % 5 = Remainder:0

11 / 5 = Quotient:2 and Remainder:1
11 % 5 = Remainder:1

etc etc etc

19 / 5 = Quotient:3 and Remainder:4
19 % 5 = Remainder:4

20 / 5 = Quotient:4 and Remainder:0
20 % 5 = Remainder:0

21 / 5 = Quotient:4 and Remainder:1
21 % 5 = Remainder:1

etc etc etc

civilian hours (0-11 am/pm):

0 hour % 12 = 0 am/pm = midnight (12:00 pm->am) or noon/midday (12 am->pm)
1 hour % 12 = 1 am/pm
2 hour % 12 = 2 am/pm
3 hour % 12 = 3 am/pm
4 hour % 12 = 4 am/pm
5 hour % 12 = 5 am/pm
6 hour % 12 = 6 am/pm (dawn/sunrise or dusk/sunset)
7 hour % 12 = 7 am/pm
8 hour % 12 = 8 am/pm
9 hour % 12 = 9 am/pm
10 hour % 12 = 10 am/pm
11 hour % 12 = 11 am/pm
12 hour % 12 = 0 am/pm = midnight (12:00 pm->am) or noon/midday (12 am->pm)
13 hour % 12 = 1 am/pm

military hours (0-23 am/pm: 0-11 am, 11-23 pm):

0 hour % 24 = 0 am/pm = midnight (12:00 pm->am)
1 hour % 24 = 1 am
2 hour % 24 = 2 am
3 hour % 24 = 3 am
4 hour % 24 = 4 am
5 hour % 24 = 5 am
6 hour % 24 = 6 am (dawn/sunrise)
7 hour % 24 = 7 am
8 hour % 24 = 8 am
9 hour % 24 = 9 am
10 hour % 24 = 10 am
11 hour % 24 = 11 am
12 hour % 24 = 12 am/pm = noon/midday (12 am->pm)
13 hour % 24 = 13 pm
14 hour % 24 = 14 pm
15 hour % 24 = 15 pm
16 hour % 24 = 16 pm (dusk/sunset)
17 hour % 24 = 17 pm
18 hour % 24 = 18 pm
19 hour % 24 = 19 pm
20 hour % 24 = 20 pm
21 hour % 24 = 21 pm
22 hour % 24 = 22 pm
23 hour % 24 = 23 pm
24 hour % 24 = 0 am/pm = midnight (12:00 pm->am)
25 hour % 24 = 1 am


In the 'NPC script' box at the bottom of the screen I have:

As far as I can tell, that script is run when it comes to a "Script:" line in the NPC's actions list. setting deletefromlist to false causes the "Script:" action to be run again next turn.

What you probably want is in the 'List of actions to perform':

Script:room5
Script:room1

In the 'NPC script' box at the bottom of the screen:

NpcGoTo (this, item)
list add (this.actions, ListItem(this.actions, 0))

That basically means that "Script:" acts the same as "GoTo:", but after executing the action it is added to the end of the NPC actions list again.

Or… if you end up wanting NPCs to repeat actions a lot, you could change the NpcAct function to something like:

  <function name="NpcAct" parameters="npc, s" type="boolean">
    ary = Split(s, ":")
    if (ListCount(ary) = 1) {
      PrintIfHere (npc.parent, s)
      f = true
    }
    else {
      objname = StringListItem(ary, 1)
      if (objname = "") {
        game.currentobj = null
      }
      else {
        game.currentobj = GetObject (objname)
        if (game.currentobj = null) {
          error ("Failed to find object in NpcAct: " + objname)
        }
      }
      action = StringListItem(ary, 0)
      cycle = false
      if (Left (action, 1) = "@") {
        action = Mid (action, 2)
        cycle = true
      }
      game.currentnpc = npc
      f = Eval("Npc" + action + "(game.currentnpc, game.currentobj)")
      if (f and cycle) {
        list add (npc.actions, s)
      }
    }
    return (f)
  </function>

In that case, you could have the actions list like:

@GoTo:room1
@GoTo:room5

with the @ sign meaning "after doing this action, add it to the end of the list to do again". Basically gives you an easy way to repeat some or all of an NPC's actions.


@HK: I think that code has issues.

You've removed the existing behaviour from player.changedparent, which does things such as calling room enter/exit scripts, updating the map, and showing the new room description.


Edit: Sorry if there's mistakes in my code. I've had a complete emotional breakdown and am mostly non-functional. I also have never used NpcLib and don't have Quest installed here, so I'm trying to diagnose your problem just by skim-reading the code for the library.


oops, sorry about that! (didn't realize the issue with using the 'changedparent' on a Player Object and its over-riding of all of quest's built-in functionality with it)


I can't quite make sense of this, but there's probably/maybe a way to get at the 'oldvalue' for the 'changedparent' Script on a Player Object:

http://docs.textadventures.co.uk/quest/change_scripts.html (the oldvalue variable section)

or... using the 'OnEnterRoom', but I'm not sure how it works... as it's not explained here... (I'd have to go look/find it in the quest code... which probably I can't be able to find it... argh)

or... just find/get the built-in code, and re-add it in to the over-ridden 'changedparent' Script of a Player Object... meh


@HK:

or... just find/get the built-in code, and re-add it in to the over-ridden 'changedparent' Script of a Player Object... meh

Yeah, that's the only realistic way to do it. I've looked at that a few times now for various reasons. It's not really elegant, but it works.

The script on the defaultobject type is:

    <changedparent type="script">
      if (game.pov = this) {
        if (IsDefined("oldvalue")) {
          OnEnterRoom(oldvalue)
        }
        else {
          OnEnterRoom(null)
        }
        if (game.gridmap) {
          MergePOVCoordinates
        }
      }
      this.hasbeenmoved = true
    </changedparent>

So you'd want to make sure you don't remove that unless you're sure some of those features aren't necessary.


Oooh, here's another way to do it.

NPC actions:

Script:
GoTo:room1
GoTo:room2

And the 'NPC script' would be:

this.actions = ListCombine (this.actions, this.actions)

The only issue there is that the NPC would take a turn queueing up the second copy of their actions list. Unless you made the NPC Script:

this.actions = ListCombine (this.actions, this.actions)
list remove (this.actions, "Script:")
do (this, "takeaturn")
this.deletefromlist = false

This duplicates the list of actions, removes the "Script:" action from it, and immediately runs the next action in the queue.

Or you could have an exit on the NPC's route with an npcallowedtouse script attribute, which adds items to the NPC's actions list. So when the NPC leaves room 1 through that exit, it adds "GoTo:room1" to the end of the list.


Wow, thanks guys.

Really appreciate all your help and experience.


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

Support

Forums