Changing a property of random object from an array

SugarCube 2.36.1

Hello, not sure how exactly should I phrase the question, so I am just going to show what’s my problem.
Lets say I have something like this in StoryInit:

<<set $Enemy1 = {"name" : "A","health" : 5,}>>
<<set $Enemy2 = {"name" : "B","health" : 5,}>>
<<set $Enemy2 = {"name" : "C","health" : 5,}>>

And this in a passage:

<<set $Array to [$Enemy1, $Enemy2, $Enemy3]>>
<<set $EnemyNow to $Array.random()>>
<<set $ -=1>>
<<print $>>
<<print $>>
<<print $>>

So, the goal is to change ceratain property of a random object from the array. And the code above works. The confusing part is that it works only if the $Array is created in the same passage where the rest of the code is. If the array was made sooner (no matter if it’s in StoryInit or any other passage), it doesn’t work. Why is it so?

Thank you very much in advance!

I don’t know why it works when you declare your array in the same passage. Someone less ignorant than me might explain, but I can’t.

Here’s a code that works when I test it, and I know why it works ($Array declaration in StoryInit):

<<set _EnemyNow to random(0,$Array.length-1)>>
<<set $Array[_EnemyNow].health -=1>>
<<print $Array[0].health>>
<<print $Array[1].health>>
<<print $Array[2].health>>

Each time you’ll have one 4 and two 5 as a result.

I probably should add at this point that you array is not dynamic. If you add

<<set $ +=1>>
<<print $Array[1].health>>
<<print $>>

You’ll see that now $Array[1] is not the same as $Enemy2.

Each time a Passage Transition occurs the current state of all known Story Variables is cloned/copied. The original state is added to the History system, and the “copy” is made available to the Passage that is about to be “shown”.

This cloning/copying process breaks the integrity of any variable or array element or Generic Object property that were previously referencing the same Object instance. And results in each of those variables or array elements or Generic Object properties now referencing its own unique “copy” of the original Object.

The recommend solution to overcome this behaviour is to something like what was suggested by Souppilouliouma, which is to create a single instance of each Object and to use identifiers to reference them from other sources.

eg. If you want to pre-define three Enemy objects, and then add them to an Array so you can randomly select one to act upon you could do something like the following…
(note: example written using TWEE Notation)

:: StoryInit
<<set $Enemies to {
  "EnemyA": {"name": "A", "health": 5},
  "EnemyB": {"name": "B", "health": 5},
  "EnemyC": {"name": "C", "health": 5}

:: Start
<<set $group to ["EnemyA", "EnemyB", "EnemyC"]>>
<<set $attacker to $group.random()>>
<<set $Enemies[$attacker].health -= 1>>

As you can see, we store the identifier of each Enemy within the Array, not the objects themselves. We then use that identifier to lookup the Enemy object within $Enemies variable and then access the property that is being changed.

note: It’s unclear from your example if the variable containing the Array or that containing the Identifier needs to be used in any other Passage than the current one. If they don’t then they should be changed to be Temporary variables instead.

<<set _group to ["EnemyA", "EnemyB", "EnemyC"]>>
<<set _attacker to _group.random()>>
<<set $Enemies[_attacker].health -= 1>>
1 Like