How to make button combination locks?

I've seen it used in a few games and downloaded their code but I can't seem to find an explanation on HOW exactly it works, and I don't want to rip the other games off.
Help gladly accepted.


I can think of a few things you could mean by "button combination locks".

The first that comes to mind is something I've seen in one of the first Quest games I played, where there are five coloured buttons. The player needs to "push red button", "push green button", "push push purple button", "push blue button" in the right order.

Something like that?

I'm assuming that a door (or something) unlocks when you enter the correct sequence.

Is there any immediate sign of failure if you press the wrong one? Does the lock buzz to let you know you've got it wrong? Or does it only give a signal if your combination is right or wrong after you've pressed all four (or however many) buttons?

Does the combination reset so that you can start again immediately when you press a wrong button? Does it reset after yuou've entered an incorrect combination? Or is there a reset button you've got to press before you start again?

Do you want a screen that shows the combination you've entered so far? Or do the buttons you've already pressed light up so you know which ones you've pressed?

There's a few different variations, and I think they'd likely be coded in slightly different ways.


J_J

So, for the button code on my game I just used flags. So, when you press a button set a flag to indicate that was done.

Let's say they need to press yellow, blue, red. They press yellow first, set flag: yellowpress. Have an if expression that checks it is the only color flag set. Then they press red. Have another if (){expression here. It will check if flag yellowpress and bluepress = success msg, else = failure msg (and clear flags if they get a second chance)

If that is confusing I can add some code to show you if you need.


Or easier yet... is it a number code, like “12345”?

“So the combination is 1,2,3,4,5... That's the stupidest combination I've ever heard in my life! That's the kind of thing an idiot would have on his luggage!”
-Lord Helmet

I guess we just need to know what kind of combination lock you’re using.


Close... the code was 1, 2, 3, 4, 5, 6...
(then in walks President Scrube…) (However it is spelt)…
I did something similar in my Adventure game (in Visual Basic)…
Right combo "clicked" for each correct choice, but auto-reset on a wrong choice...
It should be just about the same in Quest...


for the one of the puzzles in Maniac Mansion, you could put in: 0000

and it works, instead of going through the steps to get the actual combination


true story:

I was playing 'might and magic world of xeen' (4+5: xeen/light + dark side of xeen), as a kid, and there was this one chest that required a password, so just for the heck of it, I typed in 'open sesame', and the chest opened! I should have gone out and bought a lottery ticket! I was so shocked that it worked! (it was the actual correct password for the chest). I'm sure in-game there was a clue somewhere for its password, but I never found it. (and this was before the internet, so no free solution/help lookup)


Like others, I generally use string input for keypads and combination locks but I do have one (in Giantkiller Too) which is much more elaborate. A three by three keypad is displayed and updated as the player presses each key. The pressing order has to create a magic square to open a cage. The implementation is pretty much hardwired into the game but I'm happy to discuss the details.


Wow, I wasn't expecting just a large amount of responses overnight! To answer which kind of lock I need, mrangel pretty much hits it on the head.

It's a 4 digit lock on a box, where instead of numbers (with it just being a case of recognising the string) there are images on the buttons, and you'd have to press in the right order. If the wrong button was pressed, then the player would be returned to the starting room with damage done to them (a.k.a being "knocked out"). The button presses would then reset so that the player can't trail and error the lock particularly easily.

Once again thanks for all the responses!


Is it "press 4 buttons, then if they're not right you get knocked out and sent back", or "you get knocked out as soon as you press a wrong button"?

Also, does pressing a button you've already pressed reset the combination, count as a wrong button, or not do anything?


The way I'd implement it to start with is to make the lock a "surface" type container, with four buttons "on" it (making sure that the buttons can't be taken).

Then the buttons each have a 'push' verb, looking something like this:

msg ("The button presses in with a click.")
if (HasString (this.parent, "buttons_pressed")) {
  this.parent.buttons_pressed = this.parent.buttons_pressed + "/" + this.name
}
else {
  this.parent.buttons_pressed = this.name
}

And then on the lock, you have a script attribute named changedbuttons_pressed which contains:

correct_combination = "circle button/square button/triangle button/star button"
if (this.buttons_pressed = correct_combination) {
  // code here to open a door, or whatever else the lock is for
}
else if (not StartsWith (correct_combination, this.buttons_pressed)) {
  msg ("The panel gives you a shock, and you find yourself passing out.")
  // any code you need to knock out the player goes here
  MoveObject (player, starting area)
  this.buttons_pressed = null
}

If you want the combination to be different sometimes, you could have correct_combination as an attribute of the lock.
I've just made it the names of the buttons, with slashes between them.


