My code is... executing in the wrong order? [Solved]

Io

My current indev game, I make heavy use of cloning objects. I have a debug room filled with stuff like FightingCharacterBase, CelestialBodyBase, BuffBase etc. As needed, I change the attributes of the objects, clone-and-move to the needed room, and have the player interact with the clone. When no longer needed, I FilterByAttribute for the object clones and destroy them.

Them problem I'm getting is that in some cases, the objects, uh, clone in the wrong order. The best example I can give is the SpaceRoom that holds Earth and Luna. It's supposed to set CelestialBodyBase's alias to Earth, clone-and-move it, then set CelestialBodyBase's alias to Luna, clone-and-move that. So you'd get Earth first, and Luna second. Relevant code below.

// Make the worlds via a Switch and a While Loop
set (StellarSystemFolder, "WorldsToMake", 2)
while (StellarSystemFolder.WorldsToMake>0) {
  switch (StellarSystemFolder.WorldsToMake) {
    case (1) {
      set (CelestialBodyBase, "alias", "Luna")
      set (CelestialBodyBase, "CanLand", False)
      set (CelestialBodyBase, "CanMine", False)
      set (CelestialBodyBase, "StarPlanet", "Planet")
      CloneObjectAndMove (CelestialBodyBase, StellarSystemC4)
    }
    case (2) {
      set (CelestialBodyBase, "alias", "Earth")
      set (CelestialBodyBase, "CanLand", True)
      set (CelestialBodyBase, "CanMine", False)
      set (CelestialBodyBase, "StarPlanet", "Planet")
      CloneObjectAndMove (CelestialBodyBase, StellarSystemC4)
    }
  }
  set (StellarSystemFolder, "WorldsToMake", StellarSystemFolder.WorldsToMake-1)
}

But at times, I get Luna first and Earth second.

Something similar happens when I clone FightingCharacterBase to make characters in a fight. I'd go 'make and clone Big Boss, then make and clone Small Enemy 1, make and clone Small Enemy 2' and I'll get them showing up in the order of "Small Enemy 1, Small Enemy 2, Big Boss" or something, with no apparent rhyme or reason (Different order every time). And it should be noted that even when the object clones APPEAR in the wrong order, they still have all the correct attributes that they should have - Small Enemy 1 never ever has Big Boss's HP.

Does anyone know what's going on? I'm going insane trying to solve this.


I would guess the clones are created in the right order, but it is later that it gets messed up, possibly because of when they are added to the game world or possibly because of how Quest decides the order of stuff, though both seem unlikely to cause a problem.

What happens if you print a message in the loop saying which clone is being done? Is it done in order?

Unrelated to your issue, but...

Why are you doing it in a loop?

You should get the same with this:

set (CelestialBodyBase, "alias", "Luna")
set (CelestialBodyBase, "CanLand", False)
set (CelestialBodyBase, "CanMine", False)
set (CelestialBodyBase, "StarPlanet", "Planet")
CloneObjectAndMove (CelestialBodyBase, StellarSystemC4)

set (CelestialBodyBase, "alias", "Earth")
set (CelestialBodyBase, "CanLand", True)
set (CelestialBodyBase, "CanMine", False)
set (CelestialBodyBase, "StarPlanet", "Planet")
CloneObjectAndMove (CelestialBodyBase, StellarSystemC4)

Also, I would create the clone first, and set the attributes on it. Keep the prototype as the vanilla version, with all the default values, and just set the non-defaults for each clone. I am not sure which are defaults, but it might look like this:

clone = CloneObjectAndMove (CelestialBodyBase, StellarSystemC4)
set (clone, "alias", "Luna")

clone = CloneObjectAndMove (CelestialBodyBase, StellarSystemC4)
set (clone, "alias", "Earth")
set (clone, "CanLand", True)

Io

I'm doing it in a loop because there are some very complicated systems, and the Switch view is more compact; I wouldn't have to scroll through several pages to find the obscure alien planet I wanted to edit. I omitted a few Switch cases in the code above (And also reduced the WorldsToMake value) because they weren't relevant.

As for checking when it's moved... I put in some debug code and got a following event on the fight I'm testing.

Boss has been made and moved
Small Bad 1 had been made and moved
Small Bad 2 has been made and moved
Small Bad 3 has been made and moved

However, in the actual game the order I saw was:

Small Bad 3
Small Bad 2
Big Boss
Small Bad 1

