Cloning Randomly Generated Objects and Their Scripts
TFG
05 Dec 2013, 04:48How can I go about doing this? I thought I would use cloning, but I have no idea how I could make it so the scripts would also apply to the new cloned objects. My goal is to be able to have the scripts used once and be able to call upon them easily when creating or cloning new objects using commands, rather than having to tediously copy and paste all the scripts for each individual object. It's such a repetitive task of manually going into each script and changing each and every possible randomly generated attribute and assigning it to the new object that I'd rather just have an easy script to do it all for me.
Thanks.
george
05 Dec 2013, 06:50Below is an example of an object that creates other objects, and gives them random descriptions.
In play,
You are in a room.
You can see a foobazatron.
> press foobazatron
You are in a room.
You can see a foobazatron and a glop.
> look at glop
It is argent
> press foobazatron
You are in a room.
You can see a foobazatron, a glop and a bar.
> look at bar
It is green
> press foobazatron
You are in a room.
You can see a foobazatron, a glop, a bar and a biff.
> look at biff
It is magenta
(it doesn't make objects of a particular name if it already exists, since I didn't handle duplicates).
The code:
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
<object name="foobazatron">
<inherit name="editor_object" />
<press type="script">
name = ChooseOne(this.names)
create (name)
set (GetObject(name), "look", "It is " + ChooseOne(this.colors))
MoveObjectHere (GetObject(name))
ShowRoomDescription
</press>
<names type="stringlist">
<value>foo</value>
<value>baz</value>
<value>bar</value>
<value>biff</value>
<value>buffy</value>
<value>glop</value>
<value>zwert</value>
</names>
<colors type="stringlist">
<value>red</value>
<value>green</value>
<value>blue</value>
<value>magenta</value>
<value>cyan</value>
<value>fuschia</value>
<value>argent</value>
</colors>
<look>It's the foobazatron</look>
</object>
</object>
<verb>
<property>press</property>
<pattern>press</pattern>
<defaultexpression>"You can't press " + object.article + "."</defaultexpression>
</verb>
<function name="ChooseOne" parameters="ss" type="string">
return (StringListItem(ss, GetRandomInt(0, ListCount(ss) - 1)))
</function>
TFG
05 Dec 2013, 07:26The idea is so I can populate in-game towns with NPCs with randomly generated names, physical characteristics, and personality traits.
I don't know if it is possible, but it would be so much easier to be able to do this than making hundreds of objects and copying and pasting these really long, detailed switch scripts hundreds of times just so I can have a multitude of NPCs with unique character traits in my game.
If it can't be done using the cloning/creating objects idea I had, I am open to any other way I can accomplish my goal. And thanks for bearing with me on this, I know how much of a noob I am.

george
05 Dec 2013, 07:37TFG
05 Dec 2013, 07:56But I want to make sure I understand how your scripts are working, so I can of course better utilize them. You are creating objects and then randomly selecting attributes, like the name and color, of the objects from string lists, yeah? In your code, I notice it says '(this.colors)' and '(this.names)'. What is the 'this' it is referring to, the newly created object? If so, how are you using it so it knows that 'this' is the newly created object and not something else?
Sorry, I am sort of new to this. And I should probably admit that I insert scripts mostly using the interface, since I knew next to nothing about any of this until I downloaded this program way back when and have absolutely no background in coding.
The Pixie
05 Dec 2013, 08:05Have an original NPC set up in a room the player cannot get to. You can set attributes and types and scripts on this that are the same for all NPCs (and during development, go to the room, and check the NPC works properly, has suitable display verbs, cannot be picked up, etc.
The script on the foobazatron might then look like this (if the original has the name originalobject):
<press type="script">
newobject = Clone (originalobject)
newobject.look = "It is " + ChooseOne(this.colors))
newobject.name = ChooseOne(this.names)
newobject.parent = this.parent
ShowRoomDescription
</press>
The object is cloned, then the indivuidual attributes set.
"this" refers to the object that owns the script. In the example above, it refers to the foobazatron, because the script is an attribute of the foobazatron.
TFG
05 Dec 2013, 08:45<press type="script">
newobject = Clone (originalobject)
newobject.look = "It is " + ChooseOne(this.colors)
newobject.alias = ChooseOne(this.names)
newobject.parent = this.parent
ShowRoomDescription
</press>
Unlocking one door leads to another locked door, though. What if I wanted to make scripts that affected these new clones? Or refer to any of the clones for that matter? Since cloning makes the name of each clone like originalobject1, originalobject2, and so on and so forth, would I have to just write the scripts for each object leading from one to however many I expect there to be? Or is there something like the 'this' thing that I can use to refer to the cloned objects without having to do that?
If that made no sense, imagine if I wanted to simply hyperlink one of the cloned objects in the text processor. Normally, I'd just put {object:example}, but is there any way to do that for a clone without assuming that example1 to whatever indeterminate number was present? I mean, what if I create so many clones that it exceeds the premeditated amount of clones that I wanted, how would I be able to do that for them? Certainly there must be a way.
And yeah, I do realize that I have no idea what I'm talking about. I apologize for that.

