Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Global timer for Sugarcube 2? My solution only increments once per passage

edited November 2015 in Help! with 2.0
Hi,

I have an idea that requires a global timer that continues counting up in the sidebar regardless of what passage you're in, and I'm having trouble implementing it.

I've tried using the <<timed>> macro to increment a numerical variable that gets stored in Twine's memory to stop the timer resetting with every passage load, but the problem is I can only seem to get it to increment once per passage. Is there a way I can loop this incrementation until the condition is met independently of passage navigation?

This is what I've got in my StoryCaption:
<<if $seconds lt 1000>>
<span id="time">$seconds</span>\
<<timed 1s>><<set $seconds to $seconds + 1>><<replace "#time">>$seconds<</replace>>\
<<next>><<set $seconds to $seconds + 1>><<replace "#time">>$seconds<</replace>>\
<</timed>>
<</if>>

It adds one to the $seconds variable every time a new passage is loaded. How do I make it keep running until $seconds reaches 1000?

Any assistance would be much appreciated.

Comments

  • Okay. Phew. I've kiiiind of managed to solve this by tweaking code from this thread.

    In the init file:
    <<set $seconds to 0>>
    

    Then in the StoryCaption:
    <<set $maxseconds to 1000>>
    
    Timer: <span id="timer">$seconds</span> seconds
    
    <<set $command to "<<timed 1s>>">>
    <<for $i to 0; $i lt $maxseconds; $i++>>
    	<<set $command += "<<set $seconds += 1>><<replace \"#timer\">>$seconds<</replace>><<next>>">>
    <</for>>
    
    <<set $command += "<<replace \"#timer\">>Time's up<</replace>><</timed>>">>
    <<print $command>>
    

    This creates a persistent global timer, which pauses during passage transition - this means it's not precisely real-time accurate, but that's what I wanted, since it means it doesn't penalise you for connection speed. It also, for some reason, counts up in increments of 2 on the first passage of the game, but I don't need it to start until later.

    I need to figure out how to turn this into a readable timestamp, but the functionality is there now.

  • First. You're using the wrong macro for what you're trying to do. You want the <<repeat>> macro, not the <<timed>> macro. The <<timed>> macro executes its contents once (by using <<next>> you've bumped that to twice), while the <<repeat>> macro repeatedly executes its contents.

    Second. You've got your <<if>> on the outside, when it should be on the inside. Are you trying to hide the timer display when $seconds reaches 1000, in addition to stopping the incrementation of $seconds?

    Third. As noted in their documentation, passage navigation terminates all pending timed executions for both <<timed>> and <<repeat>>. The only reason what you want to do will work at all is because most of the special passages which place content in the UI bar are run every turn by default (this includes StoryCaption)—thus, even though the previous invocation of <<repeat>> will be terminated when the player navigates to a new passage, placing it in StoryCaption will start a new one. That said, and while it will work, whenever a player navigates to a new passage a brief pause will occur (as the old timer is terminated and the new one is started), so you'd probably be better off using a global JavaScript timer rather than the <<repeat>> macro for this.

    For example, put something like the following in your Story JavaScript (story menu > Edit Story JavaScript):
    (function () {
    	setInterval(function () {
    		var sv = State.variables;
    		if (sv.seconds < sv.timeLimit) {
    			++sv.seconds;
    			$("#time").text(sv.seconds);
    		}
    	}, 1000);
    })();
    
    The JavaScript above won't clear or hide the timer display once the max timer value has been reached, so if you want it to do that too, let me know.

    Then, put something like the following in your StoryInit special passage:
    <<set
    	$timeLimit to 1000,
    	$seconds   to 0
    >>
    
    $timeLimit is the maximum timer value, so you don't have to muck with the JavaScript to change it.

    And finally, put something like the following in your StoryCaption special passage:
    <span id="time">$seconds</span>
    
  • edited November 2015
    This is enormously helpful, thank you - I ended up doing something quite a bit hackier before I saw this (but after I discovered the repeat macro!) to account for both minutes and seconds in the timer and a couple of conditions that need to be in place. I suspect your implementation is neater. Mine didn't involve Javascript.

    My eventual solution was this in the init file:
    <<set $humanhome to false>>
    <<set $timerstarted to false>>
    <<set $minutes to 9>>
    <<set $seconds to 59>>
    

    Then in the StoryCaption:
    <<if $humanhome is false, $timerstarted is true>>
    
    <span id="clock">Countdown: <span id="minutes">$minutes</span> minutes <span id="countdown">$seconds</span> seconds remaining!</span>\
    <<silently>>
    <<repeat 1s>>
    	<<set $seconds -= 1>>
    	<<if $seconds gte 1>>
    		<<replace "#countdown">>$seconds<</replace>>
    	<<elseif $seconds lte 1 and $minutes gt 0>>
    		<<set $seconds to 61>>
    		<<set $minutes -=1>>
    		<<if $minutes gte 0>>
    			<<replace "#minutes">>$minutes<</replace>>
    		<</if>>
    	<<else>>
    		<<replace "#clock">>Your human is home! 
    		<<if $humanhome is false>>
    		<<goto "Too Late">>
    		<</if>>
    		<<set $humanhome to true>>
    		<</replace>>
    		<<stop>>
    	<</if>>
    <</repeat>>
    <</silently>>
    <<elseif $humanhome is false, $timerstarted is false>>
    Your human has not left yet.
    <<else>>
    Your human is home!
    <</if>>
    

    This appears to work really well but I have my suspicions that stuff like having to set the seconds to 61 is indicative of lousy code on my part, but it was the only way I could get it to both cycle until $minutes hits zero, and display correctly.
Sign In or Register to comment.