Locked doors like Resident Evil

I have a project where the player has to collect different theme keys (like in the Resident Evil games, these keys often are supposed to unlock several different doors).

Standard doors work to me with a simple script, to make it more appealing:

msg ("You go through the door.")
play sound ("0001_b.wav", true, false)
play sound ("0021_b.wav", true, false)
player.parent = this.to

The sound effects are to have a knob turning and the door opening. So here are the two things I'd like to do if the door is locked

  1. Play the knob sound
  2. Display the message "It's locked. There's a carving of the Wind".

With the Print message when locked option in the exit I manage to do the second part, however, I can't play a sound nor can I make a script to run only if the exit is locked.

I checked the forum and found this:
https://textadventures.co.uk/forum/quest/topic/eweqzj1dkuyb3juacbgvrg/run-script-if-door-is-locked

Seems like what I need, however the part:
if(this.locked)
Doesn't work, as the message in Print message when locked overrides it. Deleting that message doesn't work, as it just makes the game not say anything if the player tries to use the locked door.

Another thing that would be great to know:
Say I have 3 doors that requird the Wind Key, after unlocking all of them, is it possible to tell the player that this key has no more use and can be discarded? I wanna implement inventory limitations so that'd allow the player to know he can drop the key with no fear of having to backtrack for it.

Thanks in advance!


Hmm... Well, one way to get around it would be to completely bypass the in-built lock function.

Rather than setting the exit to locked, make an attribute for it instead -- 'locked' is taken by Quest, I assume, so just call it lock. You can make it a Boolean - true or false - or an integer that goes from 0 to 1. 0 for unlocked, 1 for locked. The same effect, but some people prefer one way or the other.

Give your exit a name, first. It's the box just above the checkbox for 'visible'.

Activate the 'run a script' button beneath that box that sets the 'print when locked' message, then make an if check.

if (exit name.lock = 1) {
//Stuff in this section will appear when the door is locked! You can make a second if check to see if the player has a key -- if it's an item, check to see if the item's .parent attribute is the player object -- in other words, is it in their inventory! If the key is simply an attribute set to true in the player's attributes, then instead check to see if that attribute is true or false.
if (player.key) {
msg ("You insert the key, give it a turn, and the door opens!")
//Then move the player into the room, which can be as simple as inserting a move object script where the object is the player, and the new room is the target destination!
MoveObject (player, roomname)
}
else if (not player.key) {
msg ("You don't have the right key for this door!")
}
}
else if (exit name.lock = 0) {
//The door's already unlocked, so you don't have to worry about anything here, other than inserting the script to move the player into the next room as above, seeing as you disabled the automatic movement!
MoveObject (player, room)
}

That should look neater -- with the //comments appearing in green -- in the engine itself. Have a play with it, but be aware that the great thing about Quest is that you can have 50 solutions for one problem, and the best advice I can give is if it works, it ain't stupid!

I need to go pass out, but if there are any issues, I'll try to help tomorrow if no one else has offered solutions or advice! Hell, someone might have a solution more in keeping with your original question. I've not played with the built-in locks in ages, so my solution was to work around them.

Oh! As for your second question, yeah, that's totally possible. You could make an attribute on the key object or the player entitled Wind Key Uses, set it to 3, and then every door you unlock with it in the manner above, add in;

player.Wind Key Uses = player.Wind Key Uses - 1

Then, you could use a change script, a timer script or just an if check at the end of each door unlock with the Wind Key to check if this variable has hit 0. If it has, you can print a message telling them to discard it... or you could just move the object out of their inventory into a dev room, or even outright destroy the object, with a message like 'The Wind Key crumbles to dust, its purpose fulfilled!'

edit; Your existing code already handles player movement in another valid way, d'oh. Then you should be able to understand that mess I posted just fine, I hope! Good luck!


The problem is that the script on an exit runs instead of sending the player through it; so only if the door isn't locked. So you would probably want to have your own attribute, maybe unlocked, to keep track of when the door has been unlocked without using Quest's default "lock" behaviour.

So the script would be something like:

