Generating stuff
The Pixie
22 Apr 2016, 13:36Occasionally you want to create items in the middle of a game, and you want some variety. Random treasure in an RPG is a good example (see Deeper for instance). Here is a way of doing that. Just paste the code at the bottom into your own game (in code view, paste it just before the last line, which will be "</asl>").
The way it works is you send a prototype and a location to the ClonePrototype function, and a copy of the prototype will appear at the given location. Let us say we want lots of hats in the game. Create a prototype hat in a hidden room, and the you can place copies with this function.
No different to CloneObjectAndMove so far, but you can set up the prototype to give some variety to the cloned object. Firstly you can set attributes.
Random Integer Attributes
If your prototype has a string attribute that in the form "r_int_<attname>", this will set an attribute, "<attname>", as an integer. Set "r_int_<attname>" to the range (no spaces). For example, for the hat, you might set this:
The first clone will get the name hat1. The system will then set hat1.size to a random number from 2 to 5.
Random String Attributes
If your prototype has a stringlist attribute that in the form "r_str_<attname>", this will set an attribute, "<attname>", as a string, randomly chosen from the string list.
The system will set hat1.colour to a randomly chosen colour.
Random Description
Set the description (the "look" attribute) like this:
... and one of "big", "small" and "floppy" will be selected at random. Why not use the text processor? Well the random option in the text processor makes a new selection each time the text is displayed. This will just do it when the item is created; thereafter it will stay the same for that specific hat.
Or it can select from a list on any object; useful if you want the same set of options several times:
In this case, hatmaterials is a string list on the game object. You can also include attributes of the object:
Here it is also including the string attribute colour and the integer size set up earlier.
Random Alias
It will do the same for the alias, so you could set that like this:
Note the name and description will match, because both use the "colour" attribute set up previously.
Text Process Directives
There is a issue using the text processor with cloned items (whether made by this system or not) in that you do not know what the name in advance. For this, you can use #### as a stand-in for the object name. For instance:
The Code
This is version 1.1 (23/Apr/16), and includes the text processor bit.
The way it works is you send a prototype and a location to the ClonePrototype function, and a copy of the prototype will appear at the given location. Let us say we want lots of hats in the game. Create a prototype hat in a hidden room, and the you can place copies with this function.
ClonePrototype (hat, room)
No different to CloneObjectAndMove so far, but you can set up the prototype to give some variety to the cloned object. Firstly you can set attributes.
Random Integer Attributes
If your prototype has a string attribute that in the form "r_int_<attname>", this will set an attribute, "<attname>", as an integer. Set "r_int_<attname>" to the range (no spaces). For example, for the hat, you might set this:
hat.r_int_size = "2-5"
The first clone will get the name hat1. The system will then set hat1.size to a random number from 2 to 5.
Random String Attributes
If your prototype has a stringlist attribute that in the form "r_str_<attname>", this will set an attribute, "<attname>", as a string, randomly chosen from the string list.
hat.r_str_colour = "blue;green;red"
The system will set hat1.colour to a randomly chosen colour.
Random Description
Set the description (the "look" attribute) like this:
It was a [big|small|floppy] hat.
... and one of "big", "small" and "floppy" will be selected at random. Why not use the text processor? Well the random option in the text processor makes a new selection each time the text is displayed. This will just do it when the item is created; thereafter it will stay the same for that specific hat.
Or it can select from a list on any object; useful if you want the same set of options several times:
It was a [big|small|floppy] hat made of [#game.hatmaterials].
In this case, hatmaterials is a string list on the game object. You can also include attributes of the object:
It was a [big|small|floppy] hat made of [#game.hatmaterials]. It was [#colour], and size [#size].
Here it is also including the string attribute colour and the integer size set up earlier.
Random Alias
It will do the same for the alias, so you could set that like this:
[#colour] hat
Note the name and description will match, because both use the "colour" attribute set up previously.
Text Process Directives
There is a issue using the text processor with cloned items (whether made by this system or not) in that you do not know what the name in advance. For this, you can use #### as a stand-in for the object name. For instance:
A [#colour] hat.{if ####.size>4: It is too big for you.}{if ####.size<5: It is too small for you.}
The Code
This is version 1.1 (23/Apr/16), and includes the text processor bit.
<function name="ClonePrototype" parameters="obj, room">
o = CloneObjectAndMove(obj, room)
foreach (att, GetAttributeNames(o, true)) {
if (StartsWith(att, "r_")) {
s = GetString(o, att)
name = Mid(att, 7)
if (StartsWith(att, "r_int_")) {
l = Split(s, "-")
if (not ListCount(l) = 2) {
error ("Failed to clone object, could not parse attribute " + att + " (" + s + ")")
}
val = GetRandomInt(ToInt(StringListItem(l, 0)), ToInt(StringListItem(l, 1)))
}
if (StartsWith(att, "r_str_")) {
val = PickOneStr(GetAttribute(o, att))
}
// msg ("setting; " + name + " with " + val)
set (o, name, val)
}
}
if (HasString(o, "look")) {
o.look = Randomise(o, "look")
}
if (HasString(o, "alias")) {
o.alias = Randomise(o, "alias")
}
</function>
<function name="Randomise" parameters="o, attname" type="string">
s = GetAttribute(o, attname)
mylist = Split (s, "[")
output = StringListItem (mylist, 0)
list remove (mylist, output)
foreach (s1, mylist) {
list1 = Split (s1, "]")
if (not ListCount (list1) = 2) {
error ("Unable to parse (no matching ]): " + s)
}
s2 = StringListItem (list1, 0)
if (StartsWith(s2, "#")) {
s2 = Mid(s2, 2)
list2 = Split (s2, ".")
if (ListCount (list2) = 1) {
extra = GetAttribute(o, StringListItem(list2, 0))
}
else if (ListCount (list2) = 2) {
obj = GetObject(StringListItem(list2, 0))
if (obj = null) {
error ("Unable to parse (could not find object in the {#...} bit): " + s2)
}
list3 = GetAttribute(obj, StringListItem(list2, 1))
if (not TypeOf(list3) = "stringlist") {
error ("Unable to parse (could not find list attribute in the {#...} bit): " + s2)
}
extra = PickOneStr(list3)
}
else {
error ("Unable to parse (the {#...} bit): " + s2)
}
}
else {
list2 = Split (s2, "|")
pos = GetRandomInt (0, ListCount (list2) - 1)
extra = StringListItem (list2, pos)
}
output = output + extra + StringListItem (list1, 1)
}
return (Replace(output, "####", o.name))
</function>
<function name="PickOneStr" parameters="lst" type="string">
if (TypeOf(lst) = "string") {
lst = Split(lst, "|")
}
index = GetRandomInt(0, ListCount(lst) - 1)
return (StringListItem(lst, index))
</function>