The Pixie
05 Dec 2013, 09:07TFG wrote:Thank you George and The Pixie! Your combined code is exactly what I needed. However, it was giving me some errors, so I switched 'name' to 'alias'.
Oops, my bad!
What if I wanted to make scripts that affected these new clones?
It depends. If you have a script on your original object, then should get copied to the clone, and work just fine (but use "this" in the script to refer to the object).
Otherwise, you would probably be best searching for it by alias.
result = null
foreach (o, AllObjects ()) {
if (HasString (o, "alias") {
if (o.alias = nametosearchfor) {
result = o
}
}
}
There may be alternatives, depending on exactly what you want to do.
If that made no sense, imagine if I wanted to simply hyperlink one of the cloned objects in the text processor. Normally, I'd just put {object:example}, but is there any way to do that for a clone without assuming that example1 to whatever indeterminate number was present? I mean, what if I create so many clones that it exceeds the premeditated amount of clones that I wanted, how would I be able to do that for them? Certainly there must be a way.
You cannot do it using the text processor (text processor does not support the "this" thing). You would have to add it as a script, rather than text, select "Print a message", then select "Expression" instead of "Message". Then you can type in something like this:
"Here is a " + ObjectLink (example) + "."
If that does not mean anything to you, please say!
TFG
05 Dec 2013, 09:51Speaking of which, 'this' still confuses me. You mentioned before that it works because the script belongs to the object. When I usually make scripts, I generally use them in rooms or commands. I get that I could probably just make a verb and just use 'this', so it can work for any object. However, how could I use a command to access that, or could I even use a command to access a verb? I make everything in text adventure mode but I prefer making it kind of like a gamebook in the sense that I just hyperlink commands for everything and hide the command bar. So how can I just hyperlink it and throw it up as something to click?
What confuses me about how to really implement all this into the game I am making is really just how to refer to the objects. For example, if I want to use the if script for when an object's integer was to exceed a certain number, usually I'd just make it as a turn script and put the code as:
<turnscript name="health cap">
<enabled />
<script><![CDATA[
if (object.health < 0) {
object.health = 0
}
]]></script>
</turnscript>
This is an example of what I use to cap off an attribute from going below zero. However, how would I refer to a random clone? And another thing, if I make it so that this script works for the original object, does it apply also to all of that object's clones?
The searching for it by alias part I don't understand at all. The code just looks alien to me and I have no idea where I'd even put it in at. Remember, I mostly just use the interface, so my only reference for understanding is really just inserting the code and then looking at the interface to study what the scripts are and how I assume they work.
Regarding George's code, I really like how he made a function. I've never used functions before, so looking at it I have no idea how it works. The 'ss' part and then the return value line 'StringListItem(ss, GetRandomInt(0, ListCount(ss) - 1))'. Can you explain to me how this works, what it means, and how I can use functions like this for other stuff? I understand the GetRandomInt part, but I especially don't understand what ListttCount(ss) - 1) means. Really, I don't understand what anything but the GetRandomInt part means, lol.
Please excuse all the hand holding. I almost nearly completed a game I had been working on before and never did I have to use anything like this. Just when I thought I had it all figured out, this one little thing proves me to be the most ignorant, lol. It is very humbling.
The Pixie
05 Dec 2013, 11:53I sort of understand the last bit. But when you put the 'ObjectLink (example)', do you have to put like (example1) or (example2) to specify? If not, how are you specifying which clone to work with? You guys are blowing my mind with some of this code being able to refer to objects without having to manually specify their names, like with the 'newobject' and 'this'.
It depends how you are using it. If you are describing a room, you could get all the objects in the room, and then display the link for each one.
foreach (obj, ScopeVisibleNotHeld ()) {
msg ("You can see " + ObjectLink (obj))
}
This will go through each object in the current room, and (kind of) temporarily call each one "obj" (actually it assigns each to a variable called "obj"). Of course, Quest does that for you, so it might be better if you gave a specific example of what you are trying to do.
Speaking of which, 'this' still confuses me. You mentioned before that it works because the script belongs to the object. When I usually make scripts, I generally use them in rooms or commands. I get that I could probably just make a verb and just use 'this', so it can work for any object. However, how could I use a command to access that, or could I even use a command to access a verb? I make everything in text adventure mode but I prefer making it kind of like a gamebook in the sense that I just hyperlink commands for everything and hide the command bar. So how can I just hyperlink it and throw it up as something to click?
You cannot use "this" with commands and functions.
With commands, you often have an "object" that does the same sort of thing. If your command pattern is "kiss #object#" then Quest will assign the thing to the variable "object". Then you just do something like this:
msg ("You can see " + ObjectLink (object))
What confuses me about how to really implement all this into the game I am making is really just how to refer to the objects. For example, if I want to use the if script for when an object's integer was to exceed a certain number, usually I'd just make it as a turn script and put the code as:
Great. But you weant to do this for all your NPCs, so you need to go through them all. The trick is to get all objects, check if each is an NPC (just set a boolean atribute on your original called "isnpc" to true), and if it is, do the code.
<turnscript name="health cap">
<enabled />
<script><![CDATA[
foreach (object, AllObjects ()) {
if (GetBoolean (object, "isnpc")) {
if (object.health < 0) {
object.health = 0
}
}
}
]]></script>
</turnscript>
And another thing, if I make it so that this script works for the original object, does it apply also to all of that object's clones?
No. Once cloned, the state of the original has no effect on the clone.
Bit stuck for time, but here is how to get an object by its alias as a function.
<function name="Search" parameters="name" type="object">
result = null
foreach (o, AllObjects ()) {
if (HasString (o, "alias") {
if (o.alias = nametosearchfor) {
result = o
}
}
}
return (result)
</function>
george
05 Dec 2013, 16:22TFG wrote:
Regarding George's code, I really like how he made a function. I've never used functions before, so looking at it I have no idea how it works. The 'ss' part and then the return value line 'StringListItem(ss, GetRandomInt(0, ListCount(ss) - 1))'. Can you explain to me how this works, what it means, and how I can use functions like this for other stuff? I understand the GetRandomInt part, but I especially don't understand what ListttCount(ss) - 1) means. Really, I don't understand what anything but the GetRandomInt part means, lol.
I think The Pixie answered most of your questions, however I'll give this a try. I'll just try to break down the function piece by piece.
If you'd like this explained in terms of the GUI say so but doing it in code view is just a lot faster (to do and to explain

<function name="ChooseOne" parameters="ss" type="string">
return (StringListItem(ss, GetRandomInt(0, ListCount(ss) - 1)))
</function>
* Here we have the function element.
* It is called like ChooseOne(ss).
* ss is the only parameter of the function definition. Another way to say 'function definition' is 'function signature'. However when you use the function, you would call ss the only argument. Yes, this is mostly programming mumbo-jumbo

* I have to admit I was lazy in calling the parameter 'ss'. Usually you should make parameter names more self-explanatory. For me 'ss' stands for strings, and means the function expects its argument to be a StringList.
* The return type is a string.
* OK, the actual code.
return (StringListItem(ss, GetRandomInt(0, ListCount(ss) - 1)))
* return () is a Quest script command, http://quest5.net/wiki/Return . Its only argument is StringListItem.
* StringListItem gets one item from a StringList. It takes two arguments, a StringList and a number, here they are ss, and the function GetRandomInt. In other words, StringListItem gets the 'number' item from its list, like the 0th, the 2nd, the 4th, etcetera. You start counting from 0.
* As I mentioned ss is the only argument when you call ChooseOne. It's a StringList.
* GetRandomInt, http://quest5.net/wiki/GetRandomInt , takes two arguments. You see it a lot in many programming languages. It takes two arguments, both numbers, that are the minimum and maximum between which it'll randomly choose a number. Here the minimum is 0 and the maximum is another function, ListCount, with 1 subtracted from it.
* ListCount, http://quest5.net/wiki/ListCount , tells you how many items are in a list. Why is this the maximum argument in our GetRandomInt? Because we don't want GetRandomInt to give us a number bigger than the number of items in our list. But, because we start counting from 0, we have to subtract one from the number returned by ListCount.
So to summarize:
When you call ChooseOne(this.names), this.names is a StringList which gets sent to ChooseOne. ChooseOne gets a random number between 0 and the number of items in the StringList (minus 1), gets the 'number'th item from the StringList, and returns it. So, you put that item in place of wherever you called ChooseOne.
Holy crap that was long, I hope I didn't put you to sleep!
