First of all, you shouldn’t use passages to store data. It’s inefficient (as you can see from the number of lines of code it takes for you to extract that data), and the more passages you have, the slower the Twine editor is.
Instead, for any data which never changes, you should store that on a property of the setup object in the JavaScript section and/or the StoryInit passage. So you might have something like this in your JavaScript section:
setup.peopleNames = ["Anne", "Bob", "Charlie"];
You could then add names to the $photos array like this:
<<run $photos.push({ name: setup.peopleNames.random() })>>
Though I should note that there’s a risk you’ll get the same name more than once.
Then, to display the links, you’d only need to do this in your passage:
<<for _i = 0; _i < $photos.length; _i++>>\
<<capture _i>>\
<<link $photos[_i].name $photos[_i].name>><<set $personIndex = _i>><</link>>\
<</capture>>\
<<if _i < $photos.length - 1>> | <</if>>\
<</for>>
That would create clickable links to the “person name” passages, each separated by a “pipe” ("|
") character. After the user clicks the link, the code could then access the person’s info using $photos[$personIndex]
. (The backslashes ("\
") prevent line breaks.)
Note that you need to use the <<capture>>
macro, in order to “capture” the value of _i at the point in the loop where the link is created, otherwise the <<set $personIndex = _i>>
code would use the value that _i had at the point where the user clicked.
Also, using the <<link>>
macro prevents the Twine editor from trying to show links to invalid passage names, like it would if you used the square brackets method of creating links.
That said, instead of making different passages for each person, you could simply store all of the data you need on the setup object, have the $photos objects refer to that data, and then send all links to the same passage where that information is displayed based on the $personIndex value.
For example, you might have this in your JavaScript section:
setup.peopleNames = ["Anne", "Bob", "Charlie"];
setup.peopleJobs = ["Architect", "Business Person", "Chef"];
Build up the $photos array like this:
<<set _tmpObj = {}>>
<<set _tmpObj.name = random(0, setup.peopleNames.length - 1)>>
<<set _tmpObj.job = random(0, setup.peopleJobs.length - 1)>>
<<run $photos.push(_tmpObj)>>
So now you’re only storing the indexes of the data on the setup objects, rather than the data itself. That would help minimize the amount of data you’re storing in the game history, which means faster saves, loads, and passage transitions.
You’d then display the links like this:
<<for _i = 0; _i < $photos.length; _i++>>\
<<capture _i>>\
<<link setup.peopleNames[$photos[_i].name] "Person Info">><<set $personIndex = _i>><</link>>\
<</capture>>\
<<if _i < $photos.length - 1>> | <</if>>\
<</for>>
That would point all of the links to the “Person Info” passage, and set $personIndex to indicate which person was clicked on.
Then, in the “Person Info” passage you could just do this:
''Name: '' <<= setup.peopleNames[$photos[$personIndex].name]>>
''Job: '' <<= setup.peopleJobs[$photos[$personIndex].job]>>
and that one passage would work for every person. You’d just need to create data for each of the fields you want to display there on the setup object. (<<=>>
is shorthand for the <<print>>
macro.)
Hope that helps!