Preventing the player missing a message
GregC
18 Aug 2017, 00:45Here's my issue:
I clear the screen when the player moves location. This is a pretty good way to do things and I don't really want to change it if I can help it.
In my game the player can become poisoned. This is a long term issue that gives increasingly urgent messages every 50 actions. The player needs to act on these or they'll eventually die (They get a lot of actions, finding a cure should take a small fraction of them if they make it their top priority)
The problem is that if the player is moving it's really easy for them to miss a message. Players moving through an area they've already explored tend to click a handful of moves really quickly. If a message pops up during one of those moves saying "The poison is getting worse, you really ought to do something to not die." in the middle of a series of quick moves the player might register that something popped up, but it gets cleared before they get a chance to read it.
My ideal solution would be able to give a command that's the equivalent of "If the script hits this line, stop taking player input for 2 seconds" to prevent this. Is there anything like that? Alternatively "If the script hits this line, stop taking player input until they hit a certain key or button to acknowledge the message"
Things that don't work:
Pause seems to have been removed
All of the other "wait" type functions just pause the script, they don't disable player input
Working a delay into movement (I mean it works, but the cure is worse than the disease)
Wait for input doesn't seem to "wait" so much as "let the player keep moving"
Disabling movement based on a timer after the message pops up (Or at least by methods that I know such as hiding exists. Hiding every exit in the game for two seconds seems like using a nuke to fight a goldfish)
Thing that kinda works:
Writing a bit of script to disable the screen clearing for a couple of moves following an urgent message.
This isn't ideal and looks super ugly in some cases, but it's better than nothing.