Sorry about asking something which is probably very obvious, but where do I add the script attribute? Is it in the "after locking" part of the Container tab?


On the 'attributes' tab (assuming you have the desktop version of Quest)

If you're on the web editor, you'd have to go to 'features', tick the initialisation script, and then on the initialisation script tab you'd put:

this.changedbuttons_pressed => {
  // script goes here
}

I was thinking about a combination lock that opens a door. Putting it on a container might be more complex, because Quest doesn't give you an easy way to distinguish between items in the box and items on the box. I'm thinking about how you'd do that,


Thank you so much!
The only concern I have left is that the "knocking out" part doesn't work:

Error running script: Error compiling expression 'not StartsWith (correct_combination, this.changedbuttons_pressed)': FunctionCallElement: Could find not function 'StartsWith(String; LazyLoadScript)'

Is there another function I need to add in to make the script work?
Aside from that, the script works really well!


The expression quoted in the error message is not StartsWith (correct_combination, this.changedbuttons_pressed); the expression in the code is not StartsWith (correct_combination, this.buttons_pressed).

Think you may have accidentally added a changed there.


(Also, I had a thought about how to make a combination-lock safe.

You could make two separate objects with the same alias:

  • combination_safe_locked
    • Is a "surface"
    • Has button objects inside it
    • Is visible
    • Has the scripts listed above
  • combination_safe_open
    • Is a "container"
    • Has treasure or something inside it
    • Is initially closed, and invisible

The // code here to open a door, or whatever else the lock is for in this case would be:

  combination_safe_open.parent = this.parent
  combination_safe_open.visible = true
  OpenObject (combination_safe_open)
  this.visible = false

and the combination_safe_open would have a changedisopen attribute:

if (not this.isopen) {
  combination_safe_locked.parent = this.parent
  combination_safe_locked.visible = true
  combination_safe_locked.buttons_pressed = ""
  this.visible = false
}

The problem with this method is that "open safe" when it's locked would generate the message "It is already open", and I can't see a way to get around that without modifying TryOpenClose.


Unfortunately, the same message appears, which is probably due to the StartsWith being identified for some reason by Quest as a function.
However, the actual script itself works perfectly, so if there is a way to hide an error message that might be easier than trying to solve the error itself.


StartsWith() is a function. But because it's a built-in function, Quest checks that it's receiving the right kinds of arguments. StartsWith only works on two strings, so when it was looking at the change script it complained that there isn't a StartsWith function that compares a string and a script.

I looked at the code again, and spot a possible issue. Is the error now: Error running script: Error compiling expression 'not StartsWith (correct_combination, this.buttons_pressed)': FunctionCallElement: Could find not function 'StartsWith(String; Object)'?

If so, that would be because it's resetting the string to null after the player gets it wrong, and null isn't a string.

In that case, it should be:

correct_combination = "circle button/square button/triangle button/star button"
if (this.buttons_pressed = correct_combination) {
  // code here to open a door, or whatever else the lock is for
}
else if (HasString (this, "buttons_pressed")) {
  if (not StartsWith (correct_combination, this.buttons_pressed)) {
    msg ("The panel gives you a shock, and you find yourself passing out.")
    // any code you need to knock out the player goes here
    MoveObject (player, starting area)
    this.buttons_pressed = null
  }
}

Checking that the player has actually pressed buttons before checking if their combination-so-far is right.


If you want the code to be random, so the player can't just look it up in a walkthrough, you could generate it in the lock's _initialise_ script (which is run as soon as the game starts).

You'd remove the correct_combination = line from the start of the changedbuttons_pressed script, and change the correct_combination in the two if lines to this.correct_combination.

Then the initialise script (which can be enabled on the 'features' tab) would be:

buttons_in_combination = NewStringList()
buttons_not_used = GetDirectChildren (this)
while (ListCount (buttons_not_used) > 0) {
  next_button = PickOneObject (buttons_not_used)
  list remove (buttons_not_used, next_button)
  list add (buttons_in_combination, next_button.name)
}
this.correct_combination = Join (buttons_in_combination, "/")

And if there's a note somewhere because a manager has written down the combination, you could make its look attribute something like "Don't forget, the combination is {combination lock.correct_combination}."
To use the aliases of the buttons wouldn't be much harder; or even give the buttons an attribute like "human_name" so you could have the manager write "CSTSt" or something that might take a few seconds to understand.


Hallelujah! The error has been solved! Thank you so much for your help mate, I'm relatively new to coding and scripting (only about a year's practice!).


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

Support

Forums