Iterating an array is not working quite right for items in a shop

Twine Version: 2.3.9
Story Format: SugarCube 2.33.2

I must be missing something simple here, but I’m stuck I have an array for vehicles that can be bought by the player.

I iterate through the array and try to populate the field. I’m guessing it’s the way the for loop is iterating the array?

Array setup in the StoryInit (I trimmed out all but the values I’m trying to test, there are more of each):

<<set $mc to {
	money: 1500
}>>

<<set $transportation to {
	foot: {
		name: 'foot',
		description: 'Without a vehicle, you travel by foot or bus',
		owned: true,
		price: 0,
		traveltime: 4,
		img: './images/goods/walk.jpg'
	},
	usedcar: {
		name: 'used car',
		description: 'A basic used car that works ok and is faster than being on foot',
		owned: false,
		price: 1500,
		traveltime: 2,
		img: './images/goods/carused.jpg'
	},
	newcar: {
		name: 'new car',
		description: 'A brand new car that looks good and gets you around quickly',
		owned: false,
		price: 5000,
		traveltime: 1.5,
		img: './images/goods/carnew.jpg'
	},
	luxurycar: {
		name: 'luxury car',
		description: 'A top of the line car that looks fantastic and gets you around very quickly',
		owned: false,
		price: 20000,
		traveltime: 1,
		img: './images/goods/carluxury.jpg'
	}
}>>

Then I parse the array and print out the values. I added some comments. In order to keep proper spacing I’ve slashed out some lines and left some.:

<<for _i, _name range $transportation>>\
	<<if _name.name == "foot">>\  /*skip the first one as it's not buyable */
	<<else>>\
		Type: _name.name
		Description: _name.description
		Price: _name.price
		<<if _name.owned>>\
			Sold Out!
		<<elseif not _name.owned and $mc.money >= _name.price>>\
			<<link [[Buy->dealership]]>><<set _name.owned to true>><<set $mc.money -= _name.price>><</link>> /* This reloads the passage at present */
		<<elseif not _name.owned and $mc.money < _name.price>>\
			Not enough money!
		<</if>>
	<</if>>
<</for>>

There’s room for a lot of optimization in this code, I’m just trying to rough out a prototype just so I get the concept of what I’m doing. Everything displays perfectly, but when I try to buy something it fails… In the current setup, the new and luxury car are marked as not enough money, but the used car can be bought. If you change the money, then they’ll reflect as appropriate.

The problem I have is that when I “buy” the used car, it deducts the price of the luxury car, and not the used car, leaving the wallet with -18,500, instead of 0. I imagine it’s the way I’m iterating the array and populating the values. But what did I do wrong?

Thanks in advance

You need to use the <<capture>> macro to capture the value of _name.

That’s necessary because you’re changing the value of _name each time the loop iterates, but the code within the <<link>> macro only executes whenever the player activates it—I.e., it’s asynchronous wrt. the loop code. Thus, that code will normally always see the value set by the last loop iteration, since that’s what it (probably) has when activated by the player.

By using <<capture>>, you let the code within the <<link>> access the value that _name held during the loop iteration that spawned the <<link>> itself.

Edit: Clarity.

1 Like

Hah… it even provides a perfect example when iterating a loop.

Thanks!

Major, major facepalm moment… but I got it working perfectly!

In order to make the change quick and easy, I tossed a <<set $mc.money to 50000>> at the top of the passage. Then I clicked buy for one of them, and the were properly marked as bought, but the funds never dropped. I must have spent 30 minutes trying to figure out what I did, when I realized that every time I pressed ‘buy’ it was reloading the passage which reset the funds to 50000. I’ll show myself out now… :crazy_face:

Anyways, got it working nicely now!