DarkLizerd
18 Aug 2017, 02:31There is a way to show a message, with a "false" statement, meaning the player must respond to the message before they can do anything else.
So... short answer... yes...
Details (from someone else) in
5
4
3
2
1
...
( I guess that should have been a ShowMenu...)
jmnevil54
18 Aug 2017, 03:13WHO?
I just use the show menu... so...
I don't understand why a disable script wouldn't work...
hegemonkhan
18 Aug 2017, 08:38(filler for getting my edited post, updated/posted)
(again, filler for getting my edited post, updated/posted)
have a condition so you can control (via toggle) the ClearScreen on/off as when-needed:
// in your 'on player moving / entering room / whatever the built-in thing you're using lol' scripting location:
if (game.is_clear_screen_enabled_boolean_attribute) {
ClearScreen
}
// set/re-set it as desired, when/where desired:
//
// game.is_clear_screen_enabled_boolean_attribute = true
// game.is_clear_screen_enabled_boolean_attribute = false
// ---------------------------
// for an example (using a global Turnscript and special 'changed' Script Attributes on the 'player' Player Object, just for an example only --- this is definately NOT the best design, but should be a good example for you to get some ideas on how things can be done):
<object name="player">
<attr name=is_clear_screen_enabled_boolean_attribute" type="boolean">true</attr>
<attr name="poisoned_turn_count" type="int">0</attr>
<attr name="poisoned" type="boolean">false</attr>
<attr name="changedpoisoned" type="script">
player.poisoned_turn_count = 0
if (player.poisoned) {
EnableTurnscript (poisoned_global_turnscript)
} else {
DisableTurnscript (poisoned_global_turnscript)
}
</attr>
<attr name="changedparent" type="script">
if (player.is_clear_screen_enabled_boolean_attribute) {
ClearScreen
}
</attr>
</object>
<turnscript name="poisoned_global_turnscript">
<attr name="enabled" type="boolean">false</attr>
<attr name="script" type="script">
if (player.poisoned_turn_count = 50) {
player.poisoned_turn_count = 0
player.current_life = player.current_life - 100
game.is_clear_screen_enabled_boolean_attribute = false
msg ("Since you're poisoned, you lose 100 life every 50 turns, and it's been 50 turns")
wait {
game.is_clear_screen_enabled_boolean_attribute = true
}
} else {
player.poisoned_turn_count = player.poisoned_turn_count + 1
}
</attr>
</turnscript>
Disabled player input involves removing/hiding the input command box and/or maybe other such stuff (aka: User Interface / JavaScript, customizing) .... which is not my area of knowledge yet (eventually... I'll get around to learning this stuff), there's guides on how to do this, and others who can help you on it.
GregC
18 Aug 2017, 09:09I'm not sure I can see what that last chunk of code does that's different from my existing "Don't clear the screen for a few moves following a message" pseudo solution that I mentioned in the first post.
I feel like jmnevil gives the obvious answer though: Using show menu to put up a one item menu with "continue" as the only option. I've been using menus to construct dialogue trees - I don't know why that didn't occur to me, that feels like it's going to be the most elegant solution. Thanks.

Richard Headkid
18 Aug 2017, 10:07This should do the trick:
Turn Script (enabled at start of game):
//player.poisoned = true
if (player.poisoned) {
player.parent.alias = "YOU HAVE BEEN POISONED"
request (UpdateLocation, "YOU HAVE BEEN POISONED")
JS.eval ("$('#status').css('background-color', 'red')")
JS.eval ("$('#status').css('background-image', 'none')")
request (Show, "Panes")
JS.eval ("$('#gameBorder').css('background-color', 'red');")
JS.addText ("YOU HAVE BEEN POISONED!")
msg ("YOU HAVE BEEN POISONED")
JS.setInterfaceString ("InventoryLabel", "YOU HAVE BEEN POISONED")
JS.setInterfaceString ("PlacesObjectsLabel", "YOU HAVE BEEN POISONED")
JS.setInterfaceString ("CompassLabel", "YOU HAVE BEEN POISONED")
JS.setInterfaceString ("TypeHereLabel", "YOU HAVE BEEN POISONED")
JS.setInterfaceString ("ContinueLabel", "YOU HAVE BEEN POISONED")
request (GameName, "YOU HAVE BEEN POISONED")
game.gamename = "YOU HAVE BEEN POISONED"
ClearScreen
PrintCentered ("<span><h1 style=\"font-size:255%\">{game.gamename}</span><br/><span style=\"font-size:145%\">by The Person Who Poisoned You</span><br/>")
HandleSingleCommand ("look")
ShowMenu ("DO YOU KNOW THAT YOU'RE POISONED???", Split("yes;no", ";"), false) {
}
wait {
}
}
hegemonkhan
18 Aug 2017, 10:07just a comment about using a 'menu' ('show menu (args/params)', 'ShowMenu (args/params)', 'ask (args/params)', 'Ask (args/params)', and any etc such menu Functions) vs using the 'wait' Function:
(lowercase menu Functions are the popup window menus)
(uppercase menu Functions are the 'inline', aka hyperlink, menus)
I don't see how using the menu's forcing a click-selection on a popup menu option or click on a hyperlink (as an option/item you give to the menu) on an 'inline' menu, to continue with the game, any different from the 'wait' Function forcing a click on a 'continue' hyperlink (or the pressing any keyboard key, actually) to continue with the game
GregC
18 Aug 2017, 10:21The wait function seemed to accept any sort of input at all - so if the player wanted to backtrack three rooms west they might click west three times rapidly. Suppose the poison message was supposed to display this tick you'd get
Click west - taken as move
Poison message displayed. Wait started
Click west - taken as input for wait, wait ended
Click west - player moves west, poison message deleted without being read.
I think Richard's solution is too subtle, I don't think the player would notice that ;)
On a side note one of the reasons for having the first poison message happen 50+/- 10 steps after the player is poisoned is so that I didn't want it to display to the player what had poisoned them. A few characters will offer the player food and drink, I'd like a sense of paranoia about which one is trying to kill them.
GregC
18 Aug 2017, 10:34So the poison is now working how I'd like and I figured I'd use this approach in other turn scripts that display some extra text after a player action. It's not working as planned:
Witch.ritual = Witch.ritual + 1
if (Witch.ritual = 4) {
msg ("----------------------------------------------------------------------------------------------------------------")
msg ("The chanting continues, getting faster and louder.")
Continue
}
if (Witch.ritual = 8) {
msg ("----------------------------------------------------------------------------------------------------------------")
msg ("A light flickers and a portal starts to open.")
Continue
}
if (Witch.ritual = 10) {
msg ("----------------------------------------------------------------------------------------------------------------")
msg ("A demon steps through the portal, the lead figure starts to say something, but the demon launches itself into the lead cultist and tears him in half.")
MoveObject (Demon, Ritual Chamber)
Continue
}
if (Witch.ritual = 11) {
msg ("----------------------------------------------------------------------------------------------------------------")
msg ("The demon finishes rampaging through the cultists and turns its attention to you. You barely raise your sword before it strikes")
finish
}
(Continue is just a function that saves me writing the same show message command a bunch of times)
So the intended behavior is that after four and eight moves messages indicate the progress of the ritual. After ten the demon appears in the room. If the player hasn't done something to the demon to stop this script then on eleven it kills the player. And it was working fine.
However now it's treating the showmenu choices as ticks. So when the player hits "continue" after 10 it jumps straight to the message for 11 without giving them a chance to do anything to the new object in the room.
Now I can fix that any number of ways: Disabling the turn script, increasing 11 to 12 (actually increasing all of the numbers if every continue is taking up a tick), etc - but I want to understand why it's happening because it'll probably matter later when I'm writing some other part of the game.
Other showmenu calls aren't counting as a tick - if they speak to someone in the room then they might get into a dialogue tree with a whole bunch of them, but it only ever counts as one tick for the ritual. So why does using a show menu in the turn script itself take up a tick?
hegemonkhan
18 Aug 2017, 10:58(filler for getting this edited post, updated/posted)
ah okay, I didn't realize that you had the issue of the 'wait' Function preserving/keeping/using/doing your inputs (after the wait functionality had ended), which matter for your design... (I didn't know/realized your design involved this stuff, nor did I realize that the 'wait' preserved the inputs.
ya, then you want to wipe out the inputs all together, via hiding the input command bar, in which, Richard knows this UI/pane/JS customization stuff well, ... this is something that I need to eventually get to learning... lol
or... you can use a condition toggle/control:
such as Pixie's custom 'notaturn' Boolean Attribute either within your global Turnscript (as this is the only way of accessing the 'internal turns', unless someone knows what-are (name) the internal turns and/or where they're located within quest's underlying code. I forgot what library of pixie involves this mechanic/design/functionality.... maybe his 'shop' library... ??? You can probably also put in the hide the input command bar into the scripting for a conditional Attribute within a global Turnscript too, instead.
<game name="example_game">
<attr name="is_a_turn" type="boolean">true</attr>
<attr name="turn" type="int">0</attr>
</game>
// you toggle turns on/off by setting/re-setting in whatever scripting location / action / event within the game:
//
// game.is_a_turn = true
// game.is_a_turn = false
<turnscript name="global_turnscript">
<attr name="enabled" type="boolean">true</attr>
<attr name="script" type="script">
// whatever other scripting you want happening globally per turn
if (game.is_a_turn) {
game.turn = game.turn + 1
}
// optionally: else { /* scripting */ }
</attr>
</turnscript>
GregC
18 Aug 2017, 14:43I've actually already hidden the command bar (I didn't want one for this game) originally through javascript, but later found out there was just a checkbox for "I don't want this game to have a command bar" which was much simpler :D
I can see how I could use this script in order to ensure that a particular menu button click didn't advance turn counters - but rather than patching over the problem I'd really like to understand what it is in the first place.
Why do some showmenu clicks trigger turn scripts while others do not?
GregC
18 Aug 2017, 15:43So the example code given above doesn't actually work in this context.
If I create an object and give it a verb script like:
if (game.is_a_turn = true) {
game.is_a_turn = false
}
else {
game.is_a_turn = true
}
And have my turn script not do anything if "game.is_a_turn" is false then it works exactly as intended. I activate the object, ticks stop happening. No more ticks till I activate it again. Great job.
However if I create a turn timer and give it this script:
if (game.is_a_turn = true)
{
msg("Tick")
game.is_a_turn= false
msg ("Turns disabled")
Continue = NewStringList()
list add (Continue, "Continue")
ShowMenu ("", Continue, false)
{
game.is_a_turn = true
msg ("Turns enabled")
}
}
Produces:
Tick
Turns disabled
Continue
(waits until user clicks continue)
Turns enabled
Tick
Turns disabled
Continue
(waits until user clicks continue)
Turns enabled
Tick
...and so on to infinity
Removing the Show Menu command causes it to Tick once and wait for the user to do something else before it ticks again.
So it seems like clicking on the continue button is being causing a tick - but at the point "game.is_a_turn" should be false (we even have a message saying turns are disabled to help us confirm), which means it should skip the tick.
While I'm getting a better picture of the behaviour, I still have no idea why!
GregC
18 Aug 2017, 15:45If I was feeling blunt I could stop trying to disable the ticker and just subtract one from the current turn number instead, but I'm sure having the same turn twice is going to cause some sort of undesirable effect somewhere down the line ;)
GregC
18 Aug 2017, 15:58So here's what I think is happening:
When the player does something the engine sets a variable "under the hood" that means they did something.
Then when all other scripts have finished if that variable is true, it flips it to false, then iterates through the turn scripts one by one.
So when the player clicks on the menu it sets the variable to say that the player has taken their turn - but it doesn't actually execute the turn scripts for that turn until all current scripts have finished. Which means that "game.is_a_turn" is false when the player takes their turn (clicks on the thing) but true when the effects of the player taking their turn are happening (after the current script has finished)
All just conjecture, but that'd explain the behaviour.
GregC
18 Aug 2017, 16:15Okay, I've got it! I'm sure this isn't the most elegant solution, but I'll post it here because there's nothing worse than googling a solution in a forum and finding a thread where someone says they have it and doesn't post their solution ;)
My continue function looks like this:
if (game.continuepause = 0) {
game.continuepause = 2
Continue = NewStringList()
list add (Continue, "Continue")
ShowMenu ("", Continue, false) {
}
}
I have a turn event to manage this. This turn event absolutely must 100% be the first one that runs or it won't work
if (game.continuepause = 2) {
game.ticking = false
game.continuepause = game.continuepause - 1
}
else if (game.continuepause = 1) {
game.ticking = true
game.continuepause = 0
}
else {
}
All of my other turnscripts need this statement around the whole thing
if (game.ticking = true) {
}
Now I can just put
Continue
Anywhere I like in a turnscript and when it hits it the player will have an option to continue printed on screen, the game will pause in all respects until it is clicked, but the tick won't be advanced by this.
Three problems:
- Having to do something to every turn script is annoying (but it's one if, so it's not a huge deal)
- The error catching for "Two turn scripts wanted a continue at the same time" is slightly suboptimal because the first continue is displayed not the second
- I'm pretty sure using the same continue function outside of a turnscript will screw with the ticker, so I need to do something slightly different if (for instance) I want to put this sort of pause into an object's verb script or something like that.
They're pretty minor issues though. Also thinking about it I can fix the second one by taking ShowMenu out of my continue function and put it into another event that goes at the end of the list and triggers if continuepause is 2
hegemonkhan
18 Aug 2017, 16:57there's internal turns (which are a mystery to most people, but maybe Pixie or Pertex knows how the work / where are they in the underlying quest code), which occur upon any action (using the input command box: hitting enter in it, mouse click on a hypertext or menu option or Verb-Object button in the right pane).
but you can control what actions occur with the Turnscript through a conditional:
<turnscript name="global_turnscript">
<enabled />
<script>
if (player.is_a_turn) {
// controlled actions
} else {
// controlled actions
}
</script>
</turnscript>
but, indeed you still got the problem with using the 'wait' Function with input....
you could maybe do this, by the way:
wait {
// to get capture and get rid of any lingering typed-in input:
get input {
result = null // you can do this to be sure the input is gone that was stored into 'result'
}
}
GregC
21 Aug 2017, 10:06I don't think that's true, I think the above fairly conclusively demonstrates that the internal turns don't occur on any action, but instead that doing the action sets a flag which causes the turn to occur later (so the conditional turnscript doesn't behave as you'd expect because turn actions taken while the turnscript is disabled can still cause a turn if it's re-enabled before the flag is checked)
The Pixie
21 Aug 2017, 12:30Clicking a button or hyperlink just sends a command to Quest exactly as if the player typed a command.
Part of processing a command is that at the end of it all enabled turnscripts are run using a function called RunAllTurnscripts I think.

