From SHOWMENU to OBJECT.SCRIPT
TriangleGames
26 Dec 2013, 15:22I feel like I asked about this before a long time ago, but I couldn't find it in my posts list or by searching (probably too many common search words). At any rate ...
(This is for part of the menu based combat I'm working on. Most of it seems to be going well, but now I've gotten to the idea of having the combat options include: Attack, Use Item, Run. It's the Use Item part that I'm worried about.)
What I ideally would like to do is,
present a forced menu to the player listing "battle items" (heal potion, firebomb, gem of boss-kill, etc.),
and have an inherited script attribute be activated for whatever item they choose (as, result.script).
I get the feeling it's going to be more complicated than that.
As far as I can tell, ShowMenu will only accept stringlists or stringdictionaries, NOT objectdictionaries.
So I'm thinking I'll have to somehow make a list/dictionary of the names/aliases of the items to display in the menu,
then somehow connect that over to the relevant object.
My concern is that this will inevitably mean listing ALL the battle items in the menu function itself. Is there a better way to achieve the effect I'm after that maybe I'm not thinking of?
(This is for part of the menu based combat I'm working on. Most of it seems to be going well, but now I've gotten to the idea of having the combat options include: Attack, Use Item, Run. It's the Use Item part that I'm worried about.)
What I ideally would like to do is,
present a forced menu to the player listing "battle items" (heal potion, firebomb, gem of boss-kill, etc.),
and have an inherited script attribute be activated for whatever item they choose (as, result.script).
I get the feeling it's going to be more complicated than that.
As far as I can tell, ShowMenu will only accept stringlists or stringdictionaries, NOT objectdictionaries.
So I'm thinking I'll have to somehow make a list/dictionary of the names/aliases of the items to display in the menu,
then somehow connect that over to the relevant object.
My concern is that this will inevitably mean listing ALL the battle items in the menu function itself. Is there a better way to achieve the effect I'm after that maybe I'm not thinking of?

jaynabonne
26 Dec 2013, 16:01I had worked on a menu-based combat system as well, and to be honest, I didn't even go near ShowMenu. Of course, back then, it didn't have the inline display it does now... The way I did mine was to use command links and just dump out menus myself. The command links would invoke commands, and the commands could be generated on the fly (e.g. "useitem InvisibilityPotion").
The actual mechanism isn't really important - the critical thing is how do you deal with strings, because even a command link requires string parameters sent to the command. So you can easily use ShowMenu, if you can decide on the scheme for encoding what you want done in the string.
The scheme I used was this. I decided that I wanted to invoke a script on an object, with arguments, in response to the click. You can use a similar scheme. You just need to set up the strings when you call ShowMenu and then parse it out afterwards.
The format I used is: "object:script arg1,arg2,arg3...". The number of arguments can vary from 0 to whatever your script wants. So, for example, if you have a heal potion (with object name HealPotion), and it had a "use" script attribute, then your string would be "HealPotion:heal".
The code to handle this would be something like this, where "result" is the string result from ShowMenu.
If you had a string like this: "Monster:attack sword,25", then it would invoke the "attack" script on the object "Monster", and there would be an "arg1" parameter with value "sword", and "arg2" would be "25".
How you build the strings depends on the circumstances. You can always use "o.name" to get the name of the object to invoke the script on. I tended to have the scripts hanging off of rooms or other stable objects that I globally knew. But there is nothing that says it can't be dynamic.
Let me know if you any of that is unclear.
The actual mechanism isn't really important - the critical thing is how do you deal with strings, because even a command link requires string parameters sent to the command. So you can easily use ShowMenu, if you can decide on the scheme for encoding what you want done in the string.
The scheme I used was this. I decided that I wanted to invoke a script on an object, with arguments, in response to the click. You can use a similar scheme. You just need to set up the strings when you call ShowMenu and then parse it out afterwards.
The format I used is: "object:script arg1,arg2,arg3...". The number of arguments can vary from 0 to whatever your script wants. So, for example, if you have a heal potion (with object name HealPotion), and it had a "use" script attribute, then your string would be "HealPotion:heal".
The code to handle this would be something like this, where "result" is the string result from ShowMenu.
pieces = Split(result, " ")
// Get object and script to invoke.
object_script = StringListItem(pieces, 0)
object_script = Split(object_script, ":")
object = StringListItem(object_script, 0)
attribute = StringListItem(object_script, 1)
// Get any arguments and create params dictonary.
args = StringListItem(pieces, 1)
args = Split(args, ",")
params = NewDictionary()
argnum = 1
foreach (arg, args) {
dictionary add(params, "arg"+argnum, arg)
argnum = argnum + 1
}
do (GetObject(object), attribute, params)
If you had a string like this: "Monster:attack sword,25", then it would invoke the "attack" script on the object "Monster", and there would be an "arg1" parameter with value "sword", and "arg2" would be "25".
How you build the strings depends on the circumstances. You can always use "o.name" to get the name of the object to invoke the script on. I tended to have the scripts hanging off of rooms or other stable objects that I globally knew. But there is nothing that says it can't be dynamic.
Let me know if you any of that is unclear.


