NPC walking path
Groctel
30 Jun 2016, 10:19Hello fellow makers!
I have one small(1) problem with a room I am making.
I want to create a hall in which a guard npc moves in cycles, one square per turn. The point is to make it roam around the rooms that create the big open room (note that there are no doors involved anywhere here).
First of all, here's the room map:
Now, here's the part where I seem to fail horribly:
I know the code is NOT clean at all and that I lack a turn-based script, which I don't know how to use and would like to learn to too >.<
So, if ayone can help me... I would be really really really grateful
(1) The word small is open to interpretation.
I have one small(1) problem with a room I am making.
I want to create a hall in which a guard npc moves in cycles, one square per turn. The point is to make it roam around the rooms that create the big open room (note that there are no doors involved anywhere here).
First of all, here's the room map:
____ ____ ____ ____ ____ ____ ____
| | | | | | | |
| NW | N1 | N2 | N3 | N4 | N5 | NE |
|____|____|____|____|____|____|____|
| | | |
| W1 | | E1 |
|____| |____|
| | | |
| W2 | | E2 |
|____| |____|
| | | |
| W3 | | E3 |
|____|____ ____ ____ ____ ____|____|
| | | | | | | |
| SW | S1 | S2 | S3 | S4 | S5 | SE |
|____|____|____|____|____|____|____|
Now, here's the part where I seem to fail horribly:
while (Guard.movement = true) {
if (Guard.parent = N1) {
MoveObject (Guard, N2)
}
else if (Guard.parent = N2) {
MoveObject (Guard, N3)
}
else if (Guard.parent = N3) {
MoveObject (Guard, N4)
}
else if (Guard.parent = N4) {
MoveObject (Guard, N5)
}
else if (Guard.parent = N5) {
MoveObject (Guard, NE)
}
else if (Guard.parent = W1) {
MoveObject (GuardU, NW)
}
else if (Guard.parent = W2) {
MoveObject (Guard, W1)
}
else if (Guard.parent = W3) {
MoveObject (Guard, W2)
}
else if (Guard.parent = E1) {
MoveObject (Guard, E2)
}
else if (Guard.parent = E2) {
MoveObject (Guard, E3)
}
else if (Guard.parent = E3) {
MoveObject (Guard, SE)
}
else if (Guard.parent = S1) {
MoveObject (Guard, SW)
}
else if (Guard.parent = S2) {
MoveObject (Guard, S1)
}
else if (Guard.parent = S3) {
MoveObject (Guard, S2)
}
else if (Guard.parent = S4) {
MoveObject (Guard, S3)
}
else if (Guard.parent = S5) {
MoveObject (Guard, S4)
}
else if (Guard.parent = NW) {
MoveObject (Guard, N1)
}
else if (Guard.parent = NE) {
MoveObject (Guard, E1)
}
else if (Guard.parent = SW) {
MoveObject (Guard, W3)
}
else if (Guard.parent = SE) {
MoveObject (Guard, S5)
}
else {
}
}
}
I know the code is NOT clean at all and that I lack a turn-based script, which I don't know how to use and would like to learn to too >.<
So, if ayone can help me... I would be really really really grateful

