0 votes
by (300 points)

hello everyone

 

ok, so this one is a little bit technical. I'm on Twine/Sugarcube and Tweego/Sugarcube, Linux version. I have a widget which create a dynamic number of links which goes to the same passage. The only change is in the Setter where one of my variable change. Here is a simplified example :

::Widget [widget]
<<widget "charalinks">>
  <<set _c to $args[0]>>\
  <<for _i to 0; _i lt _c.length; _i++>>\
	  _c[_i].name
	  [[Passage2][$actual_character = _c[_i]]]
  <</for>>\
<</widget>>

 

::Passage1
<<nobr>>
<<set $character = [{name:"a"}, {name:"b"}, {name:"c"}]>>
<<set $actual_character = {name:"john"}>>
<</nobr>>

$character[0].name
$character[1].name
$character[2].name
$actual_character.name

<<charalinks $character>>

 

::Passage 2
$actual_character.name

 

I expect a character name in "Passage 2" but the $actual_character seems not initialized.

 

It looks a bit tricky so, any ideas? 

1 Answer

0 votes
by (159k points)
selected by
 
Best answer

There are two issues with your example:

1. Story variables referenced within Links with Setters or within the body of a <<link>> macro are not evaluated until after the associated link is selected, this means that by the time the _c and _i temporary variables referenced in the _c[_i] part of the setter where actually evaluated they either no longer existed or they equalled what ever values they had at the end of the looping process.

You need to use the <<capture>> macro to capture those variable's current value at the time each link was created. In theory your widget's code would need to look something like the following:

<<widget "charalinks">>
	<<set _c to $args[0]>>\
	<<for _i to 0; _i lt _c.length; _i++>>\
		<<set _character to _c[_i]>>\
		_character.name
		<<capture _character>>[[Passage2][$actual_character = _character]]<</capture>>
	<</for>>\
<</widget>>

... however...

2. You are assigning the $actual_character story variable a reference to a object that will be cloned during the Passage Transition process, which will result in that story variable pointing to a different (but equal in 'value') object than the object contained within the Array you passed to your widget.

eg. Lets assume you have an Array of character objects named $party and you pass this array to your <<charalinks>> widget, and that the Reader selects the first link then you would think that the $actual_character story variable would now reference the same character object as $party[0] does, but you would be wrong. They would both reference a different clone of the original character object.

:: Passage 1
<<set $party to [
	{name: "Char 1"},
	{name: "Char 2"},
	{name: "Char 3"}
]>>
<<charalinks $party>>

:: Passage 2
Party Member 1: <<= $party[0].name>>
Actual Character: <<= $actual_character.name>>

Change the name of Party Member 1. <<set $party[0].name to "Abcde">>

Party Member 1: <<= $party[0].name>>
Actual Character: <<= $actual_character.name>> (didn't change!)


The solution to this problem is to assign the index number of the $party member in your Setter and then use that to access the correct character object later.

a. Your widget would look something like the following

<<widget "charalinks">>
	<<set _c to $args[0]>>\
	<<for _i to 0; _i lt _c.length; _i++>>\
		_c[_i].name
		<<capture _i>>[[Passage2][$selected = _i]]<</capture>>
	<</for>>\
<</widget>>

b. And the Passage 2 in my previous example would change to something like

:: Passage 2
<<set $actual_character = $party[$selected]>>

Party Member 1: <<= $party[0].name>>
Actual Character: <<= $actual_character.name>>

Change the name of Party Member 1. <<set $party[0].name to "Abcde">>

Party Member 1: <<= $party[0].name>>
Actual Character: <<= $actual_character.name>> (it also changed!)

WARNING: All the above code examples were written from memory and have not been tested, so while they are conceptually correct they may contain syntax errors.

by (300 points)
I knew i was missing something. Thanks a lot for your big help, i get where is the problem now

 

many many thanks :)
...