Random Object Spawn in player specific rooms?
onimike
26 Aug 2016, 00:56Hello all Mike here and its been awhile. Any way getting back in flow of things been really making things alot easier on myself by cloning and moving objects to rooms before first entry. So I want every room(forest area) to have this function but have no idea how to call the room the player is entering without being specific and saying room1 but problem its only 1 room. How could I make this function that when called it would clone and move to player specific room? Any help is appreciated and btw im worker in the d&d scripting.
Thanks
Mike
hegemonkhan
26 Aug 2016, 05:37the 'parent-child containment heirarchy' design/concept:
grandfather
-> father
->-> son
->->-> grandson
'grandfather' is the main (root) parent of 'father', 'son', and 'grandson'
'grandfather' is the direct parent of 'father'
'grandfather' is the indirect parent of 'son' and 'grandson'
'father' is the direct child of 'grandfather'
'father' is the direct parent of 'son'
'father' is the indirect parent of 'grandson'
'son' is the indirect child of 'grandfather'
'son' is the direct child of 'father'
'son' is the direct parent of 'grandson'
'grandson' is the indirect child of 'grandfather' and 'father'
'grandson' is the direct child of 'son'
here, would be the same structure in quest:
<object name="grandfather">
<object name="father">
<object name="son">
<object name="grandson">
</object>
</object>
</object>
</object>
and here is the exact same structure in quest too:
<object name="grandfather">
</object>
<object name="father">
<attr name="parent" type="object">grandfather</attr>
</object>
<object name="son">
<attr name="parent" type="object">father</attr>
</object>
<object name="grandson">
<attr name="parent" type="object">son</attr>
</object>
quest uses the built-in 'parent' Object Attribute to determine the location of Objects
the same structure can be created through scripting in quest:
create ("grandfather")
create ("father")
create ("son")
create ("grandson")
father.parent = grandfather
son.parent = father
grandson.parent = son
-----------
let's go back to this real fast, for a quick quiz:
grandfather
-> father
->-> son
->->-> grandson
if I did this:
grandson.parent = father
how would containment heirarchy look/change?
Answer:
grandfather
-> father
->-> son
->-> grandson
what if I now do this:
son.parent = grandson
answer:
grandfather
-> father
->-> grandson
->->-> son
what if I now do this:
grandson.parent = grandfather
answer:
grandfather
-> father
-> grandson
->-> son
what if I now do this:
father.parent = son
answer:
grandfather
-> grandson
->-> son
->->-> father
the built-in 'parent' Object Attribute is (probably) how the 'MoveObject' Script/Function actually works:
<function name="MoveObject" parameters="moving_object_parameter,destination_object_parameter">
moving_object_parameter.parent = destination_object_parameter
</function
-----------
anyways, a trick (which is what you're asking for) with using the 'parent' Object Attribute, is that you can do this, an example:
I.parent = room3
you.parent = I.parent
think of it like this:
if 'I' am in 'room3',
and 'you' are in the room that 'I' am in,
what room are 'you' in?
Answer: room3 // you.parent = room3
team_member.parent = player.parent
for explanation of what this is doing and how it works:
player.parent = room
// you ('player') are in 'room', and 'room' is STORED/SAVED into the 'parent' Attribute VARIABLE of the 'player' Player Object
team_member.parent = player.parent
// 'team_member' is in the room that the 'player' is in (which is: room), so: team_member.parent = room, which is done by STORING/SAVING whatever the stored/saved Value of 'player.parent' (which is: room) into the 'parent' Attribute VARIABLE of the 'team_member' Object. This also tells quest to set/put/move the 'team_member' Object to be in that same room (which is: room)
// team_member.parent = player.parent = room // team_member.parent <--- player.parent <---- room
// team_member.parent = room // team_member.parent <---- room
let's say you (move to / are now in) 'room2' :
player.parent = room2
team_member.parent = player.parent
// 'team_member' is in the room that the 'player' is in (which is: room2), so: team_member.parent = room2
// team_member.parent = player.parent = room2
// team_member.parent = room2
let's say you (move to / are now in) 'room99' :
player.parent = room99
team_member.parent = player.parent
// 'team_member' is in the room that the 'player' is in (which is: room2), so: team_member.parent = room99
// team_member.parent = player.parent = room99
// team_member.parent = room99
let's say you (move to / are now in) 'room2' :
player.parent = room2
team_member.parent = player.parent
// 'team_member' is in the room that the 'player' is in (which is: room2), so: team_member.parent = room2
// team_member.parent = player.parent = room2
// team_member.parent = room2
and thus, we got a 'following' effect taking place, regardless of what room the 'player' moves to or is put/set within, the 'team_member' will also move/be-put-set-into the same room as the 'player'
--------------
this, can be or maybe-probably, is technically wrong/off, as I don't know quest's underlying structure (and am still in the early stages of learning programming), but in general, this is how programming works, underneath what quest has given to us to use at the user-level)
actually every quest game is a parent-child heirarchy:
OBJECT-ORIENTED PROGRAMMING (OOP) / OBJECT-ORIENTED DESIGN (OOD)
(my capitolized 'OBJECT' is not to be confused with Quest's user-level 'Object' Element)
(all of quest's 'Elements': Verbs, Commands, Functions, Exits, Objects, Turnscripts, Timers, Object Types / Types, and etc : are OBJECTS)
simple example:
'asl' OBJECT // root parent OBJECT // your actual/true game OBJECT (all other OBJECTS must be inside of here: your game, obviously, lol)
-> 'game' OBJECT // actually this is just your: game/global settings OBJECT
-> 'room' OBJECT
->-> 'player' OBJECT
-> 'Verb' OBJECTS
-> 'Function' OBJECTS
-> 'Command' OBJECTS
-> 'Exit' OBJECTS
-> 'Turnscript' OBJECTS
-> 'Timer' OBJECTS
-> 'Object Type / Type' OBJECTS
-> etc etc etc OBJECTS
The Pixie
26 Aug 2016, 07:01You have three options. As HK says above, you can use player.parent
, which will be the current room.
You can also use this
, which is the object that the script is attached to, which will be the room for the on first entry script.
So the second option is to have a function called, say, SetUpForestRoom, with a single parameter, "currentroom". In the function, usecurrentroom
. Call the function in the on first entry script:
SetUpForestRoom(this)
Thirdly, if you are using the offline editor, you could set up a "forestroom" type, and set all rooms in the forest to be of that type. Then you can put code in the on first entry of the type, and all the rooms will have it. In this case use this
to refer to the current room, because the script will be on the room.
I personally would do the third. It is a bit more tricky to get your head round, but the actual coding is about the same, and once you have set up a "forestroom" type, you can use it for other things, such as checking if the player is in a forest, with minimal effort, because all the rooms ion the forest have already been given that type.
onimike
26 Aug 2016, 14:07Well thank you both but I must be pretty dumb cause I can not seem to figure out what your saying lol sorry! I made a Function called 'RandomResourceSpawner' (I know long name) but inside I set a random chance to spawn objects like trees, stones, ponds etc. So then I made a Object Type called it 'ForestRoomType' then attach to all rooms that are forest types. Then in before enter room first time I run scripts attribute but nothing it just says Object reference not set to an instance of an object.
if (RandomChance(40)) {
CloneObjectAndMove (Boulder, current.room)
}
if (RandomChance(75)) {
CloneObjectAndMove (Grass, current.room)
}
if (RandomChance(55)) {
CloneObjectAndMove (Tree, current.room)
}
That is my function above and I know current.room is not right but just not understanding sorry again.
Sorry guys I fixed it in the Function instead of above I used this
if (RandomChance(40)) {
CloneObjectAndMove (Boulder, player.parent)
}
if (RandomChance(75)) {
CloneObjectAndMove (Grass, player.parent)
}
if (RandomChance(55)) {
CloneObjectAndMove (Tree, player.parent)
}
and all seems to be working well, thank you both again very much. Also one more thing , ok so I can call reference to a cloned item in itself by calling "this" but how do I call a reference to another cloned object from different object like: In my main Tree object i created a Verb 'Chop' which requires object 'Stone Axe' in this verb it calls this script
if (Got(Stone Axe)) {
DecreaseObjectCounter (Stone Axe, "Durability")
DecreaseObjectCounter (this, "Health")
if (GetInt(this, "Health") <= 0) {
RemoveObject (this)
CloneObjectAndMove (Sticks, player)
}
}
else if (not Got(Stone Axe)) {
msg ("Not Carrying an Axe
")
}
So when calling my if statement for Stone Axe how do I use a clone reference on it instead of stone axe itself so i can just use clones and not have to reset all values each time a new one is made?
Again I am using GUI Editor just get code for easy posting :)
Thanks Again
Mike
hegemonkhan
26 Aug 2016, 18:30'this' is a special keyword/keycommand that GETS/RETURNS the Object (well, technically it returns its name/reference of the Object for you to use it) that contains your script using it (the 'this'), which makes it (the 'this') useful:
for example, instead of doing this (no pun intended, lol. I don't know of any alternative word to use, lol):
<object name="player1">
<attr name="current_life" type="int">999</attr>
<attr name="maximum_life" type="int">999</attr>
<attr name="life_displayment" type="string">999/999</attr>
<attr name="changedcurrent_life" type="script">
player1.life_displayment = player1.current_life + "/" + player1.maximum_life
</attr>
<attr name="changedmaximum_life" type="script">
player1.life_displayment = player1.current_life + "/" + player1.maximum_life
</attr>
<statusattributes type="simplestringdictionary">life_displayment = Life: !</statusattributes>
</object>
<object name="player2">
<attr name="current_life" type="int">999</attr>
<attr name="maximum_life" type="int">999</attr>
<attr name="life_displayment" type="string">999/999</attr>
<attr name="changedcurrent_life" type="script">
player2.life_displayment = player2.current_life + "/" + player2.maximum_life
</attr>
<attr name="changedmaximum_life" type="script">
player2.life_displayment = player2.current_life + "/" + player2.maximum_life
</attr>
<statusattributes type="simplestringdictionary">life_displayment = Life: !</statusattributes>
</object>
<object name="player3">
<attr name="current_life" type="int">999</attr>
<attr name="maximum_life" type="int">999</attr>
<attr name="life_displayment" type="string">999/999</attr>
<attr name="changedcurrent_life" type="script">
player3.life_displayment = player3.current_life + "/" + player3.maximum_life
</attr>
<attr name="changedmaximum_life" type="script">
player3.life_displayment = player3.current_life + "/" + player3.maximum_life
</attr>
<statusattributes type="simplestringdictionary">life_displayment = Life: !</statusattributes>
</object>
we can use 'this.ATRTIBUTE_NAME' instead of having to specifically use 'player.ATTRIBUTE_NAME', 'player2.ATTRIBUTE_NAME, and 'player3.ATTRIBUTE_NAME' for each of our Player Objects:
<object name="player1">
<attr name="current_life" type="int">999</attr>
<attr name="maximum_life" type="int">999</attr>
<attr name="life_displayment" type="string">999/999</attr>
<attr name="changedcurrent_life" type="script">
this.life_displayment = this.current_life + "/" + this.maximum_life
</attr>
<attr name="changedmaximum_life" type="script">
this.life_displayment = this.current_life + "/" + this.maximum_life
</attr>
<statusattributes type="simplestringdictionary">life_displayment = Life: !</statusattributes>
</object>
<object name="player2">
<attr name="current_life" type="int">999</attr>
<attr name="maximum_life" type="int">999</attr>
<attr name="life_displayment" type="string">999/999</attr>
<attr name="changedcurrent_life" type="script">
this.life_displayment = this.current_life + "/" + this.maximum_life
</attr>
<attr name="changedmaximum_life" type="script">
this.life_displayment = this.current_life + "/" + this.maximum_life
</attr>
<statusattributes type="simplestringdictionary">life_displayment = Life: !</statusattributes>
</object>
<object name="player3">
<attr name="current_life" type="int">999</attr>
<attr name="maximum_life" type="int">999</attr>
<attr name="life_displayment" type="string">999/999</attr>
<attr name="changedcurrent_life" type="script">
this.life_displayment = this.current_life + "/" + this.maximum_life
</attr>
<attr name="changedmaximum_life" type="script">
this.life_displayment = this.current_life + "/" + this.maximum_life
</attr>
<statusattributes type="simplestringdictionary">life_displayment = Life: !</statusattributes>
</object>
and we can reduce the amount of code further, by using Object Types:
<object name="player1">
<inherit name="player_type" />
</object>
<object name="player2">
<inherit name="player_type" />
</object>
<object name="player3">
<inherit name="player_type" />
</object>
<type name="player_type"
<attr name="current_life" type="int">999</attr>
<attr name="maximum_life" type="int">999</attr>
<attr name="life_displayment" type="string">999/999</attr>
<attr name="changedcurrent_life" type="script">
this.life_displayment = this.current_life + "/" + this.maximum_life
</attr>
<attr name="changedmaximum_life" type="script">
this.life_displayment = this.current_life + "/" + this.maximum_life
</attr>
<statusattributes type="simplestringdictionary">life_displayment = Life: !</statusattributes>
</type>
unfortunately, when you create Clones, they've got different names (original Object: axe, Clone Object 1: axe1, Clone Object 2: axe2, etc etc etc)
so, you need an 'indicator/flag' to identify each of your clones...
there's a few (well, many ways actually, lol) ways of doing this:
- you can have your original Object have a normal Attribute (String, Boolean, Integer, etc) as its indicator/flag (which all of the clones will have too):
(I'll use a String Attribute for the example below, as it's the most useful one to use, for a simple game design anyways)
<object name="katana">
<attr name="our_type_of_object_indicator_flag" type="string">sword</attr>
</object>
<object name="claymore">
<attr name="our_type_of_object_indicator_flag" type="string">sword</attr>
</object>
<object name="hand_axe">
<attr name="our_type_of_object_indicator_flag" type="string">axe</attr>
</object>
<object name="npc1">
<attr name="our_type_of_object_indicator_flag" type="string">npc</attr>
</object>
<object name="monster1">
<attr name="our_type_of_object_indicator_flag" type="string">monster</attr>
</object>
// and your scripting (at where-ever you want it used), an example:
if (GetString (DEPENDS_USE_OBJECT_NAME_OR_USE_this, our_type_of_object_indicator_flag) = "sword") {
// whatever script(s) you want here
// stupid example: msg ("This is a sword.")
} else if (GetString (DEPENDS_USE_OBJECT_NAME_OR_USE_this, our_type_of_object_indicator_flag) = "axe") {
// whatever script(s) you want here
// stupid example: msg ("This is an axe.")
} else if (GetString (DEPENDS_USE_OBJECT_NAME_OR_USE_this, our_type_of_object_indicator_flag) = "npc") {
// whatever script(s) you want here
// stupid example: msg ("This is a NPC.")
} else if (GetString (DEPENDS_USE_OBJECT_NAME_OR_USE_this, our_type_of_object_indicator_flag) = "monster") {
// whatever script(s) you want here
// stupid example: msg ("This is a monster.")
}
- you can have your original Object have an Inherited Attribute (Object Type / Type) as its indicator/flag (which all of the clones will have too):
(this is just a quick limited example for this method, see #1 for seeing how a more expanded example looks - though you' use this code design instead of course)
<object name="katana">
</object>
<type name="sword_type">
</type>
// scripting:
if (DoesInherit (DEPENDS_USE_OBJECT_NAME_OR_USE_this, "sword_type")) {
msg ("This is a sword.")
}
- and there's this method too, using the Object's name itself as the indicator/flag and using the string manipulation Functions with it:
http://docs.textadventures.co.uk/quest/functions/ (scroll down to the very bottom, to the 'string functions' section)
(since, for example, 'katana' clones names are all like this: katana1 katana2 katana3 etc etc etc: they all start with 'katana' in their names. You can 'check' for if their names start with 'katana' to see if they're indeed your 'katana' clones, to do whatever you want with them, and likewise for all your other clone types: 'claymore' clones, 'tavern_maid' clones, 'giant_spider' clones, etc etc etc clones)
<object name="katana">
</object>
<object name="claymore">
</object>
<object name="tavern_maid">
</object>
<object name="giant_spider">
</object>
// scripting:
if (StartsWith (DEPENDS_USE_OBJECT_NAME_OR_USE_this, "katana") and DEPENDS_USE_OBJECT_NAME_OR_USE_this.name > LengthOf (DEPENDS_USE_OBJECT_NAME_OR_USE_this)) {
msg ("This is a katana clone")
// we needed the 'OBJECT_NAME_OR_this.name > LengthOf (OBJECT_NAME_OR_this)' because we don't want to include the original object. Since the clones have numbers on their names, they're longer than the original object's name ('katana2' is longer than 'katana'), and thus if we check that the object's name is longer than the original object's name, we know that object is a clone of our original object.
// if you do want to include the original object along with its clones, then do not have this second condition of checking the length of the object's name.
} else if (StartsWith (DEPENDS_USE_OBJECT_NAME_OR_USE_this, "claymore") and DEPENDS_USE_OBJECT_NAME_OR_USE_this.name > LengthOf (DEPENDS_USE_OBJECT_NAME_OR_USE_this)) {
msg ("This is a claymore clone")
} else if (StartsWith (DEPENDS_USE_OBJECT_NAME_OR_USE_this, "tavern_maid") and DEPENDS_USE_OBJECT_NAME_OR_USE_this.name > LengthOf (DEPENDS_USE_OBJECT_NAME_OR_USE_this)) {
msg ("This is a tavern maid clone")
} else if (StartsWith (DEPENDS_USE_OBJECT_NAME_OR_USE_this, "giant_spider") and DEPENDS_USE_OBJECT_NAME_OR_USE_this.name > LengthOf (DEPENDS_USE_OBJECT_NAME_OR_USE_this)) {
msg ("This is a giant spider clone")
}
and there's probably many more ways of using your clones, but these are generally the main ways of doing so
onimike
27 Aug 2016, 01:13Hello HK thanks again for all the info but I cannot for the life of me reference the clone other then "this" in the object or like you said Stone Axe1, Stone Axe2, etc. I do have Object Type made and inherited called Basic Item Data which holds Boolan, Strings, Int and so on but can not figure out how to just call an Attribute reference without call Stone Axe itself.
Like I tried pretty much every way I can think of following your examples, I know im probably messing things up but just not understanding it lol sorry.
EDIT: Ok seems I found a temp fix by just destroying the cloned actor before making a new one, I been reading around and found this post kinda same issues http://textadventures.co.uk/forum/quest/topic/3647/expression-this-in-functions cloning is a little more difficult then I expected lol. Would still like to understand better about clones and referencing them and loops, I am reading docs some is confusing while some is very short. Thanks Again
Mike
hegemonkhan
27 Aug 2016, 06:19you can use an Object Attribute (or an Objectlist Attribute if you want to store/hold multiple references/pointers of Objects / clone Objects) to store/hold the (just like a pointer if you know programming, a reference to the) clone object, which you can then use for whatever, for a simple example:
data_object.example_clone_pointer_object_attribute = Clone (axe)
msg ("Clone's Name: " + data_object.example_clone_pointer_object_attribute.name)
destroy (data_object.example_clone_pointer_object_attributer.name)
// output: Clone's Name: axe2 // or whatever number the clone function starts with, lol (I've never used cloning yet, laughs)
The Pixie
27 Aug 2016, 07:50In the script that you create the clone, you can assign it to a local variable, and do stuff with that.
new_object = Clone(axe)
new_object.alias = axe.name
new_object.parent = player.parent
As it happens, there is a helper function that does all that.
new_object = CloneObjectAndMove(axe, player.parent)
onimike
27 Aug 2016, 15:18Thank you HK and Pixie sorry for my noobness lol I think I can get it now ;)