jaynabonne
26 Dec 2013, 16:36Just to be complete, let me drop in how you'd use it from ShowMenu. Note that I'm typing this in off the top of my head and not actually trying it in Quest!
Assume that the above code has been put into a function called "ExecuteMenuResult", with a single "result" parameter coming in.
If you had a list of objects that could be used, you could do this (assume the list is "olist"):
You then just need to create a "use" script on each object.
(Looking back at this, I don't know why I used ":" for the separator. I think "." would make more sense, as in "HealingPotion.use". That's an easy enough change.)
Assume that the above code has been put into a function called "ExecuteMenuResult", with a single "result" parameter coming in.
choices = NewDictionary()
dictionary add("GemOfDestiny:use", "Use gem of destiny")
dictionary add("HealingPotion:use", "Use healing potion")
...
ShowMenu("Use Item", choices, false) {
ExecuteMenuResult(result)
}
If you had a list of objects that could be used, you could do this (assume the list is "olist"):
choices = NewDictionary()
foreach (object, olist) {
dictionary add(object.name + ":use", "Use " + object.alias)
}
You then just need to create a "use" script on each object.
(Looking back at this, I don't know why I used ":" for the separator. I think "." would make more sense, as in "HealingPotion.use". That's an easy enough change.)
HegemonKhan
26 Dec 2013, 20:48I'm not exactly clear on what you want, so my apologizes, but here's a response by me regardless, lol:
you can use a menu's string list to get the choiced string that you want, then you can use that to compare with an object list, to select the object and then what you want done with it. If you can use an objectlist or object dictionary, then this would make it even simplier to do then the below
for a quick (conceptual) conception of it:
Battle Items' TYPES:
1. HP restoration
2. MP restoration
3. (negative) status effect removal
4. damage dealing (to the monsters of course)
5. etc other types of battle items
so my menu's string list would be:
show menu ("What Type of Battle Item do you wish to use?", global_data_object.battle_item_types_string_list, false) {
}
<object name="global_data_object">
<battle_item_types_string_list type="simplestringlist">hp_restoration;mp_restoration;status_effect_removal;damage_dealing</battle_item_types_string_list>
</object>
<object name="player">
-> <object name="hp_plus_50_points">
->-> <battle_item_type_string type="string">hp_restoration</battle_item_type_string>
-> </object>
</object>
than for the following script:
show menu ("What Type of Battle Item do you wish to use?", global_data_object.battle_item_types_string_list, false) {
-> foreach (item_x, ScopeInventory ()) {
->-> if (result=item_x.battle_item_type_string) {
->->-> global_data_object.choosen_battle_item_type_items_list = NewStringList ()
->->-> list add (global_data_object.choosen_battle_item_type_items_list, item_x.alias)
->-> }
->-> on ready {
->->-> show menu ("What battle item do you want to use?, global_data_object.choosen_battle_item_type_items_list, false) {
->->->-> battle_item_choosen_for_use = GetObject (result)
->->->-> battle_item_choosen_for_use.use_on_monster // or *.use_on_self, *.cast_on_self, *.cast_on_monster, etc...
->->-> }
->-> }
-> }
}
-----------------------
"COMPARING" is a huge coding-logic concept (well it was for me a breakthrough, lol):
if (this = that), then do ...
if (this list's selected choice as an attribute string or object = that list's "any-number-of" (using the "foreach" script~function) attributes=strings or object's attributes), then do this for every one of them that which applies to the above conditional code line.
you can use a menu's string list to get the choiced string that you want, then you can use that to compare with an object list, to select the object and then what you want done with it. If you can use an objectlist or object dictionary, then this would make it even simplier to do then the below
for a quick (conceptual) conception of it:
Battle Items' TYPES:
1. HP restoration
2. MP restoration
3. (negative) status effect removal
4. damage dealing (to the monsters of course)
5. etc other types of battle items
so my menu's string list would be:
show menu ("What Type of Battle Item do you wish to use?", global_data_object.battle_item_types_string_list, false) {
}
<object name="global_data_object">
<battle_item_types_string_list type="simplestringlist">hp_restoration;mp_restoration;status_effect_removal;damage_dealing</battle_item_types_string_list>
</object>
<object name="player">
-> <object name="hp_plus_50_points">
->-> <battle_item_type_string type="string">hp_restoration</battle_item_type_string>
-> </object>
</object>
than for the following script:
show menu ("What Type of Battle Item do you wish to use?", global_data_object.battle_item_types_string_list, false) {
-> foreach (item_x, ScopeInventory ()) {
->-> if (result=item_x.battle_item_type_string) {
->->-> global_data_object.choosen_battle_item_type_items_list = NewStringList ()
->->-> list add (global_data_object.choosen_battle_item_type_items_list, item_x.alias)
->-> }
->-> on ready {
->->-> show menu ("What battle item do you want to use?, global_data_object.choosen_battle_item_type_items_list, false) {
->->->-> battle_item_choosen_for_use = GetObject (result)
->->->-> battle_item_choosen_for_use.use_on_monster // or *.use_on_self, *.cast_on_self, *.cast_on_monster, etc...
->->-> }
->-> }
-> }
}
-----------------------
"COMPARING" is a huge coding-logic concept (well it was for me a breakthrough, lol):
if (this = that), then do ...
if (this list's selected choice as an attribute string or object = that list's "any-number-of" (using the "foreach" script~function) attributes=strings or object's attributes), then do this for every one of them that which applies to the above conditional code line.
TriangleGames
26 Dec 2013, 21:21I had to try it to really get, and apparently I was a bit backwards on how dictionaries work with the menu, but I think I understand it all now. It's sort of like manually parsing the key to activate the object's script attribute, as if the player had typed "use object" at the command line. That should work great, thank you!
HegemonKhan
26 Dec 2013, 22:24I think my "travel" code demonstrates this stuff, if you want to look at a concrete example or try it out (if you can get it working if you're using a newer version of quest than my usage of 540 ~ 5.40 version still):
I didn't use an object dictionary to get the new player.parent 's room object, but meh, that's just using an object dictionary's syntax correctly, lol. But, regardless, all the concepts~elements~aspects involved are demonstrated, or most of them anyways.
I didn't use an object dictionary to get the new player.parent 's room object, but meh, that's just using an object dictionary's syntax correctly, lol. But, regardless, all the concepts~elements~aspects involved are demonstrated, or most of them anyways.
<asl version="540">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Testing Game Stuff">
<gameid>eef801a1-4e6b-4b0a-bdbf-8f3ecfa8389c</gameid>
<version>1.0</version>
<firstpublished>2013</firstpublished>
<turns type="int">0</turns>
<statusattributes type="simplestringdictionary">turns=</statusattributes>
<start type="script">
msg ("Important Note:")
msg ("Type in: help")
</start>
</game>
<object name="homeland">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
<object name="grassland">
<inherit name="editor_room" />
</object>
<object name="plains">
<inherit name="editor_room" />
</object>
<object name="desert">
<inherit name="editor_room" />
</object>
<object name="tundra">
<inherit name="editor_room" />
</object>
<object name="swampland">
<inherit name="editor_room" />
</object>
<object name="mountains">
<inherit name="editor_room" />
</object>
<object name="forest">
<inherit name="editor_room" />
</object>
<object name="wasteland">
<inherit name="editor_room" />
</object>
<object name="coastland">
<inherit name="editor_room" />
</object>
<object name="hills">
<inherit name="editor_room" />
</object>
<command name="help_command">
<pattern>help</pattern>
<script>
help_function
</script>
</command>
<command name="explore_command">
<pattern>explore</pattern>
<script>
explore_function
</script>
</command>
<command name="travel_command">
<pattern>travel</pattern>
<script>
travel_function
</script>
</command>
<object name="data_object">
<inherit name="editor_object" />
<travel_string_list type="simplestringlist">homeland</travel_string_list>
<homeland_events_string_list type="simplestringlist">grassland_discovery;plains_discovery;desert_discovery;tundra_discovery;swampland_discovery;forest_discovery;mountains_discovery;hills_discovery;wasteland_discovery;coastland_discovery</homeland_events_string_list>
<homeland_events_script_dictionary type="scriptdictionary">
<item key="grassland_discovery">
list add (data_object.travel_string_list, "grassland")
msg ("You've discovered the grassland! Now, you can travel to the grassland and explore it!")
</item>
<item key="plains_discovery">
list add (data_object.travel_string_list, "plains")
msg ("You've discovered the plains! Now, you can travel to the plains and explore it!")
</item>
<item key="desert_discovery">
list add (data_object.travel_string_list, "desert")
msg ("You've discovered the desert! Now, you can travel to the desert and explore it!")
</item>
<item key="tundra_discovery">
list add (data_object.travel_string_list, "tundra")
msg ("You've discovered the tundra! Now, you can travel to the tundra and explore it!")
</item>
<item key="swampland_discovery">
list add (data_object.travel_string_list, "swampland")
msg ("You've discovered the swampland! Now, you can travel to the swampland and explore it!")
</item>
<item key="forest_discovery">
list add (data_object.travel_string_list, "forest")
msg ("You've discovered the forest! Now, you can travel to the forest and explore it!")
</item>
<item key="mountains_discovery">
list add (data_object.travel_string_list, "mountains")
msg ("You've discovered the mountains! Now, you can travel to the mountains and explore it!")
</item>
<item key="hills_discovery">
list add (data_object.travel_string_list, "hills")
msg ("You've discovered the hills! Now, you can travel to the hills and explore it!")
</item>
<item key="wasteland_discovery">
list add (data_object.travel_string_list, "wasteland")
msg ("You've discovered the wasteland! Now, you can travel to the wasteland and explore it!")
</item>
<item key="coastland_discovery">
list add (data_object.travel_string_list, "coastland")
msg ("You've discovered the coastland! Now, you can travel to the coastland and explore it!")
</item>
</homeland_events_script_dictionary>
</object>
<turnscript name="global_turnscript">
<enabled />
<script>
game.turns = game.turns + 1
</script>
</turnscript>
<function name="help_function">
msg ("Type 'explore' to explore your area.")
msg ("Type 'travel' to travel to different areas.")
</function>
<function name="explore_function"><![CDATA[
switch (game.pov.parent) {
case (homeland) {
result_1 = ListCount (data_object.homeland_events_string_list) - 1
if (result_1 >= 0) {
result_2 = StringListItem (data_object.homeland_events_string_list,GetRandomInt(0,result_1))
invoke (ScriptDictionaryItem (data_object.homeland_events_script_dictionary,result_2))
on ready {
foreach (item_x, split ("grassland_discovery;plains_discovery;desert_discovery;tundra_discovery;swampland_discovery;forest_discovery;mountains_discovery;hills_discovery;wasteland_discovery;coastland_discovery",";")) {
if (result_2 = item_x) {
list remove (data_object.homeland_events_string_list, result_2)
}
}
}
} else {
msg ("There seemingly is nothing left to explore in this area.")
}
}
}
]]></function>
<function name="travel_function">
show menu ("Where do you wish to travel?",data_object.travel_string_list,false) {
if (not game.pov.parent = GetObject (result)) {
game.pov.parent = GetObject (result)
} else {
msg ("You are already at this area.")
ask ("Try again?") {
if (result=true) {
travel_function
} else {
msg ("You realize that you need to discover a new area to travel to first, before you can travel to that place.")
}
}
}
}
</function>
</asl>