(1) The word small is open to interpretation.
HegemonKhan
30 Jun 2016, 11:32Your code logic is fine (assuming you didn't mess up the room transitions ~ hard to tell as you don't have them in simple easy-to-see clockwise or counter clockwise order), what's the error/going wrong with it?
the 'while' in quest often causes problems... your guard probably is infinitely moving non-stop... your 'while' loop has nothing to terminate/stop it...
instead, you can either use a (global) Turnscript or add the special 'changed' Script Attribute to your 'player' Player Object, examples in code below
quest has internal turns, which increment (by 1), with every/any clicking of the mouse button on something clickable or entering something you typed-in into the command text box. You can add an Integer Attribute if you want those turns to be seen/displayed to the person playing the game.
(Global) Turnscript:
click on the upper left most 'object' (the root) in the left side's "tree of stuff" so it is highlighted (this will make the added Turnscript global: not added to a specific Room Object which would make it a 'local' Turnscript). Then in the menu bar at the top, under 'add', select 'Turnscript', and then add in your same scripting (except remove the 'while' Script from it). Check the 'enabled' check box. Or, you can add in more control over it, but let's not get into that unless you let me know you want to do so.
each internal turn (click or type) the guard will move to the next room, from the moment the game begins. Let me know if you want something different to happen or more control over what happens.
(I added in some extra stuff of my own... ask if you got any questions about any of it or about anything)
the special 'changed' Script Attribute:
(too lazy to describe what is going on here at the moment, lol ... hopefully you can figure it out... if not, ask me and I'll help/explain)
---------
a different method would be to use List Attribute and its iteration, but List usage is a bit more complex if you're new to quest and especially to coding.
----------
an entirely different method would be to give all of your Room Objects: 'x_coordinate' and 'y_coordinate' (and if you want to do 3D: 'z_coordinate') Integer Attributes, and then handle it in many various ways with coding... not going to get into the methods here though.
the 'while' in quest often causes problems... your guard probably is infinitely moving non-stop... your 'while' loop has nothing to terminate/stop it...
instead, you can either use a (global) Turnscript or add the special 'changed' Script Attribute to your 'player' Player Object, examples in code below
quest has internal turns, which increment (by 1), with every/any clicking of the mouse button on something clickable or entering something you typed-in into the command text box. You can add an Integer Attribute if you want those turns to be seen/displayed to the person playing the game.
(Global) Turnscript:
click on the upper left most 'object' (the root) in the left side's "tree of stuff" so it is highlighted (this will make the added Turnscript global: not added to a specific Room Object which would make it a 'local' Turnscript). Then in the menu bar at the top, under 'add', select 'Turnscript', and then add in your same scripting (except remove the 'while' Script from it). Check the 'enabled' check box. Or, you can add in more control over it, but let's not get into that unless you let me know you want to do so.
each internal turn (click or type) the guard will move to the next room, from the moment the game begins. Let me know if you want something different to happen or more control over what happens.
(I added in some extra stuff of my own... ask if you got any questions about any of it or about anything)
<game name="blah">
<attr name="turn" type="int">0</attr>
<status_attributes type="simplestringdictionary">turn = Turn: !</statusattributes>
</game>
// see how the Turnscript below, isn't inside of a Room Object, which makes it a global Turnscript:
<turnscript name="global_turnscript">
<enabled />
<script>
Guard_movement_function
game.turn = game.turn + 1
</script>
</turnscript>
<function name="Guard_movement_function">
if (Guard.movement) { // you don't need to use the '=true', as quest understands this shortened syntax form to be '=true'
if (Guard.parent = NW) {
MoveObject (Guard, N1) // the 'MoveObject' Script/Function and the 'parent' Attribute via 'Guard.parent = N2', do the exact same thing
}
else if (Guard.parent = N1) {
MoveObject (Guard, N2)
}
else if (Guard.parent = N2) {
MoveObject (Guard, N3)
}
else if (Guard.parent = N3) {
MoveObject (Guard, N4)
}
else if (Guard.parent = N4) {
MoveObject (Guard, N5)
}
else if (Guard.parent = N5) {
MoveObject (Guard, NE)
}
else if (Guard.parent = NE) {
MoveObject (GuardU, E1)
}
else if (Guard.parent = E1) {
MoveObject (Guard, E2)
}
else if (Guard.parent = E2) {
MoveObject (Guard, E3)
}
else if (Guard.parent = E3) {
MoveObject (Guard, SE)
}
else if (Guard.parent = SE) {
MoveObject (Guard, S5)
}
else if (Guard.parent = S5) {
MoveObject (Guard, S4)
}
else if (Guard.parent = S4) {
MoveObject (Guard, S3)
}
else if (Guard.parent = S3) {
MoveObject (Guard, S2)
}
else if (Guard.parent = S2) {
MoveObject (Guard, S1)
}
else if (Guard.parent = S1) {
MoveObject (Guard, SW)
}
else if (Guard.parent = SW) {
MoveObject (Guard, W3)
}
else if (Guard.parent = W3) {
MoveObject (Guard, W2)
}
else if (Guard.parent = W2) {
MoveObject (Guard, W1)
}
else if (Guard.parent = W1) {
MoveObject (Guard, NW)
}
}
</function>
the special 'changed' Script Attribute:
(too lazy to describe what is going on here at the moment, lol ... hopefully you can figure it out... if not, ask me and I'll help/explain)
<game name="blah">
<attr name="turn" type="int">0</attr>
<status_attributes type="simplestringdictionary">turn = Turn: !</statusattributes>
</game>
<object name="player">
<attr name="changedparent" type="script">
Guard_movement_function
// example: increment_turn_function (1)
</attr>
</object>
// add 'increment_turn_function (type_in_a_number_here_for_how_much_to_increment_your_turn_by)' into where-ever whatever script location you want, or via the GUI~Editor: 'where/what-ever' -> run as script -> add new script -> 'output' category (I believe) -> 'call function' Script -> type your function's name into the small rectangle text box, and however you add in your argument/parameter amount, lol - I'm not familiar with the GUI~Editor
<function name="increment_turn_function" parameters="amount">
if (IsInt (amount)) {
game.turn = game.turn + ToInt (amount)
} else {
msg ("Error in your code: You didn't enter an integer number for its argument/parameter")
}
</function>
<function name="Guard_movement_function">
if (Guard.movement) { // you don't need to use the '=true', as quest understands this shortened syntax form to be '=true'
if (Guard.parent = NW) {
MoveObject (Guard, N1) // the 'MoveObject' Script/Function and the 'parent' Attribute via 'Guard.parent = N2', do the exact same thing
}
else if (Guard.parent = N1) {
MoveObject (Guard, N2)
}
else if (Guard.parent = N2) {
MoveObject (Guard, N3)
}
else if (Guard.parent = N3) {
MoveObject (Guard, N4)
}
else if (Guard.parent = N4) {
MoveObject (Guard, N5)
}
else if (Guard.parent = N5) {
MoveObject (Guard, NE)
}
else if (Guard.parent = NE) {
MoveObject (GuardU, E1)
}
else if (Guard.parent = E1) {
MoveObject (Guard, E2)
}
else if (Guard.parent = E2) {
MoveObject (Guard, E3)
}
else if (Guard.parent = E3) {
MoveObject (Guard, SE)
}
else if (Guard.parent = SE) {
MoveObject (Guard, S5)
}
else if (Guard.parent = S5) {
MoveObject (Guard, S4)
}
else if (Guard.parent = S4) {
MoveObject (Guard, S3)
}
else if (Guard.parent = S3) {
MoveObject (Guard, S2)
}
else if (Guard.parent = S2) {
MoveObject (Guard, S1)
}
else if (Guard.parent = S1) {
MoveObject (Guard, SW)
}
else if (Guard.parent = SW) {
MoveObject (Guard, W3)
}
else if (Guard.parent = W3) {
MoveObject (Guard, W2)
}
else if (Guard.parent = W2) {
MoveObject (Guard, W1)
}
else if (Guard.parent = W1) {
MoveObject (Guard, NW)
}
}
</function>
---------
a different method would be to use List Attribute and its iteration, but List usage is a bit more complex if you're new to quest and especially to coding.
----------
an entirely different method would be to give all of your Room Objects: 'x_coordinate' and 'y_coordinate' (and if you want to do 3D: 'z_coordinate') Integer Attributes, and then handle it in many various ways with coding... not going to get into the methods here though.
Groctel
30 Jun 2016, 12:29Ok, I understood it all, I think.
I perfectly got how the turnscript works, but I don't know where in the code I have to implement the movement function
Also, I forgot to say that I want to create some more rooms exactly like this one. Do I have to make the turnscript global or do I just turn on and off the guards every time the player enters and leaves the room (don't worry about the position, that's already fixed, kinda)?
I perfectly got how the turnscript works, but I don't know where in the code I have to implement the movement function

Also, I forgot to say that I want to create some more rooms exactly like this one. Do I have to make the turnscript global or do I just turn on and off the guards every time the player enters and leaves the room (don't worry about the position, that's already fixed, kinda)?
HegemonKhan
01 Jul 2016, 04:00this post is just a brief repsonse... let me know if you're still confused and try to explain exactly what you want to do, so I can then try to be more specific and helpful
-----------------
left side's "tree of struff" :
Object
-> Game
->-> Verbs
->-> Commands
Functions <---------------- click on this, and add in your function (name it whatever you want), put/add your Guard_1 movement scripts into this Function
etc etc etc
A Function acts as like a storage spot for some action/event/scripting that you want (such as for moving your Guard_1), well there's more specifics about a Functions capabilities (but let's not get into that here), you can then add/use/call/put the Function into where-ever you want and as many of them as you want, via in the GUI~Editor: run as script -> add new script -> 'output' category I believe -> 'call function' -> skinny rectangle text box: your_functions_name -> Add arguments/parameters if you got any - not sure how this works in the GUI~Editor
A 'Function' Element is a container for scriptings (just like a Verb is), just as an 'Object' Element is a container for Attributes and/or other 'Object' Elements
for an example:
the 'testing 1 2 3' will be displayed when the game starts ('game' Game Object's 'start' Script Attribute), upon each internal turn (Turnscript), and whenever you use the 'look' Verb for 'npc_1' Object.
---------
or, if Functions still are confusing, here's not using them:
------------------------
do you just mean expanding/increasing your Guard's patrolled rooms, or do you mean creating separate/more npcs and with their own separate patrolled rooms?
If you add a Turnscript to an individual room (a 'local' Turnscript), then it (and any of its scripts running) is ONLY in effect when you're in that specific room, if this isn't what you want, then you need to make the Turnscript global (don't add it to a room, see my previous post for how to add in a global Turnscript). The Turnscript should be a global Turnscript (the Guard will be always moving to a new room each internal turn)... unless you want to have an "activator" room, which will activate the Turnscript or change the Value of your 'Guard.move_whatever' Boolean Attribute to 'true', and also then when done, you'd have to 'disable' the Turnscript or set: 'Guard.move_whatever=false'
yes, by using the first condition of 'Guard.move_whatever_it_called', you thus then are controling whether the nested scripts run or (nothing happens or optionally the 'else' scripts run)
There's also Functions to toggle the Turnscripts "on" ('enabled=true') or "off" ('enabled=false')
-----------------
left side's "tree of struff" :
Object
-> Game
->-> Verbs
->-> Commands
Functions <---------------- click on this, and add in your function (name it whatever you want), put/add your Guard_1 movement scripts into this Function
etc etc etc
A Function acts as like a storage spot for some action/event/scripting that you want (such as for moving your Guard_1), well there's more specifics about a Functions capabilities (but let's not get into that here), you can then add/use/call/put the Function into where-ever you want and as many of them as you want, via in the GUI~Editor: run as script -> add new script -> 'output' category I believe -> 'call function' -> skinny rectangle text box: your_functions_name -> Add arguments/parameters if you got any - not sure how this works in the GUI~Editor
A 'Function' Element is a container for scriptings (just like a Verb is), just as an 'Object' Element is a container for Attributes and/or other 'Object' Elements
for an example:
<game name="sample">
// the built-in 'game.start' Script Attribute is the first thing to run at game start, making it good, for example, for: 'character creation'. In the GUI~Editor, you'll find the 'start' Script in the 'Scripts' Tab of the 'game' Game Object:
<attr name="start" type="script">
test_function
</attr>
</game>
<object name="npc_1">
<attr name="look" type="script">
test_function
</attr>
</object>
<turnscript name="global_turnscript">
<enabled />
<script>
test_function
</script>
</turnscript>
<verb>
<propety>look</property>
<pattern>look</property>
<defaultexpression>You can't look at that!</defaultexpression>
</verb>
<function name="test_function">
msg ("testing 1 2 3")
</function>
the 'testing 1 2 3' will be displayed when the game starts ('game' Game Object's 'start' Script Attribute), upon each internal turn (Turnscript), and whenever you use the 'look' Verb for 'npc_1' Object.
---------
or, if Functions still are confusing, here's not using them:
<game name="sample">
<attr name="start" type="script">
msg ("testing 1 2 3")
</attr>
</game>
<object name="npc_1">
<attr name="look" type="script">
msg ("testing 1 2 3")
</attr>
</object>
<turnscript name="global_turnscript">
<enabled />
<script>
msg ("testing 1 2 3")
</script>
</turnscript>
<verb>
<propety>look</property>
<pattern>look</property>
<defaultexpression>You can't look at that!</defaultexpression>
</verb>
------------------------
grotel wrote:Also, I forgot to say that I want to create some more rooms exactly like this one. Do I have to make the turnscript global or do I just turn on and off the guards every time the player enters and leaves the room (don't worry about the position, that's already fixed, kinda)?
do you just mean expanding/increasing your Guard's patrolled rooms, or do you mean creating separate/more npcs and with their own separate patrolled rooms?
If you add a Turnscript to an individual room (a 'local' Turnscript), then it (and any of its scripts running) is ONLY in effect when you're in that specific room, if this isn't what you want, then you need to make the Turnscript global (don't add it to a room, see my previous post for how to add in a global Turnscript). The Turnscript should be a global Turnscript (the Guard will be always moving to a new room each internal turn)... unless you want to have an "activator" room, which will activate the Turnscript or change the Value of your 'Guard.move_whatever' Boolean Attribute to 'true', and also then when done, you'd have to 'disable' the Turnscript or set: 'Guard.move_whatever=false'
yes, by using the first condition of 'Guard.move_whatever_it_called', you thus then are controling whether the nested scripts run or (nothing happens or optionally the 'else' scripts run)
There's also Functions to toggle the Turnscripts "on" ('enabled=true') or "off" ('enabled=false')
The Pixie
01 Jul 2016, 09:57I have had a bit of a play around, and created a turn script and a couple of functions that might be helpful, if you are still struggling. The way I have approached it is to have a list of rooms on the route, and track the NPC's progress.
If you are working off-line, you can copy the lot into your game code; if you are editing on-line, you will need to create the turnscript and each function individually, making sure the attributes are right, and then paste the code for each in. Say if that is not clear.
Once you have the code, you can set an NPC to patrol by setting an attribute called "patrol_type" on the NPC. Set it to "circuit" to have the NPC going on a loop, to "return" to have her go there and back, or "random" to have her just wander at random. For the first two options you also need a string list, "patrol_route" that contains the names of the rooms on the route.
If you are working on-line, you cannot set attributes directly, so would have to set the in game.start. Again, say if not clear.
You can have the NPC stop patrolling by setting "patrol_paused" to true, and have her resume by setting it to false. You can also set any number of NPCs to patrol in the same way.
If you are working off-line, you can copy the lot into your game code; if you are editing on-line, you will need to create the turnscript and each function individually, making sure the attributes are right, and then paste the code for each in. Say if that is not clear.
Once you have the code, you can set an NPC to patrol by setting an attribute called "patrol_type" on the NPC. Set it to "circuit" to have the NPC going on a loop, to "return" to have her go there and back, or "random" to have her just wander at random. For the first two options you also need a string list, "patrol_route" that contains the names of the rooms on the route.
If you are working on-line, you cannot set attributes directly, so would have to set the in game.start. Again, say if not clear.
You can have the NPC stop patrolling by setting "patrol_paused" to true, and have her resume by setting it to false. You can also set any number of NPCs to patrol in the same way.
<turnscript name="patrolling">
<enabled />
<script>
foreach (o, AllObjects()) {
if (HasString(o, "patrol_type")) {
if (not HasInt(o, "patrol_pos")) {
o.patrol_pos = 0
}
if (not HasBoolean(o, "patrol_paused")) {
o.patrol_paused = false
}
if (not o.patrol_paused) {
Patrol (o)
}
}
}
</script>
</turnscript>
<function name="Patrol" parameters="o"><![CDATA[
oldroom = o.parent
if (o.patrol_type = "circuit") {
o.patrol_pos = o.patrol_pos + 1
if (o.patrol_pos >= ListCount(o.patrol_route)) {
o.patrol_pos = 0
}
o.parent = GetObject(StringListItem(o.patrol_route, o.patrol_pos))
}
if (o.patrol_type = "return") {
o.patrol_pos = o.patrol_pos + 1
if (o.patrol_pos > 2 * ListCount(o.patrol_route) - 3) {
o.patrol_pos = 0
}
if (o.patrol_pos >= ListCount(o.patrol_route)) {
pos = ListCount(o.patrol_route) * 2 - o.patrol_pos - 2
}
else {
pos = o.patrol_pos
}
o.parent = GetObject(StringListItem(o.patrol_route, pos))
}
if (o.patrol_type = "random") {
o.parent = RandomNextUnlockedRoom(o.parent)
}
if (oldroom = player.parent) {
exitname = GetExitByLink(player.parent, o.parent)
s = GetDisplayName(o) + " has left the room"
if (not exitname = null) {
exit = GetObject(exitname)
s = s + ", heading " + exit.alias
}
msg (s + ".")
}
if (o.parent = player.parent) {
exitname = GetExitByLink(player.parent, oldroom)
s = GetDisplayName(o) + " enters the room"
if (not exitname = null) {
exit = GetObject(exitname)
s = s + ", from " + exit.alias
}
msg (s + ".")
}
// msg (o.alias + " is now " + o.parent.name)
]]></function>
<function name="ScopeUnlockedExitsForRoom" parameters="room" type="objectlist">
result = NewObjectList()
foreach (exit, AllExits()) {
if (exit.parent = room) {
if (exit.visible and not exit.locked) {
if (GetBoolean(room, "darklevel")) {
if (GetBoolean(exit, "lightsource")) {
list add (result, exit)
}
}
else {
list add (result, exit)
}
}
}
}
return (result)
</function>
<function name="RandomNextUnlockedRoom" parameters="currentroom" type="object">
exts = ScopeUnlockedExitsForRoom (currentroom)
if (ListCount(exts) = 0) {
return (currentroom)
}
exit = ObjectListItem(exts, GetRandomInt(0, ListCount(exts) - 1))
return (exit.to)
</function>