Preventing the player missing a message

Here'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.


There 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...)


WHO?
I just use the show menu... so...
I don't understand why a disable script wouldn't work...


(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.


I'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.


This 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 {
 }
}

just 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


The 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.


So 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?


(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>

I'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?


So 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!


If 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 ;)


So 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.


Okay, 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:

  1. Having to do something to every turn script is annoying (but it's one if, so it's not a huge deal)
  2. 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
  3. 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


there'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'
  }
}

I 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)


Clicking 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.
CLICK 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.

Make 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.


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

Support

Forums