Push #object# direction

I 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.

It 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.


Hmmm, 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.

It works for me.

Here's the proof:

move_object_east


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>


Thanks 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.

Sorry 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.


Whilst 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.

Did 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.

Upon 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.

The 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>

Doing 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.

> 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.

Okay:

^(?<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.


How about pushing the block at/toward/on a monster. Using the block as a crushing weapon? Yeah, uh huh, what about that?


Doing 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.


@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.


It 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 of x. x? matches either a single copy of x, or nothing. x+ matches one or more copies of x. x{2,5} matches between 2 and 5 copies of x (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 put an before a, 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+?, and x{2,4}?. These will match the smallest number of copies of x that still allows the rest of the pattern to match. (the numbers in the x{n,m}? one are just for example; you can use any number you want. Omitting either number makes it unbounded; for example a{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?+, and x++. 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 the etc to match against, so the match always fails.

Arraghhh. 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)


if (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


Thanks HK, I'll check out the link.


While 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?


not 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)


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

Support

Forums