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] Issue with identical Tokens ?

1657015731

Edited 1657017906
I noticed a little issue on the concentration script : When i Drag 2 identical monsters from journal, and i "concentrate" one of them, both of them get the symbol on, and if one of them is losing concentration failing its Constitution check, both of them lose their concentration... Is there a way that this doesn't happen ? It only happens for concentration and not if you apply another status marker from another script... I know that this script isn't maintained anymore (unfoirtunately) but if anyone could find the solution ? I'm using the 0.1.16 version of the script /* * 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); }); }; }, 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(); }); I made a few translations, but otherwise teh script is the same... I guess there must be a referencing problem between the character concentrating and something like represents or character name. Maybe changing the script to identify the selected token_id instead of the "represents" or the "character name" could solve the issue but i don't know how to do that.... Thanks for anyone's help. EDIT : The issue actually occurs when casting a spell from a NPC Character's sheet. It doesn't happen if i manually call for the !concentration
Am I the only one with this issue ?
1657118050
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Hi Lionel! It might be difficult finding someone who still uses the script. I use a much simpler one: on('ready', () =&gt; { const TOKEN_CONCENTRATING_STATUS_MARKER = "status_" + "Concentrating::35390"; on("change:graphic:bar1_value", function(obj, prev) { &nbsp; &nbsp; if (obj.get(TOKEN_CONCENTRATING_STATUS_MARKER)) { &nbsp; &nbsp; &nbsp; &nbsp; log ("status mareker is " + obj.get(TOKEN_CONCENTRATING_STATUS_MARKER)); &nbsp; &nbsp; &nbsp; &nbsp; //let playerPage = Campaign().get("playerpageid"); &nbsp; &nbsp; &nbsp; &nbsp; //let tokenPage = obj.get("_pageid"); &nbsp; &nbsp; &nbsp; &nbsp; if (prev["bar1_value"] &gt; obj.get("bar1_value")) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let final_conc_DC = 10; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let calc_conc_DC = (prev["bar1_value"] - obj.get("bar1_value")) / 2; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (calc_conc_DC &gt; final_conc_DC) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final_conc_DC = Math.floor(calc_conc_DC); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let tokenName = obj.get("name"); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let theMessage = "/w gm &amp;{template:npcaction} {{rname=Concentration Check "+tokenName+"}} {{name="+tokenName+"}} {{description=[DC " +final_conc_DC + " Constitution](~selected|constitution_save)"+ "&amp;#10;" +"*[Toggle Concentration Marker](!token-mod --sel --set statusmarkers|!Concentrating)*}}"; sendChat("Concentration",theMessage );&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; } }); }); Line 2 requires the full name of the concentration marker you are using (you can get this from the help document of Token Mod). If you do not use bar 1 for hp, you will need to change&nbsp; bar1_value &nbsp;to&nbsp; bar2_value &nbsp;or&nbsp; bar3_value .
1657118688
timmaugh
Pro
API Scripter
I like Keith's answer. I was reading through the script you originally posted, Lionel, and it doesn't look like it is set up for mook-able tokens. Everything is character driven. I could point you to the line you would want to change for the specific fix you're wanting, but then other portions of the script look to still work at the character level (for instance, reporting whether the character is already concentrating... which won't work if different mooks are concentrating while others aren't). It would take a more significant investment to make it do what you want and test it, and then to provide the configuration option (or command line option) to juggle between character-driven or token-driven processing.
timmaugh said: I like Keith's answer. I was reading through the script you originally posted, Lionel, and it doesn't look like it is set up for mook-able tokens. Everything is character driven. I could point you to the line you would want to change for the specific fix you're wanting, but then other portions of the script look to still work at the character level (for instance, reporting whether the character is already concentrating... which won't work if different mooks are concentrating while others aren't). It would take a more significant investment to make it do what you want and test it, and then to provide the configuration option (or command line option) to juggle between character-driven or token-driven processing. That's what i Thought... Too bad. This script is great apart from that differenciation thing... I thought putting everything on token level instead of having it on character level would work for everyone, but i guess i was wrong... Too bad, i'll have to deal with it the way i do for the moment, only trying to remember who concentrated and who didn't lol Thanks for the quick look you gave to the script anyway...
keithcurtis said: Hi Lionel! It might be difficult finding someone who still uses the script. I use a much simpler one: on('ready', () =&gt; { const TOKEN_CONCENTRATING_STATUS_MARKER = "status_" + "Concentrating::35390"; on("change:graphic:bar1_value", function(obj, prev) { &nbsp; &nbsp; if (obj.get(TOKEN_CONCENTRATING_STATUS_MARKER)) { &nbsp; &nbsp; &nbsp; &nbsp; log ("status mareker is " + obj.get(TOKEN_CONCENTRATING_STATUS_MARKER)); &nbsp; &nbsp; &nbsp; &nbsp; //let playerPage = Campaign().get("playerpageid"); &nbsp; &nbsp; &nbsp; &nbsp; //let tokenPage = obj.get("_pageid"); &nbsp; &nbsp; &nbsp; &nbsp; if (prev["bar1_value"] &gt; obj.get("bar1_value")) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let final_conc_DC = 10; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let calc_conc_DC = (prev["bar1_value"] - obj.get("bar1_value")) / 2; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (calc_conc_DC &gt; final_conc_DC) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final_conc_DC = Math.floor(calc_conc_DC); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let tokenName = obj.get("name"); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let theMessage = "/w gm &amp;{template:npcaction} {{rname=Concentration Check "+tokenName+"}} {{name="+tokenName+"}} {{description=[DC " +final_conc_DC + " Constitution](~selected|constitution_save)"+ "&amp;#10;" +"*[Toggle Concentration Marker](!token-mod --sel --set statusmarkers|!Concentrating)*}}"; sendChat("Concentration",theMessage );&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; } }); }); Line 2 requires the full name of the concentration marker you are using (you can get this from the help document of Token Mod). If you do not use bar 1 for hp, you will need to change&nbsp; bar1_value &nbsp;to&nbsp; bar2_value &nbsp;or&nbsp; bar3_value . Hey,&nbsp; I am potentially being an idiot but I tried this out after watching Nick Olivos youtube video and it wouldn't work for me. I am using your "Easy to read token markers" any thoughts on what I could be doing wrong :(
1657753545
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Did you follow the customization instructions above?: Line 2 requires the full name of the concentration marker you are using (you can get this from the help document of Token Mod). If you do not use bar 1 for hp, you will need to change&nbsp; bar1_value &nbsp;to&nbsp; bar2_value &nbsp;or&nbsp; bar3_value .
keithcurtis said: Did you follow the customization instructions above?: Line 2 requires the full name of the concentration marker you are using (you can get this from the help document of Token Mod). If you do not use bar 1 for hp, you will need to change&nbsp; bar1_value &nbsp;to&nbsp; bar2_value &nbsp;or&nbsp; bar3_value . just found your post from a while back on how to get the ID of the marker. Will take another look when I get time. Thanks