How to History's (not) last?

Twine Version:Twine 2.10

Harlowe 3.3.9

Sorry its long, idk how to express myself.
Also trigger warning: Extreme mess, idk what i am doing but it somehow works? :sweat_smile:

Curently working on detective IF for my teenage scout kiddos for Halloween. Part of the game is online - MC is sending letters, player uncover a cypher in each of them.
To read the next letter and advance with the story the player has to input correct solution of the cypher into input box.

I run into very specific situation in this game and didnt find anyone asking this yet (correct me if someone did please!).
At certain points i offer hints to help solve mentioned cyphers, so players can proceed even if they aren’t able to get theere entierly themselves.
I have that fixed with “Append:?Sidebar” passage tags situation, where a lightbulb icon takes player to the passage “Hint”.

There they input a specific code (fe: Cypher 1 has code ABCD) and thru display macro i show them what they need to solve it (Cypher 1: Here are 2 different hints on how to solve that one!).

So far so good, but here is where it gets messy, so hold on to your hats.
In theory i want them to go right back to “history’s last’” passage - let’s name it Cypher 1 for this Q.
However if they make a mistake in the specific cypher code, they need to rerun the Hint passage and in that moment the last in the history is the Hint passage and the

(go-to: (history:)'s last))

became unusable, bc History’s last is no longer “Cypher 1” passage, but “Hint” instead.

Here is what i came with so far:

(if: (history:)'s last is not “Hint”)
[(set: $historylast to (history:)'s last) [(link-goto: “Go back where you came from”, $historylast)] ]

(else:)[ (link-goto: “Go back where you came from”, $historylast) ]

It works as far as i can tell, but i have no idea how and i know in my bones there is a better solution for what i need.
And i am also kinda worried what will happen if they visit the Hint passage more then once, i have 8 cyphers in total and i still didnt manage to test what will happen when they visit passage Hint from passages Cypher 1 and Cypher 2, 3, … as well.

I strongly susspect it could work better with counting the visits for passage “Hint” and then forgetting the amount of the visits, but it breaks my brain.

If you have any ideas how to make this more functional and less qoofy looking please let me know!
Thank you all for any and all ideas for this.

3 Likes

The How to know which Passage was being visited before a "menu" like Passage was transitioned to situation you’re describing is sometimes known as an Arbitrarily long return. And while the SugarCube based solution I’ve linked to won’t work as is in your Harlowe based project, the basic principles do have Harlowe equivalents.

1: Marking “menu” type child Passages so they can be distinguished from “normal” ones.

Assign a known Passage Tag (like noreturn or menu) to any Passage like your Hint named one that you want excluded when considering which “navigable” Passage to return to.

2: Tracking the last “navigable” Passage, so it can be returned to.

Harlowe automatically processes the contents of any Passage that has been assigned the special header Passage Tag before it processes the contents of the Passage being visited. This behaviour along with the following code can be used to conditionally save the Name of the visited Passage to a Story variable.

note: the Name of the header tagged Passage isn’t important, but it should reflect the purpose of that Passage. In my test case I named it Track Non-returnable Passages.

(set: _passage to (passage:))
(unless: _passage's tags contains 'noreturn')[
	(set: $return to _passage's name)
]

The above code does the following:

  • uses the (passage:) macro to gain access to a Datamap that contains information about the Passage being visited, like that Passage’s Name and what Passage Tags have been assigned to it.
  • uses the Array data-type’s contains operator to search the visited Passage’s assigned tags, to determine if it is a “menu” type Passage or not.
  • uses the (unless:) macro to gate the processing of the associated Hook, so that content is only processed when the condition is false.

3: Assign a default value to the tracking Story variable if the 1st Passage shown by the project is also a “menu” type Passage.

Harlowe automatically assigns the number Zero (0) to any variable that is referenced before the Author has assigned a value to it. This could potentially cause an issue if the 1st visited Passage is also a “menu” type one, because the condition being evaluated in the header tagged Passage would be true, thus the $return variable would potentially equal zero instead of the String based Name of a Passage.

In this situation code like the following should be added to the project’s startup tagged Passage, so that variable will be initialised when the project’s other main Story variables are.

(set: $return to "The name of a Navigable Passage")

4: Making use of the Passage Name being tracked in the variable.

Harlowe’s Markup based Links can have issues when a variable is used in the Target Passage Name of the link. For this reason one of the Macro based Links is a better choice.

<!-- If no additional code needs to be executed when the link is selected -->
(link-goto: "Return",  $return)

<!-- If additional code does need to be executed when the link is selected -->
(link-reveal-goto: "Return",  $return)[
    <!-- the additional code to execute before the target passed transitioned to -->
    (set: $variable to "value")
]

note: Obviously you can rename the tracking variable, the known Passage Tag being used to mark “menu” type passages, and the Name of the header tagged Passage to whatever makes sense to you & your project, as long as you apply those new names to all of the relevant places in the above examples.

3 Likes