Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

[Harlowe] Displaying Passage INLINE

Alright, so I'm very new to Twine but I'm starting to get it down. I try to steer clear of asking questions and scour the internet for my answer first. This particular problem is one I've been hunting down for about a solid week now so here I am.

I'm using an array for an inventory, and I'd like to have each item be clickable to open up a submenu within the inventory. At first I was using separate passages for each inventory item that held nothing but that item's submenu (and linking to a datamap defined earlier):

::Inventory::
(if: $inv's length > 0)[
You are currently carrying:
(print: $inv.join("\n"))[


(click: "Kaskade Multiband v3.7")[(display: "KMB")]
(click: "Passport Chip")[(display: "PassChip")]
(click: "Time Chip")[(display: "TimeChip")]
(click: "Sandgrain Pouch")[(display: "Sandgrain Pouch")]
(click: "Potion")[(display: "Potion")]
(click: "Transcript of email to mom")[(display: "XmasEmail")]

]]
(else:)[You have nothing of value.]

::PassChip::
(link: " Inspect")[\
	(print: $PassChip's description)]
(if: $multiband's isCarried is true)[\
	(link: " Install")[\
		(goto: "Passport Install")]]

This method works, but these submenus are displayed beneath ALL of the items in the array, and each subsequent submenu is displayed underneath the submenu above it. Not very organized. I assume it's because I am printing the array and defining the click links after the array is printed in full. So I tried a different approach. This time, I have a primary Inventory screen that begins a loop, and references yet another passage that contains the actual printed information. The idea being, I would print each value of the array separately, avoiding printing the whole array before the submenus can be called:

::Inventory::
(if: $inv's length > 0)[
You are currently carrying:
(set: $n to $inv's length)
(set: $count to 0)
(display: "InvCount")


]
(else:)[You have nothing of value.]
::InvCount::
(set: $count to it + 1)
(print: $inv's ($count))[\

(click: "Kaskade Multiband v3.7")[(display: "KMB")]\
(click: "Passport Chip")[(display: "PassChip")]\
(click: "Time Chip")[(display: "TimeChip")]\
(click: "Sandgrain Pouch")[(display: "Sandgrain Pouch")]\
(click: "Potion")[(display: "Potion")]\
(click: "Transcript of email to mom")[(display: "XmasEmail")]\
]
\\
(if: $count < $n)[(display: "InvCount")]
(else:)[]

The good news is that this works just as well, it seems. The bad news is that it works just as well...no better. Is there any way to code the passages inline so that each submenu displays directly below the line item from the inventory array?

Comments

  • Three quick points before I get to the actual solution:

    A. There are three main type of looping in Harlowe:

    1. Combining a Named Hook with a (live:) macro.
    2. Using the (subarray:) macro to process an array of (display:) macros.
    3. Recursive (display:) macros, although this method can lead to a nesting error.

    You are using type 3 and could end up with the nesting error if your list becomes too long.

    B. If you are trying to use Twee notation to identify your passage examples then the correct format of the passage name line should be either:
    If the Passage has no tags, note the space character between the :: and the Passage Name.
    
    :: The Passage Name
    
    If the Passage has tags, note the space character between the Passage Name and the open square bracket [
    
    :: The Passage Name [tag1 tag2 tag3]
    

    C. The solution assumes that the Submenu Passage Names for each of the items will be the item's name with " - Submenu" appended to the end.

    eg. The "Passport Chip" item will display a Passage named Passport Chip - Submenu

    Now for the solution!

    1. Your main Inventory passage would look something like the following:
    (if: $inv's length > 0)[\
    You are currently carrying:
    |inv>[]{
    
    (set: $index to 0)
    (live: 10ms)[
    	(set: $index to it + 1)
    	(set: $item to $inv's ($index))
    
    	<!-- Display the item using a dynamic generated link. -->
    	(append: ?inv)[{
    		(print: "(link: $item)[(display: '" + $item + " - Submenu')]<br>")
    	}]
    
    	(if: $index >= $inv's length)[(stop:)]
    ]}]\
    (else:)[You have nothing of value.]
    
    Note the usage of a (print:) macro to dynamically create the item's (link:), this is needed because the value of variables used within a link's/click's associated hook are not evaluated until after the link is clicked on which means that the value of $item in all the links associated hooks would equal the value of the last item in the $inv array.

    2. The structure of the code in each of the Submenu related passages would look similar to the following, which is an example of the Passport Chip - Submenu passage.
    Passport Chip
    |submenu>[\
    (link: " Inspect")[\
    	(print: $PassChip's description)]
    (if: $multiband's isCarried is true)[\
    	(link: " Install")[\
    		(goto: "Passport Install")]]\
    ]
    
    Note the usage of a Named Hook to distinguish the submenu output, this is done so that you can use CSS to style it. (eg. indent it.)

    3. CSS you can use to style the submenu, this goes in your story's Story Stylesheet area.
    tw-hook[name="submenu"] {
        margin-left: 2em;
        display: inline-block;
    }
    
  • This is excellent. Works perfectly as far as I can tell, thanks so much for the tips! This has had me stuck for a week!
Sign In or Register to comment.