K.V.
21 Aug 2017, 17:07CLICK HERE to few the 'Finish turn' scripts.
Finish turn:
RunTurnScripts
UpdateStatusAttributes
CheckDarkness
UpdateObjectLinks
RunTurnScripts:
if (IsGameRunning()) {
if (game.menucallback = null) {
foreach (turnscript, AllTurnScripts()) {
if (GetBoolean(turnscript, "enabled")) {
inscope = false
if (turnscript.parent = game or turnscript.parent = null) {
inscope = true
}
else {
if (Contains(turnscript.parent, game.pov)) {
inscope = true
}
}
if (inscope) {
do (turnscript, "script")
}
}
}
}
}
UpdateStatusAttributes:
if (game.enablehyperlinks) {
data = NewStringDictionary()
foreach (object, ScopeVisible()) {
dictionary add (data, object.name, Join(GetDisplayVerbs(object), "/"))
}
JS.updateObjectLinks (data)
exits = NewStringList()
foreach (exit, ScopeExits()) {
list add (exits, exit.name)
}
JS.updateExitLinks (exits)
commands = NewStringList()
foreach (cmd, ScopeCommands()) {
list add (commands, cmd.name)
}
JS.updateCommandLinks (commands)
}
CheckDarkness:
if (game.enablehyperlinks) {
data = NewStringDictionary()
foreach (object, ScopeVisible()) {
dictionary add (data, object.name, Join(GetDisplayVerbs(object), "/"))
}
JS.updateObjectLinks (data)
exits = NewStringList()
foreach (exit, ScopeExits()) {
list add (exits, exit.name)
}
JS.updateExitLinks (exits)
commands = NewStringList()
foreach (cmd, ScopeCommands()) {
list add (commands, cmd.name)
}
JS.updateCommandLinks (commands)
}
UpdateObjectLinks:
if (game.enablehyperlinks) {
data = NewStringDictionary()
foreach (object, ScopeVisible()) {
dictionary add (data, object.name, Join(GetDisplayVerbs(object), "/"))
}
JS.updateObjectLinks (data)
exits = NewStringList()
foreach (exit, ScopeExits()) {
list add (exits, exit.name)
}
JS.updateExitLinks (exits)
commands = NewStringList()
foreach (cmd, ScopeCommands()) {
list add (commands, cmd.name)
}
JS.updateCommandLinks (commands)
}

