Concatenating Variable Names within Macros and For Loops

Twine Version: 2.3.14
Story Format: Sugarcube 2.34.1

I just spent most of my evening trying to work out how to do this without using several hard-coded if statements. What I want to do is use a for loop to check a list of NPCs locations. These NPCs are set in generic objects like this:

<<set $npc to {
	"Derek" : {
		"location" : "npchome",
		"relationship" : 1
	},
	"Austin" : {
		"location" : "npchome",
		"relationship" : 1
	}

And I also have an array of each NPC’s name set to $npcName

Naturally can access them with $npc.Derek.location and such.

However, what I want to do is, if any of these NPCs are at the player’s home, I add their names to an array, $npcPresent (set up in the StoryInit passage), so that, on the next “turn” of the player, when the NPC’s location is updated, they give the player a message that they’re leaving.

So in the passage, before the player clicks the link to advance, I have this:

<<for _num to 0; _num lt $npcName; _num++>>
	<<if `'$npc.' + $npcName[_num] + '.location'` is "playerhome">>
		<<silently>>
			$npcPresent.push($npcName[_num])
		<</silently>>
	<</if>>
<</for>>

I’m just having an incredibly difficult time getting the expression itself to cooperate inside the if statement. I’ve tried this with backquotes, as you can see in the example, both with and without the single quotes within the backquotes. I also tried the stupid print trick:

<<for _num to 0; _num lt $npcName; _num++>>
	<<= "<<if $npc." + $npcName[_num] + ".location is 'playerhome'>>
		<<silently>>
			$npcPresent.push($npcName[_num])
		<</silently>>
	<</if>>">>
<</for>>

With no luck, though I did figure out the correct structure for the trick with simpler macros, at least.

I’m just frustrated because I feel like I’m so close to making this work, but there’s something I’m not understanding about how this like, concatenation works within macros.

My ultimate question is, how can I accomplish something like this, where I’m substituting in the name of each NPC, so that I can use this loop, since I feel like hard-coding this in is so much less flexible?

Am I completely misunderstanding how Sugarcube handles these things? Am I overcomplicating things? I DON’T KNOW ahaha

I think you’re overcomplicating things? The point of putting things in an array or dictionary is that you don’t need to generate the variable accesses as text like that. Did you try:

<<if $npc[$npcName[_num]].location is "playerhome">>

If you don’t care about the order of NPC names (which you might), you can also do:

<<for _name, _info range $npc>>
	<<if _info.location is "playerhome>>
		...
	<</if>>
<</for>>
1 Like

You need to use the square bracket notation for what you’re attempting. Your $npcPresent code isn’t being run either.

Try something like the following:

<<for _i to 0; _i lt $npcName; _i++>>
	<<if $npc[$npcName[_i]].location is "playerhome">>
		<<run $npcPresent.push($npcName[_i])>>
	<</if>>
<</for>>

Alternatively. If the ordering of the names within $npcPresent isn’t significant, you could use the range form to simplify things:

<<for _name, _data range $npc>>
	<<if _data.location is "playerhome">>
		<<run $npcPresent.push(_name)>>
	<</if>>
<</for>>
2 Likes