Why does ShowMenu lose variable contents?
GregC
27 Aug 2017, 19:51This code:
Options = NewStringList()
list add (Options, "One")
list add (Options, "Two")
TheNumberFour = 4
msg (TheNumberFour)
ShowMenu ("Make a choice", Options, false) {
msg (TheNumberFour)
}
Produces a menu, clicking on either option produces this result:
4
Error running script: Error compiling expression 'TheNumberFour': Unknown object or variable 'TheNumberFour'
I'm not sure why calling showmenu loses all variable values. It's pretty annoying. I guess I could store any value I want to remember after showing a menu in an object attribute.
That feels like a pretty messy solution, is there a better one?
hegemonkhan
27 Aug 2017, 20:33the 'ShowMenu (args/params)' is a Function, and the 'TheNumberFour' is a Variable (a local/temporary) VARIABLE, you'd have to use it as an Argument/input of the 'ShowMenu' Function, which would be stored into a Parameter of the 'ShowMenu' Function, for the 'ShowMenu' Function to be able to use it, but the 'ShowMenu' is set up only having specific Parameters: prompt/message, list, boolean_for_if_menu_is_cancelable.
You can just use an Attribute (a global/permanent) VARIABLE instead, for example:
<game name="example_game">
<attr name="TheNumberFour" type="int">0</attr>
</game>
// your scripting:
Options = NewStringList()
list add (Options, "One")
list add (Options, "Two")
game.TheNumberFour = 4
msg (TheNumberFour)
ShowMenu ("Make a choice", Options, false) {
msg (game.TheNumberFour)
// what are you doing with the selected menu item, by the way ??? (result = YOUR_SELECTED_MENU_ITEM)
}
you can also always manually create your own menu too
jmnevil54
27 Aug 2017, 20:40Well, first, I don't think you typed it right.
Example:
msg ("See something that catches your eye?")
options = Split("Potion (100);Hyper Potion (200)", ";")
ShowMenu ("Shop", options, true) {
switch (result) {
case ("Potion (100)") {
if (player.gold >= 100) {
player.gold = player.gold - 100
player.potion = player.potion + 1
msg ("You bought a Potion.")
}
else {
msg ("You don't have enough gold.")
}
}
case ("Hyper Potion (200)") {
if (player.gold >= 200) {
player.gold = player.gold - 200
player.hyper_potion = player.hyper_potion + 1
msg ("You bought a Hyper Potion.")
}
else {
msg ("You don't have enough gold.")
}
}
}
}
I'm sure you are supposed to put the cases in the attribute. Unless otherwise notified.
Edit: You will also need to type:
msg (game.TheNumberFour)

K.V.
27 Aug 2017, 22:45This drove me crazy as well, but I do what HK advised 1. Now, the games run smoothly, and I'm much calmer.
hegemonkhan
28 Aug 2017, 00:10@ jmnevil54:
I might be misunderstanding, but if you don't know:
there's (at least) 2 ways of creating a list:
// using the built-in 'Split' Function:
// (the quick method, but less powerful)
color_list = Split ("red;blue;yellow", ";")
// --------------------------------------------------------------
// or, creating a new (blank) List VARIABLE, and adding items to it:
// (the manual (slower/longer: more typing) method, but more powerful)
color_list = NewStringList () // for example, creating specifically a 'Stringlist' list Variable
list add (color_list, "red")
list add (color_list, "blue")
list add (color_list, "yellow")

