+1 vote
by (170 points)

Hi,

I'm using Twine 2.1.3 and Harlowe 2.0.1.

I have a dataset that contains datamaps. This represents a itemlist (dataset) with items (datamaps) that have some characteristics. So for example:

(set: $itemlist to (ds:
  (dm: "name", "item1", "value", 0, "useable", false),
  (dm: "name", "item2", "value", 0, "useable", false)
))

While playing several items can be added or subtracted from the $itemlist.

Now I want to make a link for every item in $itemlist. Once the player clicks on the link the corresponding item has to be stored in a variable. So I tried:

(for: each _item , ...$itemlist)[
  (link: _item's name)[
    (set: $youritem to _item)
    (go-to: "SomePage")
  ]
]

But if you click the link it gives the error "There isn't a temp variable named _item in this place".
I think _item is destroyed before clicking on the link. So I think this isn't the way. But..

How can this be accomplished?

PS: In SugarCube v2, I think this can be solved by enclosing the link in the <<capture variable_list>> macro.

<<for etc _item etc>>
<<capture _item>>
  link
<</capture>>
<</for>>

 But I don't want to switch from Harlowe ^^.

Hope the question is clear enough and that someone can help me. Thanks!

1 Answer

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

1. The temporary variable used within the (for:) macro only exists within the scope of the macro's associated hook, and that hook no longer exists after the (for:) macro is finished creating your links, and this is why you are getting that error message.

Using a story variable instead of a temporary variable would not solve this issue because variables contained within the associated hook of macros that require end-user interaction (like the (link:) macro does) are not evaluated until after the interaction occurs, and at the time of that interaction the variable will equal whatever it did at the end of the (for:) macro's looping.

To get around this issue you generally use a (print:) macro to dynamically create the macro & associated hook you need to include the value in.

(set: $array to (array: 1,2,3,4,5))

(for: each _item, ...$array)[
	(print: "(link: 'item: " + (text: _item) + "')[(set: $var to " + (text: _item) + ")(goto: 'Next')]")
]

 

2. The (set:) macro is assigning a clone of the original data-map object to the $youritem variable, so the object referenced in the $itemlist variable and the object referenced in the $youritem are no longer the same object even though the two objects have the 'same' value. Cloning of an object also occurs when (set:) is used to modify a property/element of an object.

The following example demonstrate this cloning process and the disassociation of the two copies of the original data-map object:

{
(set: $itemlist to (ds:
  (dm: "name", "item1", "value", 0, "useable", false),
  (dm: "name", "item2", "value", 0, "useable", false)
))

(for: each _item , ...$itemlist)[
	(if: _item's name is "item1")[
		(set: $youritem to _item)
	]
]
}

(set: $youritem's value to 1)

itemlist: (print: $itemlist)
youritem value: (print: $youritem's value)

To get around this issue I suggest that instead of assign an object reference to the $youritem variable that you assign an identifier to the original data-map stored within the $itemlist variable, this will require you to change the data-type of the collection object being used within $itemlist from a data-set to one that allows referencing it's contents via either an index or a property name. (eg. an Array or a (Data-)Map)

by (170 points)

Thank you for the respons, it was really helpful! I managed to accomplish it using the 'print-trick' and using the find macro to identify the item like this:

{(for: each _item , ...$itemlist)[
	(print: 
		"(link: '" + _item's name + "')[
			(set: $youritem to 1st of (find: _item2 where _item2's name is '" + _item's name + "', ... $itemlist))(go-to: 'Next')
		]"
	)
]}

The identification using the name works since no two items have the same name in my case. And the cloning isn´t a problem for me either.. This allows me to alter ´$youritem´ and get a new one from the ´$itemlist´. Not very elegant that you have to search trough the whole dataset again.. but it works..
Thanks for the print-trick!

by (120 points)
this somehow does not work with strings, any idea?
by (159k points)

@lasse

this somehow does not work with strings, any idea?

Without seeing your code it is difficult to guess why a piece of code doesn't work as you want it to.

Also because the site's software doesn't notify people when an old question is added to, I suggest you create a new question and include an example of your existing code within it.

...