Unlocking / opening and closing/locking a container object with a separate door object

Hi, I'm brand new to Quest - thought I'd try to learn how to use it now that I have time on my hands! I've made some progress creating a small adventure, but now I've hit a snag. No doubt the answer to this is blindingly obvious, but in the game:

I have a locker (container) with a separate door. The door is a separate object as I need a different description when specifically the door is examined, and there is a coin in it (it's a changing room type door with a coin slot key release mechanism). My problem is that I can open/close/lock/unlock the locker fine, but I can't do the same with the door. What I need to happen is for 'open/close/lock/unlock door' to have the same effect as 'open/close/lock/unlock locker' as it is as natural to say 'open door' as 'open locker', but I can't figure out a simple way to do that; at the moment 'unlock door' gives 'you can't do that', whereas 'unlock locker' does what it is meant to. I'm sure there is a straightforward way to accomplish this...but how?


Is the door already a container?

You can set script attributes on a container (openscript, closescript, onlocked and onunlocked, I think) to run when the player opens or unlocks an object. I believe that the default lockable type uses the openscript and closescript to prevent the object being opened when locked.

I'd make the door a container, but change the scripts so that they open the container instead.

If you're having trouble, I can take a proper look at this in the morning.


Thanks mrangel - yes, the door is an object. How do I change those scripts? I've looked in all the places I can think of and trawled through the code view (which is pretty baffling), but I can't fathom it. I had an idea that I could use a script on the door object to point to the relevant scripts in the locker object using 'do', but couldn't get it to work!


[disclaimer - writing code off the top of my head, I haven't tested this]

The scripts are on the 'Container' tab I think.
If you make a container lockable, then it should automatically fill in openscript and closescript to make the lock work; you could then change the name of the object in those.

If you're on the desktop version of Quest, you could also add script attributes on the 'Attributes' tab.

The possible problem I can see is that you mention having a coin in the door; if this is an object that can be taken, then you would need to make the door "open" so that the object can be taken out of it; and the open/close commands only run the user script if the object isn't already open/closed.

Method 1


Discounting the coin for now, I'd probably do something like this:

On the door:

<openscript type="script">
  do (locker, "openscript")
</openscript>

<closescript type="script">
  do (locker, "closescript")
</closescript>

<lock type="script">
  do (locker, "lock")
</lock>

<unlock type="script">
  do (locker, "unlock")
</unlock>

And on the locker:

<changedisopen type="script">
  locker_door.isopen = this.isopen
</changedisopen>

(assuming that locker and locker_door are the object names)
This means that the verbs lock and unlock will be run on the locker, whether the player types "locker" or "door".
The same can't be done for "open" and "close", because they're commands rather than verbs. The nearest we can get is using the script attributes openscript and closescript - but openscript will only be run after the core test to see whether the door is already open or closed. So we also put a changedisopen script on the locker itself, to ensure that the door's open/closed state is the same as the locker's.

If you can't take the coin out of the door, then this should work fine. You'd just make the door a transparent container in order to enable the coin to be seen.

Method 2


An alternate way of doing this. Put a command in the room:

<command name="door_stuff">
  <pattern type="string"><![CDATA[^(?<object_command>open|close|lock|unlock) (?<object>.+)$]]></pattern>
  <changecommandscope type="script">
    if (variable = "object_command") {
      while (ListCount (items) > 0) {
        list remove (items, ListItem (items, 0))
      }
      list add (items, open)
      list add (items, close)
      list add (items, lock)
      list add (items, unlock)
    }
  </changecommandscope>

  <script>
    params = NewDictionary()
    if (object = locker_door) {
     object = locker
    }
    do (object_command, "script", QuickParams ("object", object))
  </script>
</command>

This overrides 4 commands at once, using changecommandscope so that the parameter object_command will match a command rather than an object, and then uses do to execute the underlying command.

This means that if the door is a container in its own right (so you can put a coin in it and take it out), it will work like any other container; it's only the four verbs listed that will be redirected. (If adding other commands to this function, note that it ignores the pattern of the real commands, and looks at the name of the commands. If a command's name and pattern aren't the same, you would need to put the words that you expect the player to type within the <pattern> line, the name of the command in the list within the changecommandscope block, and give the command an alias attribute to match what the player typed)


(Just in case anybody's interested but confused by the comments about using method 2 with other commands, here's another example:

Another example
<command name="mesmerised">
  <pattern type="string"><![CDATA[^(?<object_command>look|look at|x|examine|exam|ex|listen|listen to|taste) (?<object>.+)$]]></pattern>
  <changecommandscope type="script">
    if (variable = "object_command") {
      while (ListCount (items) > 0) {
        list remove (items, ListItem (items, 0))
      }
      list add (items, lookat)
      list add (items, listento)
      list add (items, taste)
    }
  </changecommandscope>

  <script>
    params = NewDictionary()
    if (spiral.switchedon and RandomChance (30)) {
      msg ("You try to "+GetDisplayAlias (object_command) + " the " +GetDisplayName (object) + ", but you can't tear your attention away from the mesmerising spiral in the centre of the room.")
     object = spiral
    }
    do (object_command, "script", QuickParams ("object", object))
  </script>
</command>

And then in the start script (or somewhere before entering this room), you'd need to put:

lookat.alias = "look at"
lookat.alt = Split ("x;examine")
listento.alias = "listen to"

Hi

Method 1 works perfectly - thank you.

I've managed the coin behaviour by running a script when the door is examined to move the coin to the locker. So, when the locker is examined after the door has been examined (revealing the coin slot mechanism), the coin is present in the locker and can be taken.

A problem that I now have is that I don't want it to be possible to put anything in the door expect the coin. I can add a script to run when trying to add an object to the door, to say 'you can't do that' but I want to respond to the input 'put COIN in door' by moving the coin to the locker . What I can't figure out is how to reference the object that the player has entered...I need something like: Player inputs 'put X in door': if player says 'put COIN in door' then move coin to locker, else say 'you can't do that'.

I've avoided method 2 because, frankly, I don't really understand enough about how it works yet. But perhaps it would be simpler to use that than try and do what I am trying to do?


In the script when trying to add an object, you can do something like:

if (object = coin) {
  object.parent = locker
}
else {
  msg ("You can't do that.")
}

Brilliant! It works, thanks. I have learnt a lot, just from trying to figure out this little bit of the game.


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

Support

Forums