Current variable value for loop (Twine 2, Sugarcube)

I'm working on an inventory system and I've fixed lots of little problems so far...the only problem is this:
<<set $items to ["testitem", "stick", "rock", "watch"]>>
<<set $locs to ["inv", "Your Bedroom", "Your Bedroom", "Upstairs Hallway"]>>
<<set $desc to ["Test", "A small stick broken from a tree branch.", "A smooth stone.", "A plain digital watch."]>>

<<widget "roominv">>
You can see:

<<nobr>>
<<for $i to 0; $i < $items.length; $i++>>
<<set $baseString to "(T): Take the " + $items[$i] + "">>
<<set $passageString to passage()>>
<<if $locs[$i] is passage()>>
    <<print "a " + $items[$i]>>
	<br>
<</if>>
<<if $locs[$i] is passage()>>
    <<click $baseString $passageString>>
    	<<if $invCur < $invMax>>
This is where the problem is:
        	        <<set $locs[$i] to "inv">>
        	<<set $invCur to $invCur++>>
        <<else>>
        	<<alert "You can't pick it up: you're carrying too much as it is.">>
        <</if>>
    <</click>>
    <br>
<</if>>
<</for>>
<</nobr>>
<</widget>>

I need $i to be whatever it is during that iteration of the loop, and not equal to what it is afterward. (Which happens to be the length of the array; I checked.)

For example, the 3rd link printed (3rd iteration of the for loop):

<<set $locs[2] to "inv">>

Or, for the 7th link printed:

<<set $locs[6] to "inv">>

If I replace the $i value with a specific number, the inventory works perfectly (I can pick up and drop the item represented by the number, and it's added to the current room and stays there. I just can't do it with the other items.) Is there a way to do this, or some sort of workaround, if possible?

Comments

  • The $i inside the <<click>> is being bound late (i.e. when the player clicks it). You're going to have to force the $i to be bound early (i.e. when the <<click>> is constructed).

    Try the following, it's ugly, but it should work:
    <<widget "roominv">>
    You can see:
    
    <<nobr>>
    <<for $i to 0; $i < $items.length; $i++>>
    <<set $baseString to "(T): Take the " + $items[$i]>>
    <<set $passageString to passage()>>
    <<if $locs[$i] is passage()>>
        <<print "a " + $items[$i]>>
        <br>
        <<print '<<click [[' + $baseString + '|' + $passageString + ']]>><<if $invCur < $invMax>><<set $locs[' + $i + '] to "inv">><<set $invCur++>><<else>><<alert "You can\'t pick it up: you\'re carrying too much as it is.">><</if>><</click>>'>>
        <br>
    <</if>>
    <</for>>
    <</nobr>>
    <</widget>>
    
    I also fixed a few oddities in your shown example (back to back <<if>>s which had the exact same condition and you don't need to assign when you use the increment/decrement operators, they modify the variable's value in-place).
  • edited September 2015
    You can use a <<print>> to output the <<click>> code, it would look something like the following:
    note: I was not able to test this using your example because I don't know the values of the other variables.
    <<if $locs[$i] is passage()>>
    
    <<for $i to 0; $i < 5; $i++>>
    	<<print "<<click $baseString $passageString>><<if $invCur < $invMax>>This is where the problem is:<<set $locs[" + $i + "] to \"inv\">><<set $invCur to $invCur++>><<else>><<alert \"You can't pick it up: you're carrying too much as it is.\">><</if>><</click>>">>
    <</for>>
    
    <</if>>
    
    ... the important part is the + $i +, which is taking the current value of the loop's $i variable and concating it to the "click macro" string being built, said string is then <<print>>ed which turns it back in to code. The double quotes within the "click macro" string needed to be escaped using a backslash.
  • Works like a charm, thanks!