How to set a value by player input? Creating a 'wait' command - How to let the player decide for how long.

Hi mates,
I made a turn script for the time of day and counting the numbers of in-game days. The printed clock is working well and now I want to make a 'wait' and/or 'rest' command. I thing this is needed if quests or something else only appears at certain day times.

I want the player types something like...

>wait 2 hours
..or..
>wait 5 minutes
..or..
>wait 1 day

Thinking, this would be useful for sleeping as well.

Is it possible to set a attribute's value by player input?


K.V.

Hello,

I use The Pixie's Clock Library, so you will have to tailor this, but this is the command that lets you choose to wait n amount of minutes (or turns):

game_clock.event = true
if (not IsInt(text)) {
  msg ("Wait how long (I did not understand \"" + text + "\")?")
}
else {
  game.waitcount = WaitN(ToInt(text))
  msg ("You wait for " + game.waitcount + " minute{if game.waitcount>1:s}.")
}

https://github.com/ThePix/quest/wiki/Clock-Library


there's only two ways of getting typed-in user input:

  1. the 'get input' Script/Function: http://docs.textadventures.co.uk/quest/scripts/get_input.html
  2. the 'Command' Element: http://docs.textadventures.co.uk/quest/elements/command.html

other method of getting user input: menu selection:

the, 'show menu' (popup menu window) or the 'ShowMenu' ("in-line"/hyperlinks), Scripts/Functions:

http://docs.textadventures.co.uk/quest/scripts/show_menu.html
http://docs.textadventures.co.uk/quest/functions/showmenu.html

and there's also the 'ask/Ask' (yes/no questions) Scripts/Functions too:

http://docs.textadventures.co.uk/quest/scripts/ask.html (popup menu window)
http://docs.textadventures.co.uk/quest/functions/ask.html ("in-line"/hyperlinks)


ask if you need help with anything


Okay, the clock library doesn't fulfill my needs. Also, Pixie's 'wait' command is like my current one.

hegemonkhan, I found a earlier post of your's just tried to understand it. So for now this IsInt seems to be the big deal. My main problem is still to set an value by a player typed integer.

HegemonKhan:
topic/6086/convert-player-input-into-numeric-values

  <attr name="age_integer" type="int">0</attr> // this is the same as... *
</object>

// * within the GUI~Editor:
// 'player' Player Object -> 'Attributes' Tab -> Attributes (the bottom box, I believe) -> Add -> (see below)
// (Object Name: player)
// Attribute Name: age_integer // if you prefer, you can label-name it just as 'age' for example (also note that quest IS case-sensitive: age =/= AGE), but then everywhere you'd have to use 'age', and not 'age_integer', which is just how I personally like to label-name things, as for example, it allows for me to have another Attribute 'age_string', a String Attribute, to hold string values such as "baby", "child", "teen", or "adult", .... (develop your own convention/system for labeling/naming as quickly as you can!), as remember that names MUST be unique, as the 'name' String Attribute is the way quest 'IDs' them.
// Attribute Type: int
// Attribute Value: 0

<function name="age_integer_function">
  msg ("What is your age?")
  get input {
    if (IsInt (result) and ToInt (result) >= 16) { // checks if your inputted value is an Integer (a non-decimal number) and also then checks if the person typed in a number 16 or greater. Both conditions must be true, else they're prompted to input again (see further down for this looping).
      player.age_integer = ToInt (result) // converts your input into an Integer and stores it into the 'player' Player Object's 'age_integer' Attribute (which has to be created/added as an Integer Type Attribute, if you've used the GUI~Editor to create/add this Attribute for your 'player' Player Object)
    } else {
      msg ("wrong input, try again, make sure you input an integer number and that it is 16 or greater.")
      wait {
       ClearScreen
       age_integer_function // in code, the name of the function calls/activates the function and thus loops/repeats the function, requiring the person to input again. In the GUI~Editor, you find the 'add new script' that is the 'call function' Script, and just type in the small rectangle the name of the function that you wish to call/activate (you can ignore the adding of parameters for the time being, if you don't know how functions and parameters work). 
      }
    }
  }