The code for making an enemy doesn't use a loop, but rather a function. Basically it says:

CreateMiscFighter(IDStringOfFighter="Big Boss")
CreateMiscFighter(IDStringOfFighter="Small Bad 1")
//The Function itself being:
CreateMiscFighter{
switch (IDStringOfFighter){
case("Big  Boss"){
FighterBase.Health=999
//etc
CloneObjectAndMove(FighterBase, Fight)
}
case("Small Bad 1"){
FighterBase.Health=99
//etc
CloneObjectAndMove(FighterBase, Fight)
}
}

Also I was not aware you could set a variable equal to the CloneObjectAndMove function and get it to return the object itself! A bit late to go back and remake the code for a minor adjustment though. Unless that might be the problem?


However, in the actual game the order I saw

Where are you seeing this order?


Io

Two places. First is one the right side, under the 'Places and Objects' pane. (You know, similar to Inventory, Compass etc). You'd expect, from top down, to see BigBoss, SmallBad1, SmallBad2, SmallBad3. But you get a completely different - indeed, seemingly random - order.

Second is the room description; under 'After entering this room' I have code to print out the status of every active fighter. In psuedocode:

ForEach Fighter in FilterByAttribute(FightRoom, FighterBase){
print(Fighter.alias)
print(Fighter.Health+"/"+Fighter.MaxHealth+" Health")
print(Fighter.Energy+"/"+Fighter.MaxEnergy+" Energy")

Which gives you outputs like:

PlayerName
50/50 Health
25/50 Energy
Big Boss
999/999 Health
999/999 Energy
SmallBad1
99/99 Health
99/99 Energy

Or at least it should. What it ends up giving is something like:

PlayerName
50/50 Health
25/50 Energy
SmallBad1
99/99 Health
99/99 Energy
Big Boss
999/999 Health
999/999 Energy

Io

Bumping because still unsolved.


As for checking when it's moved... I put in some debug code and got a following event on the fight I'm testing.

Boss has been made and moved
Small Bad 1 had been made and moved
Small Bad 2 has been made and moved
Small Bad 3 has been made and moved

Okay, so the code is executing in the right order.

It might be useful to add this, after the loop (change room to the name of the room):

msg(GetAllChildObjects(room))

I would guess you will see the order is wrong there, and that would indicate a strange timing issue between the script and the underlying code, where the underlying code is getting the objects out of order. I cannot see why that should be or how it can be solved.

The best work-around I can think of is to sort the objects before displaying them.

In ScopeReachableNotHeldForRoom change the last line to:

return (ObjectListSort(result, "order", "alias"))

In FormatObjectList change the third line to:

list = RemoveSceneryObjects(ObjectListSort(GetDirectChildren(parent), "order", "alias"))

The set the "order" attribute of your boss to 1, and for minions set it to 2.


Io

msg(GetAllChildObjects(room)) gets me a similar issue as before; GetAllChildObjects says they're in the right order. I get

BigBoss, SmallBad1, SmallBad2, SmallBad3

Though it's all stuff like FightingObjectBase3, FightingObjectBase4, but I can use the debugger to look up their alias and that's what I get.

But then in the display it's

SmallBad3
BigBoss
SmallBad1
SmallBad2

That makes even less sense!

The workaround I suggested should still work, however.


Io

The work-around... sort of worked. It works for one of the two places where the display's wrong. In the Places and Objects panel it does indeed display things, first by the order attribute, then alphabetical order of their alias.

The second part, however, is the description I have printed out; the 'Player, 50/50 Health, 25/50 Energy' I gave example of earlier. It still gives them in the wrong order. I imagine the problem is in the 'FilterByAttribute' function, but I don't know what I'd replace it with. Relevant part of the code is:

foreach (Fighter, FilterByAttribute(GetDirectChildren(Fight), "prototype", FightingCharacterBase)) {
msg(Fighter.alias)
msg("Health: "+Fighter.Health+"/"+Fighter.MaxHealth)
msg("Energy: "+Fighter.Energy+"/"+Fighter.MaxEnergy)
 }

And it's called After Entering The Room.


Io

I figured it out! I replace 'GetDirectChildren(Fight)' with ObjectListSort(GetDirectChildren(Fight), "order", "alias"). Thanks everyone for the help!

Now I have to - ugh - look for each and every GetDirectChildren in my game and replace it with the correct code. Joy.


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

Support

Forums