If it's this one, I think I cleaned it up a bit at one point. After naming a token "hourglass" you should be able to run something like: !hg start 90 Code: //////////
// Hourglass Tabletop Timer
// By Déja Augustine (a.k.a. Kertész)
//
// How to Use
// 1. Add a token to the board with "hourglass" in the nameplate
// 2. Use one of the !hg commands below to get things rolling
//
// Start timer:
// !hg start <seconds>
// !hg start <minutes>:<seconds>
// !hg start <hours>:<minutes>:<seconds>
//
// Add to timer:
// !hg add <seconds>
// !hg add <minutes>:<seconds>
// !hg add <hours>:<minutes>:<seconds>
//
// Subtract from timer:
// !hg subtract <seconds>
// !hg subtract <minutes>:<seconds>
// !hg subtract <hours>:<minutes>:<seconds>
// or
// !hg sub <seconds>
// !hg sub <minutes>:<seconds>
// !hg sub <hours>:<minutes>:<seconds>
//
//
// Pause timer:
// !hg pause
//
// Resume paused timer:
// !hg start
//
// Stop timer:
// !hg stop
//
//////////
on('ready',()=>{
let hourglass = {
duration: 0,
interval: 0,
remaining: 0,
paused: true,
timeout: 0,
who: "gm"
};
const setBars = function(obj, seconds, change={}) {
change.bar1_value = (seconds / 3600);
seconds = seconds % 3600;
change.bar2_value = (seconds / 60);
seconds = seconds % 60;
change.bar3_value = (seconds);
obj.set(change);
};
const resetHourglass = function(obj) {
obj.set({
status_dead: true,
rotation: 0
});
};
const updateHourglass = function(obj) {
setBars(
obj,
hourglass.remaining,
{
rotation: Math.abs(hourglass.remaining % 360)
}
);
};
const tick = function(obj) {
hourglass.remaining -= 1;
if(hourglass.remaining <= 0) {
stopHourglass();
resetHourglass(obj);
} else {
updateHourglass(obj);
}
};
const timesUp = function(obj) {
hourglass.remaining = 0;
stopHourglass();
resetHourglass(obj);
setBars(obj, 0);
};
const stopHourglass = function() {
hourglass.paused = true;
clearInterval(hourglass.interval);
clearTimeout(hourglass.timeout);
};
const startHourglass = function(obj, timeparts) {
if (hourglass.paused === true) {
if (hourglass.remaining <= 0) {
const seconds = parseInt(timeparts[0]) || 0;
const minutes = parseInt(timeparts[1]) || 0;
const hours = parseInt(timeparts[2]) || 0;
obj.set({
bar1_max: (hours>0) ? hours : '',
bar2_max: (hours>0) ? 60 : ((minutes>0) ? minutes : ''),
bar3_max: 60
});
printMessage("<p>New Hourglass:</p><ul><li>Hours: " + hours + "</li><li>Minutes: " + minutes + "</li><li>Seconds: " + seconds + "</li></ul>", false);
hourglass.remaining = hours * 3600 + minutes * 60 + seconds;
}
resetHourglass(obj);
obj.set("status_dead",false);
updateHourglass(obj);
hourglass.interval = setInterval(() => tick(obj), 1000);
hourglass.timeout = setTimeout(() => timesUp(obj), 1000 * hourglass.remaining);
hourglass.paused = false;
}
};
const printMessage = function(msg, hide=true) {
sendChat("Hourglass", "/w " + hourglass.who + " " + msg, null, {noarchive:hide});
};
const printUsage = function(errorMsg="") {
const msg = errorMsg.length > 0 ? "<p style='color: red;'>" + errorMsg + "</p>" : "";
printMessage(msg + "<p>Add a token to the map with <strong>Hourglass</strong> as the nameplate, then...</p><p><strong>!hg start HH:MM:SS</strong> to start the timer (hours and minutes are optional)</p><p><strong>!hg pause</strong> to pause the timer</p><p><strong>!hg stop</strong> to stop and reset the timer</p><p><strong>!hg add HH:MM:SS</strong> to add to the timer.</p><p><strong>!hg sub HH:MM:SS</strong> to subract from the timer.</p><p><strong>!hg help</strong> to display this message again.");
};
const parseCommand = function(msg) {
if(msg.type !== 'api') {
return;
}
var argv = msg.content.toLowerCase().split(' ');
var cmd = argv.shift();
if(cmd === "!hg") {
cmd = argv.shift();
var obj = findObjs({_type: "graphic", name: "hourglass"}, {caseInsensitive: true})[0];
if(obj === undefined) {
printUsage("Unable to find a token named <strong>Hourglass<strong>");
return;
}
switch(cmd) {
case 'start':
if (hourglass.paused === true) {
if (hourglass.remaining <= 0) {
let time = argv.shift();
if (time === undefined) {
printUsage(`You must provide a duration to the <strong>${cmd}</strong> command`);
break;
}
let timeparts = time.split(/:/).reverse();
startHourglass(obj, timeparts);
} else {
startHourglass(obj);
}
}
break;
case 'add': {
let time = argv.shift();
if (time === undefined) {
printUsage(`You must provide a duration to the <strong>${cmd}</strong> command`);
break;
}
hourglass.remaining += time.split(/:/).reduce((m,v)=>m*60+(parseInt(v)||0),0);
clearTimeout(hourglass.timeout);
hourglass.timeout = setTimeout(() => timesUp(obj), 1000 * hourglass.remaining);
}
break;
case 'sub':
case 'subtract': {
let time = argv.shift();
if (time === undefined) {
printUsage(`You must provide a duration to the <strong>${cmd}</strong> command`);
break;
}
hourglass.remaining -= time.split(/:/).reduce((m,v)=>m*60+(parseInt(v)||0),0);
clearTimeout(hourglass.timeout);
hourglass.timeout = setTimeout(() => timesUp(obj), 1000 * hourglass.remaining);
}
break;
case 'pause':
printMessage("Pausing Hourglass (Remaining Duration: " + hourglass.remaining + " seconds)", false);
stopHourglass();
break;
case 'stop':
printMessage("Stopping Hourglass (Remaining Duration: " + hourglass.remaining + " seconds)", false);
timesUp(obj);
break;
case 'help':
printUsage();
break;
default:
printUsage(cmd + " is an unrecognized command");
break;
}
}
};
on("chat:message", parseCommand);
});