0 votes
asked by (1k points)
edited by

So... after a great many years (not really) of trying and failing to make the SugarCube Story.lookup work to retrieve tags, I finally ported an answer from GreyElf that was made for Harlowe.

It currently works and pulls in ALL the appropriate titles--in my case passages that are tagged with the word "book", but it doesn't make these titles appear as separate line items. They seem to be all concatenated into one long string: Title,Title,Title

They even have commas, and sometimes a space between the commas and sometimes not (depending on what I have tried). But they are not separate discrete items (it seems) for me to use to make links.

I feel like this is a basic array display problem I am having but I am not exactly sure (like: just add <br> or \n).

/*this is the SugarCube version*/

Story.lookup("tags", "book");

/*it gives me object Object object Object*/

/*This is the Harlowe version I have ported over to SugarCube*/
<<set $names to [GetBooks.getNamesOfPassagesWithTag('book')]>>
	<<for _i to 0; _i lt $names.length; _i++>>
    	<<capture _i>>
/* or  $names[_i] or <<print $names>> or <<print  $names[_i]>> */
		<<linkreplace "Accept books" `passage()`>><<addToBookInv $names[_i]>>You now have <<bookInvWithLinks>><</linkreplace>>

/*it gives me the correct titles, but they are all in one long line. I am trying to add line breaks or otherwise separate them to use them in variables*/


Here is the JavaScript (again, credit @Greyelf)

window.GetBooks = window.GetBooks || {};

window.GetBooks.getNamesOfPassagesWithTag = function(tag) {
	var tagged = $('tw-storydata tw-passagedata[tags~="' + tag + '"]')
	var names = tagged.map(function () {
		return this.getAttribute('name');
	return names;

If this is unclear please let me know and I can perhaps further elucidate.

One last thing that may help. There is an answer here by both Greyelf and The Mad Exile about variables being initialized improperly and then being converted by JavaScript. I am not sure if that is the issue but in my case it is initialized in StoryInit, thus:

 <<set $names = []>>

It seems to get reset here:

<<set $names to [GetBooks.getNamesOfPassagesWithTag('book')]>>

I say that because whether I try =0 or =[] I get the same result. I think that is because it gets set here (just above). Removing that from StoryInit does not solve the issue either.

I do hope that helps.

Thank you.


PS, Greyelf I will be reaching out to you next week.

2 Answers

+1 vote
answered by (115k points)
selected by
Best answer

If I understand your question correctly you want to list of Title of all Passages that have a known tag assigned to them. I will based the following explanation on the 'book' example you supplied TheMadExile.

The Story.lookup() function returns an Array object which will contain all the Passage objects that meet your supplied criteria, each Passage object includes a title property which you can use to obtain that passage's Title / Name.

The following example shows how to use the Story.lookup() function to return an Array containing all the Passage objects that have a 'book' tag, and how to use the range version of the <<for>> macro to output the Title of each of the Passage objects within the Array.

<<set _books to Story.lookup("tags", "book")>>
<<for _book range _books>>

If you want the generated Array to only contain the Title of the relevant passages then you can use the JavaScript <Array>.map() function to generate such an Array based on the one returned by Story.lookup().

<<set _titles to Story.lookup("tags", "book").map(function (book){ return book.title; })>>
<<for _title range _titles>>


commented by (1k points)
edited by

This is absolutely SOLID work! Thank you so much Greyelf! I had never even HEARD OF the Range possibility, until now, that is.

Functionally the only difference I saw between the 2 was that one generated an extra space in the output. Both work very well. I went with the following (and added a capture) which also adds it to inventory.

<<if $bookInventory.length == 0>>The pages of this magical book are empty
		<<set _titles to Story.lookup("tags", "book").map(function (book){ return book.title; })>>
		<<for _title range _titles>>
				<<capture _title>>
				<<linkreplace "Accept _title" `passage()`>><<addToBookInv _title>>You now have <<bookInvWithLinks>><</linkreplace>>

<<else>>You are carrying:


<<link `"Close the book" ` $currentRoom>><</link>>

For those who are interested in the complete system, it's a thing of beauty, really.

What it is is a very complete inventory system that even charges your character money. It began with this set up from F2Andy, which was then modified by TheMadExile (in many places actually but the one I refer to now is here (shown above as the linkreplace with backticks)) and then by adding Greyelf's answer (the one you see above) you have the complete workings of it. Well... there is also the last line that closes the room (also credit Greyelf) which is explained here.

And I would be remiss if I did not include the Sword generating widget from Chapel, here, though it doesn't show up in this section it generates items on the fly.

 The entire point of my question was so that by using passage tags (for example: gem, book, weapon, people--whatever) I don't have to chase down every passage where something occurred to then be pulled in by an <<include>>, as long as I have tagged it appropriately. It all just gets pulled in nicely in SugarCube. (with a few mods, explained earlier, I can also get it to work in Harlowe.)

Solid work everyone! SO GREAT!!

0 votes
answered by (55.4k points)
What, specifically, do you wish to accomplish?  You talk a lot about things you've tried, but not so much about what you really want.
commented by (1k points)


We can think of it like a kindle (eBook reader). If a passage is tagged "book" it has content in it that is lightly-formatted text.

When we open the "kindle" our list of books appears. We click one on the list, and the specific ebook opens and shows us our text.

The passages do not HAVE TO BE tagged as "book" of course. I can just use <<include>>.

But I can't imagine I am TOO FAR off base with the room tags.

Of course... I may be. I am the one asking for help, after all.

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.