Removing old random objects and duplicates

Hi all! Apologies for making so many topics, but I just can't solve this problem.

I'm trying to create a script that activates when the player enters a room and removes all objects of a certain type. The objects are clones of template objects in another room.

foreach (obj, AllObjects()) {
  if (obj.parent = player.parent and DoesInherit(obj, "object_type")) {
    RemoveObject (this)
  }
  else {
  }
}

The script mostly works but doesn't remove any objects, and I can't figure out why.

Secondly, once the old cloned objects have been removed, the turn script I'm using makes a few random checks to see if any new objects spawn in the player's room. In these instances I don't want more than one object to spawn at once.

How can I write a script that would check if there are multiple instances of objects of the same type, and remove all but one of them?


The site actually prefers multiple threads instead of having all of your questions/topics in a single thread, as it does make sense... searching/reading through pages upon pages within a thread for specific posts/information is not fun... thus it's better to make new threads for each topic/question you've got.


// this script needs to be used upon the 'player' already being set inside of a (the new) room, so you can test if the 'on entering a room' Script works or not (I can't remember if it's run before you're set inside of the new room or before you're set being inside of the new room):

foreach (obj, GetDirectChildren()) { // or you can use (depends on what you want/need): GetAllChildObjects ()
  if (DoesInherit(obj, "object_type")) {
    RemoveObject (obj)
  }
  else {
  }
}

