0 votes
by (250 points)

As an experiment, I've been trying to see if I can construct an exploding bomb with a countdown timer and a red wire/green wire choice that all takes place within a single passage.

Everything works, except that if you cut the red wire in the last second before the bomb explodes ... it still explodes. It momentarily displays the text 'Just in the nick of time', but then the counter hits zero and the bomb explodes anyway.

Here is the code:

[(set:$secondsleft to 10){(live: 1s)[(set:$secondsleft to it - 1)(if: $redwirecut is "yes")[(stop:)]]}The bomb timer reads (live: 0.5s)[$secondsleft]]<bombscenario|

[(link: "Cut the red wire")[(set: $redwirecut to "yes")(replace: ?greenwireoption)[](replace: ?redwireoption)[Just in the nick of time!]]]<redwireoption|
[(link: "Cut the green wire")[(replace: ?bombscenario)[BOOOOM](replace: ?greenwireoption)[](replace: ?redwireoption)[]]]<greenwireoption|

(live: 1s)[(if: $secondsleft is 0)[(replace: ?bombscenario)[BOOOOM](replace: ?greenwireoption)[](replace: ?redwireoption)[]]]

The 'Just in the nick of time' text should display in the same instant that the countdown stops, so I'm not sure what's going wrong.

2 Answers

+1 vote
by (1.6k points)

Quick fix: modify your first (live) timer to with an if/else structure as follows:

(live: 1s)[(if: $redwirecut is "yes")[(stop:)](else:)[(set:$secondsleft to it - 1)]

It was was correctly checking for the redwirecut and stopping to timer, but would decrement $secondsleft on that same update and count down one extra second, potentially reaching zero. 

+2 votes
by (159k points)

First a little background about (live:), (stop:), and timer threads:

a. Each (live:) macro creates it's own timer thread, so your example has three of these threads.
b. A Timer thread will keep firing (and executing the attached code) every X time-period until either: a passage traversal occurs; or a (stop:) macro is executed.
c. The (stop:) macro only effects the (live:) macro who's body it is contained within, so it only stops a single timer thread.
d. When a Timer thread fires it briefly interrupts the Reader's ability to interact with the page (eg. click on links), and the shorter the time-period passed to the (live:) macro the more often that interruption occurs.

Your example has three (live:) macros so there are three timer threads interrupting the Reader, two occurring every second and one occurring every half-second. This is why generally in game design only a single timer thread is used to handle basic game logic.

The following example uses a single (live:) macro to achieve the effect you desire.

(set: $seconds to 10)
(set: $wirecut to false)
|message>[The bomb timer reads [$seconds]<seconds|]

(link: "Cut the red wire")[
	(set: $wirecut to true)
	(replace: ?links)[]
	(replace: ?message)[Just in the nick of time!]
(link: "Cut the green wire")[
	(set: $wirecut to true)
	(replace: ?links)[]
	(replace: ?message)[BOOOOM]
(live: 1s)[
	(if: $wirecut)[
		(set: $seconds to it - 1)
		(if: $seconds is 0)[
			(replace: ?links)[]
			(replace: ?message)[BOOOOM]
			(replace: ?seconds)[$seconds]

... it uses a Boolean variable ($wirecut) to track if any wire has been cut and it checks that variable to determine if the timer thread should be stopped.

NOTE: You can place CSS like the following in your story's Story Stylesheet area to hide all the extra white space generated by the code contained within the workarea named hook.

tw-hook[name="workarea"] {
	display: none;