K.V.
28 Aug 2017, 01:22You can also bypass the list variable (which is what I do when I'm only using the list once).
ShowMenu ("Pick one:", Split("one;two", ";"), false) {
switch (result) {
case ("one") {
msg ("You chose 1.")
}
case ("two") {
msg ("You chose 2.")
}
}
}
The Pixie
28 Aug 2017, 05:14The documentation for ShowMenu has a link to this page:
http://docs.textadventures.co.uk/quest/blocks_and_scripts.html
GregC
28 Aug 2017, 11:00So if I've understood this...
<function name="DebugTest">
Options = NewStringList()
list add (Options, "One")
list add (Options, "Two")
TheNumberFour = 4
msg (TheNumberFour)
ShowMenu ("Make a choice", Options, false) {
msg (TheNumberFour)
}
</function>
Will fail because assigning TheNumberFour and calling TheNumberFour take place in different functions. While it looks like they both happen inside DebugTest(), calling ShowMenu() in fact created a new (unnamed?) function that is not part of the original (which takes the parameter "result" which will be what the user clicked and returns nothing).
If I had further code beneath the choice that wasn't part of the ShowMenu call and was going to be executed no matter what the user picked then that would be part of the same function and remember the variables - but couldn't access any variable assigned in the ShowMenu call and unless the user clicks inhumanly fast would probably be executed before the code higher up in the function.
The answer to the question "I'm not sure why calling showmenu loses all variable values. It's pretty annoying. I guess I could store any value I want to remember after showing a menu in an object attribute. That feels like a pretty messy solution, is there a better one?" is "No"
If I wanted to continue using a local variable then I'd need to do something to create a local copy of it inside the function, so I'd have to do something like this:
game.mem1 = NeededVariable
ShowMenu ("Make a choice", Options, false) {
NeededVariable = game.mem1
}
Obviouosly I could save the trouble of reassigning NeededVariable inside the ShowMenu function and just access game.mem1 directly, but depending on how often the situation comes up that could lead to either a lot of generally superfluous attributes or hard to read code with meaningless variable names
Have I understood correctly?
hegemonkhan
28 Aug 2017, 17:15(filler for getting this edited post, updated/posted)
(again, filler for getting this edited post, updated/posted, argh)
(again, filler for getting this edited post, updated/posted, argh)
I think so, I think you got it understood now.
the word 'scope' is used for this concept:
(and the ERROR of it is known as 'out of scope')
a local/temporary Variable's 'scope' is its parent scripting's container, as it (the local/temporary Variable) is destroyed upon the parent scripting ending, and also it (the local/temporary Variable) doesn't exist outside of its 'scope' (doesn't exist outside of its parent scripting's container).
for example:
<function name="scope_1">
string_variable = "hi"
msg (string_variable) // NO error: it's within its scope (scope_1) // maybe you notice that 'msg' is a Function itself (acting similarly as my 'scope_3' Function: using a single Argument/Parameter), the 'msg' Function is another/different 'scope' (a 'scope_4' if you will), just as 'scope_2' and 'scope_3' Functions are other/different scopes
scope_2 // ERROR: see below
scope_3 (string_variable) // NO error: see below // the 'string_variable' of 'scope_1' is stored into the 'string_parameter' while still within/for the scripting of its 'scope_1', and thus it is within its scope, and then you jump/goto the 'scope_3' Function, which uses its 'string_parameter' for its scripting, which is within its scope (scope_3), and thus no errors.
</function>
<function name="scope_2">
msg (string_variable) // ERROR: the 'string_variable' Variable does NOT exist! (it does exist within its scope: scope_1, but 'scope_2' is 'out of scope' for it)
</function>
<function name="scope_3" parameters="string_parameter">
msg (string_parameter) // NO error: as a Function can use inputs (called arguments), which are stored into the Function's local/temporary special 'Parameter' Variable VARIABLES, which can then be used by the Function's scripting // NO error as the 'string_variable' isn't ever used outside of its scope (scope_1): the 'string_variable' is NEVER used (directly) by/within the 'scope_2' Function's scripting (which would be an 'out of scope' error --- if it was), so NO error.
</function>
does this help explain it?
(and Attribute VARIABLES are 'global in scope', so long as their parent container/Object ... exists or still exists, there's no 'out of scope' error/issue with Attribute VARIABLES)
(for quest and game-making, Attributes are awesome, but for programs/software using the full-bore programming languages, global VARIABLES are usually/generally bad and thus shouldn't be used)
a bit more into the technical aspects of it, if you're interested:
ht.tp://www.cs.princeton.edu/courses/archive/spr03/cs320/notes/7-1.pdf
(remove the dot/period in 'ht.tp' for it to work in the url)
Function data must be preserved (if there's layered Functions and/or looping/recursion operation of Functions), in order for the Functions to be completed, and thus a 'activation record' is created for each Function (once the Functions are completed, their 'activation records' are destroyed), which is why recursion can use/eat-up a lot of memory (lots of 'activation records'), but it's also a very powerful tool too.
again, you can always manually create your own menu coding too, for an example using my own (without hyperlinks --- it can be done with hyperlinks, but I'd have to look a few stuff up, and I'm lazy, so not going to, unless you want/need to know how, lol):
(I like using typed-in input and making it as easy, less typing, as possible: typing in a single number)
// example scripting:
set (player, color_string_attribute, "unknown")
player.color_stringlist_attribute = NewStringList ()
list add (player.color_stringlist_attribute, "red")
list add (player.color_stringlist_attribute, "blue")
list add (player.color_stringlist_attribute, "yellow")
dynamic_menu_function ("Color", player.color_stringlist_attribute, player, "color_stringlist_attribute")
// -------------------
<function name="dynamic_menu_function" parameters="prompt_string_parameter, name_of_object_dot_name_of_stringlist_attribute_parameter, object_parameter, name_of_string_attribute_parameter">
<![CATA[
// -------------------------------------------------------------------
// Manual/Custom Menu Displayment:
msg (prompt_string_parameter + " Menu")
msg ("(Type in the number of your choice)")
msg ("")
numbering_integer_variable = 0
foreach (item_string_variable, name_of_object_dot_name_of_stringlist_attribute_parameter) {
numbering_integer_variable = numbering_integer_variable + 1
msg (numbering_integer_variable + ". " + item_string_variable) // here you can change it so they're hyperlinks, but I'm too lazy to look up the coding/syntax for it, and whatever other coding (like Commands) elsewhere, that is needed for it too. Unless, this is what you want/need, in which case, let me know, and I'll get the coding for you to do it.
}
// outputs/displays (for my example's single function call):
//
// Color Menu
// (Type in the number of your choice)
//
// 1. red
// 2. blue
// 3. yellow
// -------------------------------------------------------
get input {
ClearScreen
if (IsInt (result)) {
input_integer_variable = ToInt (result)
list_count_integer_variable = ListCount (name_of_object_dot_name_of_stringlist_attribute_parameter)
if (input_integer_variable > 0 and input_integer_variable < list_count_integer_variable) {
index_number_integer_variable = input_integer_variable - 1
selected_item_string_variable = StringListItem (name_of_object_dot_name_of_stringlist_attribute_parameter, index_number_integer_variable)
set (object_parameter, name_of_string_attribute_parameter, selected_item_string_variable)
} else {
dynamic_menu_function (prompt_string_parameter, name_of_object_dot_name_of_stringlist_attribute_parameter, object_parameter, name_of_string_attribute_parameter)
}
} else {
dynamic_menu_function (prompt_string_parameter, name_of_object_dot_name_of_stringlist_attribute_parameter, object_parameter, name_of_string_attribute_parameter)
}
}
]]>
</function>
this example's design of yours, is actually pointless/redundant (a bad design, no reason to ever do it):
// NeededVariable = 7
game.mem1 = NeededVariable
ShowMenu ("Make a choice", Options, false) {
NeededVariable = game.mem1
// msg (NeededVariable) // stupid usage of it, of course, but it's just an example usage for completion, lol
}
as can be seen (fixed up):
ShowMenu ("Make a choice", Options, false) {
NeededVariable = 7
// msg (NeededVariable) // stupid usage of it, of course, but it's just an example usage for completion, lol
}

K.V.
28 Aug 2017, 23:07What HK said.
Everyone says having a lot of attributes doesn't effect anything (besides the neatness of the code, as you say).
Sounds to me like you've got it.
I tried to avoid setting up those attributes, the same as you.
I finally gave up, though.
This sets up two attributes instead of one.
Plus, if NeededVariable wasn't in the same block of this same script, I don't think it would exist.
game.mem1 = NeededVariable
ShowMenu ("Make a choice", Options, false) {
NeededVariable = game.mem1
}
If it's an important variable at any given point, I just give it its own attribute on some object.
...even if I create an object just for that purpose. ...which is still overkill, but it's easier for me to keep up with it that way. (And I can still read the source code.)
I.e., I have an object called displayStuff under the game object, and it has all sorts of attributes I access to change CSS settings, display Base64 embedded images, and all sorts of things.
hegemonkhan
29 Aug 2017, 01:52OBJECTS (Elements: Objects, Verbs, Functions, Commands, Turnscripts, Timers, Exits, etc) hold more data than an Attribute does (in fact, an 'Attribute' is a 'member' VARIABLE of a specific Object, which holds the data of the OBJECT/Element).
any good software (including quest) can hold/handle gazillions of Objects, so don't worry about how many Attributes you have !!! (it's still good to practice/learn/have efficiency: if you don't need a CLASS/OBJECT/VARIABLE/OPERATION, then don't have it --- but this takes long years of learning to program: expertise, and also lots of intelligence or copying/using of other intelligence/expert programmers' code: "don't re-invent the wheel", to write code as efficiently as possible for what you're trying to do)
in actual programming:
https://www.cs.princeton.edu/courses/archive/spr96/cs333/java/tutorial/java/anatomy/creating.html (Java example)
a 'CLASS' (similar in usage to/of quest's user-level's: Object Types) lets up what you want, but it doesn't have a usable form yet for you to use it, and then you make it usable/tangible (known as 'instantiating', you can somewhat think of it as like a 'OBJECT = function call', except that it's a 'OBJECT = CLASS call', lol), which is known as an 'OBJECT', that you can now use/manipulate.
'OBJECTS' are also known/called as 'INSTANCES' (CLASS 'instantiation' creates 'instances', aka OBJECTS), they're interchangable (ya, the terminology is really jumbled up, confusing, and/or ambigious)
actually, when you do this in quest, for example:
VARIABLE = NewList () / NewDictionary ()
it's a similar structure/syntax/action/design as 'instantiating an OBJECT of/from a CLASS' in normal programming:
NAME_OF_CLASS NAME_OF_OBJECT_/_VARIABLE = NEW NAME_OF_CLASS (XXX)
think of a 'ball' CLASS as the idea of a 'ball' (what the ball is, what the ball does/can-do, and what traits/properties/characteristics does the ball have), but there's no 'ball' actually existing (not yet), it's just the IDEA of a 'ball'
this stuff is confusing/advanced/complicated, and it's been awhile too, so my attempt at trying to explain this stuff is really rusty (bad), it'd be better for you to just try to read and learn directly from the documentation of the 3 main full-bore programming languages:
http://www.cplusplus.com/doc/tutorial/classes/ (C++)
https://docs.oracle.com/javase/tutorial/java/javaOO/ (Java) (do NOT confuse 'Java', a full-bore programming language, with JavaScript/JS, a scripting/web/online language, they got NOTHING in common with each other except the use of 'Java' for/in their languages' names... unfortunately, this causes a lot of confusion between them and/or causes people to think they're related to each other)
https://docs.python.org/3/tutorial/classes.html (Python)
the below is quest's actual underlying code structure of the quest software itself (not merely its built-in stuff), you need to look at Alex' documentation on quest: the source code and all of its sub code parts, here: ( https://github.com/textadventures/quest )
DATA STRUCTURES:
Object-Oriented Programming (OOP) / Object-Oriented Design (OOD):
CLASSES (see above about them): universal Classes: the Data Types: Booleans, Integers, Doubles/Floats/Floating-Points, Strings, etc, and etc/custom/other Classes
'OBJECTS' of normal programming = quest's 'Elements', which contain:
(the terminology is a bit ambigious, as some of these terms are interchangable with each other, and also across languages too)
('properties' is used as a term too, basically: member, attribute, and property are often interchangable with each other)
MEMBERS (normal programming), two types (STATES: data storage vs BEHAVIORS: actions):
- 'attributes' (STATES : data members) of normal programming = quest's basic (Boolean, String, Object reference/pointer, Integer, Double) Attributes (except: Script Attributes)
- 'methods' (BEHAVIORS : member functions) of normal programming = quest's Script Attributes
'Functions' of normal programming = quest's Functions
and etc Data Structures... (depends on the languages)
GregC
30 Aug 2017, 16:01Okay, I think I followed most of that. Thank you for all of your help. I've not done any proper programming in over a decade, when I was taught at school we were told to minimise lines of code over all else, whereas this advice seems geared towards minimising runtime (which I guess is more relevant now). Since I'm not likely to either run out of space or do something in Quest so inefficiently that I notice a performance issue on a modern PC I'm probably going to do some things inefficiently when they make it easier for me to read the code.
The Pixie
30 Aug 2017, 18:51when I was taught at school we were told to minimise lines of code over all else, whereas this advice seems geared towards minimising runtime (which I guess is more relevant now).
In my opinion, your priority should be to keep it simple, so you will understand it when you look at it in three months. Computers are so fast and have so much memory that other issues are not worth considering (unless you are coding a full 3d game or operating system).
hegemonkhan
30 Aug 2017, 23:10efficiency (speed/performance: less/least operations and data usage, and also your code length/concise-ness/compact'ability) is always important, and vital for critical systems and/or compact systems, but efficiency takes a back seat for professional software nowadays, as what's most important is the/your "production efficiency": a "developer's time/work/money" (your time/work/skill is valuable, why waste time/work doing/over-doing a really complex/advanced/perfect system, when you can do something much more simple and quick that does the job, and get doing more projects too, in the same amount of time?) and also, especially due to working in large group projects, "human usage" (readability/understand'ability, editing/debugging/trouble-shooting/patching ability, scale'ability, using it and building upon it or adjusting it for new projects, etc).
And obviously for amateur programmers, if you don't have the skill, you don't have the skill, you're just happy to get something that works as you want it to, so, who cares if it's not the best, most efficient design possible. You can always make it better later, and/or if you notice that it is too slow/ineficient (you're actually noticing slow-down during running it), then you can always fix it up later too.
again, the built-in 'ShowMenu / show menu' Functions and other built-in Functions and/or Delegate-using Script Attriubtes of Objects, have already been set up with having Parameters and/or a return type, or not, and also of how many and what types of Parameters.
( I've no idea if quest can-do/has Function/Script OVER-LOADING or not: https://en.wikipedia.org/wiki/Function_overloading )
Thus, just create your own Function or Object's Delegate-using Script Attribute, if you want/need to use a (or more) VARIABLE(s) for it, allowing you to use local/temporary Variable's instead of having to create/use Attributes.
// scripting example:
TheNumberFour = 4
my_custom_menu ("BLAH", BLAH_OBJECT.BLAH_LIST_ATTRIBUTE, TheNumberFour)
// -------------
<function name="my_custom_menu" parameters="prompt_parameter, list_parameter, integer_parameter">
// again, too lazy to look up how to reproduce the built-in 'ShowMenu' Function's use of hyperlinks, for this example, but it can be done, instead of what I show below (doesn't use hyperlinks):
msg (prompt_parameter)
DisplayList (BLAH_OBJECT.BLAH_LIST_ATTRIBUTE)
get input {
// blah scripting
}
msg (integer_parameter) // here is your 'TheNumberFour' Variable being used, no need for creating/using an Attribute.
</function>