also you may want to use the 'destroy' Function instead ( http://docs.textadventures.co.uk/quest/scripts/destroy.html )

as what the 'RemoveObject' Function ( http://docs.textadventures.co.uk/quest/functions/corelibrary/removeobject.html ) actual does is this, for an example:

// the 'player' Player Object is contained within the 'room' Room Object

<object name="room">
  <inherit name="editor_room" />
  <object name="player">
    <inherit name="editor_object" />
    <inherit name="editor_player" />
  </object>
</object>

this is the exact same thing (the built-in 'parent' Object reference Attribute is what actually controls the containment heirearchy) as the above:

<object name="room">
  <inherit name="editor_room" />
</object>

<object name="player">
  <inherit name="editor_object" />
  <inherit name="editor_player" />
  <attr name="parent" type="object">room</attr>
</object>

and the same thing in scripting:

MoveObject (player, room)

and this scripting is the same thing as well:

player.parent = room

// -----------------------------------------------------------------------

so, what the 'RemoveObject' Function does is this:

<object name="room">
  <inherit name="editor_room" />
</object>

<object name="player">
  <inherit name="editor_object" />
  <inherit name="editor_player" />
  // if this was shown, this would be what it looks like:
  // <attr name="parent" type="object">null</attr>
  // when any Object's 'parent' is 'null', it means that it is NOT contained within any other Object, except that of the '<asl>game content/code</asl>' GAME CODE/CONTENT OBJECT
  // notice how the 'room' Room Object, is actually also NOT contained within any other Object (in the above example as well as this one), if it's parent was shown, its value would be 'null' too, as it is only contained within the '<asl></asl>' GAME CODE/CONTENT OBJECT
  // so, the 'RemoveObject' merely sets the 'parent' Object reference Attribute to be 'null', it removes the Object from being contained in another Object, and thus you still got the Object being maintained by the game. So, if you don't plan on reusing the Object, then you want to use the 'destroy' Function instead of the 'RemoveObject' Function. Often you want to destroy Clones, as once you're done with them, you want to get rid of them (as you can always clone more, such as when you buy an item from a shop feature, cloning and moving that item into your inventory). However, your original Object you would NOT ever want to 'destroy', so you can keep cloning it. You may want to 'RemoveObject' it however, for whatever the possible reason (can't think of one/a-scenario at the moment though, lol)
</object>

"
Secondly, once the old cloned objects have been removed, the turn script I'm using makes a few random checks to see if any new objects spawn in the player's room. In these instances I don't want more than one object to spawn at once.

How can I write a script that would check if there are multiple instances of objects of the same type, and remove all but one of them?
(scrim)
"


just give your Objects an Integer Attribute

<object name="bear">
  <inherit name="bear_type" />
  <attr name="clone_quantity_integer_attribute" type="int">0</attr>
</object>

<object name="wolf">
  <inherit name="wolf_type" />
  <attr name="clone_quantity_integer_attribute" type="int">0</attr>
</object>

<type name="bear_type">
  <inherit name="animal_type" />
</type>

<type name="wolf_type">
  <inherit name="animal_type" />
</type>

<type name="animal_type">
<attr name="clone_quantity_integer_attribute" type="int">0</attr>
</type>

// scripting:

(when you Clone, you'll need to increase the original 'clone_quantity_integer_attribute' by 1)

(err... the below needs a bit more work... as this is a bit more complex than I realized... but at least it gives you a start/idea on this stuff)

foreach (object_variable, GetDirectChildren()) {
  if (DoesInherit (object_variable, "animal_type")) {
    object_variable.clone_quantity_integer_variable = object_variable.quantity_integer_variable + 1
  }
}

// hopefully there's no issues with using a 'while' within a 'foreach'... lol:
foreach (object_variable, GetDirectChildren()) {
  if (DoesInherit (object_variable, "animal_type")) {
    while (object_variable.quantity_integer_attribute > 1) {
      Destroy (object_variable)
      object_varaible.quantity_integer_variable = object_variable.quantity_integer_variable - 1
    }
  }
}

The site actually prefers multiple threads instead of having all of your questions/topics in a single thread, as it does make sense... searching/reading through pages upon pages within a thread for specific posts/information is not fun... thus it's better to make new threads for each topic/question you've got. (hegemonkhan)

I'll keep that in mind. My only concern was that I have so many questions, and I don't want to spam the forum. I really appreciate the help, though. :)

Okay, so this is the script I'm currently using to try to remove all the old cloned animals from the room upon entry.

foreach (obj, GetDirectChildren (player.parent)) {
  if (DoesInherit(obj, "object_animal")) {
    destroy (obj)
  }
  else {
  }
}

There are two issues I'm having currently. Firstly, the script seems to pick up on objects/animals the same turn that they spawn. I figured that placing this script (in the script when entering a room field) before the spawning script would mean that the removal script activates first, and THEN the spawn script would happen, but apparently that's not the case. Perhaps I need to place the removal script elsewhere, maybe so that it runs before the player enters the room.

The second is that it doesn't actually remove the objects. It just returns this error:

Error running script: Error compiling expression 'obj': RootExpressionElement: Cannot convert type 'Element' to expression result of 'String'

It seems like 'destroy' wants me to refer to a specific object name/string rather than a generic class.

I'm still working on understanding the script you posted for removing duplicate spawns, but one thing I don't understand is what the advantage of creating both a generic animal type as well as types for each individual animal is. Would it be better to just create a generic animal type, and then create individual animal objects that inherit that generic type?


destroy needs to have the name of the object, not the object itself (no idea why).

destroy(obj.name)

Also, I would do this on the script that runs when the player leaves the room, personally.


That's strange, but thanks very much!

I think in order to run the script when the player leaves a room I would use

    <roomleave type="script"><![CDATA[
      foreach (obj, GetDirectChildren (player.parent)) {
        if (DoesInherit(obj, "object_animal")) {
          destroy (obj.name)
        }
        else {
        }
      }
    ]]></roomleave>

Correct?

Unfortunately that still doesn't seem to work.


the 'GetDirectChildren' Function does NOT use/need parameters/arguments (inputs), so you need to change it to this:

GetDirectChildren ()

    <roomleave type="script"><![CDATA[
      foreach (obj, GetDirectChildren ()) {
        if (DoesInherit(obj, "object_animal")) {
          destroy (obj.name)
        }
        else {
        }
      }
    ]]></roomleave>

also, the '<![CDATA[ /*scripting*/ ]]>' tags is ONLY needed when you are working directly in-code (well, maybe if you use the [EXPRESSION] option in the GUI/Editor you need to include the CDATA tags, or maybe you don't, no idea if the GUI/Editor handles it for you or not) and are using and/or need the 'greater than' and/or 'lesser than' operations/symbols ('<' and/or '>'), such as (pseudocode): if (test.score >= 90) then test.grade = "A", as otherwise, quest will think these symbols are the coding tag symbols, and thus you'll have errors.

"
but one thing I don't understand is what the advantage of creating both a generic animal type as well as types for each individual animal is. Would it be better to just create a generic animal type, and then create individual animal objects that inherit that generic type?
(scrim)
"


oh, you certainly don't have to... it depends on how complex/deep and/or big (scale-wise) your design/game is... if your specific animal types (Object Types / Types) share the same Attributes, then it'd be good to make another Object Type / Type (which would have those shared/universal Attributes), and have the specific animal types inherit it. Less coding / less code redundency, better organization, etc etc etc. This is a bit more advanced coding design/structure topic, but it doesn't hurt to open it up for you to consider, or at least to think about.

There's two parts to coding:

  1. the coding itself (the basic scripting and concepts, syntax, what's available/built-in/"instruction sets" with the software you're using, etc etc etc)
  2. the design, structure, logic, and/or organization of the code

once you learn how to code... then the hard part is learning how to code well... (I'm still at this stage myself, as this is a really massive and very advanced topic)


the 'GetDirectChildren' Function does NOT use/need parameters/arguments (inputs)

Yes it does, it needs to know what object you want the children of:
http://docs.textadventures.co.uk/quest/functions/getdirectchildren.html

@scrimshaw04

The code looks good to me. What does happen? Is it possible you spelt "object_animal" differently somewhere? Are you sure the script is running (try adding a msg at the start, and see if the message appears).


oops, my bad. For some reason I thought it automatically got the game.pov.parent, faulty memory... bugged (error) organic data structure design (my brain), laughs.


No worries hegemon!

I've triple checked spelling, and the object_animal should be spelled correctly everywhere, unless there's something I've missed. Or perhaps the animal objects aren't inheriting the object_animal type correctly? For each animal object I've added the object_animal type in the 'inherited types' field manually, but perhaps there's another way that I'm meant to do it?

I tried throwing in messages for each step of the script, but none of them print. I tried that before, but I couldn't see any issues so I thought that it might be a quirk of quest. Maybe I've placed the leaveroom script in the wrong place? At the moment it immediately follows the roomenter tags, as a child of the game tags.


Sounds like the script is not getting run. Hard to tell why not without more information.


Seems that way, but I can't see the reason why. Is there an alternative way to run a script on leaving a room?

Otherwise what information would help?


Is this running when the player leaves any room? If so, I will gp back on what I said earlier. Go to the game object, and on the Scripts tab you should see a script to run when entering a room. That would be the best place.


The room script invoked after you leave a room is called "onexit" not "leaveroom". I always use the Quest UI to create the scripts (e.g. with a dummy print), then I flesh them out, as I can never remember what they're called (and they're not consistent).

Keep in mind that when the script is executed, the player is already in the next room. If you want the room the player just left, you can use "this".


Thanks! That clears things up.

I've been using the enterroom field on the game object to run a number of scripts. Unfortunately placing this script at the end of what's starting to be a pretty complicated series of scripts seems to remove animals as soon as they spawn.

      foreach (obj, GetDirectChildren (player.parent)) {
        if (DoesInherit(obj, "object_animal")) {
          destroy (obj.name)
        }
        else {
        }
      }

So I made a copy of the default room type, and then added an an 'onexit' script to it. I also created an 'object' attribute on the player object called 'lastroom'. For the onexit script I used

    <onexit type="script">
      msg ("Last Room was " + player.lastroom)
      foreach (obj, GetDirectChildren (player.lastroom)) {
        if (DoesInherit(obj, "object_animal")) {
          destroy (obj.name)
        }
        else {
        }
      }
      player.lastroom = player.parent
    </onexit>

My goal was to run the script to remove all the animal objects in 'lastroom' and the redefine 'lastroom' to be the room that the player is currently in. Unfortunately, it still seems to destroy animals as soon as they spawn. It does seem to change the variable to be the previous room, though.

Any ideas?


hadn't looked at what you provided closely, but we may have to see your entire game code, as the issue may not be within the small section of code that you provided in your posts. The error could indeed just be in the code you provided in your posts, or you could have multiple errors, both in the code you provided and in code you've not provided.

I'll see if I can spot any errors in the code you provided though I'm not quite following exactly what/design you're doing...

but again, we may need to see your entire game code, as it's easier for us to look at it, than for you to try to describe everything that you've done, lol.


I can't tell from the code you've provided, we'll need to see your entire game code

I have a feeling that it's with how you're handling your 'lastroom' Object Attribute and/or possibly with the 'onenter/onenterroom' and 'onexit/onexitroom'

handling an 'OLD/PREVIOUS_VALUE' is actually a bit more tricky than it seems, as you actually have to use two Attributes

for example:

<object name="room"></object>
<object name="room_1"></object>
<object name="room_2"></object>
<object name="room_3"></object>

<object name="player">
  <attr name="parent" type="object">room</attr>
  <attr name="previous_room_object_attribute" type="object">room</attr>
  <attr name="current_room_object_attribute" type="object">room</attr>
  <attr name="changedparent" type="script">
    player.previous_room_object_attribute = player.current_room_object_attribute
    player.current_room_object_attribute = player.parent
  </attr>
</object>

// let's see how this is working:

player.parent = room // initial location
player.previous_room_object_attribute = room // initial value
player.current_room_object_attribute = room // initial value

// you move to and are now in room_3:

player.parent = room_3
// the 'changeparent' Script Attribute runs, and the results/changes are:
// first we do this:
player.previous_room_object_attribute = player.current_room_object_attribute // the 'player.current_room_object_attribute' still is equal to 'room', also the reason we need this 2nd Attribute, is because we can't use 'player.parent' as the 'player.parent' is now equal to 'room_3', it's no longer equal to 'room'
player.previous_room_object_attribute = room
// next/then/lastly we do this:
player.current_room_object_attribute = player.parent // as 'player.parent' is now equal to 'room_3', it's no longer equal to 'room'
player.current_room_object_attribute = room_3

// you move to and are now in room_1:

player.parent = room_1
// the 'changeparent' Script Attribute runs, and the results/changes are:
// first we do this:
player.previous_room_object_attribute = player.current_room_object_attribute // the 'player.current_room_object_attribute' still is equal to 'room_3', also the reason we need this 2nd Attribute, is because we can't use 'player.parent' as the 'player.parent' is now equal to 'room_1', it's no longer equal to 'room_3'
player.previous_room_object_attribute = room_3
// next/then/lastly we do this:
player.current_room_object_attribute = player.parent // as 'player.parent' is now equal to 'room_1', it's no longer equal to 'room_3'
player.current_room_object_attribute = room_1

// you move to and are now in room_2:

player.parent = room_2
// the 'changeparent' Script Attribute runs, and the results/changes are:
// first we do this:
player.previous_room_object_attribute = player.current_room_object_attribute // the 'player.current_room_object_attribute' still is equal to 'room_1', also the reason we need this 2nd Attribute, is because we can't use 'player.parent' as the 'player.parent' is now equal to 'room_2', it's no longer equal to 'room_1'
player.previous_room_object_attribute = room_1
// next/then/lastly we do this:
player.current_room_object_attribute = player.parent // as 'player.parent' is now equal to 'room_2', it's no longer equal to 'room_3'
player.current_room_object_attribute = room_2

// hopefully you can see how this is working perfectly, we can use the 'player.previous_room_object_attribute' to return/move-back to the immediately previous room we were in (if we want to be able to go back to multiple previous rooms, we'd need to store multiple rooms, which would mean we'd need it to be an Object List Attribute, and not just an Object Attribute, and we'd be adding the current room attribute as items to our previous room objectlist attribute).

and as for the 'enter/exit' it depends on how quest handles them, are they run before or after you're placed into the new room ???


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

Support

Forums