play sound ("0001_b.wav", true, false)
if (GetBoolean (this, "unlocked")) {
  msg ("You go through the door.")
  play sound ("0021_b.wav", true, false)
  player.parent = this.to
}
else {
  if (ContainsReachable (game.pov, wind key)) {
    msg ("You unlock the door with the wind key and go through.")
    play sound ("0021_b.wav", true, false)
    this.unlocked = true
    player.parent = this.to
  }
  else {
    msg ("It's locked. There's a carving of the Wind.")
  }
}

I'm assuming that the key is an object that might be in the player's inventory; while Pykrete thought it might be an attribute set on the player. Both ways work, but I prefer to use objects as objects myself.

Say I have 3 doors that requird the Wind Key, after unlocking all of them, is it possible to tell the player that this key has no more use and can be discarded? I wanna implement inventory limitations so that'd allow the player to know he can drop the key with no fear of having to backtrack for it.

There's 2 ways you could do that. You could give the key a uses attribute to track how many doors each key is needed for, but I wouldn't do it that way. Instead, I'd give the door a key attribute that points to the appropriate key. In this version you don't need an unlocked attribute; you can just remove key, which makes the code a little simpler.

play sound ("0001_b.wav", true, false)
if (HasObject (this, "key")) {
  if (ContainsReachable (game.pov, this.key)) {
    msg ("You unlock the door with the " + GetDisplayAlias (this.key) + " and go through.")
    if (ListCount (FilterByAttribute (AllExits(), "key", this.key)) = 1) {
      // This is the only door left using that key
      msg ("The key crumbles into dust, its purpose fulfilled.")
      RemoveObject (key)
    }
    this.key = null
  }
  else {
    msg ("It's locked. " + this.lockmessage)
  }
}
else {
  msg ("You go through the door.")
}
if (not HasObject (this, "key")) {
  play sound ("0021_b.wav", true, false)
  player.parent = this.to
}

In this case, it checks if there is an exit other than this one that needs the same key, and otherwise destroys it.


Thank you so much for you replies, I managed to do something that is like between both answers and that works well for me.

Although I started to wonder... What if I had a door that needs a key, but the player has another way around it. (what I mean is, the locked door would just save a lot of time during the navigation, but not really stop the player from progessing). So how can I handle the situation where the player might unlock it from either side?

I'm assuming I can do something like:

if (this.lock) {
if (Wind Key.parent = player) {
 play sound ("0031_a.wav", true, false)
msg ("You used the " +Wind Key.alias +".")
Wind Key.uses = Wind Key.uses -1
this.lock = false
if (Wind Key.uses=0) {
  RemoveObject = Wind Key
  msg ("The " + Wind Key.alias + " is now useless. Discarded it.")
}
else {
 }
}
  else {
msg ("The door is locked. Under the keyhole you see a carving of wind.")
play sound ("0041_b.wav", true, false)
}
}
else {
 msg ("You go through the door.")
 play sound ("0001_b.wav", true, false)
 play sound ("0021_b.wav", true, false)
 MoveObject (player, this.to)
}

By using the line:

this.lock = false

To also set the other side's lock to false too. Is that a good way to handle it?


What if I had a door that needs a key, but the player has another way around it.

My preferred way of doing this is using a changescript. If you have a script attribute named changedlock, Quest will run it automatically every time the lock attribute changes. So you would make it:

name_of_other_exit.lock = this.lock

Or if you don't want to name your exits, you could do:

otherside = GetObject  (GetExitByLink (this.to, this.parent))
otherside.lock = this.lock

That's actually way simpler than I expected.

If you have a script attribute named changedlock, Quest will run it automatically every time the lock attribute changes.

Does this mean I don't actually have to use the command:

name_of_other_exit.lock = this.lock

Manually once the door is unlocked?


Does this mean I don't actually have to use the command:

You can put that line in a changescript, or after you unlock the door.

The advantage of the changescript is that in games where there's more than one way to unlock or open a door, the same changescript will handle all of them. It's a one-line way to keep an attribute synchronised between two different objects or exits.

In your case, because there's only one way to unlock the door, it's just as easy to set the lock attribute for both exits in the same place. But if you do that, you'll need to remember to unlock both exits any time you add another way to unlock a door in future. I tend to prefer using changescripts as a "just in case" measure; it means that if I add some features in future, the number of details I need to remember to deal with is smaller.


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

Support

Forums