</function> ```

here's an example:

msg ("Type in whatever you want")
get input {

  // quest automatically (hidden from you) stores your typed-in input into a built-in 'result' Variable, and no matter what you typed-in, it'll be a String Value, however you can convert a String Value into a different Data/Value Type via using the 'ToXXX' Scripts/Functions, and you can check what value/variable type it is, via the 'IsXXX' and/or the 'TypeOf' Scripts/Functions

  // result = YOUR_TYPED-IN_INPUT_AS_A_STRING_VALUE_REGARDLESS_OF_WHAT_YOU_TYPED_IN

  game.string_attribute = result // your typed-in input is always a string

  game.string_attribute = ToString (result) // we don't need to do this (see the line above), as your typed-in input is always a string, see next block below for examples of really (needing to) use this to convert it into a string

  game.integer_attribute = ToInt (result) // your typed-in input needs to be an integer else you'll have an error here (to handle the error, we'd need to first use an 'if (IsInt (result))' check first, and then if true, we then do the 'game.integer_attribute = ToInt (result)', see below:

  if (IsInt (result)) {
    game.integer_attribute = ToInt (result)
  }

  game.double_attribute = ToDouble (result) // your typed-in input needs to be a double, else you'll have an error here (to handle the error, we'd need to first use an 'if (IsDouble (result))' check first, and then if true, we then do the 'game.double_attribute = ToDouble (result)', see below:

  if (IsDouble (result)) {
    game.double_attribute = ToDouble (result)
  }

  game.object_attribute = GetObject (result) // There needs to be an actual existing Object having the same name as your typed-in input (which is again, stored within the built-in 'result' Variable)

  game.string_attribute = ToString (game.integer_attribute)
  game.string_attribute = ToString (game.double_attribute)
  game.string_attribute = game.object_attribute.name // this is a way of converting an 'object' value into a 'string' value

  if (IsInt (game.integer_attribute) or TypeOf (game.integer_attribute) = "int") {
    msg ("game.integer_attribute is an integer type")
  } else {
    msg ("game.integer_attribute is NOT an integer type")
  }

  if (IsString (game.string_attribute) or TypeOf (game.string_attribute) = "string") {
    msg ("game.string_attribute is a string type")
  } else {
    msg ("game.string_attribute is NOT an string type")
  }

  if (IsDouble (game.double_attribute) or TypeOf (game.double_attribute) = "double") {
    msg ("game.double_attribute is a double type")
  } else {
    msg ("game.double_attribute is NOT an double type")
  }

}

I'd give the wait function a pattern (regex) like:
^(wait|rest)\s+(for\s+)?(?<text_number>\d*)\s*(?<text_unit>d|h|m|s|day|hour|minute|second|turn|)s?\s*$

Then in your command script, if the player types "wait for 6 minutes" or "rest 6m", you will have access to the local variable text_number which is "6", and text_unit which is "minute".
I'd probably make the script for the command something like this:

number = 1
if (not text_number = "") {
  number = ToInt(text_number)
}
switch (LCase(Left(text_unit,1))) {
  case ("d") {
    WaitForSeconds (number * 86400)
  }
  case ("h") {
    WaitForSeconds (number * 3600)
  }
  case ("m") {
    WaitForSeconds (number * 60)
  }
  case ("s") {
    WaitForSeconds (number)
  }
  default {
    WaitForTurns (number)
  }
}

(assuming you have functions WaitForSeconds and WaitForTurns that handle the actual waiting… it should be easy enough to come up with a similar script more tailored to your needs)


Oh nice, this really helped me, hegemonkhan
First of all I thought I understood your explanation, but I needed workover the command first. I a made switch to recognize which time unit (minutes, hours, ..) the player is typing.
With this in the command 'result' always led me each time to a error.

  <command name="waiting">
    <pattern>wait #text#  #object#</pattern>
    <script>
      if (IsInt (text)) {
    player.waiting_integer = ToInt (text)
      switch (object) {
        }
        case (seconds) {
          msg ("You wait " + player.waiting_integer + " seconds.")
        }
        case (minutes) {
          msg ("You wait " + player.waiting_integer + " minutes.")
        }

This small script totally worked even with the aliases for 'minutes' and 'seconds' (minute, min, second, sec). Now I'll add the other time units, double and string cases and get the correct effect for the clock.


(filler for getting my edited post, updated/posted, argh)
(again, filler for getting my edited post, updated/posted, argh)


more on DATA (VALUE and/or VARIABLE: Attribute/Variable/Parameter) TYPES:


there's also the 'IsNumeric' too:

numeric (a number) = integer number or double number


integer number (non-decimal/non-fractional number) = ..., -999, -1, 0, 1, 999, ...

double number (floating point / float / decimal-fractional number) = ..., -999.123, -1.8, 0.0, 3.6, 999.77, ...


string (aka, 'text'): a collection of alphanumeric (letters/alphabet and/or numbers) and/or some other characters/symbols too

(in programming, string's can't/don't start with a number, as it makes parsing coding much more complicated/difficult or maybe near impossible or impossible, lol. In some programming languages you can start with some of the 'other characters/symbols' like an underscore '_' or a hash/pound '#' or whatever. But to always be safe, just start with a letter/alphabet character)

(string values MUST be encased within double quotes, and thus, any value encased in double quotes IS a string value)

"a"
"abc"
"a1"
"abc123"
"abc_123"
"abc_123_xyz"
"Hi, my name is HK. What is your name?"
"true"
"false"
"HK"
"game"
"player"
"orc"


Booleans:

(these are special/reserved words, as boolean values)

true
True
false
False


in all programming languages, booleans (AND EVERYTHING!), are actually underneath broken down further into:

0 // (usually: 0 = false/no)
1 // (usually: 1 =true/yes)

as programming (thus all programming) is binary (machine language): 0s and 1s

for a pretend example:

if you type in: HK

it gets broken-down/converted/translated into:

http://www.asciitable.com

72 decimal = "H"
75 decimal = "K"

0100 1000 binary = 72 decimal = "H"
(0 x 2^7) + (1 x 2^6) + (0 x 2^5) + (0 x 2^4) + (1 x 2^3) + (0 x 2^2) + (0 x 2^1) + (0 x 2^0) = 72
(0) + (64) + (0) + (0) + (8) + (0) + (0) + (0) = 72

0100 1011 binary = 75 decimal = "K"
(0 x 2^7) + (1 x 2^6) + (0 x 2^5) + (0 x 2^4) + (1 x 2^3) + (0 x 2^2) + (1 x 2^1) + (1 x 2^0) = 75
(0) + (64) + (0) + (0) + (8) + (0) + (2) + (1) = 75

and thus:

0100 1000 0100 1011 (binary/machine-language) = "HK"

you type in and see/use "HK" (as this is human friendly/readable/understandable) (thanks to high level programming/software), but the computer itself is actually using '0100 1000 0100 1011' (which is NOT human friendly/readable/understandable). If '0100 1000 0100 1011' is just "HK", imagine what just a single paragraph would be in machine language:

0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001 0000 1111 1100 0011 0101 1010 0110 1001 1000 0001 0010 0100 0101 0110 1111 0000 1010 0101 0011 1100 1001

ya... who can recognize this as some paragraph, lol. Not people, but computers can, lol.


Objects:

(any value NOT in double quotes and NOT a special/reserved word, such as the boolean values. Also, again, you can't start with a number)

(and they have to be actually existing/created Objects in your game, of course)

HK
orc
game
player
player_99
dragon
book
abc
abc123
abc_123
spell_object
spell
orc_1_object


if (IsNumeric (VARIABLE_OR_VALUE)) {
  msg ("Your VARIABLE_OR_VALUE is either an integer or a double")
  if (IsInt (VARIABLE_OR_VALUE)) {
    msg ("Your VARIABLE_OR_VALUE is an integer")
  } else {
    msg ("Your VARIABLE_OR_VALUE is NOT an integer")
  }
  if (IsDouble (VARIABLE_OR_VALUE)) {
    msg ("Your VARIABLE_OR_VALUE is a double")
  } else {
    msg ("Your VARIABLE_OR_VALUE is NOT a double")
  }
} else {
  msg ("Your VARIABLE_OR_VALUE is NOT numeric (aka: it's NOT an integer and it's NOT a double)")
  if (IsString (VARIABLE_OR_VALUE)) {
    msg ("Your VARIABLE_OR_VALUE is a string")
  } else {
    msg ("Your VARIABLE_OR_VALUE is NOT a string")
  }
  if (IsBoolean (VARIABLE_OR_VALUE)) {
    msg ("Your VARIABLE_OR_VALUE is a boolean")
  } else {
    msg ("Your VARIABLE_OR_VALUE is NOT a boolean")
  }
  if (not GetObject (VARIABLE_OR_VALUE = null)) {
    msg ("Your VARIABLE_OR_VALUE is an Object")
  } else {
    msg ("Your VARIABLE_OR_VALUE is NOT an object")
  }
}

K.V.

You have an object called seconds and an object called hours, huh?

Pretty slick!


(in programming, string's can't/don't start with a number, as it makes parsing coding much more complicated/difficult or maybe near impossible or impossible, lol. In some programming languages you can start with some of the 'other characters/symbols' like an underscore '_' or a hash/pound '#' or whatever. But to always be safe, just start with a letter/alphabet character)

No. A string is any sequence of characters. It's variable names (and object names) that have limits about what characters they can contain. "555" and " " are both strings.

if (IsNumeric (VARIABLE_OR_VALUE)) {
msg ("Your VARIABLE_OR_VALUE is either an integer or a double")

Not quite.
IsNumeric("5") returns true, because "5" is a string that represents a numeric value
IsInt("5") likewise returns true
IsNumeric("-6.55") returns true, because its argument is a string that can be converted to a number
IsInt("-6.55") returns false, because that string doesn't represent an int
IsInt("abc") and IsNumeric("def") both return false
IsInt(666) shows you what happens if you pass it an int - it displays an error and the script crashes. Because the IsInt function tests a string to see if it's a string representing an int. Giving it something that isn't a string is an error. (Unless this behaviour was changed since November)


ah, thank you for correcting me! sorry about my post's mis-information.

I assumed in quest that VARIABLES and Object 'names (IDs)' were seen as string data types, so I lumped them all together with the rule that you can't start with a number. Yes, a String Value can indeed start with a number, but VARIABLES and Object's (names/IDs) can't.

Ya, I know the 'IsXXX' are true/false (and then you got to actually convert the VARIABLE_OR_VALUE into the data type you want --- that you can do so with of course), but I didn't want to get into that specifics (extra-explaining - lazy) into my post, lol.


K.V.
You have an object called seconds and an object called hours, huh?

Pretty slick!

Yes, but I made this objects only for this command. Seconds, minutes, hours and days. I thought it's a good way to add some aliases for the command.


There was much to figure out, but finally I did it. I wasn't sure to let the player being able to wait multiple days so I removed days from the 'waiting' command.
So, my first problem was to handle the high input numbers like when the player types, "wait 39831 min". This was so much frustrating calculating and I ran always against a wall.

I tried a other way. The waiting time for each unit is now limited. The player can only wait for maximal 60 seconds, 60 minutes or 24 hours.
This way I only need to handle to set the next higher unit correctly.
For example,
if the time is "08:50"
and the player types, "wait 20 minutes",
then the hours should be increased by 1 and the minutes should be started over from 0 to 10; "09:10".
This was much easier since the higher units can't be affected by the limited waiting duration. And if it is 23:59:59 (hh:mm:ss) o'clock, which means any duration of time increasing would have a effect on the next and over next unit, but thanks to the limitation again, the over next unit can't be increased more than 1.

If the player types anything else as a integer he get the message to use a number and it can't be a fractional number. Same for the unit; typing anything else as sec, min or hour shows a message to use one of these units. If both is wrong he get both messages.

As the player give input it counts as turn and increase the 'seconds' by 1 after wait. To get the correct time I set a "is_no_turn" flag at the end of each game aspects which shouldn't cost time, like looking for stats. I think, I saw something like this in Pixie's Adv. Clock Library. So, thanks for the idea.

<command name="waiting">
 <pattern>wait #text#  #object#</pattern>
  <script>
     if (IsInt (text)) {
      player.waiting_integer = ToInt (text)
  switch (object) {
    case (seconds) {
      msg ("  ")
      if (player.waiting_integer = 1) {
        msg ("You wait " + player.waiting_integer + " second.")
      }
      else {
        msg ("You wait " + player.waiting_integer + " seconds.")
      }
      if (world_time.clock_seconds + player.waiting_integer >= 60) {
        if (player.waiting_integer <= 60) {
          player.waiting_integer = world_time.clock_seconds + player.waiting_integer - 60
          world_time.clock_seconds = 0
          world_time.clock_seconds = world_time.clock_seconds + player.waiting_integer
          if (world_time.clock_minutes = 59) {
            world_time.clock_hours = world_time.clock_hours + 1
            if (world_time.clock_hours = 59) {
              world_time.clock_days = world_time.clock_days + 1
            }
          }
          world_time.clock_minutes = world_time.clock_minutes + 1
        }
      }
      else {
        SetObjectFlagOn (world_time, "wait_check_1")
      }
      if (player.waiting_integer >= 60) {
        msg ("<br/>You can only wait 60 seconds. Please type minutes or hours for longer waiting sessions.<br/>")
      }
      else {
        SetObjectFlagOn (world_time, "wait_check_2")
      }
      if (GetBoolean(world_time, "wait_check_1")) {
        if (GetBoolean(world_time, "wait_check_2")) {
          world_time.clock_seconds = world_time.clock_seconds + player.waiting_integer
        }
      }
    }
    case (minutes) {
      msg ("   ")
      if (player.waiting_integer = 1) {
        msg ("You wait " + player.waiting_integer + " minute.")
      }
      else {
        msg ("You wait " + player.waiting_integer + " minutes.")
      }
      if (world_time.clock_minutes + player.waiting_integer >= 60) {
        if (player.waiting_integer <= 60) {
          player.waiting_integer = world_time.clock_minutes + player.waiting_integer - 60
          world_time.clock_minutes = 0
          world_time.clock_minutes = world_time.clock_minutes + player.waiting_integer
          if (world_time.clock_hours = 59) {
            world_time.clock_days = world_time.clock_days + 1
          }
          world_time.clock_hours = world_time.clock_hours + 1
        }
      }
      else {
        SetObjectFlagOn (world_time, "wait_check_1")
      }
      if (player.waiting_integer >= 60) {
        msg ("<br/>You can only wait 60 minutes. Please type hours for longer waiting sessions.<br/>")
      }
      else {
        SetObjectFlagOn (world_time, "wait_check_2")
      }
      if (GetBoolean(world_time, "wait_check_1")) {
        if (GetBoolean(world_time, "wait_check_2")) {
          world_time.clock_minutes = world_time.clock_minutes + player.waiting_integer
        }
      }
    }
    case (hours) {
      msg ("   ")
      if (player.waiting_integer = 1) {
        msg ("You wait " + player.waiting_integer + " hour.")
      }
      else {
        msg ("You wait " + player.waiting_integer + " hours.")
      }
      if (world_time.clock_hours + player.waiting_integer >= 24) {
        if (player.waiting_integer <= 24) {
          player.waiting_integer = world_time.clock_hours + player.waiting_integer - 24
          world_time.clock_hours = 0
          world_time.clock_hours = world_time.clock_hours + player.waiting_integer
          world_time.clock_days = world_time.clock_days + 1
        }
      }
      else {
        SetObjectFlagOn (world_time, "wait_check_1")
      }
      if (player.waiting_integer >= 24) {
        msg ("<br/>You can only wait 24 hours. Please type days for longer waiting sessions.<br/>")
      }
      else {
        SetObjectFlagOn (world_time, "wait_check_2")
      }
      if (GetBoolean(world_time, "wait_check_1")) {
        if (GetBoolean(world_time, "wait_check_2")) {
          world_time.clock_hours = world_time.clock_hours + player.waiting_integer
        }
      }
    }
    case (days) {
    }
  }
}
else {
  msg ("<br/>You have to use a number for the waiting duration. It can't be a fractional number.<br/>")
}
SetObjectFlagOn (player, "no_real_turn")
SetObjectFlagOff (world_time, "wait_check_1")
SetObjectFlagOff (world_time, "wait_check_2")
    </script>
    <unresolved>You can only use seconds, minutes or hours for waiting. (Also second, sec, minute, min and hour for short.)</unresolved>
  </command>

It seems I'm finished with this command. Any test with the waiting command I can imagine works correctly and the time is always exactly displayed like it should.
Thanks to the help of this forum here.


date and time isn't easy stuff to code in, especially as you dig more into accuracy (in regards to date) with it, lol.


if you can take a look at this complicated (but novel, lol) 'countdown timer' I made years ago now, sighs. Time goes by so fast... sighs...

http://textadventures.co.uk/forum/samples/topic/4162/countdown-timer-code

and if you want a link on some time and date coding:

https://textadventures.co.uk/forum/quest/topic/_xfqu-xbq0gv1zlbkvvxew/calendar-system

ask if you need any help (I can only help so much... as I'm still struggling with time and date coding myself)


Yes I see how much work some more complex time and date systems would need. That's why I've alread removed weeks, months and years. After all it doesn't bother in a fantasy setting.

But for now I just found a mistake here. If the player types exactly the maximum (60 sec, 60 min, 24 hours) the clock doesn't change correctly. No big deal for now... I'm tired. Spend my whole day with this. Just finish the quest menu first. Not sure it will be useful for anything, but I add the place, time and day of receiving a quest to the journal's quest entries. Give's stuff some immersion.


it can be useful, as it allows for doing a lot of dynamic/random stuff (npcs moving around depending on the time of day and/or what day/month/year it is, shops closing at night, seasons, weather, events, etc), but you got to be a very good coder/programmer, as it's not easy, especially as you try to make it more advanced, doing more stuff.


P.S.

maybe you already corrected this, but in your code above, you're missing the 'CDATA' tags, as these are required, if you want to use any '<, >, <=, >=, <>' (greater/lesser than, and/or greater/lesser than and equal to, and/or not equals) symbols/characters/operations in your scripting

<NAME_OF_ELEMENT>

  <![CDATA[[

    // your scripting, an example:

    get input {
      if (IsInt (result)) {
        integer_variable = ToInt (result)
        if (integer_variable >= 0 and integer_variable <= 100) {
          // blah
        }
      }
    }

  ]]>

</NAME_OF_ELEMENT>

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

Support

Forums