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

Concentration crashing

1661198169
Surok
Roll20 Production Team
Every time I change the hp on a concentrating token it crashes the API.
1661214290
Oosh
Sheet Author
API Scripter
Which script are you using to mark Concentration?
1661273279
Surok
Roll20 Production Team
Oosh said: Which script are you using to mark Concentration? Concentration. I get the crash with only running the concentration script.
What other API's are you using? I know I had to combine two scripts together recently. One of the Concentration  scripts and the Auto Bloody and Kill script.
Surok said: Oosh said: Which script are you using to mark Concentration? Concentration. I get the crash with only running the concentration script. There is more than one Concentration script. 
1661307567

Edited 1661307803
Oosh
Sheet Author
API Scripter
Assuming it's the one-click Concentration script, try turning off auto-roll. If that stops the crash, what's the link when you mouse over the 'Roll' button it posts to chat?
1661354157
Surok
Roll20 Production Team
Jarren said: Surok said: Oosh said: Which script are you using to mark Concentration? Concentration. I get the crash with only running the concentration script. There is more than one Concentration script. 
1661357621
Surok
Roll20 Production Team
Ok I found out what happened. Apparently my player toggled/checked the constitution proficiency (honest mistake) but he didn't have that because of his class. Does the API check whether or not you are supposed to have constitution proficiency? If so then that's pretty neat.
1661752201
Victor B.
Pro
Sheet Author
API Scripter
Concentration is a dead script not supported for years
1661814056
Surok
Roll20 Production Team
Victor B. said: Concentration is a dead script not supported for years Well it seems to work good enough. What are people using instead?
If the constitution saving throw bonus is 10 or higher the script crashes. Hope this helps resolves the issue.
1661916492
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Surok said: Victor B. said: Concentration is a dead script not supported for years Well it seems to work good enough. What are people using instead? I use this very simple script from this thread .
1661933019
Oosh
Sheet Author
API Scripter
Seb said: If the constitution saving throw bonus is 10 or higher the script crashes. Hope this helps resolves the issue. Ah, nice sleuthing! It's not specifically a value of 10, it's a modified DC that becomes negative crashing the script, due to the critical fail and critical success targets. The dice parser does not like negative numbers in there. So a modifier of 12 will crash a standard concentration check with a DC of 10, but if you smack the target for 60 damage, the DC will be high enough that the 12 modifier will no longer wreck the roll expression. If I get around to it, I'll put up a fix.
1661955774

Edited 1661955895
Surok
Roll20 Production Team
Oosh said: Seb said: If the constitution saving throw bonus is 10 or higher the script crashes. Hope this helps resolves the issue. Ah, nice sleuthing! It's not specifically a value of 10, it's a modified DC that becomes negative crashing the script, due to the critical fail and critical success targets. The dice parser does not like negative numbers in there. So a modifier of 12 will crash a standard concentration check with a DC of 10, but if you smack the target for 60 damage, the DC will be high enough that the 12 modifier will no longer wreck the roll expression. If I get around to it, I'll put up a fix. Ah that makes total sense now because prior when the prof bonus for Con was checked it was pushing it over 10.
1663046718

Edited 1663048184
Victor B.
Pro
Sheet Author
API Scripter
If you are supporting it and have given support to the new icon sets, more power to you.  The original dev hasn't been around for years.  It hasn't supported different icon sets.  Maybe you have fixed that.  The script is clunky, but probably better than nothing.  Combat Master has that script updated and built in.  It auto-detects concentration spells.  Applies the concentration marker to the caster, enables selecting multple tokens that the spell has an affect on.  Tracks the duration of that spell on the affected tokens and caster.  The logic isn't perfect, because I haven't had time to make it simple, but it works.  
1663055556

Edited 1663056223
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
I believe that someone has updated that old script in at least one thread in the last month. EDIT: Jarren has a bunch of links here . Combat Master is super powerful, but does way more than I need. I posted a scriptlet I use in one of those links, and there are instructions on how to get the token marker full name.
1663063525

