0 votes
by (250 points)

Hello. As per my previous question, 'Can I have a cycling link that also changes another variable?' I've been exploring ways to create cycling links in Harlowe without using the hack or any js.

What I've come up with seems to work, but before I go round giddily implementing it left, right and center, I wanted to check if this is ill-advised and will create unforeseen problems.

Essentially, wherever I want the cycling link to appear, I have told the page to display a separate passage:

(display: "cycling link 1")

In this separate passage, 'cycling link 1', I have the following code:

(if: $conv is 0)[(link: "I agree")[(set:$conv to 1)(display: "cycling link 1")]](if: $conv is 1)[(link: "I disagree")[(set:$conv to 0)(display: "cycling link 1")]]

Essentially what's happening is that whenever you click on the link, it disappears, changes the variable and then re-displays the same passage. The re-displayed passage will now display different text because the variable has changed.

This allows me to use the cycling link to change different variables at the same time:

(if: $conv is 0)[(link: "I agree")[(set:$conv to 1)(set:$clicks to it + 1)(display: "cycling link 1")]](if: $conv is 1)[(link: "I disagree")[(set:$conv to 0)(set:$clicks to it + 1)(display: "cycling link 1")]]

So now, in addition to cycling, every time you click the link it adds 1 to the $clicks variable.

My plan/hope is to use this to create a system where a player has to cycle through all the options before they move forward in the story.  Is there something foolish about this set-up that I'm not seeing?

1 Answer

+2 votes
by (159k points)

Your solution is using Passage Recursion to simulate a cycleing link, this causes the HTML structure of each iteration to be nested/embedded within the content of the previous iteration, and there is a limit to the maximum depth that nesting can become before the web-browser throws an error.

eg. The structure when showing the link the first time.

<tw-expression type="macro" name="display">
	<tw-expression type="macro" name="if"></tw-expression>
	<tw-hook>
		<tw-expression type="macro" name="link"></tw-expression>
		<tw-hook>
			<tw-link tabindex="0" data-raw="">I agree</tw-link>
		</tw-hook>
	</tw-hook>
	<tw-expression type="macro" name="if" class="false"></tw-expression>
	<tw-hook></tw-hook>
</tw-expression>

The structure when showing the link the second time.

<tw-expression type="macro" name="display">
	<tw-expression type="macro" name="if"></tw-expression>
	<tw-hook>
		<tw-expression type="macro" name="link"></tw-expression>
		<tw-hook>
			<tw-expression type="macro" name="set"></tw-expression>
			<tw-expression type="macro" name="display">
				<tw-expression type="macro" name="if" class="false"></tw-expression>
				<tw-hook></tw-hook>
				<tw-expression type="macro" name="if"></tw-expression>
				<tw-hook>
					<tw-expression type="macro" name="link"></tw-expression>
					<tw-hook>
						<tw-link tabindex="0" data-raw="">I disagree</tw-link>
					</tw-hook>
				</tw-hook>
			</tw-expression>
		</tw-hook>
	</tw-hook>
	<tw-expression type="macro" name="if" class="false"></tw-expression>
	<tw-hook></tw-hook>
</tw-expression>

... if you notice, the structure where the tw-link element is show will increase in depth each time the link is selected. You can use a named hook combined with a (replace:) macro to get around this issue.

 

The following prototype show how to use the named hook method, it also shows how to use known variables names to: store the list of options to cycle ($cyclingOptions); and to indicate which story variable to store the selected item in.

1. The passage to show the cycling link in:

{
<!-- Initialise the story variable the cycling link will use to store the current selected option in. -->
(set: $selected to "")

<!-- Setup the list of option and the name of the story variable to use. -->
(set: $cyclingOptions to (array: "I agree", "I disagree"))\
(set: $cyclingVariable to "selected")
}\
[(display: "CyclingLink")]<cyclingLinks|

2. The contents of the CyclingLink passage:

(print: "(set: $" + $cyclingVariable + " to '" + ($cyclingOptions's 1st) + "')")\
(link: $selected)[\
	(set: $cyclingOptions to $cyclingOptions's (range: 2, $cyclingOptions's length) + (array: $selected))
	(replace: ?cyclingLinks)[(display: "CyclingLink")]
]

... the above uses a (print:) macro to dynamically update the indicated story variable with the current option, it also uses a (set:) macro within the body of the (link:) macro reorder the options array so that the last shown option is moved to the end of the options array.

by (250 points)

Many thanks for this, greyelf. Named hook solution works perfectly, as far as I can tell. Haven't tried the array yet - one step at a time!

I suppose the disadvantage of the array is that it would be harder to add other variables into the mix quite as flexibly. By that I mean, suppose the game was counting the number of times you set a cycling link to "I agree". With my above code I could use:

(if: $conv is 0)[(link: "I agree")[(set:$conv to 1)(set:$agreements to it + 1)(replace: ?cyclingLinks)[(display: "CyclingLink")]]](if: $conv is 1)[(link: "I disagree")[(set:$conv to 0)(set:$agreements to it - 1)(replace: ?cyclingLinks)[(display: "CyclingLink")]]]

At a later point I can simply check the variable $agreements to see how many previous statements the player agreed to.

...