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

In desperate need of a good way to deal with spell cooldowns

Good evening Roll20 !  As the title mentions it, I have been struggling with cooldowns for as long as I have been running my own custom game. The game is based on World of Warcraft and as a result, a specific combat system was built. Typically, fights last for 6 to 10 turns depending on how well the PCs succeed.  Yet, my issue lies in two specific points : I can't find a proper way to automatically update or keep track of cooldowns. I have tried to use another campaign to stock them there, I have tried with the turn order tool, but I don't find anything satisfying. How do you DMs or experienced players, handle combat cooldowns in between combat sequences. In the game I am running, Combat and RP are extremely separate phases and thus, I have no clue how to handle cooldown in between the two. Any general advice on how to effectively handle spell cooldowns or just convert cooldowns into an interesting RP mechanic would be loved in all due form. Boris.
1531348588
The Aaron
Pro
API Scripter
Well, the API has some nice scripts, but that requires a Pro subscription.  Can you describe your ideal flow, that might help us come up with something. 
The Aaron said: Well, the API has some nice scripts, but that requires a Pro subscription.  Can you describe your ideal flow, that might help us come up with something.  As of right now, I use a generic "Combat" character that has an "Current Turn" stat that I update at each new turn. In each spell's macro, the cool down is set as follows :{{Available=Turn [[@{Combat|Current Turn}+ X ]]}} X  being the cooldown of the spell. The turn tracker doesn't really help since I haven't found a way to properly add spell tokens inside the tracker automatically as that would require to select a spell token, then use the macro... Ideally, using a spell macro, would automatically send the spell into a list or tracker that would quickly allow me or the players to have access to the information :  Right now I am stuck with either over-complicating my experience (since I have 4 players, each using 3 to 4 spells per turn, not counting the enemies), or simply getting rid of cooldowns. I have considered getting a Pro subscription for a long time thought, would you care to explain how that could work ?
1531365214
The Aaron
Pro
API Scripter
So a few things that might help at plus: You can add a custom turn to the tracker by clicking the Gear icon. You can set an initial value and a simple formula to apply each time the turn comes up. You could add one named Combat Turn with an initial value of 1 and a formula of +1. You now have an automated counter.  That doesnt help by itself, but you can reference it with the special name tracker: @{tracker|Combat Turn} will ave the value of the Combat Turn and can be used to calculate the round an ability will be available again.  With the API, you can basically do the same thing, but have a custom turn for each ability get addedi to the turn order easily with a countdown to availability.   That’s just with “off the shelf” scripts. If you know some JavaScript, you could get even more fancy. I once saw a script where they had recreated a wall clock time cooldoen system similat to a Final Fantasy type thing. 
The Aaron said: So a few things that might help at plus: You can add a custom turn to the tracker by clicking the Gear icon. You can set an initial value and a simple formula to apply each time the turn comes up. You could add one named Combat Turn with an initial value of 1 and a formula of +1. You now have an automated counter. I tend to use a similar method as above. I just add a turn into the tracker with a simple formula (usually set up with a starting number e.g. 10 or whatever the duration is and subtracting 1 each round) and move it in the turn order to be under the person using the skill, affected by debuff, etc., although it is generally only used in situations where rounds and initiative matter, not where durations last for hours or days. I am finding that as much as it can be handy having a lot of things automated, keeping it simple tends to work best for me.
The Aaron said: So a few things that might help at plus: You can add a custom turn to the tracker by clicking the Gear icon. You can set an initial value and a simple formula to apply each time the turn comes up. You could add one named Combat Turn with an initial value of 1 and a formula of +1. You now have an automated counter.  That doesnt help by itself, but you can reference it with the special name tracker: @{tracker|Combat Turn} will ave the value of the Combat Turn and can be used to calculate the round an ability will be available again.  With the API, you can basically do the same thing, but have a custom turn for each ability get addedi to the turn order easily with a countdown to availability.   That’s just with “off the shelf” scripts. If you know some JavaScript, you could get even more fancy. I once saw a script where they had recreated a wall clock time cooldoen system similat to a Final Fantasy type thing.  Amazing ! That's one issue out of the way, thanks ! Would you know any way to generate the said "Combat Turn" tracker item with the +1 modifier through a macro ? Also, is it somewhat possible to add a value/item in the turn tracker without having to select the said token ? (e.g. through targeting) Again, many thanks for the great tips ! Martin M. said: The Aaron said: So a few things that might help at plus: You can add a custom turn to the tracker by clicking the Gear icon. You can set an initial value and a simple formula to apply each time the turn comes up. You could add one named Combat Turn with an initial value of 1 and a formula of +1. You now have an automated counter. I tend to use a similar method as above. I just add a turn into the tracker with a simple formula (usually set up with a starting number e.g. 10 or whatever the duration is and subtracting 1 each round) and move it in the turn order to be under the person using the skill, affected by debuff, etc., although it is generally only used in situations where rounds and initiative matter, not where durations last for hours or days. I am finding that as much as it can be handy having a lot of things automated, keeping it simple tends to work best for me. Yes, automation allows for a better focus on roleplaying and overall game enjoyment :D Would you know any way to add a spell token into the tracker (with a -1 modifier) without having to specifically select the spell token (e.g. through a character or general macro) ?
1531403525
The Aaron
Pro
API Scripter
I don't know if turn formulas work on tokens, I've only ever used them with custom turns.  There isn't a way in the interface to set one for a token, but you could certainly set the data for it with the API.  I'll have to try that. For adding custom turns, I have this script: on('ready',function(){ "use strict"; const checkFormulaOnTurn = () => { let to=JSON.parse(Campaign().get('turnorder')||'[]'); if(to.length && to[0].id==='-1'){ sendChat('',`[[${to[0].pr}+(${to[0].formula||0})]]`,(r)=>{ to[0].pr=r[0].inlinerolls[0].results.total; Campaign().set('turnorder',JSON.stringify(to)); }); } }; on('chat:message',function(msg){ var args,cmds,who,initial,change,entry; if('api' === msg.type) { if(msg.content.match(/^!act\b/) ){ who=(getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname'); if(_.has(msg,'inlinerolls')){ msg.content = _.chain(msg.inlinerolls) .reduce(function(m,v,k){ var ti=_.reduce(v.results.rolls,function(m2,v2){ if(_.has(v2,'table')){ m2.push(_.reduce(v2.results,function(m3,v3){ m3.push(v3.tableItem.name); return m3; },[]).join(', ')); } return m2; },[]).join(', '); m['$[['+k+']]']= (ti.length && ti) || v.results.total || 0; return m; },{}) .reduce(function(m,v,k){ return m.replace(k,v); },msg.content) .value(); } args = msg.content .replace(/<br\/>\n/g, ' ') .replace(/(\{\{(.*?)\}\})/g," $2 ") .split(/\s+--/); cmds=args.shift().split(/\s+/); change=parseFloat(cmds[1])||'+1'; change=`${/^[+-]\d/.test(change)?'':'+'}${change}`; initial=parseFloat(cmds[2])||0; entry=args.join(' '); if(entry.length){ let to=JSON.parse(Campaign().get('turnorder')||'[]'); to.unshift({ id: "-1", pr: initial, custom: entry, formula: change }); Campaign().set('turnorder',JSON.stringify(to)); if(!playerIsGM(msg.playerid)){ sendChat('ACT',`/w gm <div style="padding:1px 3px;border: 1px solid #8B4513;background: #eeffee; color: #8B4513; font-size: 80%;"><div style="background-color: #ffeeee;"><b>${who}</b> added entry for <b>${entry}</b> starting at <b>${initial}</b> and changing by <b>${change}</b>.</div></div>`); } } else { sendChat('ACT',`/w "${who}" <div style="padding:1px 3px;border: 1px solid #8B4513;background: #eeffee; color: #8B4513; font-size: 80%;"><div style="background-color: #ffeeee;">Use <b><pre>!act [formula] [starting value] --[description]</pre></b></div></div>`); } } else if(msg.content.match(/^!eot/i)){ _.defer(checkFormulaOnTurn); } } }); }); You call it like this: !act -1 10 --Bless on Bob, Nancy, and Sue And it will add a custom turn at the top of the turn order that starts at 10, subtracts 1 each time it comes up, and is named "Bless on Bob, Nancy, and Sue"
The Aaron said: I don't know if turn formulas work on tokens, I've only ever used them with custom turns.&nbsp; There isn't a way in the interface to set one for a token, but you could certainly set the data for it with the API.&nbsp; I'll have to try that. For adding custom turns, I have this script: on('ready',function(){ "use strict"; const checkFormulaOnTurn = () =&gt; { let to=JSON.parse(Campaign().get('turnorder')||'[]'); if(to.length &amp;&amp; to[0].id==='-1'){ sendChat('',`[[${to[0].pr}+(${to[0].formula||0})]]`,(r)=&gt;{ to[0].pr=r[0].inlinerolls[0].results.total; Campaign().set('turnorder',JSON.stringify(to)); }); } }; on('chat:message',function(msg){ var args,cmds,who,initial,change,entry; if('api' === msg.type) { if(msg.content.match(/^!act\b/) ){ who=(getObj('player',msg.playerid)||{get:()=&gt;'API'}).get('_displayname'); if(_.has(msg,'inlinerolls')){ msg.content = _.chain(msg.inlinerolls) .reduce(function(m,v,k){ var ti=_.reduce(v.results.rolls,function(m2,v2){ if(_.has(v2,'table')){ m2.push(_.reduce(v2.results,function(m3,v3){ m3.push(v3.tableItem.name); return m3; },[]).join(', ')); } return m2; },[]).join(', '); m['$[['+k+']]']= (ti.length &amp;&amp; ti) || v.results.total || 0; return m; },{}) .reduce(function(m,v,k){ return m.replace(k,v); },msg.content) .value(); } args = msg.content .replace(/&lt;br\/&gt;\n/g, ' ') .replace(/(\{\{(.*?)\}\})/g," $2 ") .split(/\s+--/); cmds=args.shift().split(/\s+/); change=parseFloat(cmds[1])||'+1'; change=`${/^[+-]\d/.test(change)?'':'+'}${change}`; initial=parseFloat(cmds[2])||0; entry=args.join(' '); if(entry.length){ let to=JSON.parse(Campaign().get('turnorder')||'[]'); to.unshift({ id: "-1", pr: initial, custom: entry, formula: change }); Campaign().set('turnorder',JSON.stringify(to)); if(!playerIsGM(msg.playerid)){ sendChat('ACT',`/w gm &lt;div style="padding:1px 3px;border: 1px solid #8B4513;background: #eeffee; color: #8B4513; font-size: 80%;"&gt;&lt;div style="background-color: #ffeeee;"&gt;&lt;b&gt;${who}&lt;/b&gt; added entry for &lt;b&gt;${entry}&lt;/b&gt; starting at &lt;b&gt;${initial}&lt;/b&gt; and changing by &lt;b&gt;${change}&lt;/b&gt;.&lt;/div&gt;&lt;/div&gt;`); } } else { sendChat('ACT',`/w "${who}" &lt;div style="padding:1px 3px;border: 1px solid #8B4513;background: #eeffee; color: #8B4513; font-size: 80%;"&gt;&lt;div style="background-color: #ffeeee;"&gt;Use &lt;b&gt;&lt;pre&gt;!act [formula] [starting value] --[description]&lt;/pre&gt;&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;`); } } else if(msg.content.match(/^!eot/i)){ _.defer(checkFormulaOnTurn); } } }); }); You call it like this: !act -1 10 --Bless on Bob, Nancy, and Sue And it will add a custom turn at the top of the turn order that starts at 10, subtracts 1 each time it comes up, and is named "Bless on Bob, Nancy, and Sue" This is genius work !&nbsp; It can and will handle my cooldowns very neatly. Though, do you know if there can be two different active turn tracker at the same time ? In&nbsp; the mean time, I found that sending an image representing the spell in chat through the macro also somewhat "helps"&nbsp; when the players need to know if this or that spell is available, they just scroll until they found the image which is much more visible than a line of text. Now the ultimate perfect goal would be to have the said image working with the command as for example :&nbsp; !act -1 10 -- [Coup de Pied Surpuissant du Buffle](<a href="http://wow.zamimg.com/images/wow/icons/large/ability_monk_mightyoxkick.jpg" rel="nofollow">http://wow.zamimg.com/images/wow/icons/large/ability_monk_mightyoxkick.jpg</a>) → Something that would display the picture alongside its cooldown, but I doubt it's possible :/ → Anyway, thanks a TONE, I'm just beginning to grasp the concept of the API ^^
1531404936
The Aaron
Pro
API Scripter
You can have a hundred custom turns if you want them. =D&nbsp;&nbsp; Extending this script to send images to chat when it reaches zero, or whole messages, etc. is definitely possible.&nbsp; I can probably help with that at some point.&nbsp; (today/tomorrow is pretty busy, but who knows...)
1531405940
Kirsty
Pro
Sheet Author
I'm not sure if this is exactly what you're looking for, but the TrackerJacker handles some of what you want. It doesn't put the effects in the turn tracker, but it does put a status marker on the token, with a number indicating number of rounds left. It also announces status effect on the token in the chat window:
Kirsty said: I'm not sure if this is exactly what you're looking for, but the TrackerJacker handles some of what you want. It doesn't put the effects in the turn tracker, but it does put a status marker on the token, with a number indicating number of rounds left. It also announces status effect on the token in the chat window: While this wouldn't help so much for cooldown, it certainly might be very useful to deal with damage over time or such effects, Thanks for the tip ! The Aaron said: You can have a hundred custom turns if you want them. =D&nbsp;&nbsp; Extending this script to send images to chat when it reaches zero, or whole messages, etc. is definitely possible.&nbsp; I can probably help with that at some point.&nbsp; (today/tomorrow is pretty busy, but who knows...) Sorry, I didn't mean custom turns, but turn trackers*. I don't know if two separate instances of turn tracker can be active at the same time. As for extending the script, you've already helped such a great deal that I cannot ask you to do such a thing :D
Aaron, awesome script, thank you!&nbsp; I like the idea of extending the functionality to push cooldown indicators to chat, to let folks know when conditions/effects/spells are ending.&nbsp; I'm going to try and fiddle around with trying to add some of that.&nbsp; Cool stuff!
1531424940
The Aaron
Pro
API Scripter
No worries.&nbsp; I'd like to do more in this scope, but haven't been able to prioritize it with other things going on. Feel free to ask me anything if you get stuck.
The Aaron said: No worries.&nbsp; I'd like to do more in this scope, but haven't been able to prioritize it with other things going on. Feel free to ask me anything if you get stuck. Well I have found the script you sent me earlier very useful, however, I wondered if it could be possible to make it so that when a custom turn object reaches 0 (a.k.a when the spell is ready, and cooldown over), it is automatically removed from the turn tracker. That would make life so much sweeter :D&nbsp;