Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Turn Clock

1490797372
Bast L.
Pro
API Scripter
Heya. My friend was mentioning that in his D&D game, players took too long on their turns, and so, just for fun, I made this turn clock script. I don't really know javascript at all, and just mangled this together from other code. Hopefully it'll work for you. Also, the "!Sound: Ticking Clock" and&nbsp;"!Sound: Buzzer" utilize the sound effect script I run (mangled together from someone else's sound effect script). Replace those lines with whatever you use for sound effects calls, or just remove them.&nbsp; To activate the clock, I select a token, and click the macro (on my bar) which has the body: !Clock 6 I think it won't work if you changed the macro to !Clock 10 or higher. It works by setting the stopwatch token status marker to true, and with a value (6 in this case, but anything 1-9 should work), it then begins playing a sound (I use a ticking clock), while updating the status marker to the time remaining, so 6, 5, 4, 3, 2, 1. Then it removes the status marker and plays the buzzer sound, indicating that the player has exceeded his or her allotted turn time. One bug: it sometimes, though not often, will skip an update, and then update twice the next time. So, for example, it might get to 5, wait 2 seconds, and then show a 3, with 4 never displaying. Maybe this sleep method is bad. I just copied it from a stackoverflow post. Not very useful, but maybe kinda fun :) Here's the Gist:&nbsp; <a href="https://gist.github.com/anonymous/0ae7edce088c5d4b" rel="nofollow">https://gist.github.com/anonymous/0ae7edce088c5d4b</a>... And here's some screenshots:
1490799324
Bast L.
Pro
API Scripter
Small update to make it also report to the chat that the clock has started on the character, the time remaining, and when the turn is over: <a href="https://gist.github.com/anonymous/ffecc4c44faef74f" rel="nofollow">https://gist.github.com/anonymous/ffecc4c44faef74f</a>...
That´s really cool!
1490803386
Bast L.
Pro
API Scripter
Thanks :) In case anyone needs the sound effects script, I slightly modified Joshua R's script from this post:&nbsp; <a href="https://app.roll20.net/forum/post/2459136/slug%7D" rel="nofollow">https://app.roll20.net/forum/post/2459136/slug%7D</a> Here's mine:&nbsp; <a href="https://gist.github.com/anonymous/41fe1b2e58e19f3c" rel="nofollow">https://gist.github.com/anonymous/41fe1b2e58e19f3c</a>... I removed most of the sounds, so as to not clutter the script. Just add them as needed. You'll also need to add tracks with matching names to your jukebox in the game.
1490806372

Edited 1490806709
The Aaron
Pro
API Scripter
That sleep code is certainly valid, though probably a bit overkill for this. &nbsp;One thing you can do to avoid the skipped number is to update more frequently, which requires a slight shift in the way you handle things. &nbsp;Instead of counting up, you store the time that you will be done, then on each iteration you calculate how long until you are done and update each token. &nbsp;That allows you to run the update more times than you need to count, and always set the right number. Just for reference, here's how I might rewrite this to do the updates more frequently: on("ready", function() { &nbsp; &nbsp; "use strict"; &nbsp; &nbsp; on("chat:message", function (msg) { &nbsp; &nbsp; &nbsp; &nbsp; var args; &nbsp; &nbsp; &nbsp; &nbsp; if (msg.type === "api"){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; args = msg.content.split(/\s+/); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (args[0].match(/^!clock/i)){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let time = parseInt(args[1],10)||0, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tokens = _.chain(msg.selected) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map((o)=&gt;getObj('graphic',o._id)) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .reject(_.isUndefined) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .value(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(time){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let due = _.now()+time*1000, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; updateClock = ()=&gt;{ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let num=Math.ceil((due-_.now())/1000); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(num&gt;0){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _.map(tokens,(t)=&gt;t.set('status_stopwatch',num)); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _.delay(updateClock,200); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _.map(tokens,(t)=&gt;t.set('status_stopwatch',false)); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat("TurnClock", "!Sound: Buzzer"); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat("TurnClock", "!Sound: Ticking Clock"); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; updateClock(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; }); });
1490808964
Bast L.
Pro
API Scripter
Thanks, that works. I added the code to also post to chat about the clock running. I've got to learn regular expressions someday.&nbsp; Updated
1490809672
The Aaron
Pro
API Scripter
Ah, that's only going to output the name of the last token selected, how about: on("ready", function() { &nbsp; &nbsp; "use strict"; &nbsp; &nbsp; on("chat:message", function (msg) { &nbsp; &nbsp; &nbsp; &nbsp; var args; &nbsp; &nbsp; &nbsp; &nbsp; if (msg.type === "api"){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; args = msg.content.split(/\s+/); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (args[0].match(/^!Clock/i)){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let time = parseInt(args[1],10)||0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(time){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let due = _.now()+time*1000, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tokens = _.chain(msg.selected) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map((o)=&gt;getObj('graphic',o._id)) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .reject(_.isUndefined) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .value(), &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; names = _.map(tokens,(t)=&gt;t.get('name')), &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; numCheck, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; updateClock = ()=&gt;{ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let num=Math.ceil((due-_.now())/1000); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(num&gt;0){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _.map(tokens,(t)=&gt;t.set('status_stopwatch',num)); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (numCheck !== num){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat("", "Turn Time Remaining: " + num); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; numCheck = num; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _.delay(updateClock,200); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _.map(tokens,(t)=&gt;t.set('status_stopwatch',false)); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat("TurnClock", "!Sound: Buzzer"); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat("", "Turn Over!"); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat("TurnClock", "!Sound: Ticking Clock"); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendChat("", "TurnClock Started on: " + names.join(', ')); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; updateClock(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; }); });
1490813535
Bast L.
Pro
API Scripter
That did it.&nbsp;