A few hopefully simple questions-Types to select multiple obejects?
Talon
17 Aug 2016, 18:02In the game code i'm working on I'm trying to set up, mostly to improve my grasp of the program(Always learning), The project I am working on I think would use types types, or maybe even just attributes
In my mind I'd set up character types such as NPC, Allies, Enemies, Bosses, with each type having some similar attributes on how they are encountered and treated.
I'd like to be able to affect all objects with the same type.. for example if a certain stone is used summon all the currently alive bosses to the players location(A bad idea, but certainly possible) In that case i'd think something using a for each look maybe.. Esentially I'd like to have scripts do an effect to any object with a certain type/attribute. (Similarly summon a random ally to help you having a list made dynamically where the game collects all the objects with that attribute and picks one from the list)
In short, how would be the most elegant way of setting up scripts to target groups of defined objects without manually defining orc1 to orc 20 one by one
Thank you for your time.
The Pixie
17 Aug 2016, 20:30The best way I can think of is to iterate through everything, and test to see if it is of that type.
foreach (obj, AllObjects()) {
if (DoesInherit(obj, "Allies")) {
// do stuff
}
}
By the way, did you know your types can have types too? Once you have set up the NPC type, your Ally and Enemy types can be of that type, and your Boss type can be of the Enemy.
Talon
17 Aug 2016, 22:03hmm that sounds easy, though my intial attempts at adapting the code very simply haven't been too effective, esentially gave a couple characters the type NPC to see if the code would just print out a list of them, it returns "Unable to cast object of type 'System.String' to type 'TextAdventures.Quest.Element'" error
NPClist = NewObjectList()
foreach (obj, AllObjects()) {
if (DoesInherit(obj, "NPC")) {
list add (NPClist, "this")
}
}
DisplayList (NPClist, false)
hegemonkhan
17 Aug 2016, 22:37As Pixie has demonstrated, the basic concept is to give your Objects an indicator/flag of what type object/thing it is, which can be done with either a normal Attribute (String Attribute, Integer Attribute, Boolean Attribute, etc) or via an Inherited Attribute (using the Object Types / Type), which you can then check for in your loop (usually a 'foreach' Function loop).
for checking (the 'if (condition: see #1 and #2 below)' checking):
1A. normal Attributes use the 'HasAttribute', or the specific attribute type 'Has___' Functions (HasString, HasInt, HasDouble, etc)
1B. you can also use the 'Get' Functions, 'GetAttribute' or the specific attribute type 'Get____' Functions (GetString, GetInt, GetDouble, GetObject, etc) too for normal Attributes, as they either succeed, or they fail, returning 'null'
2. Inherited Attributes use the 'DoesInherit' Function
Initially, if you haven't manually put (or have) your items into a list/dictionary or if you otherwise just need to (you're working with dynamic-ness), you use the 'foreach (Variable, AllObjects())', to search/loop/iterate through all the Objects in your game, but after this (or as apart of its scripting), you may want to put those desired items, into their own list/dictionary, so that you can now just search/loop/iterate through this smaller/specific list/dictionary of your desired items, rather than ALL of the objects in your game over and over (as this is a big waste of time and processing), if you can help it.
for an (full and complex/advanced) example of using 'Object Types / Types' capabilities/features:
<game name="xxx">
<attr name="start" type="script">
data_object.monster_list = NewObjectList()
foreach (object_variable, AllObjects()) {
if (DoesInherit (object_variable, "monster_type")) {
list add (data_object.monster_list, object_variable)
}
}
// we can then use our (much smaller) 'data_object.monster_list' Objectlist Attribute (compared to a hidden/automatic objectlist created by quest, containing every Object in the game, which the 'AllObjects()' Function uses), which contains all of our monster Objects, for whatever we want and where-ever we want.
</attr>
</game>
<object name="data_object">
<attr name="sex_list" type="simplestringlist">male;female</attr>
<attr name="homo_race_list" type="simplestringlist">human;dwarf;elf;gnome;halfling;giant</attr>
<attr name="hybrid_race_list" type="simplestringlist">centaur;minotaur;satyr;vampire;werewolf;harpy;mermaid</attr>
<attr name="monster_race_list" type="simplestringlist">orc;ogre;troll;goblin;gremlin;cyclops</attr>
<attr name="combat_class_list" type="simplestringlist">warrior;knight;berserker;ranger;paladin</attr>
<attr name="magic_class_list" type="simplestringlist">wizard;mage;cleric;necromancer;sorcerer</attr>
</object>
<object name="room">
<inherit name="room_type" />
</object>
<object name="room2">
<inherit name="room_type" />
</object>
<object name="player">
<inherit name="player_type" />
<attr name="current_life" type="int">500</attr>
<attr name="maximum_life" type="int">500</attr>
<attr name="damage" type="int">50</attr>
</object>
<object name="player2">
<inherit name="player_type" />
<attr name="current_life" type="int">999</attr>
<attr name="maximum_life" type="int">999</attr>
<attr name="damage" type="int">100</attr>
</object>
<object name="orc">
<inherit name="monster_type" />
<attr name="current_life" type="int">100</attr>
<attr name="maximum_life" type="int">100</attr>
<attr name="damage" type="int">10</attr>
</object>
<object name="ogre">
<inherit name="monster_type" />
<attr name="current_life" type="int">250</attr>
<attr name="maximum_life" type="int">250</attr>
<attr name="damage" type="int">25</attr>
</object>
<type name="room_type">
<attr name="description"> type="string">This is a room, an area of the game</attr>
</type>
<type name="character_type">
<attr name="current_life" type="int">1</attr>
<attr name="maximum_life" type="int">1</attr>
<attr name="damage" type="int">1</attr>
<attr name="life" type="string">1/1</attr>
<attr name="changedcurrent_life" type="script"><![CDATA[
if (this.current_life > this.maximum_life) {
this.current_life = this.maximum_life
} else if (this.current_life < 0) {
this.current_life = 0
}
if (this.current_life = 0) {
this.dead = true
}
this.life = this.current_life + "/" + this.maximum_life
]]></attr>
<attr name="changedmaximum_life" type="script"><![CDATA[
this.life = this.current_life + "/" + this.maximum_life
]]></attr>
</type>
<type name="player_type">
<inherit name="character_type" />
<attr name="parent" type="object">room</attr>
<attr name="changedcurrent_life" type="script"><![CDATA[
if (this.current_life <= 0) {
msg ("You were killed or died.")
msg ("GAME OVER")
finish
} else if (this.current_life > this.maximum_life) {
this.current_life = this.maximum_life
}
this.life = this.current_life + "/" + this.maximum_life
]]></attr>
<attr name="statusattributes" type="simplestringdictionary">life = Life: !; damage = Damage: !</attr>
</type>
<type name="monster_type">
<inherit name="character_type" />
<attr name="parent" type="object">room2</attr>
<attr name="dead" type="boolean">false</attr>
</type>
hegemonkhan
17 Aug 2016, 22:55@ Talon:
just replace your "this" with your use of 'obj', see corrected (and as an EXAMPLE too) code below:
(actually, you need your 'NPClist' Objectlist to be an Attribute, as it will be destroyed when your scripting is done, as you have it as a Variable, not an Attribute)
(you can replace my 'data_object' with whatever you want, this is to just show that you need an Object to make it be an Attribute VARIABLE, OBJECT_NAME.ATTRIBUTE_NAME, and not just a Variable VARIABLE, Variable_NAME)
VARIABLES (keeping this simple):
- Variable: this is local, meaning that it can only be used within its scripting, and once that scripting is done, it is destroyed
- Attribute: this is global, as it is attached/connected-to/within an Object, and thus so long as the Object exists or still exists, the Attribute is 'saved/stored' and thus you can 'load'/use it anywhere in your game, and as much as you want too.
- Arguments/Parameters: these deal with Functions/Commands/etc
<object name="data_object">
</object>
data_object.NPClist = NewObjectList()
foreach (obj, AllObjects()) {
if (DoesInherit(obj, "NPC")) {
list add (data_object.NPClist, obj)
}
}
DisplayList (data_object.NPClist, false)
this is how 'foreach' works conceptually, an example:
<object name="data_object">
<attr name="team" type="objectlist">Joe;Jim;Jeff</attr>
</object>
<object name="Joe">
<inherit name="character_type" />
</object>
<object name="Jim">
<inherit name="character_type" />
</object>
<object name="Jeff">
<inherit name="character_type" />
</object>
<type name="character_type">
<attr name="run_laps" type="script">
msg (this.name + " runs laps")
</attr>
</type>
// or in code scripting, to create your objectlist (one way of doing so): data_object.team = split ("Joe;Jim;Jeff", ";")
foreach (team_member, data_object.team) {
invoke (team_member.run_laps) // or you can use 'do', which is more powerful/useful than 'invoke', but for running a simple Script Attribute, 'invoke' is fine, and thus I used it here.
}
// team_member = Joe ----> team_member.run_laps -----> Joe.run_laps
// team_member = Jim ----> team_member.run_laps -----> Jim.run_laps
// team_member = Jeff ----> team_member.run_laps -----> Jeff.run_laps
// output:
Joe runs laps
Jim runs laps
Jeff runs laps
Talon
18 Aug 2016, 00:59This is exceptionally helpful and will get to playing around with it tomorrow and get it working, you have both been a big help, especially the Examples HK
hegemonkhan
18 Aug 2016, 20:15if you need any help with or in-understanding, anything, ask! I have a pretty lot of advanced (if you're new to this stuff) usages going on in my code.

Proudly Humble
19 Aug 2016, 01:33I learned a lot from HK when I first started looking at this last month, essentially asking the same question as you did. It made a world of difference in my understanding of coding. Now, I don't know whether you will find what I'm going to say of any use, but once you get this current NPC thing mastered, the next thing you might wish to do is to have a permanent list of your NPC's in the event that you wish to reference all NPC's several times. That way you don't have to keep scanning the entire game for NPC's each and every time -- you already have a list of them .
For instance, you mentioned summoning alive bosses to the player's location. You also mentioned randomly summoning an ally. If these are each one-time events and you'll never refer to these types again, then I'd probably just go with with the example Pixie gave you in the first response. But if you wish to later randomly resurrect a dead boss, or send the player and all allies to a random room where a boss is ready to do battle, or similarly reference these objects of these types that are all over the game, I recommend that you make a permanent object list.
For me, permanent object lists are not merely convenient, but they help me keep my thoughts straight and things neatly organized when I'm creating scripts that refer to all objects of a certain group. This is a little tricky, because unlike string lists, object lists cannot be directly attached to objects in the game until the game is actually started (or at least I haven't found a way to do this). So what I do is add a function that creates the permanent object list, and then call that function in the startup script.
Example for objects with "NPC" type:
NPC_list = NewObjectList()
foreach (obj, AllObjects()) {
if (DoesInherit(obj, "NPC")) {
list add (NPC_list, obj)
}
}
game.NPC_list = NPC_list
With that script, you now have a permanent object list of NPC's saved to game.NPC_list. Then you can directly reference the NPC's, and only the NPC's:
foreach (NPC, game.NPC_list) {
// Do stuff
}
However, NPC can be a bit too vague if you are having good guys and baddies. Fortunately, you can borrow this concept to make other permanent object lists too, provided you have those types (game.ally_list, game.boss_list, game.treasures_list, etc.). The only caution is that if you add/remove objects of these types, then you will need to update the object list.
Talon
19 Aug 2016, 15:46Mmhmm Pretty much did the saving to a game list after i made sure the testing item i had worked fine when working around with it..
Got what i wanted done conceptually to work and though I still need to do the actual details and planning around the game I know when i need it i'll have the tester object to use as a guide
Though not really connected at all.. It might be just as simple a question, Does quest have a "Between" function for numbers, lets say I want a characters description to change based on some counter that'll be going up and down with various actions each scoring a certain number of points, so if the count is 1-10 the character looks normal 11-20 they have become more deranged, 21-30 they look monstrous, and beyond that the mind is gone
Think I could do it with changing flags as thresholds are met, but it seems vastly more complicated than it should be when using attributes where the code could just see what number it is and spit out the proper description-Edit Managed to get it work with nested If statements, > and <
And more in the not connected file- Is there a way to customize/put a string comand for removing items from a container.. Ie, you take a jar of milk from a fridge vs you search around for a jar of milk in your backpack.. I'd guess it would be in the default dictionaries, but can you customize them for specific items?
hegemonkhan
20 Aug 2016, 02:05You should study the doc site's contents, such as the Scripts/Functions:
http://docs.textadventures.co.uk/quest/scripts/
http://docs.textadventures.co.uk/quest/functions/ (categorical order)
http://docs.textadventures.co.uk/quest/functions/index_allfunctions.html (alphetical order)
http://docs.textadventures.co.uk/quest/scopes.html
such as:
Contains // used upon Objects
GetDirectChildren // used upon Objects, creates and returns an Objectlist Attribute
GetAllChildObjects // used upon Objects, creates and returns an Objectlist Attribute
ListContains // used upon List Attribute
DictionaryContains // used upon Dictionary Attribute
Got // used upon the Player Object
AllObjects // creates and returns an Objectlist Attribute
various 'Scope' Functions // creates and returns an Objectlist Attribute
I'm not quite sure what you're asking for, but here's an example using the 'game.pov' Object (the currently controlled Player Object):
if (Contains (game.pov, potion)) {
invoke (potion.drink)
MoveObject (potion, data_object)
}
// or (these are/do the same thing):
if (ListContains (ScopeInventory(), potion)) {
invoke (potion.drink)
MoveObject (potion, data_object)
}
// a concrete example:
<command name="drink_command">
<pattern>drink #object1# from #object2#</pattern>
<script>
if (HasScript (object1, "drink") and game.pov.parent = object2.parent and Contains (object2, object1)) {
invoke (object1.drink)
MoveObject (object1, data_object)
} else {
msg ("The command input failed, try different inputs or a different location.")
}
</script>
</command>