0 votes
by (160 points)

I have an item setup where you can interact with various items in similar ways. I've created a widget called ItemActions which generates these actions in the form of links (Examine, Grab, etc.). This widget then has a <<link>> which runs code on click, regenerating the "Inventory" passage in the sidebar and the item list in the main page. ItemActions takes an argument of "ItemCode" so it can then handle each item appropriately.

The issue is that when I iteratively create this list, the inner variables I set up in the inner <<link>> code get over-written by the next item.

For example, let's say a room has a key and a crystal. I click the key's "Grab" link, and it runs the code that adds it to your inventory and removes it from the room. But the ID it's using to do that is the ID of the crystal, because it came afterwards and reset the _itemCode variables in my widget and in the link.

The widget looks like this:

<<widget ItemActions>>
		<<set _itemCode = $args[0]>>
		<<set _item = $items[_itemCode]>>
		<<link 'Grab'>>
			<<run $player.inventory.push(_itemCode)>>
			<<run $rooms[$player.locationCode].items.deleteWith(function (val) {
				return val.code === _itemCode;
			<<replace '#RoomItems'>>
				<<include 'Room.RoomWrapper.Items'>>
			<<replace '#story-caption'>>
				<<include 'StoryCaption'>>

This works fine to display the link, but when you click it, the temporary variables (_itemCode) have been overwritten by whichever one came last.

How can you control this?

1 Answer

+1 vote
by (37.1k points)
selected by
Best answer

This isn't a "scope" problem, the problem is that the value of the variable is different at the point when the user clicks on the link, than what it was when the link was created.

To fix that you need to use the <<capture>> macro to "capture" the value of any variables which you want to use their value at the time the link is created, instead of the value at the time the user clicks or whatever.  So you just need to wrap your <<link>> macro inside "<<capture _itemCode>>...<</capture>>" and that will probably make it do what you want.

If it helps, I have some sample code explaining the <<capture>> macro here.  (Click the "Jump to Start" link on the UI bar to see other sample code there.)

Three other issues, the first line of your code should be:

<<widget "ItemActions">>

with the quotes around the widget name (see the <<widget>> example code).  Also, it appears that you're missing a "<<nobr>>" between the first and second lines, since there's a "<</nobr>>" at the end of your widget.  And finally, it appears that you aren't using the _item variable, so you could probably get rid of the "<<set _item = $items[_itemCode]>>" line.

Hope that helps!  :-)

by (160 points)
That did it! Thanks! I saw that but didn't get what it did before. Super useful.
by (37.1k points)

Yeah, it took me a while to fully grok what the <<capture>> macro did as well, which is why I made that sample code I linked to above to help explain it.

Glad it worked.

Welcome to Twine Q&A, where you can ask questions and receive answers from other members of the community.

You can also find hints and information on Twine on the official wiki and the old forums archive.

See a spam question? Flag it instead of downvoting. A question flagged enough times will automatically be hidden while moderators review it.