Hi there. I’m writing a story that tracks has its own “time” that it tracks (essentially an integer variable between 0 and 23); the player will be able to jump around in the story’s time (i.e. what is displayed on a clock) at multiple points, but the story will also keep track of how much “time” has passed, and regular actions will add one increment to that time. To that end, I thought it would be useful to implement a custom “addTime” macro that will add to the time and change the clock at the same time.
To clarify - $rawTime is essentially military time, which is then later formatted using the $timeCalc macro to print an AM or PM, while $hoursAwake purely tracks how much “time” has elapsed since the beginning of the game (distinct from turns because I only want to add to this at certain points).
I set up a little rerunning link to check that everything is being formatted and interpreted correctly - however, every time I click the link, my addTime macro adds 2 to the $rawTime variable instead of one. I tested this in a normal link, a link with nothing else in the code hook, and simply by letting it run at the end of the passage - it always runs twice.
I also know it’s running twice because when I was troubleshooting, I attempted to fix my macro by changing the increment to 1/2 instead. This incremented by 1 appropriately, but when the rawTime “looped” (i.e. it reached 23 and was reset to 0), the next increment was 0.5 - indicating that the macro had run once, reset the time to 0, then run again and added 0.5. So yeah, it’s running twice for some reason.
Code below - excuse the horrible whitespace management - I was having trouble not getting line breaks to show up since I’m a newbie with custom macros.
(set: num-type $rawTime to 0, num-type $hoursAwake to 0)
\
\(set: $addTime to
(macro: [
\ (output:)
\ [(if: $rawTime < 23)
\ [(set: $rawTime to it + 1)]
\ (else-if: $rawTime is 23)
\ [(set: $rawTime to 0)]
\ (set: $hoursAwake to it + 1)
\ ]
\]))
\
\(set: $timeCalc to
(macro: [
\ (output:)
\ [(if: $rawTime is 0)
\ [(set: $formattedTime to "12 AM")]
\ (else-if: $rawTime <= 11)
\ [(set: $formattedTime to "$rawTime AM")]
\ (else-if: $rawTime is 12)
\ [(set: $formattedTime to "12 PM")]
\ (else-if: $rawTime > 12)
\ [(set: $formattedTime to (str: $rawTime % 12) + " PM")]
\ ]
\]))
\
[The raw time is $rawTime.]<rawTime|
[The clock reads $formattedTime.]<clockTime|
[You have been awake for $hoursAwake hours.]<hoursDisplay|
{(link-rerun: "Go forward an hour.")[
($addTime:)
($timeCalc:)
(t8n:"dissolve")(rerun: ?rawTime)
(t8n:"dissolve")(rerun: ?clockTime)
(t8n:"dissolve")(rerun: ?hoursDisplay)]
}
Huh. I made a $log variable to collect info and…yeah, that looks like a Harlowe bug to me: the macro hook runs only once, but the output hook runs twice. Seems like you can work around it by outputting nothing:
(set: $addTime to
(macro: [
(if: $rawTime < 23)
[(set: $rawTime to it + 1)]
(else-if: $rawTime is 23)
[(set: $rawTime to 0)]
(set: $hoursAwake to it + 1)
(output:)[]
]))
So I’m guessing it runs the output hook twice but only collects and displays the output once. I posted an issue to the Harlowe repository.
Another work-around: if your macro takes no inputs and only has output, no actual return value, then you can just make it a passage instead: call it addTime and then do (display: "addTime"). You should just be able to wrap the whole addTime passage in {} for whitespace management.
All this makes a ton of sense - thanks so much for the help! I also realized as I woke up this morning that I could simplify my code a ton by simply writing:
(set: $rawTime to (it + 1) % 24)
(set: $hoursAwake to it + 1)
So now my code is quite a bit better organized in multiple regards.
Actually Harlowe technically displays that output twice.
Harlowe’s Passage Transition process has a two phase rendering:
the first phase renders the HTML element structure generated by the ‘current’ Passage wrapped within a special parent container HTML element;
the 2nd phase removes that parent element (and all its children) from the page’s Document Object Model, then renders only the generated HTML element structure.
I was under the impression that the HTML elements generated for the ‘current’ Passage were temporary stored internally and then used for each of the two phases, otherwise all (set:) macros directly reference within the Passage would be executed twice. But I could be wrong, or that may not include the outputs of custom macros?
I tried to isolate it to just running the custom macro and displaying output, so it happens even without a Passage Transition involved. Though it’s still displaying, which might be a two phase thing also? Here’s the code I posted to the issue report: the custom macro hook only gets executed once but the output hook runs twice.
{(set: $macroLog to "", $outputLog to "")
(set: $test to
(macro: [
(set: $macroLog to it + "x")
(output:)[(set: $outputLog to it + "x")output
]
]))
}Macros: $macroLog
Output: $outputLog
(link: "test")[($test:)Macros: $macroLog
Output: $outputLog]