<game name="sample">
</game>
<object name="room">
</object>
<object name="player">
<attr name="parent" type="object">room</attr>
<attr name="type_of_object_string_attribute" type="string">pc</attr>
</object>
<object name="apple">
<attr name="parent" type="object">room</attr>
<attr name="type_of_object_string_attribute" type="string">food</attr>
</object>
<object name="banana">
<attr name="parent" type="object">room</attr>
<attr name="type_of_object_string_attribute" type="string">food</attr>
</object>
<object name="orc">
<attr name="parent" type="object">room</attr>
<attr name="type_of_object_string_attribute" type="string">monster</attr>
</object>
<object name="tavernmaid">
<attr name="parent" type="object">room</attr>
<attr name="type_of_object_string_attribute" type="string">npc</attr>
</object>
<command name="collect_food_command">
<pattern>collect food</pattern> // you'd type this in when playing the game: collect food
<script>
foreach (object_variable, ScopeReachableNotHeld()) {
if (GetString (object_variable, "type_of_object_string_attribute") = "food") {
object_variable.parent = player
}
}
</script>
</command>@HegemonKhan
Great! Thanks! After examining the code I was able to figure out what I needed to do in the Quest user interface. The script you supplied was what I needed!
I added the script, then figured out what I needed to do on my end to make it work. Once I got it working, I tried a few experiments. I changed that "type_of_object_string" to "test" and then "collectable" and made the other necessary corrections, and the script worked perfectly for those too. Then I changed the command so that "gather food" would work as well.
From that point, I added a new command line with an altered version of the same script to make food simply become invisible (using the Quest interface, of course). Then I changed it again to set object flags, and then tested to see if the flags worked. They did.
The links you gave me are, for the most part, over my head. They aren't as detailed as the tutorial is. I had previously looked at most of those pages. Interestingly, that ScopeReachableNotHeld() thing caught my attention, and I wondered if that was what I needed, but I didn't know how to use it to even find out.
So anyway, thanks for your help. Your example worked perfectly. By the way, if you try to parent an object to itself, this is what the output is:
Error running script: Parent of element 'player' cannot be set to itself
@XanMag
LOL, that's probably what I would do myself. Add the scenery object and then tell it what to do for all the devices at once. In the game I'm working on, I'm toying with the idea of two levels of difficulty. The hard one will have dark rooms, the easy will have none. I'm thinking of making a scenery light source follow the player on the easy level instead of messing with making scripts for each of the otherwise dark rooms.
glad you were able to make sense and/or figure it out, from my code heavy and not well-explained post(s), laughs. Helping someone through the GUI~Editor vs just copy and pasting code, is a lot more work... which is why I don't do it too often, takes too much precious time (never enough time to do everything sighs) and I am lazy, laughs.
you don't have to use a Command, you can put those scripts into various Verbs/Functions or where/what-ever else, and ya, you can change the 'name' of things, just make sure that it all matches up everywhere in your game's code/GUI~Editor where it's being used.
you can also expand upon the scripting too... putting in more conditionals ('if~else if~else' Scripts), for example using the Command again, instead of just checking if it's food, you can add additional 'else ifs' and do whatever you want (instead of making/having multiple, in this example case, Commands):
<command name="blah_command">
<pattern>blah</pattern>
<script>
foreach (object_variable, ScopeReachableNotHeld()) {
if (HasString (object_variable, "type_of_object_string_attribute") = "food") {
object_variable.parent = player
} else if (HasString (object_variable, "type_of_object_string_attribute") = "monster") {
invoke (object_variable.fight_script)
}
// etc etc etc 'else ifs' as you want for your various types of Objects
}
</script>
</command>
I just used commands at the time for the sake of the simplicity of testing things. Yeah, I know that I can also place the script somewhere else, like when something is opened, looked at, taken, etc., or when I use a user-created verb on an object.
If also figured that about expanding the scripting too. Going back to the tutorial, I had thought about flagging the perishable items (or adding another type) and only taking the perishable food items when I run the command line in-game. But I'm taking this one step at a time.
Again, thanks for your help. I've got the script saved to my tutorial game for quick reference.
I think using a command is probably the only way this will work. You would want to set it up with say this pattern:
get food;get all food;take food;take all;pick up food;pick up all food
Then go though the objects in the room, and check which are food. You could do that with an attribute or by setting them to be a type (using the DoesInherit function to check). Is that enough to get you going, or do you want more details?
err.... I don't know the new tags for these posts now... how to do the code box/quote box/etc stuff??
The forums now use "markdown". You can find things like the code tag here:
https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
Thanks, Pixie, I think I've got what I need to know for now. I got exactly the help I needed already, and have adapted the above script to figure out how to do other things as well. I really asked the question out of curiosity, because I thought there had to be more that I could do with types/attributes than what was given in the tutorial. As it turns out, I learned even more than I imagined, and am playing around with the game's response to the foreach (object_variable, ScopeReachableNotHeld()) line of the script. It's a pretty powerful line. Some time later I'll probably try another scope in it's place.
My next step might be to learn more about lists, but I'll save that for later. In the meantime, I'll be experimenting with the game, consulting the help pages, and looking at the forum.
Lists and their usage is a bit more advanced stuff, so they can take some time to learn, but they're very useful/powerful. You don't have to use a Scope (a built-in specific itemed list creation function), you can create your own lists, and do lots of cool stuff with them, such as randomly selecting one of its items:
the 'split' Script/Function is an easy quick way to create a List Attribute if you need doing so through scripting, for example:
orc.item_drop_list = split ("cash;club;potion", ";")
but I'll show the "normal" way in the code below:
<game name="sample">
<attr name="start" type="script">
orc.item_drop_list = NewStringList()
list add (orc.item_drop_list, "cash")
list add (orc.item_drop_list, "club")
list add (orc.item_drop_list, "potion")
</attr>
</game>
<object name="room">
</object>
<object name="club">
<attr name="parent" type="object">orc</attr>
</object>
<object name="potion">
<attr name="parent" type="object">orc</attr>
</object>
<object name="player">
<attr name="parent" type="object">room</attr>
<attr name="cash" type="int">0</attr>
</object>
<object name="orc">
<attr name="parent" type="object">room</attr>
<attr name="dead" type="boolean">false</attr>
<attr name="cash" type="int">50</attr>
<attr name="displayverbs" type="simplestringlist">fight</attr>
<attr name="fight" type="script">
if (orc.dead) {
msg ("The orc is already dead and looted, silly")
} else {
msg ("You fight and kill the orc.")
orc.dead = true
item_drop_function (this)
}
</attr>
</object>
<function name="item_drop_function" parameters="character_parameter">
selected_item_variable = StringListItem (character_parameter.item_drop_list, GetRandomInt (0, ListCount (character_parameter.item_drop_list) - 1))
if (selected_item_variable = "cash") {
player.cash = player.cash + character_parameter.cash
} else {
MoveObject (GetObject (selected_item_variable), player)
}
</function>
<verb>
<property>fight</property>
<pattern>fight</pattern>
<defaultexpression>You can't fight that!</attr>
</verb>
conceptual example of the 'foreach' Script/Function:
foreach (PLACEHOLDER_VARIABLE, OBJECT_NAME.LIST_ATTRIBUTE_NAME)
pretend that 'run_laps' is a Script Attribute on each of the team members, which will be run via the 'invoke' (or you can use the more powerful/useful 'do' instead if you need to do more advanced scripting) Script/Function, seen below
----
game.team = split ("john;joe;jim;jeff;james", ";")
foreach (team_member, game.team) {
invoke (team_member.run_laps)
}
// conceptual effect/result of what the 'PLACEHOLDER_VARIABLE' does automatically (hidden / behind the scenes) in the 'foreach' Script/Function:
team_member = "john" -> invoke (john.run_laps)
team_member = "joe" -> invoke (joe.run_laps)
team_member = "jim" -> invoke (jim.run_laps)
team_member = "jeff" -> invoke (jeff.run_laps)
team_member = "james" -> invoke (james.run_laps)
Well, I'm not quite ready to try out lists, or at least I didn't think I was, but since you went through the trouble of giving that example of a code using lists, I took a close look at the post. Please tell me how well I interpreted what is going on:
And here are my questions:
you didn't have to jump into Lists, I was just posting the stuff for when you do, laughs. Oh well... Lists are useful, if you can wrap your head around them / understanding them.
good luck on understanding this post... YUCK! (I did a really bad job at trying to explain and answer your questions... grr, sighs)
I did do a bit of a more complex example here... due to the handling of me using different data types, so if you can understand this example, you're much much farther along in understanding List usage, hehe.
for your #3-understanding (all others are an accurate understanding):
the 'orc' Object contains 2 Objects: 'club' Object and 'potion' Object
the 'orc' (and 'player') Object(s) also contains a 'cash' Integer Attribute, the 'player' Object's 'cash' Integer Attribute's Value starts at 0, and the 'orc' Object has its 'cash' Integer Attribute's Value at 50.
because I decided to have a mix of Data Types (2 Objects and 1 Integer Attribute), I must use a String List Attribute as it holds strings/text as its items (an Object List Attribute must have all of its items as Objects - which the 'cash' Integer Attribute would cause an error, as it's not an Object)
Thus because I'm using a String List Attribute, its items are just strings/text, so if the 'potion' or the 'club' item is selected via the random selection code ( selected_item_variable = ...... ), (see the scripting under the 'else' condition) I must convert the string/text of 'potion' selected choice into the 'potion' Object, which the 'GetObject (string/text: selected_item_variable)' does. The same is done with/for the 'club' string/text into the 'club' Object. And now, we can act upon those Objects, which in this example is to move them over to (into) the 'player' Object (aka, the "inventory"). However, if the 'cash' string/text item is selected (which is checked via the 'if' condition), it's handled differently, we just simply add the Value (50) of the 'orc' Object's 'cash' Integer Attribute to the 'player' Object's 'cash' Integer Attribute's Value (of 0).
the 'orc' Object's 'fight' Script Attribute is the same as the GUI~Editor's: 'orc' Object -> 'Verb' Tab -> 'fight' Verb -> (set it up: add new script, etc etc etc)
VARIABLES (3 Types - keeping this simple):
now, about the 'item_drop_function' Function:
Functions (and Commands) have 'argument/parameter' VARIABLES, these are inputs that are then able to be used by the Function's scripting.
so, in the 'orc' Object's 'fight' Script Attribute (the 'orc' Object's 'fight' Verb), we call/activate/run the 'item_drop_function' and provide the special 'this' keyword/keycommand as its input/argument.
The special 'this' keyword/keycommand, GETS the Object that is containing its scripting (in this case, the 'this' scripting, is / is inside, the 'fight' Script Attribute), which in this case, the 'fight' Script Attribute is contained by/in the 'orc' Object. So, 'this' GETS the 'orc' Object:
conceptual:
item_drop_function (argument/input)
item_drop_function (this)
item_drop_function (this ---> orc)
item_drop_function (orc)
now, I name/rename the Parameter VARIABLE that is holding the input/argument as 'character_parameter':
conceptually:
character_parameter = orc
which the scripting in the 'item_drop_function' can (and does) use that Parameter VARIABLE (character_parameter), so:
conceptually:
selected_item_variable = StringListItem (character_parameter.item_drop_list, GetRandomInt (0, ListCount (character_parameter.item_drop_list) - 1))
selected_item_variable = StringListItem (orc.item_drop_list, GetRandomInt (0, ListCount (orc.item_drop_list) - 1))
selected_item_variable = (one of these strings/text items: cash/club/potion)
player.cash = player.cash + character_parameter.cash
player.cash = player.cash + orc.cash
player.cash = (0) + (50)
player.cash = 50
your questions:
if you're calling the Function from a Script Attribute of the Object (aka, in GUI~Editor: an Object's Verb):
// you can always replace 'this' with the name of the Object, but by using 'this' (only when its scripting is contained by that Object you want to use) then you don't have to for each different Object you're using with this Function
in code: item_drop_function (this)
GUI~Editor: add new script -> output -> 'call function' Script -> Name: item_drop_function, Add Parameter: this)
if you're calling the 'item_drop_function' Function from another Function:
in code: item_drop_function (name_of_the_object_you_want_to_use)
GUI~Editor: add new script -> output -> 'call function' Script -> Name: item_drop_function, Add Parameter: name_of_the_object_you_want_to_use, --- you may be using scripting to determine the Object for what Object name to use)
if you're calling the 'item_drop_function' Function from a Command:
GUI~Editor: add new script -> output -> 'call function' Script -> Name: item_drop_function, Add Parameter: object, --- if using #object#, otherwise: objectXXX --- if using #objectXXX#)
and yes, each Object would need its own 'item_drop' list, unless you want a universal drop list, and/or have your own scripting for determining what 'Object.List' to use (such as with diablo games using its 'ilvl/alvl' Attributes in relation to which treasure_class/drop list to use) if you're doing more complex stuff in your game.
yes, that's how it's done directly in code, you literally write the name of the function and in the parenthesis, you either type in: 'this' (if its scripting is contained by the desired Object), or you specifically type in the name of the Object, or you're using addition scripting for determing the Object and a variable for holding the name of the scripting-gotten Object
'character_variable' is just my own personal-custom name/label for the Parameter VARIABLE, you can use whatever you want for the name/label of it, such as a simple 'x':
item_drop_function (orc)
~OR for this example~
item_drop_function (this)
// parameter="x" <=== orc
// or
// for this example: parameter="x" <==== (this = orc)
<function name="item_drop_function" parameter="x">
// x = orc
// just for quick example:
player.cash = player.cash + x.cash
// conceptually: player.cash = player.cash + orc.cash
</function>
there's various ways:
directly in code, as the 'creation' tag block (for initial game setting only):
<object name="orc">
<attr name="item_drop_list" type="simplestringlist">cash;club;potion</attr>
</object>
// in full view of everything, after the start of the game, the 'orc' Object 'creation' tag block looks like this:
<object name="orc">
<attr name="cash" type="int">50</attr>
<attr name="dead" type="boolean">false</attr>
<attr name="item_drop_list" type="simplestringlist">cash;club;potion</attr>
<attr name="displayverbs" type="simplestringlist">fight</attr>
<attr name="fight" type="script">
// blah blah blah scripting, I'm lazy, lol
</attr>
<object name="club">
</object>
<object name="potion">
</object>
</object>
the above (well, just demonstrating for this: the 'item_drop_list' String List Attribute), is the same as if you did it manually in the GUI~Editor:
'orc' Object -> 'Attributes' Tab -> Attributes -> Add -> (see below)
(Object Name: orc)
Attribute Name: item_drop_list
Attribute Type: String List
Attribute Value (add item or whatever/however it's done in the GUI~Edtor, lol): cash; club; potion
and lastly, via scripting, which is what I originally used for my example (already seen, GUI~EDitor: 'game' Game Object -> 'Scripts' Tab -> 'start' Script -> set it up: add new script and etc etc tc).
just to add on, more about a Function and its Arguments/Parameters (these examples probably explains about Functions and their arguments/parameters much better):
<game name="xxx">
<attr name="start" type="script">
answer = sum_of_five_values_function (1,2,3,4,5) // Arguments: 1,2,3,4,5 --- which match up with their Parameter slots/ordering (value_1,value_2,etc): '1' to 'value_1', '2' to 'value_2', etc etc etc
msg ("The sum of 1+2+3+4+5 is: " + answer)
// output: The sum of 1+2+3+4+5 is: 15
</attr>
</game>
<function name="sum_of_five_values_function" parameters="value_1,value_2,value_3,value_4,value_5" type="int"> // type="XXX" is the return type
sum = value_1 + value_2 + value_3 + value_4 + value_5
return (sum)
</function>
and using different arguments:
<game name="xxx">
<attr name="start" type="script">
answer = sum_of_five_values_function (23,41,17,89,66) // Arguments: 23,41,17,89,66 --- which match up with their Parameter slots/ordering (value_1,value_2,etc): '23' to 'value_1', '41' to 'value_2', etc etc etc
msg ("The sum of 23+41+17+89+66 is: " + answer)
// output: The sum of 23+41+17+89+66 is: 236
</attr>
</game>
<function name="sum_of_five_values_function" parameters="value_1,value_2,value_3,value_4,value_5" type="int"> // type="XXX" is the return type
sum = value_1 + value_2 + value_3 + value_4 + value_5
return (sum)
</function>
using Variables instead of constants for the arguments:
<game name="xxx">
<attr name="start" type="script">
arg1 = 32
arg2 = 14
arg3 = 71
arg4 = 98
arg5 = 66
answer = sum_of_five_values_function (arg1,arg2,arg3,arg4,arg5) // Arguments: arg1,arg2,arg3,arg4,arg5 --- which match up with their Parameter slots/ordering (value_1,value_2,etc): 'arg1' to 'value_1', 'arg2' to 'value_2', etc etc etc
msg ("The sum of 32+14+71+98+66 is: " + answer)
// output: The sum of 32+14+71+98+66 is: 281
</attr>
</game>
<function name="sum_of_five_values_function" parameters="value_1,value_2,value_3,value_4,value_5" type="int"> // type="XXX" is the return type
sum = value_1 + value_2 + value_3 + value_4 + value_5
return (sum)
</function>
using Attributes for the arguments:
<game name="xxx">
<attr name="start" type="script">
answer = sum_of_five_values_function (global_data_object.arg_1,global_data_object.arg_2,global_data_object.arg_3,global_data_object.arg_4,global_data_object.arg_5)
msg ("The sum of 2+4+6+8+10 is: " + answer)
// output: The sum of 2+4+6+8+10 is: 30
</attr>
</game>
<object name="global_data_object">
<attr name="arg_1" type="int">2</attr>
<attr name="arg_2" type="int">4</attr>
<attr name="arg_3" type="int">6</attr>
<attr name="arg_4" type="int">8</attr>
<attr name="arg_5" type="int">10</attr>
</object>
<function name="sum_of_five_values_function" parameters="value_1,value_2,value_3,value_4,value_5" type="int">
sum = value_1 + value_2 + value_3 + value_4 + value_5
return (sum)
</function>
using Attributes for the arguments:
(multiple uses/re-uses, one of the big purposes of Functions)
<game name="xxx">
<attr name="turn" type="int">0</attr>
<statusattributes type="simplestringdictionary">turn = Turn: !</statusattributes> // unfortunately, Dictionary Attributes still require this old syntax: <ATTRIBUTE_NAME type="xxx">content</ATTRIBUTE_NAME>, sighs. You can't do: <attr name="ATTRIBUTE_NAME" type="xxx">content</attr>
<attr name="start" type="script">
answer = sum_of_five_values_function (global_data_object.arg_1,global_data_object.arg_2,global_data_object.arg_3,global_data_object.arg_4,global_data_object.arg_5)
msg ("The sum = " + answer)
</attr>
</game>
<object name="global_data_object">
<attr name="arg_1" type="int">1</attr>
<attr name="arg_2" type="int">3</attr>
<attr name="arg_3" type="int">6</attr>
<attr name="arg_4" type="int">9</attr>
<attr name="arg_5" type="int">12</attr>
</object>
<object name="room">
</object>
<object name="player">
<attr name="parent" type="object">room</attr>
<attr name="alias" type="string">HK</attr>
<attr name="current_life" type="int">999</attr>
<attr name="maximum_life" type="int">999</attr>
<attr name="life" type="string">999/999</attr>
<statusattributes type="simplestringdictionary">life = Life: !</statusattributes> // unfortunately, Dictionary Attributes still require this old syntax: <ATTRIBUTE_NAME type="xxx">content</ATTRIBUTE_NAME>, sighs. You can't do: <attr name="ATTRIBUTE_NAME" type="xxx">content</attr>
<attr name="changedcurrent_life" type="script">
this.life = this.current_life + "/" + this.maximum_life
</attr>
<attr name="changedmaximum_life" type="script">
this.life = this.current_life + "/" + this.maximum_life
</attr>
</object>
<object name="monster">
<attr name="parent" type="object">room</attr>
<attr name="alias" type="string">orc</attr>
<attr name="dead" type="boolean">false</attr>
<attr name="current_life" type="int">500</attr>
<attr name="maximum_life" type="int">500</attr>
<attr name="life" type="string">500/500</attr>
<attr name="displayverbs" type="simplestringlist">look;fight</attr>
<attr name="changedcurrent_life" type="script">
this.life = this.current_life + "/" + this.maximum_life
</attr>
<attr name="changedmaximum_life" type="script">
this.life = this.current_life + "/" + this.maximum_life
</attr>
<attr name="look" type="script">
msg ("Life: " + this.life)
</attr>
<attr name="fight" type="script"><![CDATA[ // this '<![CDATA[ content:scripting ]]>' tag is needed to tell quest that any of the '<' and '>' symbols as the inside content:scripting are to be recognized as 'greater than' and 'lesser than' operations/symbols, and NOT as code tag symbols. Otherwise, we'd be getting an ERROR. This 'CDATA' tag is ONLY needed for if/when you're typing in the code directly. If you're using the GUI~Editor, then you don't need to ever worry about (don't need to use) this 'CDATA' tag, as it handles it for you.
if (this.dead) {
msg ("The " + this.alias + " is already dead, silly.")
} else {
damage = sum_of_five_values_function (10,20,30,40,50)
this.current_life = this.current_life - damage
msg (game.pov.alias + " attacked the " + this.alias + " for " + damage + " damage, leaving it with only " + this.current_life + " life left.")
if (this.current_life <= 0) {
this.dead = true
msg (game.pov.alias + " inflicted so much damage, he actually killed the " + this.alias + ".")
} else {
game.pov.current_life = game.pov.current_life - damage
msg (this.alias + " attacks " + game.pov.alias + ", doing " + damage + " damage to him, leaving " + game.pov.alias + " with only " + game.pov.current_life + " life left.")
if (game.pov.current_life <= 0) {
msg ("The " + this.alias + " has killed " + game.pov.alias + ".")
msg ("GAME OVER")
finish
}
}
}
]]></attr>
</object>
<verb>
<property>fight</proeprty>
<pattern>fight</pattern>
<defaultexpression>You can't fight that!</defaultexpression>
</verb>
<verb>
<property>look</proeprty>
<pattern>look</pattern>
<defaultexpression>You can't look at that!</defaultexpression>
</verb>
<turnscript name="global_turnscript">
<enabled /> // this (to the left) is the syntax quest-understood shorthand of this Boolean Atribute (of ONLY) when its Value is 'true', as shown in its longhand/normal syntax form: <attr name="enabled" type="boolean">true</attr>
<script>
answer = sum_of_five_values_function (9,8,7,6,5)
msg (game.turn + ". The sum now = " + answer)
game.turn = game.turn + 1
</script>
</turnscript>
<function name="sum_of_five_values_function" parameters="value_1,value_2,value_3,value_4,value_5" type="int">
sum = value_1 + value_2 + value_3 + value_4 + value_5
return (sum)
</function>
P.S.
if you want, I got a (badly done / confusing, as I'm not good at explaining stuff well) guide on using Lists (and Dictionaries too and on Attirbutes in general as well):
http://textadventures.co.uk/forum/samples/topic/5137/list-and-dictionary-extensive-guide-by-hk
http://textadventures.co.uk/forum/samples/topic/5138/explore-and-travel-code-sample-by-hk (if you want to see more fancy/advanced usage, though my coding is old and poor quality as I was just learning this List+Dictionary stuff back then, lol)
http://textadventures.co.uk/forum/samples/topic/5559/attributes-and-if-script-guide-by-hk
Wow, that's a lot to read through, lol.
It's funny how I perceived the cash as an object. Facepalm on that one. I knew better than that. I was just using my imagination, looking at it from a player's point of view, seeing cash actually go from the orc to the player.
And yeah, I meant string list, in that question.
Anyway, I'll go back and process this at another time. I've spent so much time experimenting that I've neglected the game I want to finish, and I don't see myself using ANY of this stuff in it, lol. I want to go ahead and finish it.