K.V.
21 Aug 2017, 17:33Make a function, then call it under else, otherwise, or default.
(I made a command to call the function, but you can call from whatever script you choose; a start script, room enter script, whatever.)
Command pattern:
test the loop
Script:
loopit
FUNCTION: loopit
msg ("CLUE: the 7th letter<br/>")
PrintCentered ("<b><u>PLEASE ENTER THE ANSWER NOW{notfirst:<br/><br/> (You must enter the correct response to proceed!)}</u></b><br/>")
get input {
switch (LCase(result)) {
case ("g") {
firsttime {
msg ("You win!")
}
otherwise {
msg ("\"" + result + "\" is incorrect.<br>")
msg ("Try again.<br/>")
loopit
}
}
default {
msg ("\"" + result + "\" is incorrect.<br>")
msg ("Try again.<br/>")
loopit
}
}
}
examplegame
CLUE: the 7th letter
PLEASE ENTER THE ANSWER NOW:
"a" is incorrect.
Try again.
CLUE: the 7th letter
PLEASE ENTER THE ANSWER NOW
(You must enter the correct response to proceed!)
"b" is incorrect.
Try again.
CLUE: the 7th letter
PLEASE ENTER THE ANSWER NOW
(You must enter the correct response to proceed!)
"c" is incorrect.
Try again.
CLUE: the 7th letter
PLEASE ENTER THE ANSWER NOW
(You must enter the correct response to proceed!)
"d" is incorrect.
Try again.
CLUE: the 7th letter
PLEASE ENTER THE ANSWER NOW
(You must enter the correct response to proceed!)
You win!
You are in a room.
You can see a thing and a widget.
Sample game:
http://textadventures.co.uk/games/view/-rbpw1_as0o2v9aciyuwyg/you-must-press-g
NOTE:
I just combined a script by HegemonKhan with a script by XanMag.