Edited 1663064053
I have a working well version of that script though I made a few translations in French.&nbsp; I'll post it once at home EDIT : Actually copied it from my mobile... It's the Robin's concentration script that has been reworked and tweaked by a few other users (such as The Aaron or David M...) /* * Version 0.1.16 * Made By Robin Kuiper * Skype: RobinKuiper.eu * Discord: Atheos#1095 * My Discord Server: <a href="https://discord.gg/AcC9VME" rel="nofollow">https://discord.gg/AcC9VME</a> * Roll20: <a href="https://app.roll20.net/users/1226016/robin" rel="nofollow">https://app.roll20.net/users/1226016/robin</a> * Roll20 Wiki: <a href="https://wiki.roll20.net/Script:Concentration" rel="nofollow">https://wiki.roll20.net/Script:Concentration</a> * Roll20 Thread: <a href="https://app.roll20.net/forum/post/6364317/script-concentration/?pageforid=6364317#post-6364317" rel="nofollow">https://app.roll20.net/forum/post/6364317/script-concentration/?pageforid=6364317#post-6364317</a> * Github: <a href="https://github.com/RobinKuiper/Roll20APIScripts" rel="nofollow">https://github.com/RobinKuiper/Roll20APIScripts</a> * Reddit: <a href="https://www.reddit.com/user/robinkuiper/" rel="nofollow">https://www.reddit.com/user/robinkuiper/</a> * Patreon: <a href="https://patreon.com/robinkuiper" rel="nofollow">https://patreon.com/robinkuiper</a> * Paypal.me: <a href="https://www.paypal.me/robinkuiper" rel="nofollow">https://www.paypal.me/robinkuiper</a> */ var Concentration = Concentration || (function() { 'use strict'; let checked = []; // Styling for the chat responses. const styles = { reset: 'padding: 0; margin: 0;', menu: 'background-color: #fff; border: 1px solid #000; padding: 5px; border-radius: 5px;', button: 'background-color: #000; border: 1px solid #292929; border-radius: 3px; padding: 5px; color: #fff; text-align: center;', textButton: 'background-color: transparent; border: none; padding: 0; color: #000; text-decoration: underline', list: 'list-style: none;', float: { right: 'float: right;', left: 'float: left;' }, overflow: 'overflow: hidden;', fullWidth: 'width: 100%;' }, script_name = 'Concentration', state_name = 'CONCENTRATION', markers = ['concentré::4012467', 'blue', 'brown', 'green', 'pink', 'purple', 'red', 'yellow', '-', 'all-for-one', 'angel-outfit', 'archery-target', 'arrowed', 'aura', 'back-pain', 'black-flag', 'bleeding-eye', 'bolt-shield', 'broken-heart', 'broken-shield', 'broken-skull', 'chained-heart', 'chemical-bolt', 'cobweb', 'dead', 'death-zone', 'drink-me', 'edge-crack', 'fishing-net', 'fist', 'fluffy-wing', 'flying-flag', 'frozen-orb', 'grab', 'grenade', 'half-haze', 'half-heart', 'interdiction', 'lightning-helix', 'ninja-mask', 'overdrive', 'padlock', 'pummeled', 'radioactive', 'rolling-tomb', 'screaming', 'sentry-gun', 'skull', 'sleepy', 'snail', 'spanner', 'stopwatch','strong', 'three-leaves', 'tread', 'trophy', 'white-tower'], handleInput = (msg) =&gt; { if(state[state_name].config.auto_add_concentration_marker &amp;&amp; msg &amp;&amp; msg.rolltemplate &amp;&amp; ((msg.rolltemplate === 'spell' &amp;&amp; msg.content.includes("{{concentration=1}}")) || (msg.rolltemplate === '5e-shaped' &amp;&amp; msg.content.includes("{{duration=^{CONCENTRATION")) || ((msg.rolltemplate === 'dmg' || msg.rolltemplate === 'atk') &amp;&amp; msg.content.includes('!concentration')))){ handleConcentrationSpellCast(msg); } if (msg.type != 'api') return; // Split the message into command and argument(s) let args = msg.content.split(' '); let command = args.shift().substring(1); let extracommand = args.shift(); let message; if (command == state[state_name].config.command) { if(playerIsGM(msg.playerid)){ switch(extracommand){ case 'reset': state[state_name] = {}; setDefaults(true); sendConfigMenu(false, '&lt;span style="color: red"&gt;The API Library needs to be restarted for this to take effect.&lt;/span&gt;'); break; case 'config': if(args.length &gt; 0){ let setting = args.shift().split('|'); let key = setting.shift(); let value = (setting[0] === 'true') ? true : (setting[0] === 'false') ? false : setting[0]; state[state_name].config[key] = value; if(key === 'bar'){ //registerEventHandlers(); message = '&lt;span style="color: red"&gt;The API Library needs to be restarted for this to take effect.&lt;/span&gt;'; } } sendConfigMenu(false, message); break; case 'advantage-menu': sendAdvantageMenu(); break; case 'toggle-advantage': let id = args[0]; if(state[state_name].advantages[id]){ state[state_name].advantages[id] = !state[state_name].advantages[id]; }else{ state[state_name].advantages[id] = true; } sendAdvantageMenu(); break; case 'roll': let represents = args[0], DC = parseInt(args[1], 10), con_save_mod = parseInt(args[2], 10), name = args[3], target = args[4]; roll(represents, DC, con_save_mod, name, target, true); break; case 'advantage': let represents_a = args[0], DC_a = parseInt(args[1], 10), con_save_mod_a = parseInt(args[2], 10), name_a = args[3], target_a = args[4]; roll(represents_a, DC_a, con_save_mod_a, name_a, target_a, false); break; default: if(msg.selected &amp;&amp; msg.selected.length){ msg.selected.forEach(s =&gt; { let token = getObj(s._type, s._id); addConcentration(token, msg.playerid, extracommand); }); return; } sendConfigMenu(); break; } }else{ if(msg.selected &amp;&amp; msg.selected.length){ msg.selected.forEach(s =&gt; { let token = getObj(s._type, s._id); addConcentration(token, msg.playerid, extracommand); }); } } } }, addConcentration = (token, playerid, spell) =&gt; { const marker = state[state_name].config.statusmarker let character = getObj('character', token.get('represents')); if((token.get('controlledby').split(',').includes(playerid) || token.get('controlledby').split(',').includes('all')) || (character &amp;&amp; (character.get('controlledby').split(',').includes(playerid) || character.get('controlledby').split(',').includes('all'))) || playerIsGM(playerid)){ if(!token.get('status_'+marker)){ let target = state[state_name].config.send_reminder_to; if(target === 'character'){ target = createWhisperName((character || { get: () =&gt; { return ''; } }).get('character_name')); }else if(target === 'everyone'){ target = '' } let message; if(spell){ message = '&lt;b&gt;'+token.get('name')+'&lt;/b&gt; se concentre sur &lt;b&gt;'+spell+'&lt;/b&gt;.'; }else{ message = '&lt;b&gt;'+token.get('name')+'&lt;/b&gt; se concentre.'; } makeAndSendMenu(message, '', target); } token.set('status_'+marker, !token.get('status_'+marker)); } }, handleConcentrationSpellCast = (msg) =&gt; { const marker = state[state_name].config.statusmarker let character_name = msg.content.match(/charname=([^\n{}]*[^"\n{}])/) /* 5eOGL */ || msg.content.match(/character_name=([^\n{}]*[^"\n{}])/) /* Shaped */; character_name = RegExp.$1; let spell_name = msg.content.match(/title=([^\n{}]*[^"\n{}])/) /* Shaped */ || msg.content.match(/name=([^\n{}]*[^"\n{}])/) /* 5eOGL */; spell_name = RegExp.$1; let player = getObj('player', msg.playerid), characterid = findObjs({ name: character_name, _type: 'character' }).shift().get('id'), represented_tokens = findObjs({ represents: characterid, _type: 'graphic' }), message, target = state[state_name].config.send_reminder_to; if(!character_name || !spell_name || !player || !characterid) return; let search_attributes = { represents: characterid, _type: 'graphic', _pageid: player.get('lastpage') } search_attributes['status_'+marker] = true; let is_concentrating = (findObjs(search_attributes).length &gt; 0); represented_tokens.forEach(token =&gt; { let attributes = {}; attributes['status_'+marker] = true; token.set(attributes); message = (is_concentrating) ? '&lt;p style="font-size: 9pt; color: red;"&gt;Concentration précédente annulée.&lt;/p&gt;' : ''; message += '&lt;b&gt;'+character_name+'&lt;/b&gt; se concentre sur &lt;b&gt;'+spell_name+'&lt;/b&gt;.'; }); if(target === 'character'){ target = createWhisperName(character_name); }else if(target === 'everyone'){ target = '' } makeAndSendMenu(message, '', target); }, handleStatusMarkerChange = (obj, prev) =&gt; { const marker = state[state_name].config.statusmarker if(!obj.get('status_'+marker)){ removeMarker(obj.get('represents')); } }, handleGraphicChange = (obj, prev) =&gt; { if(checked.includes(obj.get('represents'))){ return false; } let bar = 'bar'+state[state_name].config.bar+'_value', target = state[state_name].config.send_reminder_to, marker = state[state_name].config.statusmarker; if(prev &amp;&amp; obj.get('status_'+marker) &amp;&amp; obj.get(bar) &lt; prev[bar]){ let calc_DC = Math.floor((prev[bar] - obj.get(bar))/2), DC = (calc_DC &gt; 10) ? calc_DC : 10, con_save_mod = parseInt(getAttrByName(obj.get('represents'), state[state_name].config.bonus_attribute, 'current')) || 0, chat_text; if(target === 'character'){ chat_text = "Faites un JP constitution - &lt;b&gt;DD " + DC + "&lt;/b&gt;."; target = createWhisperName(obj.get('name')); }else if(target === 'everyone'){ chat_text = '&lt;b&gt;'+obj.get('name')+'&lt;/b&gt; Doit faire un JP constitution - &lt;b&gt;DD ' + DC + '&lt;/b&gt;.'; target = ''; }else{ chat_text = '&lt;b&gt;'+obj.get('name')+'&lt;/b&gt; Doit faire un JP constitution - &lt;b&gt;DD ' + DC + '&lt;/b&gt;.'; target = 'gm'; } if(state[state_name].config.show_roll_button){ chat_text += '&lt;hr&gt;' + makeButton('Avantage', '!' + state[state_name].config.command + ' advantage ' + obj.get('represents') + ' ' + DC + ' ' + con_save_mod + ' ' + obj.get('name') + ' ' + target, styles.button + styles.float.right); chat_text += '&amp;nbsp;' + makeButton('Roll', '!' + state[state_name].config.command + ' roll ' + obj.get('represents') + ' ' + DC + ' ' + con_save_mod + ' ' + obj.get('name') + ' ' + target, styles.button + styles.float.left); } if(state[state_name].config.auto_roll_save){ //&amp;{template:default} {{name='+obj.get('name')+' - Concentration Save}} {{Modifier='+con_save_mod+'}} {{Roll=[[1d20cf&lt;'+(DC-con_save_mod-1)+'cs&gt;'+(DC-con_save_mod-1)+'+'+con_save_mod+']]}} {{DC='+DC+'}} roll(obj.get('represents'), DC, con_save_mod, obj.get('name'), target, state[state_name].advantages[obj.get('represents')]); }else{ makeAndSendMenu(chat_text, '', target); } let length = checked.push(obj.get('represents')); setTimeout(() =&gt; { checked.splice(length-1, 1); }, 1000); } }, roll = (represents, DC, con_save_mod, name, target, advantage) =&gt; { sendChat(script_name, '[[1d20cf&lt;'+(DC-con_save_mod-1)+'cs&gt;'+(DC-con_save_mod-1)+'+'+con_save_mod+']]', results =&gt; { let title = 'JP Constitution &lt;br&gt; &lt;b style="font-size: 10pt; color: gray;"&gt;'+name+'&lt;/b&gt;', advantageRollResult; let rollresult = results[0].inlinerolls[0].results.rolls[0].results[0].v; let result = rollresult; if(advantage){ advantageRollResult = randomInteger(20); result = (rollresult &lt;= advantageRollResult) ? advantageRollResult : rollresult; } let total = result + con_save_mod; let success = total &gt;= DC; let result_text = (success) ? 'Réussite' : 'Echec', result_color = (success) ? 'green' : 'red'; let rollResultString = (advantage) ? rollresult + ' / ' + advantageRollResult : rollresult; let contents = ' \ &lt;table style="width: 100%; text-align: left;"&gt; \ &lt;tr&gt; \ &lt;th&gt;DD&lt;/th&gt; \ &lt;td&gt;'+DC+'&lt;/td&gt; \ &lt;/tr&gt; \ &lt;tr&gt; \ &lt;th&gt;Modificateur&lt;/th&gt; \ &lt;td&gt;'+con_save_mod+'&lt;/td&gt; \ &lt;/tr&gt; \ &lt;tr&gt; \ &lt;th&gt;Résultat dé&lt;/th&gt; \ &lt;td&gt;'+rollResultString+'&lt;/td&gt; \ &lt;/tr&gt; \ &lt;/table&gt; \ &lt;div style="text-align: center"&gt; \ &lt;b style="font-size: 16pt;"&gt; \ &lt;span style="border: 1px solid '+result_color+'; padding-bottom: 2px; padding-top: 4px;"&gt;[['+result+'+'+con_save_mod+']]&lt;/span&gt;&lt;br&gt;&lt;br&gt; \ '+result_text+' \ &lt;/b&gt; \ &lt;/div&gt;' makeAndSendMenu(contents, title, target); if(target !== '' &amp;&amp; target !== 'gm'){ makeAndSendMenu(contents, title, 'gm'); } if(!success){ removeMarker(represents); } }); }, removeMarker = (represents, type='graphic') =&gt; { findObjs({ type, represents }).forEach(o =&gt; { o.set('status_'+state[state_name].config.statusmarker, false); }); }, createWhisperName = (name) =&gt; { return (name||'').split(' ').shift(); }, ucFirst = (string) =&gt; { return string.charAt(0).toUpperCase() + string.slice(1); }, sendConfigMenu = (first, message) =&gt; { let markerDropdown = '?{Marker'; markers.forEach((marker) =&gt; { markerDropdown += '|'+ucFirst(marker).replace('-', ' ')+','+marker }) markerDropdown += '}'; let markerButton = makeButton(state[state_name].config.statusmarker, '!' + state[state_name].config.command + ' config statusmarker|'+markerDropdown, styles.button + styles.float.right), commandButton = makeButton('!'+state[state_name].config.command, '!' + state[state_name].config.command + ' config command|?{Command (without !)}', styles.button + styles.float.right), barButton = makeButton('bar ' + state[state_name].config.bar, '!' + state[state_name].config.command + ' config bar|?{Bar|Bar 1 (green),1|Bar 2 (blue),2|Bar 3 (red),3}', styles.button + styles.float.right), sendToButton = makeButton(state[state_name].config.send_reminder_to, '!' + state[state_name].config.command + ' config send_reminder_to|?{Send To|Everyone,everyone|Character,character|GM,gm}', styles.button + styles.float.right), addConMarkerButton = makeButton(state[state_name].config.auto_add_concentration_marker, '!' + state[state_name].config.command + ' config auto_add_concentration_marker|'+!state[state_name].config.auto_add_concentration_marker, styles.button + styles.float.right), autoRollButton = makeButton(state[state_name].config.auto_roll_save, '!' + state[state_name].config.command + ' config auto_roll_save|'+!state[state_name].config.auto_roll_save, styles.button + styles.float.right), //advantageButton = makeButton(state[state_name].config.advantage, '!' + state[state_name].config.command + ' config advantage|'+!state[state_name].config.advantage, styles.button + styles.float.right), bonusAttrButton = makeButton(state[state_name].config.bonus_attribute, '!' + state[state_name].config.command + ' config bonus_attribute|?{Attribute|'+state[state_name].config.bonus_attribute+'}', styles.button + styles.float.right), showRollButtonButton = makeButton(state[state_name].config.show_roll_button, '!' + state[state_name].config.command + ' config show_roll_button|'+!state[state_name].config.show_roll_button, styles.button + styles.float.right), listItems = [ '&lt;span style="'+styles.float.left+'"&gt;Command:&lt;/span&gt; ' + commandButton, '&lt;span style="'+styles.float.left+'"&gt;Statusmarker:&lt;/span&gt; ' + markerButton, '&lt;span style="'+styles.float.left+'"&gt;HP Bar:&lt;/span&gt; ' + barButton, '&lt;span style="'+styles.float.left+'"&gt;Send Reminder To:&lt;/span&gt; ' + sendToButton, '&lt;span style="'+styles.float.left+'"&gt;Auto Add Con. Marker: &lt;p style="font-size: 8pt;"&gt;Works only for 5e OGL and Shaped sheets.&lt;/p&gt;&lt;/span&gt; ' + addConMarkerButton, '&lt;span style="'+styles.float.left+'"&gt;Auto Roll Save:&lt;/span&gt; ' + autoRollButton, ], resetButton = makeButton('Reset', '!' + state[state_name].config.command + ' reset', styles.button + styles.fullWidth), title_text = (first) ? script_name + ' First Time Setup' : script_name + ' Config'; /*if(state[state_name].config.auto_roll_save){ listItems.push('&lt;span style="'+styles.float.left+'"&gt;Advantage:&lt;/span&gt; ' + advantageButton); }*/ if(state[state_name].config.auto_roll_save){ listItems.push('&lt;span style="'+styles.float.left+'"&gt;Bonus Attribute:&lt;/span&gt; ' + bonusAttrButton) } if(!state[state_name].config.auto_roll_save){ listItems.push('&lt;span style="'+styles.float.left+'"&gt;Roll Button:&lt;/span&gt; ' + showRollButtonButton); } let advantageMenuButton = (state[state_name].config.auto_roll_save) ? makeButton('Advantage Menu', '!' + state[state_name].config.command + ' advantage-menu', styles.button + styles.fullWidth) : ''; message = (message) ? '&lt;p&gt;'+message+'&lt;/p&gt;' : ''; let contents = message+makeList(listItems, styles.reset + styles.list + styles.overflow, styles.overflow)+'&lt;br&gt;'+advantageMenuButton+'&lt;hr&gt;&lt;p style="font-size: 80%"&gt;You can always come back to this config by typing `!'+state[state_name].config.command+' config`.&lt;/p&gt;&lt;hr&gt;'+resetButton; makeAndSendMenu(contents, title_text, 'gm'); }, sendAdvantageMenu = () =&gt; { let menu_text = ""; let characters = findObjs({ type: 'character' }).sort((a, b) =&gt; { let nameA = a.get('name').toUpperCase(); let nameB = b.get('name').toUpperCase(); if(nameA &lt; nameB) return -1; if(nameA &gt; nameB) return 1; return 0; }); characters.forEach(character =&gt; { let name = (state[state_name].advantages &amp;&amp; state[state_name].advantages[character.get('id')]) ? '&lt;b&gt;'+character.get('name')+'&lt;/b&gt;' : character.get('name'); menu_text += makeButton(name, '!' + state[state_name].config.command + ' toggle-advantage ' + character.get('id'), styles.textButton) + '&lt;br&gt;'; }); makeAndSendMenu(menu_text, 'Advantage Menu', 'gm'); }, makeAndSendMenu = (contents, title, whisper, callback) =&gt; { title = (title &amp;&amp; title != '') ? makeTitle(title) : ''; whisper = (whisper &amp;&amp; whisper !== '') ? '/w ' + whisper + ' ' : ''; sendChat(script_name, whisper + '&lt;div style="'+styles.menu+styles.overflow+'"&gt;'+title+contents+'&lt;/div&gt;', null, {noarchive:true}); }, makeTitle = (title) =&gt; { return '&lt;h3 style="margin-bottom: 10px;"&gt;'+title+'&lt;/h3&gt;'; }, makeButton = (title, href, style) =&gt; { return '&lt;a style="'+style+'" href="'+href+'"&gt;'+title+'&lt;/a&gt;'; }, makeList = (items, listStyle, itemStyle) =&gt; { let list = '&lt;ul style="'+listStyle+'"&gt;'; items.forEach((item) =&gt; { list += '&lt;li style="'+itemStyle+'"&gt;'+item+'&lt;/li&gt;'; }); list += '&lt;/ul&gt;'; return list; }, pre_log = (message) =&gt; { log('---------------------------------------------------------------------------------------------'); if(!message){ return; } log(message); log('---------------------------------------------------------------------------------------------'); }, checkInstall = () =&gt; { if(!_.has(state, state_name)){ state[state_name] = state[state_name] || {}; } setDefaults(); log(script_name + ' Ready! Command: !'+state[state_name].config.command); if(state[state_name].config.debug){ makeAndSendMenu(script_name + ' Ready! Debug On.', '', 'gm') } }, registerEventHandlers = () =&gt; { on('chat:message', handleInput); on('change:graphic:bar'+state[state_name].config.bar+'_value', handleGraphicChange); on('change:graphic:statusmarkers', handleStatusMarkerChange); //register this script to SmartAoE to handle linked bar hp changes if('undefined' !== typeof SmartAoE &amp;&amp; SmartAoE.ObserveTokenChange){ SmartAoE.ObserveTokenChange(function(obj,prev){ handleGraphicChange(obj, prev); }); }; //register this script to TokenMod to handle linked bar hp changes if('undefined' !== typeof TokenMod &amp;&amp; TokenMod.ObserveTokenChange){ TokenMod.ObserveTokenChange(function(obj,prev){ handleGraphicChange(obj, prev); }); }; }, setDefaults = (reset) =&gt; { const defaults = { config: { command: 'concentration', statusmarker: 'stopwatch', bar: 1, send_reminder_to: 'everyone', // character,gm, auto_add_concentration_marker: true, auto_roll_save: true, advantage: false, bonus_attribute: 'constitution_save_bonus', show_roll_button: true }, advantages: {} }; if(!state[state_name].config){ state[state_name].config = defaults.config; }else{ if(!state[state_name].config.hasOwnProperty('command')){ state[state_name].config.command = defaults.config.command; } if(!state[state_name].config.hasOwnProperty('statusmarker')){ state[state_name].config.statusmarker = defaults.config.statusmarker; } if(!state[state_name].config.hasOwnProperty('bar')){ state[state_name].config.bar = defaults.config.bar; } if(!state[state_name].config.hasOwnProperty('send_reminder_to')){ state[state_name].config.send_reminder_to = defaults.config.send_reminder_to; } if(!state[state_name].config.hasOwnProperty('auto_add_concentration_marker')){ state[state_name].config.auto_add_concentration_marker = defaults.config.auto_add_concentration_marker; } if(!state[state_name].config.hasOwnProperty('auto_roll_save')){ state[state_name].config.auto_roll_save = defaults.config.auto_roll_save; } if(!state[state_name].config.hasOwnProperty('advantage')){ state[state_name].config.advantage = defaults.config.advantage; } if(!state[state_name].config.hasOwnProperty('bonus_attribute')){ state[state_name].config.bonus_attribute = defaults.config.bonus_attribute; } if(!state[state_name].config.hasOwnProperty('show_roll_button')){ state[state_name].config.show_roll_button = defaults.config.show_roll_button; } } if(!state[state_name].advantages){ state[state_name].advantages = defaults.advantages; } if(!state[state_name].config.hasOwnProperty('firsttime') &amp;&amp; !reset){ sendConfigMenu(true); state[state_name].config.firsttime = false; } }; return { CheckInstall: checkInstall, RegisterEventHandlers: registerEventHandlers } })(); on('ready',function() { 'use strict'; Concentration.CheckInstall(); Concentration.RegisterEventHandlers(); }); Just add the marker you want to use in the list of markers at the beginning of the script and switch back the translations if you need to. It works well with token mod. Smart AoE too as Smart AoE is registering the use of token mod for the damages... Hope that helps.