Referencing Clones?

How do you reference a specific clone you've created?

For instance, I want to create multiple copies of an item that is supposed to disappear after a number of turns:

SetTurnTimeout (15) {
  RemoveObject ([clone])
}

Io

The code for this is a special variant of 'For Each'. Specifically, the format I use is:

foreach (TheActualClone, FilterByAttribute(GetDirectChildren(PlaceTheCloneIsIn), "prototype", WhateverOriginalObjectYouCloned)) {
 //Do stuff to clone TheActualClone
}

What this does is look in an object/room for any clone of WhateverOriginalObjectYouCloned, and does something to each one in turn. So you could give the clones a 'TurnsLeft' attribute, and every turn you search for every clone and reduce TheActualClone.TurnsLeft by 1 and, at 0 or lower, get rid of it.

WARNING! You don't want to use RemoveObject! I have a game that uses clones a lot too, and until recently I was doing this too. It leads to a memory leak; RemoveObject doesn't actually get rid of the object. It merely sets its 'parent' to null. Basically the object in question gets punted into nowhere, but it's still there if you check the Debugger, taking up space. What you want is Destroy.

Destroy, as far as I can tell, actually destroys the object. The input has to be not an object, but an object's name. Not alias, the actual name in code. So it'd be:

destroy (TheActualClone.name)

Hope this helps!


When you create a clone, you probably have a variable referring to it (the clone returned by CloneObject or similar).

You'll want to put this in an attribute somewhere, so you know which object to destroy. However, if you're creating multiple clones, you'd need multiple attributes. Doing this with a turnscript for each is inefficient, but possible. Doing it with a TurnTimeout is not, because you can't pass data in to them.
(I've previously posted a modified version of the SetTurnTimeout function that would allow you to do this, but in this example it isn't the best solution.

Instead, you're probably better having a turnscript like this:

foreach (object, AllObjects()) {
  if (HasInt (object, "destroy_after_turns")) {
    if (object.destroy_after_turns = 0) {
      object.destroy_after_turns = null
      RemoveObject (object)
    }
    else {
      object.destroy_after_turns = object.destroy_after_turns - 1
    }
  }
}

That means that the number of turns left until the object is destroyed is stored as an attribute of the object; and a single turnscript keeps count of all the objects with that attribute.
So when you create a clone, you'd just do:

myClone = CloneObject (original object)
myClone.destroy_after_turns = 15

PS: RemoveObject throws an object into space, and leaves it floating around in a place the player can't reach. The object is removed from wherever it is, but it still exists. If you create a lot of clones, there will be an awful lot of defunct clones floating around in space, and this will make your save files huge. You're probably better using destroy for clones.


Thanks! I think I've managed to figure out something that works. I also appreciate the tip about RemoveObject.


the 4 indicator/reference methods:


  1. storing within a VARIABLE (objectlist VARIABLE for multiple objects or an object reference/pointer VARIABLE for a single object), and then using the VARIABLE

  1. using its 'name' String Attribute and probably along with using the String Manipulation Functions/Scripts ( http://docs.textadventures.co.uk/quest/functions/#string )

  2. creating/adding some other (string, boolean, integer, double, script, list, or dictionary) Attribute (including the already built-in Attributes like the 'alias' String Attribute), and using that --- such as via the 'HasATTRIBUTE' or 'GetATTRIBUTE' Scripts/Functions, or if able to via direct comparison expressions: if (OBJECT.alias = "potion") { /* scripting */ } --- the 'HasATTRIBUTE' and 'GetATTRIBUTE' are nearly the same as the direct comparison expression, but has some differences in how to handle them with scripting properly

  3. creating/adding an Inherited Attribute (Object Type / Type), and using that (via with the 'DoesInherit' Function/Script: http://docs.textadventures.co.uk/quest/functions/doesinherit.html )


Although it's not the most efficient way to do it, if you really wanted to make a script that looks like your original one, you could include this function:

  <function name="SetTurnTimeoutParams" parameters="turncount, params, script" type="object">
    turnscriptname = GetUniqueElementName("turnscript")
    create turnscript (turnscriptname)
    turnscript = GetObject(turnscriptname)
    turnscript.turncount = 0
    turnscript.triggerturncount = turncount
    turnscript.timeoutscript = script
    turnscript.parameters = params
    SetTurnScript(turnscript) {
      this.turncount = this.turncount + 1
      if (this.turncount >= this.triggerturncount) {
        this.enabled = false
        if (not EndsWith (TypeOf (this, "parameters"), "dictionary")) {
          this.parameters = QuickParams (this, this.parameters)
        }
        invoke (this.timeoutscript, this.parameters)
        destroy (this.name)
      }
    }
    EnableTurnScript(turnscript)
    return (turnscript)
  </function>

I think I got that right off the top of my head.
With that script, you can do:

SetTurnTimeoutParams (15, myClone) {
  RemoveObject (this)
}

Or if you want to change an NPC's name after 5 turns (just as an example) you could do:

SetTurnTimeoutParams (5, QuickParams ("npc", myClone, "newname", "George")) {
  npc.alias = newname
}

This method might work out easier if you have multiple scripts trying to the same thing to a clone repeatedly at different times; in which case the attributes would get quite complex to handle. It also returns the turnscript object, which you can keep in an attribute somewhere in case you want to pause it (with DisableTurnScript and EnableTurnScript functions) or cancel it (with destroy) later.


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums