Push #object# direction

Doctor Agon
21 Mar 2018, 22:23I first asked this question in August last year.
See here for that thread: https://textadventures.co.uk/forum/quest/topic/guvemyyxheio3tiogk6m9q/push-object-direction
With a great deal of help from KV, The Pixie, and a few others, the coding worked. Thankyou.
Recently, I thought of updating the command so that a 'Npc' could 'Pull, Push or Move' the object.
This then caused a bit of head-scratching as to make the exit message display the correct syntax in all cases, and the creation of three new functions to achieve this. WriteVerb2
, Conjugate2
and Conjugate3
(all of which are Pixie inspired), also a very poor attempt at a template FormatCmdVerb
.
I am however having problems with one of my commands, 'CmdNpcPushObjDir
', it's not taking the correct input as I thought it would, and I'm hoping someone can help fix it. I've put a little note in the CmdPush Object1 Direction
, so you can test out how it should behave.
I'm attaching a little game, so you can see it all in action.
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<template name="You">You</template>
<template name="the">the</template>
<dynamictemplate name="FullInventory">WriteVerb(object, "be") + " too heavy to be taken."</dynamictemplate>
<dynamictemplate name="ObjectNotOpen">CapFirst(GetDisplayAlias(object)) + " " + Conjugate(object, "be") + " not open."</dynamictemplate>
<dynamictemplate name="DefaultAsk">WriteVerb(object, "do") + " not reply."</dynamictemplate>
<game name="Test - Npc Move">
<gameid>d59aebb9-33bb-4b95-8719-89a67c44c6c0</gameid>
<version>1.0</version>
<firstpublished>2018</firstpublished>
<feature_lightdark />
<attr name="feature_limitinventory" type="boolean">false</attr>
<feature_advancedscripts />
<marginscolour type="string"></marginscolour>
<inituserinterface type="script">
</inituserinterface>
<clearscreenonroomenter />
</game>
<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>You can't go there.</unresolved>
<script>
if (HasString (player, "immobilisedmessage")) {
msg (player.immobilisedmessage)
}
else if (exit.visible) {
if (exit.locked) {
msg (exit.lockmessage)
}
else if (exit.runscript) {
if (HasScript(exit, "script")) {
do (exit, "script")
}
}
else if (exit.lookonly) {
msg ("You can't go there.")
}
else {
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 ("You can't go there.")
}
</script>
</command>
<command name="CmdTie Object1">
<pattern type="string"><![CDATA[^(tie|attach|fasten) (?<object1>.*)$]]></pattern>
<script>
// 1: Checks for the command used (tie/attach/fasten) and puts it into the variable 'cc'.
cc = player.currentcommand
// The function GetCmdVerb(cc) is used to display (tie/attach/fasten).
if (not Got(object1)) {
msg ("You are not carrying the " + GetDisplayAlias(object1) + ".")
// 2: Check if you are carrying object1.
}
else if (GetBoolean(object1, "tie_able")) {
msg (GetCmdVerb(cc) + " " + GetDisplayAlias(object1) + " to what?")
// 3: Check if you can attach object1 to anything. What do you want it attached to?
}
else {
msg ("You cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " to anything.")
// 4: Check if you can attach object1 to anything.
}
</script>
</command>
<command name="CmdUntie Object1">
<pattern type="string"><![CDATA[^(untie|unattach|unfasten) (?<object1>.*)$]]></pattern>
<script>
// 1: Checks for the command used (untie/unattach/unfasten) and puts it into the variable 'cc'.
cc = player.currentcommand
// The function GetCmdVerb(cc) is used to display (untie/unattach/unfasten).
if (not GetBoolean(object1, "tiedto")) {
msg ("The " + GetDisplayAlias(object1) + " is not " + Conjugate3(cc) + " to anything.")
// 2: Check if object1 is attached to anything.
}
else {
// 3: Unattach object1 from what?
msg (GetCmdVerb(cc) + " " + GetDisplayAlias(object1) + " from what?")
}
</script>
</command>
<command name="CmdUntie Object1 from Object2">
<pattern type="string"><![CDATA[^(untie|unattach|unfasten) (?<object1>.*) from (?<object2>.*)$]]></pattern>
<script>
// 1: Checks for the command used (untie/unattach/unfasten) and puts it into the variable 'cc'.
cc = player.currentcommand
// The function GetCmdVerb(cc) is used to display (untie/unattach/unfasten).
if (not GetBoolean(object1, "tiedto")) {
msg ("The " + GetDisplayAlias(object1) + " is not " + Conjugate3(cc) + " to anything.")
// 2: Check if object1 is attached.
}
else if (not HasAttribute(object2, "attachedto")) {
msg ("The " + GetDisplayAlias(object2) + " is not " + Conjugate3(cc) + " to anything.")
// 3: Check if object2 is attached.
}
else {
// 4: Unattach objects and reset variables.
msg ("You " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " from the " + GetDisplayAlias(object2) + ".")
object1.tiedto = false
object1.attachedto = null
object2.attachedto = null
object1.take = true
}
</script>
</command>
<command name="CmdTie Object1 to Object2">
<pattern type="string"><![CDATA[^(tie|attach|fasten) (?<object1>.*) to (?<object2>.*)$]]></pattern>
<unresolved type="string"></unresolved>
<script>
cc = player.currentcommand
if (GetBoolean(object1, "tiedto") and (object1.attachedto = object2)) {
msg ("You've already done that.")
// 2: Check if object1 is already attached to object2.
}
else if (GetBoolean(object1, "tiedto")) {
msg ("The " + GetDisplayAlias(object1) + " is already " + Conjugate3(cc) + " to the " + GetDisplayAlias(object1.attachedto) + ".")
// 3: Check if object1 is attached.
}
else if (HasAttribute(object2, "attachedto")) {
msg ("The " + GetDisplayAlias(object2) + " is already " + Conjugate3(cc) + " to the " + GetDisplayAlias(object2.attachedto) + ".")
// 4: Check if object2 is attached.
}
else if (not object1.parent = player) {
msg ("You are not holding " + GetDisplayName(object1) + ".")
// 5: Check if you are carrying object1.
}
else if (not GetBoolean(object1, "tie_able")) {
msg ("You cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " to anything.")
// 6: Check if object1 can be attached.
}
else if (not GetBoolean(object2, "attachable")) {
msg ("You cannot " + GetCmdVerb(cc) + " anything to the " + GetDisplayAlias(object2) + ".")
// 7: Check if object2 can be attached.
}
else {
// 8: Success. Attach the two objects.
msg ("You " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " to the " + GetDisplayAlias(object2) + ".")
object1.tiedto = true
object1.attachedto = object2
object2.attachedto = object1
object1.parent = player.parent
object1.take = false
}
</script>
</command>
<command name="CmdPush Object1 Direction">
<pattern type="string"><![CDATA[^(push|pull|move) (?<object1>.*) (?<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>
<script>
// Testing: Change 'player' to 'quinn', 'lucy' or 'olivers army' to get an idea of how CmdNpcPushObjDir should work.
PushPullMoveObjDir (player.currentcommand, player, object1, exit)
</script>
</command>
<command name="CmdPush Object1">
<pattern type="string"><![CDATA[^(push|pull|move) (?<object1>.*)$]]></pattern>
<script>
// 1: This section checks for the command used (push/pull/move) and puts it into the variable 'cc'.
cc = player.currentcommand
if (HasAttribute(object1, "pushable")) {
msg (GetCmdVerb(cc) + " " + GetDisplayAlias(object1) + " where?")
}
else if (HasAttribute(object1, "moveable")) {
msg ("You " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + ".")
do (object1, "moveable")
}
else {
msg ("You cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + ".")
}
</script>
</command>
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
<maxobjects type="int">0</maxobjects>
<volume type="int">0</volume>
<maxvolume type="int">1</maxvolume>
</object>
<exit alias="east" to="room2">
<inherit name="eastdirection" />
<locked type="boolean">false</locked>
</exit>
<object name="pen">
<inherit name="editor_object" />
<take />
<volume type="int">0</volume>
</object>
<object name="stone block">
<inherit name="editor_object" />
<alt type="stringlist">
<value>block</value>
</alt>
<pushable />
<push type="script">
cc = player.currentcommand
HandleSingleCommand ("CmdPush Object1" + cc)
</push>
<pull type="script">
do (this, "push")
</pull>
<move type="script">
do (this, "push")
</move>
<climbup type="script">
msg ("You climb up onto the top of the stone block.")
player.immobilisedmessage = "You cannot move whilst standing on top of a stone block."
SetObjectFlagOn (player, "stand")
MakeObjectVisible (lamp)
</climbup>
<climbdown type="script">
msg ("You climb down from the top of the stone block.")
player.immobilisedmessage = null
SetObjectFlagOff (player, "stand")
if (not Got(lamp)) {
MakeObjectInvisible (lamp)
}
</climbdown>
</object>
<object name="quinn">
<inherit name="editor_object" />
<inherit name="male" />
<alias>Quinn</alias>
<look>A mighty Eskimo, of immense stature.</look>
<usedefaultprefix type="boolean">false</usedefaultprefix>
</object>
<object name="branch">
<inherit name="editor_object" />
<attachable />
<look>A oak branch.</look>
</object>
<object name="rope">
<inherit name="editor_object" />
<take />
<tie_able />
<look>A long length of rope.</look>
</object>
<object name="hook">
<inherit name="editor_object" />
<attachable />
<look>A plain looking hook.</look>
</object>
<object name="cord">
<inherit name="editor_object" />
<tie_able />
<take />
<look type="string"></look>
</object>
<object name="rug">
<inherit name="editor_object" />
<look>A very plain looking rug carpet.</look>
<alt type="stringlist">
<value>carpet</value>
</alt>
<moveable type="script">
msg ("A key is revealed.")
</moveable>
<push type="script">
cc = player.currentcommand
HandleSingleCommand ("CmdPush Object1" + cc)
</push>
<pull type="script">
do (this, "push")
</pull>
<move type="script">
do (this, "push")
</move>
</object>
<object name="lucy">
<inherit name="editor_object" />
<inherit name="namedfemale" />
<alias>Lucy</alias>
<look>A girl with kaleidoscope eyes, wearing a diamond.</look>
</object>
<object name="olivers army">
<inherit name="editor_object" />
<inherit name="maleplural" />
<alias>Oliver's Army</alias>
<usedefaultprefix type="boolean">false</usedefaultprefix>
<look><![CDATA[They're here to stay.<br/>They're on their way.]]></look>
<alt type="stringlist">
<value>army</value>
<value>goblins</value>
</alt>
</object>
</object>
<object name="room2">
<inherit name="editor_room" />
<dark type="boolean">false</dark>
<exit alias="west" to="room">
<inherit name="westdirection" />
</exit>
<object name="shelf">
<inherit name="editor_object" />
<inherit name="surface" />
<feature_container />
<listchildren />
<look type="script"><![CDATA[
if (GetBoolean(player, "stand")) {
msg ("A wooden shelf.")
}
else {
msg ("A wooden shelf.<br/>The shelf is too high for you to see what, if anything is on it.")
}
]]></look>
<object name="lamp">
<inherit name="editor_object" />
<inherit name="switchable" />
<take />
<feature_switchable />
<feature_lightdark />
<lightstrength>strong</lightstrength>
<volume type="int">0</volume>
<onswitchon type="script">
this.lightsource = true
</onswitchon>
<onswitchoff type="script">
this.lightsource = false
</onswitchoff>
<visible type="boolean">false</visible>
<ontake type="script">
</ontake>
</object>
</object>
</object>
<command name="CmdNpcPushObjDir">
<pattern type="string"><![CDATA[^(?<object2>.*):(push|pull|move) (?<object1>.*) (?<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>
<script>
input = Split(player.currentcommand, ":")
obj = GetObject(StringListItem(input,0))
input1 = Split(StringListItem(input,1), " ")
cc = StringListItem(input1,0)
n = ListCount(Input1) -2
object1 = GetObject(StringListItem(input1, n))
exit = StringListItem(input1, ListCount(input1) -1)
msg (obj)
msg (cc)
msg (object1)
PushPullMoveObjDir (cc, obj, object1, exit)
</script>
</command>
<verb>
<property>climbup</property>
<pattern>climb up; climb on; stand; stand on; get on</pattern>
<defaultexpression>"You can't climb up; climb on; stand; stand on; get on " + object.article + "."</defaultexpression>
</verb>
<verb>
<property>climbdown</property>
<pattern>climb down; climb off; get off</pattern>
<defaultexpression>"You can't climb down; climb off; get off " + object.article + "."</defaultexpression>
</verb>
<function name="GetCmdVerb" parameters="cc" type="string">
// Doctor Agon. GetCmdVerb Inspired by KV.
// 1: Set Variable cc=player.currentcommand. Use GetCmdVerb(cc) in script calling function.
// 2: This section checks for the command used (push/pull/move) and puts it into the variable 'cmdverb'.
if (StartsWith(cc, "push")) {
return ("push")
}
else if (StartsWith(cc, "pull")) {
return ("pull")
}
else if (StartsWith(cc, "move")) {
return ("move")
}
// 3: This section checks for the command used (tie/attach/fasten) and puts it into the variable 'cmdverb'.
if (StartsWith(cc, "tie")) {
return ("tie")
}
else if (StartsWith(cc, "attach")) {
return ("attach")
}
else if (StartsWith(cc, "fasten")) {
return ("fasten")
}
// 4: This section checks for the command used (untie/unattach/unfasten) and puts it into the variable 'cmdverb'.
if (StartsWith(cc, "untie")) {
return ("untie")
}
else if (StartsWith(cc, "unattach")) {
return ("unattach")
}
else if (StartsWith(cc, "unfasten")) {
return ("unfasten")
}
</function>
<function name="FormatCmdVerb" parameters="pre, con, mid, obj, dir, post" type="string">
result = pre + " " + con + " "
result = result + mid + " "
result = result + GetDisplayAlias(obj) + " "
result = result + dir.alias
result = result + post
return (result)
</function>
<function name="WriteVerb2" parameters="obj" type="string">
// Pixie inspired coding.
return (CapFirst(obj.gender))
</function>
<function name="Conjugate2" parameters="obj, cc" type="string">
// Pixie inspired coding.
gender = obj.gender
if (gender = "he" or gender = "she") {
gender = "it"
}
switch (GetCmdVerb(cc)) {
case ("push") {
switch (gender) {
case ("it") {
return (GetCmdVerb(cc)+"es")
}
default {
return (GetCmdVerb(cc))
}
}
}
case ("pull") {
switch (gender) {
case ("it") {
return (GetCmdVerb(cc)+"s")
}
default {
return (GetCmdVerb(cc))
}
}
}
case ("move") {
switch (gender) {
case ("it") {
return (GetCmdVerb(cc)+"s")
}
default {
return (GetCmdVerb(cc))
}
}
}
default {
return (GetCmdVerb(cc))
}
}
</function>
<function name="Conjugate3" parameters="cc" type="string">
// Pixie inspired coding.
switch (GetCmdVerb(cc)) {
case ("tie") {
return ("tied")
}
case ("attach") {
return ("attached")
}
case ("fasten") {
return ("fastened")
}
case ("untie") {
return ("tied")
}
case ("unattach") {
return ("attached")
}
case ("unfasten") {
return ("fastened")
}
default {
return (GetCmdVerb(cc))
}
}
</function>
<function name="PushPullMoveObjDir" parameters="cc, obj, object1, exit">
// 1: This section checks for the command used (push/pull/move) and puts it into the variable 'cc'.
cc = player.currentcommand
object2 = obj
// 2: Check to see if player is immobilised.
if (player.immobilisedmessage = null) {
// 3: Checks if the object1 has the attribute 'pushable'.
if (HasAttribute(object1, "pushable")) {
if (game.unresolvedcommand = null) {
// 4: Check if exit is locked.
if (exit.locked) {
msg (exit.lockmessage)
}
else {
// 5: Sets the exit.message, moves the object in the direction indicated, moves object2(player/npc) in the direction indicated, resets exit.message.
exit.message = FormatCmdVerb(WriteVerb2(object2),Conjugate2(object2,cc),Template("the"),object1,exit,".")
object1.parent = exit.to
if (object2 = player) {
HandleSingleCommand ("go " + exit.alias)
}
else {
MoveObject (object2, exit.to)
msg (exit.message)
}
}
exit.message = null
}
}
else {
// 6: Immovable object message.
msg (WriteVerb2(object2) + " cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " " + exit.alias + ".")
}
}
else {
// 7: Player is immobilised message.
msg (player.immobilisedmessage)
}
</function>
</asl>
Oops, maybe not so little.

K.V.
22 Mar 2018, 00:25It works for me with these changes:
<command name="CmdNpcPushObjDir">
<pattern type="string"><![CDATA[^(?<object2>.*), (?<text>push|pull|move) (?<object1>.*) (?<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>
<script>
PushPullMoveObjDir (text, object2, object1, exit)
</script>
</command>
<function name="PushPullMoveObjDir" parameters="cc, object2, object1, exit">
// 1: This section checks for the command used (push/pull/move) and puts it into the variable 'cc'.
//cc = player.currentcommand
//object2 = obj
// 2: Check to see if player is immobilised.
if (player.immobilisedmessage = null) {
// 3: Checks if the object1 has the attribute 'pushable'.
if (HasAttribute(object1, "pushable")) {
if (game.unresolvedcommand = null) {
// 4: Check if exit is locked.
if (exit.locked) {
msg (exit.lockmessage)
}
else {
// 5: Sets the exit.message, moves the object in the direction indicated, moves object2(player/npc) in the direction indicated, resets exit.message.
exit.message = FormatCmdVerb(WriteVerb2(object2),Conjugate2(object2,cc),Template("the"),object1,exit,".")
object1.parent = exit.to
if (object2 = player) {
HandleSingleCommand ("go " + exit.alias)
}
else {
MoveObject (object2, exit.to)
msg (exit.message)
}
}
exit.message = null
}
}
else {
// 6: Immovable object message.
msg (WriteVerb2(object2) + " cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " " + exit.alias + ".")
}
}
else {
// 7: Player is immobilised message.
msg (player.immobilisedmessage)
}
</function>
> quinn, push the branch east
He cannot push the branch east.
> quinn, push the block east
He pushes the stone block east.

Doctor Agon
22 Mar 2018, 08:20Hmmm, Still doesn't work KV, keeps putting out an error message. Object not set to instance of an object
, or something like that.

K.V.
22 Mar 2018, 15:02It works for me.
Here's the proof:
Did you change both scripts I posted? I don't know why I put "Hack 1" and "Hack 2"... You need to change them both.
Here's the whole game
<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<template name="You">You</template>
<template name="the">the</template>
<dynamictemplate name="FullInventory">WriteVerb(object, "be") + " too heavy to be taken."</dynamictemplate>
<dynamictemplate name="ObjectNotOpen">CapFirst(GetDisplayAlias(object)) + " " + Conjugate(object, "be") + " not open."</dynamictemplate>
<dynamictemplate name="DefaultAsk">WriteVerb(object, "do") + " not reply."</dynamictemplate>
<game name="Test - Npc Move">
<gameid>d59aebb9-33bb-4b95-8719-89a67c44c6c0</gameid>
<version>1.0</version>
<firstpublished>2018</firstpublished>
<feature_lightdark />
<attr name="feature_limitinventory" type="boolean">false</attr>
<feature_advancedscripts />
<marginscolour type="string"></marginscolour>
<clearscreenonroomenter />
<inituserinterface type="script">
</inituserinterface>
</game>
<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>You can't go there.</unresolved>
<script>
if (HasString (player, "immobilisedmessage")) {
msg (player.immobilisedmessage)
}
else if (exit.visible) {
if (exit.locked) {
msg (exit.lockmessage)
}
else if (exit.runscript) {
if (HasScript(exit, "script")) {
do (exit, "script")
}
}
else if (exit.lookonly) {
msg ("You can't go there.")
}
else {
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 ("You can't go there.")
}
</script>
</command>
<command name="CmdTie Object1">
<pattern type="string"><![CDATA[^(tie|attach|fasten) (?<object1>.*)$]]></pattern>
<script>
// 1: Checks for the command used (tie/attach/fasten) and puts it into the variable 'cc'.
cc = player.currentcommand
// The function GetCmdVerb(cc) is used to display (tie/attach/fasten).
if (not Got(object1)) {
msg ("You are not carrying the " + GetDisplayAlias(object1) + ".")
// 2: Check if you are carrying object1.
}
else if (GetBoolean(object1, "tie_able")) {
msg (GetCmdVerb(cc) + " " + GetDisplayAlias(object1) + " to what?")
// 3: Check if you can attach object1 to anything. What do you want it attached to?
}
else {
msg ("You cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " to anything.")
// 4: Check if you can attach object1 to anything.
}
</script>
</command>
<command name="CmdUntie Object1">
<pattern type="string"><![CDATA[^(untie|unattach|unfasten) (?<object1>.*)$]]></pattern>
<script>
// 1: Checks for the command used (untie/unattach/unfasten) and puts it into the variable 'cc'.
cc = player.currentcommand
// The function GetCmdVerb(cc) is used to display (untie/unattach/unfasten).
if (not GetBoolean(object1, "tiedto")) {
msg ("The " + GetDisplayAlias(object1) + " is not " + Conjugate3(cc) + " to anything.")
// 2: Check if object1 is attached to anything.
}
else {
// 3: Unattach object1 from what?
msg (GetCmdVerb(cc) + " " + GetDisplayAlias(object1) + " from what?")
}
</script>
</command>
<command name="CmdUntie Object1 from Object2">
<pattern type="string"><![CDATA[^(untie|unattach|unfasten) (?<object1>.*) from (?<object2>.*)$]]></pattern>
<script>
// 1: Checks for the command used (untie/unattach/unfasten) and puts it into the variable 'cc'.
cc = player.currentcommand
// The function GetCmdVerb(cc) is used to display (untie/unattach/unfasten).
if (not GetBoolean(object1, "tiedto")) {
msg ("The " + GetDisplayAlias(object1) + " is not " + Conjugate3(cc) + " to anything.")
// 2: Check if object1 is attached.
}
else if (not HasAttribute(object2, "attachedto")) {
msg ("The " + GetDisplayAlias(object2) + " is not " + Conjugate3(cc) + " to anything.")
// 3: Check if object2 is attached.
}
else {
// 4: Unattach objects and reset variables.
msg ("You " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " from the " + GetDisplayAlias(object2) + ".")
object1.tiedto = false
object1.attachedto = null
object2.attachedto = null
object1.take = true
}
</script>
</command>
<command name="CmdTie Object1 to Object2">
<pattern type="string"><![CDATA[^(tie|attach|fasten) (?<object1>.*) to (?<object2>.*)$]]></pattern>
<unresolved type="string"></unresolved>
<script>
cc = player.currentcommand
if (GetBoolean(object1, "tiedto") and (object1.attachedto = object2)) {
msg ("You've already done that.")
// 2: Check if object1 is already attached to object2.
}
else if (GetBoolean(object1, "tiedto")) {
msg ("The " + GetDisplayAlias(object1) + " is already " + Conjugate3(cc) + " to the " + GetDisplayAlias(object1.attachedto) + ".")
// 3: Check if object1 is attached.
}
else if (HasAttribute(object2, "attachedto")) {
msg ("The " + GetDisplayAlias(object2) + " is already " + Conjugate3(cc) + " to the " + GetDisplayAlias(object2.attachedto) + ".")
// 4: Check if object2 is attached.
}
else if (not object1.parent = player) {
msg ("You are not holding " + GetDisplayName(object1) + ".")
// 5: Check if you are carrying object1.
}
else if (not GetBoolean(object1, "tie_able")) {
msg ("You cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " to anything.")
// 6: Check if object1 can be attached.
}
else if (not GetBoolean(object2, "attachable")) {
msg ("You cannot " + GetCmdVerb(cc) + " anything to the " + GetDisplayAlias(object2) + ".")
// 7: Check if object2 can be attached.
}
else {
// 8: Success. Attach the two objects.
msg ("You " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " to the " + GetDisplayAlias(object2) + ".")
object1.tiedto = true
object1.attachedto = object2
object2.attachedto = object1
object1.parent = player.parent
object1.take = false
}
</script>
</command>
<command name="CmdPush Object1 Direction">
<pattern type="string"><![CDATA[^(push|pull|move) (?<object1>.*) (?<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>
<script>
// Testing: Change 'player' to 'quinn', 'lucy' or 'olivers army' to get an idea of how CmdNpcPushObjDir should work.
PushPullMoveObjDir (player.currentcommand, player, object1, exit)
</script>
</command>
<command name="CmdPush Object1">
<pattern type="string"><![CDATA[^(push|pull|move) (?<object1>.*)$]]></pattern>
<script>
// 1: This section checks for the command used (push/pull/move) and puts it into the variable 'cc'.
cc = player.currentcommand
if (HasAttribute(object1, "pushable")) {
msg (GetCmdVerb(cc) + " " + GetDisplayAlias(object1) + " where?")
}
else if (HasAttribute(object1, "moveable")) {
msg ("You " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + ".")
do (object1, "moveable")
}
else {
msg ("You cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + ".")
}
</script>
</command>
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
<maxobjects type="int">0</maxobjects>
<volume type="int">0</volume>
<maxvolume type="int">1</maxvolume>
</object>
<exit alias="east" to="room2">
<inherit name="eastdirection" />
<locked type="boolean">false</locked>
</exit>
<object name="pen">
<inherit name="editor_object" />
<take />
<volume type="int">0</volume>
</object>
<object name="stone block">
<inherit name="editor_object" />
<alt type="stringlist">
<value>block</value>
</alt>
<pushable />
<push type="script">
cc = player.currentcommand
HandleSingleCommand ("CmdPush Object1" + cc)
</push>
<pull type="script">
do (this, "push")
</pull>
<move type="script">
do (this, "push")
</move>
<climbup type="script">
msg ("You climb up onto the top of the stone block.")
player.immobilisedmessage = "You cannot move whilst standing on top of a stone block."
SetObjectFlagOn (player, "stand")
MakeObjectVisible (lamp)
</climbup>
<climbdown type="script">
msg ("You climb down from the top of the stone block.")
player.immobilisedmessage = null
SetObjectFlagOff (player, "stand")
if (not Got(lamp)) {
MakeObjectInvisible (lamp)
}
</climbdown>
</object>
<object name="quinn">
<inherit name="editor_object" />
<inherit name="male" />
<alias>Quinn</alias>
<look>A mighty Eskimo, of immense stature.</look>
<usedefaultprefix type="boolean">false</usedefaultprefix>
</object>
<object name="branch">
<inherit name="editor_object" />
<attachable />
<look>A oak branch.</look>
</object>
<object name="rope">
<inherit name="editor_object" />
<take />
<tie_able />
<look>A long length of rope.</look>
</object>
<object name="hook">
<inherit name="editor_object" />
<attachable />
<look>A plain looking hook.</look>
</object>
<object name="cord">
<inherit name="editor_object" />
<tie_able />
<take />
<look type="string"></look>
</object>
<object name="rug">
<inherit name="editor_object" />
<look>A very plain looking rug carpet.</look>
<alt type="stringlist">
<value>carpet</value>
</alt>
<moveable type="script">
msg ("A key is revealed.")
</moveable>
<push type="script">
cc = player.currentcommand
HandleSingleCommand ("CmdPush Object1" + cc)
</push>
<pull type="script">
do (this, "push")
</pull>
<move type="script">
do (this, "push")
</move>
</object>
<object name="lucy">
<inherit name="editor_object" />
<inherit name="namedfemale" />
<alias>Lucy</alias>
<look>A girl with kaleidoscope eyes, wearing a diamond.</look>
</object>
<object name="olivers army">
<inherit name="editor_object" />
<inherit name="maleplural" />
<alias>Oliver's Army</alias>
<usedefaultprefix type="boolean">false</usedefaultprefix>
<look><![CDATA[They're here to stay.<br/>They're on their way.]]></look>
<alt type="stringlist">
<value>army</value>
<value>goblins</value>
</alt>
</object>
</object>
<object name="room2">
<inherit name="editor_room" />
<dark type="boolean">false</dark>
<exit alias="west" to="room">
<inherit name="westdirection" />
</exit>
<object name="shelf">
<inherit name="editor_object" />
<inherit name="surface" />
<feature_container />
<listchildren />
<look type="script"><![CDATA[
if (GetBoolean(player, "stand")) {
msg ("A wooden shelf.")
}
else {
msg ("A wooden shelf.<br/>The shelf is too high for you to see what, if anything is on it.")
}
]]></look>
<object name="lamp">
<inherit name="editor_object" />
<inherit name="switchable" />
<take />
<feature_switchable />
<feature_lightdark />
<lightstrength>strong</lightstrength>
<volume type="int">0</volume>
<visible type="boolean">false</visible>
<onswitchon type="script">
this.lightsource = true
</onswitchon>
<onswitchoff type="script">
this.lightsource = false
</onswitchoff>
<ontake type="script">
</ontake>
</object>
</object>
</object>
<command name="CmdNpcPushObjDir">
<pattern type="string"><![CDATA[^(?<object2>.*), (?<text>push|pull|move) (?<object1>.*) (?<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>
<script>
PushPullMoveObjDir (text, object2, object1, exit)
</script>
</command>
<verb>
<property>climbup</property>
<pattern>climb up; climb on; stand; stand on; get on</pattern>
<defaultexpression>"You can't climb up; climb on; stand; stand on; get on " + object.article + "."</defaultexpression>
</verb>
<verb>
<property>climbdown</property>
<pattern>climb down; climb off; get off</pattern>
<defaultexpression>"You can't climb down; climb off; get off " + object.article + "."</defaultexpression>
</verb>
<function name="GetCmdVerb" parameters="cc" type="string">
// Doctor Agon. GetCmdVerb Inspired by KV.
// 1: Set Variable cc=player.currentcommand. Use GetCmdVerb(cc) in script calling function.
// 2: This section checks for the command used (push/pull/move) and puts it into the variable 'cmdverb'.
if (StartsWith(cc, "push")) {
return ("push")
}
else if (StartsWith(cc, "pull")) {
return ("pull")
}
else if (StartsWith(cc, "move")) {
return ("move")
}
// 3: This section checks for the command used (tie/attach/fasten) and puts it into the variable 'cmdverb'.
if (StartsWith(cc, "tie")) {
return ("tie")
}
else if (StartsWith(cc, "attach")) {
return ("attach")
}
else if (StartsWith(cc, "fasten")) {
return ("fasten")
}
// 4: This section checks for the command used (untie/unattach/unfasten) and puts it into the variable 'cmdverb'.
if (StartsWith(cc, "untie")) {
return ("untie")
}
else if (StartsWith(cc, "unattach")) {
return ("unattach")
}
else if (StartsWith(cc, "unfasten")) {
return ("unfasten")
}
</function>
<function name="FormatCmdVerb" parameters="pre, con, mid, obj, dir, post" type="string">
result = pre + " " + con + " "
result = result + mid + " "
result = result + GetDisplayAlias(obj) + " "
result = result + dir.alias
result = result + post
return (result)
</function>
<function name="WriteVerb2" parameters="obj" type="string">
// Pixie inspired coding.
return (CapFirst(obj.gender))
</function>
<function name="Conjugate2" parameters="obj, cc" type="string">
// Pixie inspired coding.
gender = obj.gender
if (gender = "he" or gender = "she") {
gender = "it"
}
switch (GetCmdVerb(cc)) {
case ("push") {
switch (gender) {
case ("it") {
return (GetCmdVerb(cc)+"es")
}
default {
return (GetCmdVerb(cc))
}
}
}
case ("pull") {
switch (gender) {
case ("it") {
return (GetCmdVerb(cc)+"s")
}
default {
return (GetCmdVerb(cc))
}
}
}
case ("move") {
switch (gender) {
case ("it") {
return (GetCmdVerb(cc)+"s")
}
default {
return (GetCmdVerb(cc))
}
}
}
default {
return (GetCmdVerb(cc))
}
}
</function>
<function name="Conjugate3" parameters="cc" type="string">
// Pixie inspired coding.
switch (GetCmdVerb(cc)) {
case ("tie") {
return ("tied")
}
case ("attach") {
return ("attached")
}
case ("fasten") {
return ("fastened")
}
case ("untie") {
return ("tied")
}
case ("unattach") {
return ("attached")
}
case ("unfasten") {
return ("fastened")
}
default {
return (GetCmdVerb(cc))
}
}
</function>
<function name="PushPullMoveObjDir" parameters="cc, object2, object1, exit">
// 1: This section checks for the command used (push/pull/move) and puts it into the variable 'cc'.
//cc = player.currentcommand
//object2 = obj
// 2: Check to see if player is immobilised.
if (player.immobilisedmessage = null) {
// 3: Checks if the object1 has the attribute 'pushable'.
if (HasAttribute(object1, "pushable")) {
if (game.unresolvedcommand = null) {
// 4: Check if exit is locked.
if (exit.locked) {
msg (exit.lockmessage)
}
else {
// 5: Sets the exit.message, moves the object in the direction indicated, moves object2(player/npc) in the direction indicated, resets exit.message.
exit.message = FormatCmdVerb(WriteVerb2(object2),Conjugate2(object2,cc),Template("the"),object1,exit,".")
object1.parent = exit.to
if (object2 = player) {
HandleSingleCommand ("go " + exit.alias)
}
else {
MoveObject (object2, exit.to)
msg (exit.message)
}
}
exit.message = null
}
}
else {
// 6: Immovable object message.
msg (WriteVerb2(object2) + " cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " " + exit.alias + ".")
}
}
else {
// 7: Player is immobilised message.
msg (player.immobilisedmessage)
}
</function>
</asl>

Doctor Agon
23 Mar 2018, 07:47Thanks again KV, the first time I saw your 'hacks', I thought it was just the coding you'd changed. Didn't realise you'd changed the parameters too.

K.V.
24 Mar 2018, 18:15Sorry about that, DrAgon!
I normally make sure I point out any parameter changes. That was my fault.
You have NPC slaves now, though. So, that's a silver lining.

Doctor Agon
25 Mar 2018, 18:42Whilst testing this out, I entered the command: Quinn, push block
The game then produced an unexpected error message.
Error running script: Error evaluating expression 'DynamicTemplate(defaulttemplate, object)': No template named 'DefaultTellTo'
There is a ^tell (?<object>.*) about (?<text>.*)$
, which picks up a 'DefaultTell' script.
But, ^(tell|ask) (?<object>.*) to (?<text>.*)$
, picks up 'DefaultTellTo' instead.
Is it the same message 'DefaultTell', or are they two different messages?

K.V.
25 Mar 2018, 20:05Did you change the command pattern? (I did.)
You originally had this:
<pattern type="string"><![CDATA[^(?<object2>.*):(push|pull|move) (?<object1>.*) (?<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>
That only handled "Quinn:push the thing east"
...so I changed it to this:
<pattern type="string"><![CDATA[^(?<object2>.*), (?<text>push|pull|move) (?<object1>.*) (?<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>

K.V.
25 Mar 2018, 20:07Upon reflection, I'd make that:
EDITED (and tested)
^(?<object2>.*), (?<text>push|pull|move) (?<object1>.*) (towards the |to the |)(?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$|^(ask|tell|order|command) (?<object2>.*) to (?<text>push|pull|move) (?<object1>.*) (towards the |to the |)(?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$

K.V.
25 Mar 2018, 20:24The entire game:
<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<template name="You">You</template>
<template name="the">the</template>
<dynamictemplate name="FullInventory">WriteVerb(object, "be") + " too heavy to be taken."</dynamictemplate>
<dynamictemplate name="ObjectNotOpen">CapFirst(GetDisplayAlias(object)) + " " + Conjugate(object, "be") + " not open."</dynamictemplate>
<dynamictemplate name="DefaultAsk">WriteVerb(object, "do") + " not reply."</dynamictemplate>
<game name="Test - Npc Move">
<gameid>d59aebb9-33bb-4b95-8719-89a67c44c6c0</gameid>
<version>1.0</version>
<firstpublished>2018</firstpublished>
<feature_lightdark />
<attr name="feature_limitinventory" type="boolean">false</attr>
<feature_advancedscripts />
<marginscolour type="string"></marginscolour>
<clearscreenonroomenter />
</game>
<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>You can't go there.</unresolved>
<script>
if (HasString (player, "immobilisedmessage")) {
msg (player.immobilisedmessage)
}
else if (exit.visible) {
if (exit.locked) {
msg (exit.lockmessage)
}
else if (exit.runscript) {
if (HasScript(exit, "script")) {
do (exit, "script")
}
}
else if (exit.lookonly) {
msg ("You can't go there.")
}
else {
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 ("You can't go there.")
}
</script>
</command>
<command name="CmdTie Object1">
<pattern type="string"><![CDATA[^(tie|attach|fasten) (?<object1>.*)$]]></pattern>
<script>
// 1: Checks for the command used (tie/attach/fasten) and puts it into the variable 'cc'.
cc = player.currentcommand
// The function GetCmdVerb(cc) is used to display (tie/attach/fasten).
if (not Got(object1)) {
msg ("You are not carrying the " + GetDisplayAlias(object1) + ".")
// 2: Check if you are carrying object1.
}
else if (GetBoolean(object1, "tie_able")) {
msg (GetCmdVerb(cc) + " " + GetDisplayAlias(object1) + " to what?")
// 3: Check if you can attach object1 to anything. What do you want it attached to?
}
else {
msg ("You cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " to anything.")
// 4: Check if you can attach object1 to anything.
}
</script>
</command>
<command name="CmdUntie Object1">
<pattern type="string"><![CDATA[^(untie|unattach|unfasten) (?<object1>.*)$]]></pattern>
<script>
// 1: Checks for the command used (untie/unattach/unfasten) and puts it into the variable 'cc'.
cc = player.currentcommand
// The function GetCmdVerb(cc) is used to display (untie/unattach/unfasten).
if (not GetBoolean(object1, "tiedto")) {
msg ("The " + GetDisplayAlias(object1) + " is not " + Conjugate3(cc) + " to anything.")
// 2: Check if object1 is attached to anything.
}
else {
// 3: Unattach object1 from what?
msg (GetCmdVerb(cc) + " " + GetDisplayAlias(object1) + " from what?")
}
</script>
</command>
<command name="CmdUntie Object1 from Object2">
<pattern type="string"><![CDATA[^(untie|unattach|unfasten) (?<object1>.*) from (?<object2>.*)$]]></pattern>
<script>
// 1: Checks for the command used (untie/unattach/unfasten) and puts it into the variable 'cc'.
cc = player.currentcommand
// The function GetCmdVerb(cc) is used to display (untie/unattach/unfasten).
if (not GetBoolean(object1, "tiedto")) {
msg ("The " + GetDisplayAlias(object1) + " is not " + Conjugate3(cc) + " to anything.")
// 2: Check if object1 is attached.
}
else if (not HasAttribute(object2, "attachedto")) {
msg ("The " + GetDisplayAlias(object2) + " is not " + Conjugate3(cc) + " to anything.")
// 3: Check if object2 is attached.
}
else {
// 4: Unattach objects and reset variables.
msg ("You " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " from the " + GetDisplayAlias(object2) + ".")
object1.tiedto = false
object1.attachedto = null
object2.attachedto = null
object1.take = true
}
</script>
</command>
<command name="CmdTie Object1 to Object2">
<pattern type="string"><![CDATA[^(tie|attach|fasten) (?<object1>.*) to (?<object2>.*)$]]></pattern>
<unresolved type="string"></unresolved>
<script>
cc = player.currentcommand
if (GetBoolean(object1, "tiedto") and (object1.attachedto = object2)) {
msg ("You've already done that.")
// 2: Check if object1 is already attached to object2.
}
else if (GetBoolean(object1, "tiedto")) {
msg ("The " + GetDisplayAlias(object1) + " is already " + Conjugate3(cc) + " to the " + GetDisplayAlias(object1.attachedto) + ".")
// 3: Check if object1 is attached.
}
else if (HasAttribute(object2, "attachedto")) {
msg ("The " + GetDisplayAlias(object2) + " is already " + Conjugate3(cc) + " to the " + GetDisplayAlias(object2.attachedto) + ".")
// 4: Check if object2 is attached.
}
else if (not object1.parent = player) {
msg ("You are not holding " + GetDisplayName(object1) + ".")
// 5: Check if you are carrying object1.
}
else if (not GetBoolean(object1, "tie_able")) {
msg ("You cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " to anything.")
// 6: Check if object1 can be attached.
}
else if (not GetBoolean(object2, "attachable")) {
msg ("You cannot " + GetCmdVerb(cc) + " anything to the " + GetDisplayAlias(object2) + ".")
// 7: Check if object2 can be attached.
}
else {
// 8: Success. Attach the two objects.
msg ("You " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " to the " + GetDisplayAlias(object2) + ".")
object1.tiedto = true
object1.attachedto = object2
object2.attachedto = object1
object1.parent = player.parent
object1.take = false
}
</script>
</command>
<command name="CmdPush Object1 Direction">
<pattern type="string"><![CDATA[^(push|pull|move) (?<object1>.*) (?<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>
<script>
// Testing: Change 'player' to 'quinn', 'lucy' or 'olivers army' to get an idea of how CmdNpcPushObjDir should work.
PushPullMoveObjDir (player.currentcommand, player, object1, exit)
</script>
</command>
<command name="CmdPush Object1">
<pattern type="string"><![CDATA[^(push|pull|move) (?<object1>.*)$]]></pattern>
<script>
// 1: This section checks for the command used (push/pull/move) and puts it into the variable 'cc'.
cc = player.currentcommand
if (HasAttribute(object1, "pushable")) {
msg (GetCmdVerb(cc) + " " + GetDisplayAlias(object1) + " where?")
}
else if (HasAttribute(object1, "moveable")) {
msg ("You " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + ".")
do (object1, "moveable")
}
else {
msg ("You cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + ".")
}
</script>
</command>
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
<maxobjects type="int">0</maxobjects>
<volume type="int">0</volume>
<maxvolume type="int">1</maxvolume>
</object>
<exit alias="east" to="room2">
<inherit name="eastdirection" />
<locked type="boolean">false</locked>
</exit>
<object name="pen">
<inherit name="editor_object" />
<take />
<volume type="int">0</volume>
</object>
<object name="stone block">
<inherit name="editor_object" />
<alt type="stringlist">
<value>block</value>
</alt>
<pushable />
<push type="script">
cc = player.currentcommand
HandleSingleCommand ("CmdPush Object1" + cc)
</push>
<pull type="script">
do (this, "push")
</pull>
<move type="script">
do (this, "push")
</move>
<climbup type="script">
msg ("You climb up onto the top of the stone block.")
player.immobilisedmessage = "You cannot move whilst standing on top of a stone block."
SetObjectFlagOn (player, "stand")
MakeObjectVisible (lamp)
</climbup>
<climbdown type="script">
msg ("You climb down from the top of the stone block.")
player.immobilisedmessage = null
SetObjectFlagOff (player, "stand")
if (not Got(lamp)) {
MakeObjectInvisible (lamp)
}
</climbdown>
</object>
<object name="quinn">
<inherit name="editor_object" />
<inherit name="male" />
<alias>Quinn</alias>
<look>A mighty Eskimo, of immense stature.</look>
<usedefaultprefix type="boolean">false</usedefaultprefix>
</object>
<object name="branch">
<inherit name="editor_object" />
<attachable />
<look>A oak branch.</look>
</object>
<object name="rope">
<inherit name="editor_object" />
<take />
<tie_able />
<look>A long length of rope.</look>
</object>
<object name="hook">
<inherit name="editor_object" />
<attachable />
<look>A plain looking hook.</look>
</object>
<object name="cord">
<inherit name="editor_object" />
<tie_able />
<take />
<look type="string"></look>
</object>
<object name="rug">
<inherit name="editor_object" />
<look>A very plain looking rug carpet.</look>
<alt type="stringlist">
<value>carpet</value>
</alt>
<moveable type="script">
msg ("A key is revealed.")
</moveable>
<push type="script">
cc = player.currentcommand
HandleSingleCommand ("CmdPush Object1" + cc)
</push>
<pull type="script">
do (this, "push")
</pull>
<move type="script">
do (this, "push")
</move>
</object>
<object name="lucy">
<inherit name="editor_object" />
<inherit name="namedfemale" />
<alias>Lucy</alias>
<look>A girl with kaleidoscope eyes, wearing a diamond.</look>
</object>
<object name="olivers army">
<inherit name="editor_object" />
<inherit name="maleplural" />
<alias>Oliver's Army</alias>
<usedefaultprefix type="boolean">false</usedefaultprefix>
<look><![CDATA[They're here to stay.<br/>They're on their way.]]></look>
<alt type="stringlist">
<value>army</value>
<value>goblins</value>
</alt>
</object>
</object>
<object name="room2">
<inherit name="editor_room" />
<dark type="boolean">false</dark>
<exit alias="west" to="room">
<inherit name="westdirection" />
</exit>
<object name="shelf">
<inherit name="editor_object" />
<inherit name="surface" />
<feature_container />
<listchildren />
<look type="script"><![CDATA[
if (GetBoolean(player, "stand")) {
msg ("A wooden shelf.")
}
else {
msg ("A wooden shelf.<br/>The shelf is too high for you to see what, if anything is on it.")
}
]]></look>
<object name="lamp">
<inherit name="editor_object" />
<inherit name="switchable" />
<take />
<feature_switchable />
<feature_lightdark />
<lightstrength>strong</lightstrength>
<volume type="int">0</volume>
<visible type="boolean">false</visible>
<onswitchon type="script">
this.lightsource = true
</onswitchon>
<onswitchoff type="script">
this.lightsource = false
</onswitchoff>
<ontake type="script">
</ontake>
</object>
</object>
</object>
<command name="CmdNpcPushObjDir">
<pattern type="string"><![CDATA[^(?<object2>.*), (?<text>push|pull|move) (?<object1>.*) (towards the |to the |)(?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$|^(ask|tell|order|command) (?<object2>.*) to (?<text>push|pull|move) (?<object1>.*) (towards the |to the |)(?<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>
<script>
PushPullMoveObjDir (text, object2, object1, exit)
</script>
</command>
<verb>
<property>climbup</property>
<pattern>climb up; climb on; stand; stand on; get on</pattern>
<defaultexpression>"You can't climb up; climb on; stand; stand on; get on " + object.article + "."</defaultexpression>
</verb>
<verb>
<property>climbdown</property>
<pattern>climb down; climb off; get off</pattern>
<defaultexpression>"You can't climb down; climb off; get off " + object.article + "."</defaultexpression>
</verb>
<function name="GetCmdVerb" parameters="cc" type="string">
// Doctor Agon. GetCmdVerb Inspired by KV.
// 1: Set Variable cc=player.currentcommand. Use GetCmdVerb(cc) in script calling function.
// 2: This section checks for the command used (push/pull/move) and puts it into the variable 'cmdverb'.
if (StartsWith(cc, "push")) {
return ("push")
}
else if (StartsWith(cc, "pull")) {
return ("pull")
}
else if (StartsWith(cc, "move")) {
return ("move")
}
// 3: This section checks for the command used (tie/attach/fasten) and puts it into the variable 'cmdverb'.
if (StartsWith(cc, "tie")) {
return ("tie")
}
else if (StartsWith(cc, "attach")) {
return ("attach")
}
else if (StartsWith(cc, "fasten")) {
return ("fasten")
}
// 4: This section checks for the command used (untie/unattach/unfasten) and puts it into the variable 'cmdverb'.
if (StartsWith(cc, "untie")) {
return ("untie")
}
else if (StartsWith(cc, "unattach")) {
return ("unattach")
}
else if (StartsWith(cc, "unfasten")) {
return ("unfasten")
}
</function>
<function name="FormatCmdVerb" parameters="pre, con, mid, obj, dir, post" type="string">
result = pre + " " + con + " "
result = result + mid + " "
result = result + GetDisplayAlias(obj) + " "
result = result + dir.alias
result = result + post
return (result)
</function>
<function name="WriteVerb2" parameters="obj" type="string">
// Pixie inspired coding.
return (CapFirst(obj.gender))
</function>
<function name="Conjugate2" parameters="obj, cc" type="string">
// Pixie inspired coding.
gender = obj.gender
if (gender = "he" or gender = "she") {
gender = "it"
}
switch (GetCmdVerb(cc)) {
case ("push") {
switch (gender) {
case ("it") {
return (GetCmdVerb(cc)+"es")
}
default {
return (GetCmdVerb(cc))
}
}
}
case ("pull") {
switch (gender) {
case ("it") {
return (GetCmdVerb(cc)+"s")
}
default {
return (GetCmdVerb(cc))
}
}
}
case ("move") {
switch (gender) {
case ("it") {
return (GetCmdVerb(cc)+"s")
}
default {
return (GetCmdVerb(cc))
}
}
}
default {
return (GetCmdVerb(cc))
}
}
</function>
<function name="Conjugate3" parameters="cc" type="string">
// Pixie inspired coding.
switch (GetCmdVerb(cc)) {
case ("tie") {
return ("tied")
}
case ("attach") {
return ("attached")
}
case ("fasten") {
return ("fastened")
}
case ("untie") {
return ("tied")
}
case ("unattach") {
return ("attached")
}
case ("unfasten") {
return ("fastened")
}
default {
return (GetCmdVerb(cc))
}
}
</function>
<function name="PushPullMoveObjDir" parameters="cc, object2, object1, exit">
// 1: This section checks for the command used (push/pull/move) and puts it into the variable 'cc'.
// cc = player.currentcommand
// object2 = obj
// 2: Check to see if player is immobilised.
if (player.immobilisedmessage = null) {
// 3: Checks if the object1 has the attribute 'pushable'.
if (HasAttribute(object1, "pushable")) {
if (game.unresolvedcommand = null) {
// 4: Check if exit is locked.
if (exit.locked) {
msg (exit.lockmessage)
}
else {
// 5: Sets the exit.message, moves the object in the direction indicated, moves object2(player/npc) in the direction indicated, resets exit.message.
exit.message = FormatCmdVerb(WriteVerb2(object2),Conjugate2(object2,cc),Template("the"),object1,exit,".")
object1.parent = exit.to
if (object2 = player) {
HandleSingleCommand ("go " + exit.alias)
}
else {
MoveObject (object2, exit.to)
msg (exit.message)
}
}
exit.message = null
}
}
else {
// 6: Immovable object message.
msg (WriteVerb2(object2) + " cannot " + GetCmdVerb(cc) + " the " + GetDisplayAlias(object1) + " " + exit.alias + ".")
}
}
else {
// 7: Player is immobilised message.
msg (player.immobilisedmessage)
}
</function>
</asl>

Doctor Agon
25 Mar 2018, 22:27Doing tell Quinn to push stone block towards the east
, results in a message "I can't see that(stone block towards the)".
Even tried typing tell Quinn to push block
, received same error message as before.
Tell Quinn to kick
or Tell Quinn to move
all result in the same error message.
There is no Dynamic Template for 'DefaultTellTo'
.
Setting this up in the game will be the following template, which solves the problem
<dynamictemplate name="DefaultTellTo">WriteVerb(object, "do") + " nothing."</dynamictemplate>

K.V.
26 Mar 2018, 00:11> quinn, move the block to the east
I can't see that. (the block to the)
> tell quinn to move the block to the east
I can't see that. (the block to the)
> tell quinn to move block east
He moves the stone block east.
> undo
Undo: tell quinn to move block east
> quinn, move the block east
He moves the stone block east.
Hrmm...
The Regex matching is trying to include the text after object1. I may be able to fix that.
DefaultTellTo (which doesn't exist by default, but I think the pull request has already been merged) will take over if the command doesn't match the pattern (like when we leave off a direction at the end).
You can add a template to handle that, or add the default script to each NPC. (The template would be easier.)
UPDATE: Whoops! I see your other post now. You've already got the template down.

K.V.
26 Mar 2018, 00:36Okay:
^(?<object2>.*), (?<text>push|pull|move) (?<object1>.*) to(wards|) (the |)(?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$|^(?<object2>.*), (?<text>push|pull|move) (?<object1>.*) (?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$|^(ask|tell|order|command) (?<object2>.*) to (?<text>push|pull|move) (?<object1>.*) to(wards|) (the |)(?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$|^(ask|tell|order|command) (?<object2>.*) (towards|to) (?<text>push|pull|move) (?<object1>.*) (?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$
> quinn, move block east
He moves the stone block east.
> undo
Undo: quinn, move block east
> quinn, move block to the east
He moves the stone block east.
> undo
Undo: quinn, move block to the east
> quinn, move block towards the east
He moves the stone block east.
> undo
Undo: quinn, move block towards the east
> tell quinn to move the block towards the east
He moves the stone block east.
> undo
Undo: tell quinn to move the block towards the east
> tell quinn to move the block east
He moves the stone block east.ne block east.

Forgewright
26 Mar 2018, 12:42How about pushing the block at/toward/on a monster. Using the block as a crushing weapon? Yeah, uh huh, what about that?
mrangel
26 Mar 2018, 13:10Doing tell Quinn to push stone block towards the east, results in a message "I can't see that(stone block towards the)".
If you have optional words immediately after a (?<object>.*)
, they won't work. Because .*
matches as many characters as possible, and only backs off if the next part of the pattern can't match.
You want to make it non greedy, as (?<object1>.*?)
... so the string that Quest checks against the scope is the shortest string possible so that the rest of the string matches the rest of the pattern.

Doctor Agon
26 Mar 2018, 19:55@Forgewright: Never thought of that. I've just been using the block as something to stand on, the idea being that it's located in an adjacent room, and moving the block, and then standing on it, enables you to pick up an object that was out of reach.
@mrangel: Thanks for the info, as always.
mrangel
27 Mar 2018, 09:30It seems there's a number of people having issues with the way patterns match. Maybe I should try offering a kind of beginner's guide to regular expression priority. Feel free to share with anyone else having similar issues.
There's often more than one set of characters that a regular expression will match. And if you stick several blocks together, there's several ways they could share the string between them. For example, (.* )
could match "block "
, "block to "
, or "block to the "
. While (to(wards)? the )?
would match "to the "
or ""
.
The leftmost part of the expression takes priority. So the first part of the pattern gets first choice of which bit it wants, and then the remaining parts of the expression have to share out what's left between them. The first part of the expression will take the longest thing it can, as long as the remainder can still possibly match.
But what's its "first choice"? With an expression that can match a couple of different things, which one will it prefer?
x*
matches zero or more copies ofx
.x?
matches either a single copy ofx
, or nothing.x+
matches one or more copies ofx
.x{2,5}
matches between 2 and 5 copies ofx
(inclusive). In all of these,x
can either be a single character, an expression in parentheses, or a characters class. These are the greedy quantifiers - they will take as many characters as they can, as long as the rest of the string can still match.(fish|chips|lemons)
will match any of the patterns between its|
s. It will try to match them in order - if the first one both matches the string and allows the remainder of the pattern to match, it will use that one. That's why if you're doing something like(an|a|the|)
you putan
beforea
, and the empty pattern at the end, unless the expression after it would fail match a string that started with"n apple"
.- The greedy quantifiers all have non-greedy versions. These are
x*?
,x??
,x+?
, andx{2,4}?
. These will match the smallest number of copies ofx
that still allows the rest of the pattern to match. (the numbers in thex{n,m}?
one are just for example; you can use any number you want. Omitting either number makes it unbounded; for examplea{3,}?
will match at least 3 "a"s in a row.) - There are also possessive expressions, but you rarely want to use them. These are
x*+
,x?+
, andx++
. They will "claim" as many instances of 'x' as there are at that point in the string, and will not let the rest of the expression have them. So(.++) etc
will never match. The(.++)
will match all of the string, leaving nothing for theetc
to match against, so the match always fails.

Doctor Agon
29 Mar 2018, 20:35Arraghhh. Having to do another re-write. I changed my mind, whilst still wanting an Npc character to move the object, I also want the player to have the ability to be able to move the object later in the game, which necessitated a Boolean attribute and hence a re-write.
Also, upon further testing of the original scripting above, I discovered I can type pen, push block e
, and received the message, 'It pushes the block e'
. How can I check if an object has an inherited type.
In this case If object 2 has inherited type(NpcType)
hegemonkhan
29 Mar 2018, 20:44if (DoesInherit (NAME_OF_OBJECT, "NAME_OF_OBJECT_TYPE")) {
// scripting
}
// optional:
else if {
// scripting
}
// optional:
else {
// scripting
}
here's the link
http://docs.textadventures.co.uk/quest/functions/doesinherit.html
Object Type = Inherited Attribute // they're the same thing

Doctor Agon
30 Mar 2018, 07:14Thanks HK, I'll check out the link.

Doctor Agon
31 Mar 2018, 06:49While doing further testing, I was not getting the expected response when trying to get a group of characters to move the object.
I have it on the object's setup tab as being 'Male Character (plural)' or 'Female Character (plural)'. Their is no 'Inherited Type' for such groups of characters, so had to add 'npc_type' to the list of Inherited Types. Is there a reason behind this?
hegemonkhan
31 Mar 2018, 13:03not sure on the built-in stuff, though there should be these Object Types:
http://docs.textadventures.co.uk/quest/elements/object.html (scroll down to the very bottom, to the 'Object types defined by Core.aslx' section/category) (as well using any of the rest of the Object's built-in Attributes above too, though you'd NOT use the 'DoesInherit' for them of course, as they're not: Inherited Attributes / Object Types)
female
femaleplural
male
maleplural
namedmale
namedfemale
if quest is not recognizing them via:
if (DoesInherit (NAME_OF_OBJECT, "NAME_OF_OBJECT_TYPE")) { /*scripting */ }
then, someone who knows quest better, can hopefully explain why it's not working, as I don't know why it'd not be working
though, you can always make and use your own Object Types
(as remember, the 'editor_room', 'editor_object', and 'editor_player', are just for the GUI/Editor's controls/features/options/tabs/etc, they're destroyed when you actually play/start the game, so you can't use them within any scripting, such as with 'if does inherit', so, you'll have to make your own such Object Types, in order to use them within scripting during actual game play usage)