Randomness
mrangel
07 Sept 2021, 13:49I was recently playing a game, and someone advised that if you're after a particular status effect you can keep surrendering to one of the bosses. (you get one at random if you surrender in battle; each monster has 1-4 options). But their method for getting there quickly was an interesting one: walk around until you get a battle. If it's not a monster that offers the ending you want, undo and repeat. Once you have the monster you want, surrender. If the result isn't the one you want, undo and do it again.
Since then, I've been wondering if there could be a way to prevent the abuse of 'undo' to redo random stuff.
Not sure if there's really a point; I want the game to be fun. But it would be nice if it wasn't so easy to 'cheat'. So, here's my solution (pseudocode):
Random Number function
As well as the range of numbers to select, this will have a parameter for 'reason'. This would be a string like attackroll_goblin
or Wizard_Nigel_drops
. In the case of PickOneString, it probably makes sense to use the list of options as the reason.
RandomNumber does:
- If there is a number in
game.rng_pending
with the same reason, choose it (and remove it) - Otherwise, call
GetRandomInt
- Store the number in
game.rng_generated
- This is a list of dictionaries. Each dict contains a random number, its range, and its reason.
- To prevent file bloating, you could remove items from the beginning of the list if it's over a certain length
- Then return the number
The 'undo' command will:
- Copy rng_pending and rng_generated into local variables (which aren't affected by transactions)
- call
undo
- Compare the local variables to the list attributes.
- Entries in
rng_generated
before the undo that are no longer there should be added torng_generated
unless they're already there - Then any entries that were in
rng_pending
before the undo but aren't now should be added.
- Entries in
This basically means that when the game generates a random number for some specific purpose (treasure, combat, etc), it records it in a log. When you undo, those stored numbers will be put into a queue, so that they'll be used the next time you roll for that thing. You presumably don't need to save numbers for purely cosmetic things like using {random:
in the text processor to taunt the player, but it does mean that you can't keep undoing and attacking the same monster again until you get a critical hit. And (unlike a random queue without the reasons), you can't respond to a fumble by undoing and skipping a turn so an enemy gets your bad luck.
What do you think? I'm pretty sure I'm thinking about this too much; but it would be nice to have an anti-cheating feature that doesn't disable 'undo' entirely.

DavyB
07 Sept 2021, 18:02Perhaps UNDO is itself a 'cheat'? I don't think I've encountered a case where a designer has incorporated it in game play? Indeed, as you know, UNDO in standard Quest is broken so perhaps most designers don't even think about it?
Out of curiousity, I tried UNDO in The Mansion (2004, Quest 3), with the following surprising result:
> n
The glass paned door is locked. If you had a weapon, you could smash it open, or maybe there's a key somewhere around.
> undo
You pick it up.
mrangel
07 Sept 2021, 19:01I think there is a place for undo in games. I know I use the up/down arrows a lot when repeating commands; but sometimes memory is imperfect and you enter the wrong thing. I think 'undo' and 'oops' are reasonable if you mistyped a command; or hit enter before completing a list of objects. (Especially as I'm in the habit of only typing the first few letters of an object's name, for speed. Sometimes it's possible for a typo to select completely the wrong object.
Very much a personal thing. Using it to cheese the random number generator feels like cheating to me. Correcting a typo seems like intended behaviour. Trying an option and then going back, I'm not sure about… maybe depends on the game. Somewhere in between the other two.
Pertex
07 Sept 2021, 19:48Wouldn't it be easier to randomly populate an enemy dictionary at game start and then access it with an index variable? With Undo then only the index variable must be reset.
mrangel
08 Sept 2021, 00:22What do you put in the dictionary? All the random numbers for the game?
mrangel
08 Sept 2021, 15:54And that's got me thinking about another useful thing you could do.
If you have a custom function that's used whenever you generate a random number, you could have it call something like JS.recordRandom()
. Have a function which does nothing on the desktop player (as it's not needed), but records the random numbers used into a big array. The array also stores the commands that the player has entered.
Then, if the web player is disconnected (wifi signal issues, server fell over, timeout, or whatever), these arrays are saved to LocalStorage. The JS on the client side pops up a message "you have been disconnected from the server. Reconnect?" And when you reconnect, it reloads the game from the last save.
However, the UI Initialisation script now checks LocalStorage for an array of saved commands and random numbers. If found, they can be splatted back to the server. your rng_pending
is populated with all the random numbers, and the commands from the previous attempt are splatted back into commandqueue
.
Quest can replay the game from your last save point, using a saved copy of all the random numbers you entered so that it's guaranteed to play out the same way. Would enable you to work around any stability issues with the server, and allow players to continue from where they were up to after a timeout or other disconnection.
Pertex
09 Sept 2021, 09:32What do you put in the dictionary? All the random numbers for the game?
It depends on what you need the random numbers for. If you want to randomly spawn monsters, at the start of the game the monsters will be randomly added to a monster dictionary.