0 votes
asked by (640 points)
edited by

Hello! I was wondering if it was possible to make a timer and keep it 'active' whilst switching passages (meaning it doesn't pause during a reload or passage switch). I have tried the following:

  // 'Active' passage:

    (if: $drp1 is >=1)[(live: 1s)[(set: $btc to it + $drp1)]]
    (if: $drp2 is >=1)[(live: 1s)[(set: $btc to it + ($drp2 * 10))]]
    (if: $drp3 is >=1)[(live: .75s)[(set: $btc to it + ($drp3 *13))]]

  // Timer passage 1:
    (display: "'Active' passage")

  // Timer passage 2:

    (display: "'Active' passage")

I am using Harlowe 2.1.0. 

I am using Twine 2.2.1 on Windows 10 (downloaded version).

2 Answers

0 votes
answered by (139k points)
selected by
Best answer

You can use the JavaScript setTimeout() function to create such a timer, it's what Harlowe's own (live:) macro uses internally.

However getting such a timer to execute a Harlowe macro (or and other engine functionallity) is difficult because this story format has been deliberately design to restrict the Author's access to it's JavaScript based engine.

What exactly do you want to do with such a timer?

commented by (640 points)
I am using this for a tycoon with droppers that run on certain intervals.

There is a 'click' function that adds 1 to the money ($btc). When it is clicked on, it goes to a passage called 'click', then is redirected to the main passage. I want the timer to keep going when the 'click' link is clicked on. Currently the timer resets itself on click.
commented by (139k points)

>  a tycoon with droppers that run on certain intervals.

I'm unsure what you mean be this statement.

> Currently the timer resets itself on click.

That's because the timers created by the (live:) macro are associacted with the current Passage being shown, which is why the timer is destroyed when a Passage Transition occurs.

Based on your example you are currently:

a. Starting between 0 and 3 (live:) macro timers, depending on the current value of three variables.

b. Each of these timers updates the same $btc story variable every X time units.

c. Once started each of those timers will keep updating that variable until the next Passage Transition occurs, because Harlowe doesn't include any other means for (externally) stopping a timer.

Is continuiously updating the $btc story variable every X time units for the rest of the Reader's play-through the functionality you want the permanent timer to perform?

Do you plan to give the Reader a means to stop the permanent timer?

warning: Active timers (like those created by the (live:) macro) interfere with the end-user's ability to interact with the page every time their associated code block (hook) is executed, the more often a timer fires or the more active timers there are, the more noticeable that interference is. This is why it is recomended to never have more than a single timer active at any one time.

commented by (640 points)

A tycoon with droppers that run on certain intervals:

A system that gives you points on certain intervals depending on the quantity.


A few notes:

1. The reader will not be able to stop the timers; they are permanent.

2. I do intend to continuously update the $btc variable. 

3. Is there an alternative to this system that will not cause user interference or lag? I do suppose so using JS but I am relatively inept at it.

commented by (139k points)

> Is there an alternative to this system that will not cause user interference or lag?

No, basically your web-browser can only do one (fore-ground) action at a time.
eg. Said actions include things like: Render the page; Accept User Input (mouse, keyboard, tap); Execute code associated with a timer thread; etc...

Harlowe is deliberately designed to restrict an Author's ability to use JavaScript to access the internal components of its engine, and it has no documented JavaScript API to do things like accessing/modifying the current value of a Story Variable. You would need to use a Scope Escalation Hack like the one included in this answer by @davemee to the How can I get live data from JavaScript into Twine/Harlowe variables? question to do something like that, and such a hack may stop working if the Harlowe Developer changes how the internals of the engine work.


0 votes
answered by (300 points)

Honestly, seeing your situation, I'd reccommend setting a short interval such that the lost time is negligible, and placing whatever timer code is running in the header. You could even set a separate variable timer for $drp3, since it operates off og .75s rather than 1s.

Here's my inefficient but usable solution:

(set:$Timer1 to it + 1)(set:$Timer75 to it + 1)
(if:$Timer75 is 75)[

(if: $drp3 is >=1)[(set: $btc += ($drp3 *13))]

(set:$Timer75 to 0)
(if:$Timer1 is 100)[

(if: $drp1 is >=1)[(set: $btc += $drp1)]
(if: $drp2 is >=1)[(set: $btc += ($drp2 * 10))]

(set:$Timer1 to 0)]

I hope this helps! If it needs more work, just ask! I'm around : )

commented by (139k points)
edited by


One major issue with your solution is that it interupts the end-user's ability to interact with the page 100 times a second, this may result in both a visible flicker as well as nothing happening when a link is selected.

A better solution would be to change the (live:) macro's delay to 0.25 (which is a divisor of both 1.0 and 0.75 seconds), and to have a single counter. You could then check if the current value of the counter is:

a. A multiplication of 3, in the case of the 0.75 second requirement.

b. A multiplication of 4, in the case of the 1.0 second requirement.

The following demostrates such a counter.

(set: $counter to 0)
(live: 0.25s)[{
	(set: $counter to it + 1)
	(if: $counter % 3 is 0)[
		(append: ?output1)[<br>another 0.75 seconds]
	(if: $counter % 4 is 0)[
		(append: ?output2)[<br>another 1.0 seconds]


commented by (640 points)

@ClariseTG The .01 second (live:) timer is really lagging the interface, so, in the case of a 1-second timer, it takes about 3-4 seconds for $btc to go up. I tried a .05 second timer, but the delay is noticable and still significantly lags the interface. I attempted to compensate by decreasing the timer delay, but I can't get it even close to exact.

(if: $drp1 is >=1)[(live: .05s)[(set: $drp1tmr to it +1)(if: $drp1tmr >14)[(set: $btc to it + $drp1)(set: $drp1tmr to 0)]]]
(if: $drp2 is >=1)[(live: .05s)[(set: $drp2tmr to it +1)(if: $drp2tmr >14)[(set: $btc to it + ($drp2 *10))(set: $drp2tmr to 0)]]]
(if: $drp3 is >=1)[(live: .05s)[(set: $drp3tmr to it +1)(if: $drp3tmr >9)[(set: $btc to it + ($drp3 *13))(set: $drp3tmr to 0)]]]
(if: $drp4 is >=1)[(live: .05s)[(set: $drp3tmr to it +1)(if: $drp3tmr >19)[(set: $btc to it + ($drp3 *20))(set: $drp3tmr to 0)]]]


commented by (640 points)

This worked.


There is still a notable amount of hesitation between passage switches, but other than that, it worked perfectly.

I edited the code a bit to suit my needs:

(set: $counter to 0)
(live: 0.25s)[{
	(set: $counter to it + 1)
	(if: $drp3 > 0)[(if: $counter % 3 is 0)[
		(append: ?output1)[(set: $btc to it + ($drp3 * 13))]
	(if: $drp1 > 0)[(if: $counter % 4 is 0)[
		(append: ?output2)[(set: $btc to it + $drp1)]
		(if: $drp2 > 0)[(if: $counter % 4 is 0)[
		(append: ?output2)[(set: $btc to it + ($drp2 * 5))]
		(if: $drp4 > 0)[(if: $counter % 4 is 0)[
		(append: ?output2)[(set: $btc to it + ($drp4 * 20))]


*ps. thanks for replying

commented by (139k points)


A couple of things:

1. I may of been unclear in my previous comment but the (append:) macro calls in my demostration were only there so you could see that the (if:) macros were working correctly, they can be removed for your implementation.

2. To futher reduce the amount of potential interference caused by a (live:) macro timer you want the code within it's associated hook to be as concise as possible, because while that code is being executed the end-user can't interact with the page.

3. [related to point 2] You are potentually doing the $counter % 4 is 0 check multiple times depending on the current value of the $drp1$drp2, & $drp4 story variables, which addes time to execution of the (live:) macro's associated hook.

The following is a modified version of your example.

(set: $counter to 0)
(live: 0.25s)[{
	(set: $counter to it + 1)
	(if: $counter % 3 is 0 and $drp3 > 0)[
		(set: $btc to it + ($drp3 * 13))
	(if: $counter % 4 is 0)[
		(if: $drp1 > 0)[
			(set: $btc to it + $drp1)
		(if: $drp2 > 0)[
			(set: $btc to it + ($drp2 * 5))
		(if: $drp4 > 0)[
			(set: $btc to it + ($drp4 * 20))


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.