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 .
×

Aura/Tint HealthColors Can anyone bring this back to its former glory?

1769937624
Rogue
Pro
Marketplace Creator
This was one of my favorites, loved the blood spatter and the aura heal effect. However, ever since Jumpgate it was lost and now I sad. I know it has some bugs especially if you are using other APIs with the 2nd aura. I only use this one and Group Initiative though.
1769967982

Edited 1769969563
This was sent to me as part of a discussion about the same- certainly works for me - here's the original discussion <a href="https://app.roll20.net/forum/post/12478610/aura-tint-health-colors-and-jumpgate/?pageforid=12478610#post-12478610" rel="nofollow">https://app.roll20.net/forum/post/12478610/aura-tint-health-colors-and-jumpgate/?pageforid=12478610#post-12478610</a> /* global createObj TokenMod spawnFxWithDefinition getObj state playerIsGM sendChat _ findObjs log on*/ /* My Profile link: <a href="https://app.roll20.net/users/262130/dxwarlock" rel="nofollow">https://app.roll20.net/users/262130/dxwarlock</a> GIT link: <a href="https://github.com/dxwarlock/Roll20/blob/master/Public/HeathColors" rel="nofollow">https://github.com/dxwarlock/Roll20/blob/master/Public/HeathColors</a> Roll20Link: <a href="https://app.roll20.net/forum/post/4630083/script-aura-slash-tint-healthcolor" rel="nofollow">https://app.roll20.net/forum/post/4630083/script-aura-slash-tint-healthcolor</a> Version 1.7.1 - Mar 6 2025 - Updated FX effects: The damage/healing FX now use the simpler DeathTracker approach. (Damage FX uses the HurtFX type (default "splatter-blood") and Healing FX uses the HealFX type (default "glow-holy").) - Added a new command/button ("LISTFX") that displays a graphical menu listing custom FX objects with their IDs. */ /*jshint bitwise: false*/ var HealthColors = HealthColors || (function () { 'use strict'; var version = '1.7.1', ScriptName = "HealthColors", schemaVersion = '1.0.3', Updated = "Feb 16 2025", /*------------------------ ON TOKEN CHANGE/CREATE ------------------------*/ handleToken = function (obj, prev, update) { //CHECK IF TRIGGERED------------ if(state.HealthColors.auraColorOn !== true || obj.get("layer") !== "objects") return; if(obj.get("represents") !== "" || (obj.get("represents") === "" &amp;&amp; state.HealthColors.OneOff === true)) { //**CHECK BARS------------// var barUsed = state.HealthColors.auraBar; var maxValue, curValue, prevValue; if(obj.get(barUsed + "_max") !== "" || obj.get(barUsed + "_value") !== "") { maxValue = parseInt(obj.get(barUsed + "_max"), 10); curValue = parseInt(obj.get(barUsed + "_value"), 10); prevValue = prev[barUsed + "_value"]; } if(isNaN(maxValue) || isNaN(curValue) || isNaN(prevValue)) return; //CALC PERCENTAGE------------ var percReal = Math.round((curValue / maxValue) * 100); var markerColor = PercentToHEX(percReal); //DEFINE VARIABLES--- var pColor = '#ffffff'; var GM = '', PC = ''; var IsTypeOn, PercentOn, ShowDead, UseAura; //**CHECK MONSTER OR PLAYER------------// var oCharacter = getObj('character', obj.get("_represents")); var type = (oCharacter === undefined || oCharacter.get("controlledby") === "") ? 'Monster' : 'Player'; var colortype = (state.HealthColors.auraTint) ? 'tint' : 'aura1'; //IF PLAYER------------ if(type == 'Player') { GM = state.HealthColors.GM_PCNames; PC = state.HealthColors.PCNames; IsTypeOn = state.HealthColors.PCAura; PercentOn = state.HealthColors.auraPercPC; ShowDead = state.HealthColors.auraDeadPC; var cBy = oCharacter.get('controlledby'); var player = getObj('player', cBy); pColor = '#000000'; if(player !== undefined) pColor = player.get('color'); } //IF MONSTER------------ else if(type == 'Monster') { GM = state.HealthColors.GM_NPCNames; PC = state.HealthColors.NPCNames; IsTypeOn = state.HealthColors.NPCAura; PercentOn = state.HealthColors.auraPerc; ShowDead = state.HealthColors.auraDead; } else return; //CHECK DISABLED AURA/TINT ATTRIB------------ if(oCharacter !== undefined) { UseAura = lookupUseColor(oCharacter); } //SET HEALTH COLOR---------- if(IsTypeOn &amp;&amp; UseAura !== "NO") { percReal = Math.min(percReal, 100); if(percReal &gt; PercentOn || curValue === 0) SetAuraNone(obj); else TokenSet(obj, state.HealthColors.AuraSize, markerColor, pColor, update); //SHOW DEAD---------- if(ShowDead === true) { if(curValue &gt; 0) obj.set("status_dead", false); else if(curValue &lt; 1) { var DeadSounds = state.HealthColors.auraDeadFX; if(DeadSounds !== "None" &amp;&amp; curValue != prevValue) PlayDeath(DeadSounds); obj.set("status_dead", true); SetAuraNone(obj); } } } else if((!IsTypeOn || UseAura === "NO") &amp;&amp; obj.get(colortype + '_color') === markerColor) SetAuraNone(obj); //SET SHOW NAMES------------ SetShowNames(GM, PC, obj); //**FX for Damage/Healing using DeathTracker's approach------------ if(curValue != prevValue &amp;&amp; prevValue != "" &amp;&amp; update !== "YES") { let left = parseInt(obj.get('left')), top = parseInt(obj.get('top')); if(state.HealthColors.FX === true) { if(curValue &lt; prevValue) { // Damage FX – using HurtFX type (default: splatter-blood) spawnFxBetweenPoints({ x: left, y: top }, { x: left, y: top }, state.HealthColors.HurtFX, obj.get('_pageid')); } else if(curValue &gt; prevValue) { // Healing FX – using HealFX type (default: glow-holy) spawnFxBetweenPoints({ x: left, y: top }, { x: left, y: top }, state.HealthColors.HealFX, obj.get('_pageid')); } } } } }, /*------------------------ CHAT MESSAGES ------------------------*/ handleInput = function (msg) { var msgFormula = msg.content.split(/\s+/); var command = msgFormula[0].toUpperCase(), UPPER =""; if(msg.type == "api" &amp;&amp; command.indexOf("!AURA") !== -1) { var OPTION = msgFormula[1] || "MENU"; if(!playerIsGM(msg.playerid)) { sendChat('HealthColors', "/w " + msg.who + " you must be a GM to use this command!"); return; } else { if(OPTION !== "MENU") GMW("UPDATING TOKENS..."); switch(OPTION.toUpperCase()) { case "MENU": break; case "ON": state.HealthColors.auraColorOn = !state.HealthColors.auraColorOn; break; case "BAR": state.HealthColors.auraBar = "bar" + msgFormula[2]; break; case "TINT": state.HealthColors.auraTint = !state.HealthColors.auraTint; break; case "PERC": state.HealthColors.auraPercPC = parseInt(msgFormula[2], 10); state.HealthColors.auraPerc = parseInt(msgFormula[3], 10); break; case "PC": state.HealthColors.PCAura = !state.HealthColors.PCAura; break; case "NPC": state.HealthColors.NPCAura = !state.HealthColors.NPCAura; break; case "GMNPC": state.HealthColors.GM_NPCNames = msgFormula[2]; break; case "GMPC": state.HealthColors.GM_PCNames = msgFormula[2]; break; case "PCNPC": state.HealthColors.NPCNames = msgFormula[2]; break; case "PCPC": state.HealthColors.PCNames = msgFormula[2]; break; case "DEAD": state.HealthColors.auraDead = !state.HealthColors.auraDead; break; case "DEADPC": state.HealthColors.auraDeadPC = !state.HealthColors.auraDeadPC; break; case "DEADFX": state.HealthColors.auraDeadFX = msgFormula[2]; break; case "SIZE": state.HealthColors.AuraSize = parseFloat(msgFormula[2]); break; case "ONEOFF": state.HealthColors.OneOff = !state.HealthColors.OneOff; break; case "FX": state.HealthColors.FX = !state.HealthColors.FX; break; case "HEAL": UPPER = msgFormula[2]; state.HealthColors.HealFX = UPPER; break; case "HURT": UPPER = msgFormula[2]; state.HealthColors.HurtFX = UPPER; break; case "LISTFX": listCustomFX(); break; case "RESET": delete state.HealthColors; GMW("STATE RESET"); checkInstall(); break; case "UPDATE": manUpdate(msg); return; } aurahelp(OPTION); } } }, // New function: List Custom FX IDs in a formatted menu listCustomFX = function() { var allCustFX = findObjs({ _type: "custfx" }); var output = "&lt;div style='border: 1px solid #000; background-color: #f2f2f2; padding: 5px; border-radius: 4px; max-width: 400px;'&gt;"; output += "&lt;strong&gt;Custom FX IDs:&lt;/strong&gt;&lt;br&gt;&lt;ul style='list-style: none; padding: 0; margin: 0;'&gt;"; if(allCustFX.length &gt; 0) { allCustFX.forEach(function(custfx) { var fxName = custfx.get("name") || "[Unnamed]"; output += "&lt;li style='padding: 2px 0;'&gt;&lt;span style='font-weight:bold;'&gt;" + fxName + ":&lt;/span&gt; " + custfx.get("_id") + "&lt;/li&gt;"; }); } else { output += "&lt;li&gt;No custom FX objects found.&lt;/li&gt;"; } output += "&lt;/ul&gt;&lt;/div&gt;"; sendChat('HealthColors', "/w gm " + output); }, //SET TOKEN COLORS------------ TokenSet = function (obj, sizeSet, markerColor, pColor, update) { var Pageon = getObj("page", obj.get("_pageid")); var scale = Pageon.get("scale_number") / 10; if(state.HealthColors.auraTint === true) { if(obj.get('aura1_color') == markerColor &amp;&amp; update === "YES") { obj.set({'aura1_color': "transparent"}); } obj.set({'tint_color': markerColor}); } else { if(obj.get('tint_color') == markerColor &amp;&amp; update === "YES") { obj.set({'tint_color': "transparent"}); } obj.set({ 'aura1_radius': sizeSet * scale * 1.8, 'aura1_color': markerColor, 'showplayers_aura1': true }); } }, //REMOVE ALL------------ SetAuraNone = function (obj) { if(state.HealthColors.auraTint === true) obj.set({'tint_color': "transparent"}); else obj.set({'aura1_color': "transparent"}); }, //FORCE ALL TOKEN UPDATE------------ MenuForceUpdate = function(){ let i = 0; const start = new Date().getTime(); const barUsed = state.HealthColors.auraBar; const workQueue = findObjs({type: 'graphic', subtype: 'token', layer: 'objects'}) .filter((o) =&gt; o.get(barUsed + "_max") !== "" &amp;&amp; o.get(barUsed + "_value") !== ""); const drainQueue = () =&gt; { let t = workQueue.shift(); if(t){ const prev = JSON.parse(JSON.stringify(t)); handleToken(t, prev, 'YES'); setTimeout(drainQueue, 0); } else { sendChat('Fixing Tokens', `/w gm Finished Fixing Tokens`); } }; sendChat('Fixing Tokens', `/w gm Fixing ${workQueue.length} Tokens`); drainQueue(); var end = new Date().getTime(); return "Tokens Processed: " + workQueue.length + "&lt;br&gt;Run time in ms: " + (end - start); }, SetShowNames = function(GM, PC, obj) { if(GM != 'Off' &amp;&amp; GM != '') { GM = (GM == "Yes") ? true : false; obj.set({'showname': GM}); } if(PC != 'Off' &amp;&amp; PC != '') { PC = (PC == "Yes") ? true : false; obj.set({'showplayers_name': PC}); } }, //MANUAL UPDATE------------ manUpdate = function (msg) { var selected = msg.selected; var allNames = ''; _.each(selected, function (obj) { var token = getObj('graphic', obj._id); var tName = token.get("name"); allNames = allNames.concat(tName + '&lt;br&gt;'); var prev = JSON.parse(JSON.stringify(token)); handleToken(token, prev, "YES"); }); GMW(allNames); }, //ATTRIBUTE CACHE------------ makeSmartAttrCache = function (attribute, options) { let cache = {}, defaultValue = options.default || 'YES', validator = options.validation || _.constant(true); on('change:attribute', function (attr) { if(attr.get('name') === attribute) { if(!validator(attr.get('current'))) { attr.set('current', defaultValue); } cache[attr.get('characterid')] = attr.get('current'); var tokens = findObjs({type: 'graphic'}).filter((o) =&gt; o.get('represents') === attr.get("characterid")); _.each(tokens, function (obj) { var prev = JSON.parse(JSON.stringify(obj)); handleToken(obj, prev, "YES"); }); } }); on('destroy:attribute', function (attr) { if(attr.get('name') === attribute) { delete cache[attr.get('characterid')]; } }); return function(character){ let attr = findObjs({type: 'attribute', name: attribute, characterid: character.id}, {caseInsensitive:true})[0] || createObj('attribute', {name: attribute, characterid: character.id, current: defaultValue}); if(!cache[character.id] || cache[character.id] !== attr.get('current')){ if(!validator(attr.get('current'))){ attr.set('current', defaultValue); } cache[character.id] = attr.get('current'); } return cache[character.id]; }; }, lookupUseBlood = makeSmartAttrCache('USEBLOOD', { default: 'DEFAULT' }), lookupUseColor = makeSmartAttrCache('USECOLOR', { default: 'YES', validation: (o) =&gt; o.match(/YES|NO/) }), //DEATH SOUND------------ PlayDeath = function (trackname) { var RandTrackName; if(trackname.indexOf(",") &gt; 0) { var tracklist = trackname.split(","); RandTrackName = tracklist[Math.floor(Math.random() * tracklist.length)]; } else RandTrackName = trackname; var track = findObjs({type: 'jukeboxtrack', title: RandTrackName})[0]; if(track) { track.set('playing', false); track.set('softstop', false); track.set('volume', 50); track.set('playing', true); } else { log(ScriptName + ": No track found named " + RandTrackName); } }, //PERC TO RGB------------ PercentToHEX = function (percent) { var HEX; if(percent &gt; 100) HEX = "#0000FF"; else { if(percent === 100) percent = 99; var r, g, b = 0; if(percent &lt; 50) { g = Math.floor(255 * (percent / 50)); r = 255; } else { g = 255; r = Math.floor(255 * ((50 - percent % 50) / 50)); } HEX = "#" + ((1 &lt;&lt; 24) + (r &lt;&lt; 16) + (g &lt;&lt; 8) + b).toString(16).slice(1); } return HEX; }, //HEX TO RGB------------ HEXtoRGB = function (hex) { let parts = (hex || '').match(/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/); if(parts) { let rgb = _.chain(parts).rest().map((d) =&gt; parseInt(d, 16)).value(); rgb.push(1.0); return rgb; } return [0, 0, 0, 0.0]; }, //SPAWN FX------------ SpawnFX = function (Scale, HitSize, left, top, FX, pageid) { _.defaults(FX, { "maxParticles": 100, "duration": 100, "size": 100, "sizeRandom": 100, "lifeSpan": 100, "lifeSpanRandom": 100, "speed": 0, "speedRandom": 0, "angle": 0, "angleRandom": 0, "emissionRate": 100, "startColour": [255, 255, 255, 1], "endColour": [0, 0, 0, 1], "gravity": {"x": 0, "y": 0.0} }); var newFX = { "maxParticles": FX.maxParticles * HitSize, "duration": FX.duration * HitSize, "size": FX.size * Scale / 2, "sizeRandom": FX.sizeRandom * Scale / 2, "lifeSpan": FX.lifeSpan, "lifeSpanRandom": FX.lifeSpanRandom, "speed": FX.speed * Scale, "speedRandom": FX.speedRandom * Scale, "angle": FX.angle, "angleRandom": FX.angleRandom, "emissionRate": FX.emissionRate * HitSize * 2, "startColour": FX.startColour, "endColour": FX.endColour, "gravity": {"x": FX.gravity.x * Scale, "y": FX.gravity.y * Scale} }; spawnFxWithDefinition(left, top, newFX, pageid); }, //HELP MENU------------ aurahelp = function (OPTION) { var Update = ''; if(OPTION !== "MENU") Update = MenuForceUpdate(); var img = "background-image: -webkit-linear-gradient(left, #76ADD6 0%, #a7c7dc 100%);"; var tshadow = "-1px -1px #222, 1px -1px #222, -1px 1px #222, 1px 1px #222 , 2px 2px #222;"; // Base style for buttons with fixed width (for most items) var style = 'style="padding-top: 1px; text-align:center; font-size: 9pt; width: 48px; height: 14px; border: 1px solid black; margin: 1px; background-color: #6FAEC7; border-radius: 4px; box-shadow: 1px 1px 1px #707070;"'; // FX type buttons use a wider style var fxStyle = 'style="padding-top: 1px; text-align:center; font-size: 9pt; width: 80px; height: 14px; border: 1px solid black; margin: 1px; background-color: #6FAEC7; border-radius: 4px; box-shadow: 1px 1px 1px #707070;"'; // For buttons that should adjust to the text length, we use auto width. var autoStyle = 'style="padding: 1px 3px; text-align:center; font-size: 9pt; border: 1px solid black; margin: 1px; background-color: #6FAEC7; border-radius: 4px; box-shadow: 1px 1px 1px #707070; display:inline-block; width:auto;"'; var off = "#A84D4D"; var disable = "#D6D6D6"; var HR = "&lt;hr style='background-color: #000000; margin: 5px; border-width:0; color: #000000; height: 1px;'/&gt;"; var FX = state.HealthColors.auraDeadFX.substring(0, 4); // New button renamed "Custom FX ids" using autoStyle so it adjusts to the text length. var listFXButton = '&lt;a ' + autoStyle + ' href="!aura LISTFX"&gt;Custom FX ids&lt;/a&gt;&lt;br&gt;'; sendChat('HealthColors', "/w gm &lt;b&gt;&lt;br&gt;" + '&lt;div style="border-radius: 8px; padding: 5px; font-size: 9pt; text-shadow: ' + tshadow + '; box-shadow: 3px 3px 1px #707070; ' + img + ' color:#FFF; border:2px solid black; text-align:right; vertical-align:middle;"&gt;' + '&lt;u&gt;&lt;big&gt;HealthColors Version: ' + version + '&lt;/u&gt;&lt;/big&gt;&lt;br&gt;' + HR + 'Is On: &lt;a ' + style + 'background-color:' + (state.HealthColors.auraColorOn !== true ? off : "") + ';" href="!aura on"&gt;' + (state.HealthColors.auraColorOn !== true ? "No" : "Yes") + '&lt;/a&gt;&lt;br&gt;' + 'Bar: &lt;a ' + style + ' href="!aura bar ?{Bar|1|2|3}"&gt;' + state.HealthColors.auraBar + '&lt;/a&gt;&lt;br&gt;' + 'Use Tint: &lt;a ' + style + 'background-color:' + (state.HealthColors.auraTint !== true ? off : "") + ';" href="!aura tint"&gt;' + (state.HealthColors.auraTint !== true ? "No" : "Yes") + '&lt;/a&gt;&lt;br&gt;' + 'Percentage(PC/NPC): &lt;a ' + style + ' href="!aura perc ?{PCPercent?|100} ?{NPCPercent?|100}"&gt;' + state.HealthColors.auraPercPC + '/' + state.HealthColors.auraPerc + '&lt;/a&gt;&lt;br&gt;' + HR + 'Show PC Health: &lt;a ' + style + 'background-color:' + (state.HealthColors.PCAura !== true ? off : "") + ';" href="!aura pc"&gt;' + (state.HealthColors.PCAura !== true ? "No" : "Yes") + '&lt;/a&gt;&lt;br&gt;' + 'Show NPC Health: &lt;a ' + style + 'background-color:' + (state.HealthColors.NPCAura !== true ? off : "") + ';" href="!aura npc"&gt;' + (state.HealthColors.NPCAura !== true ? "No" : "Yes") + '&lt;/a&gt;&lt;br&gt;' + 'Show Dead PC: &lt;a ' + style + 'background-color:' + (state.HealthColors.auraDeadPC !== true ? off : "") + ';" href="!aura deadPC"&gt;' + (state.HealthColors.auraDeadPC !== true ? "No" : "Yes") + '&lt;/a&gt;&lt;br&gt;' + 'Show Dead NPC: &lt;a ' + style + 'background-color:' + (state.HealthColors.auraDead !== true ? off : "") + ';" href="!aura dead"&gt;' + (state.HealthColors.auraDead !== true ? "No" : "Yes") + '&lt;/a&gt;&lt;br&gt;' + HR + 'GM Sees all PC Names: &lt;a ' + style + 'background-color:' + ButtonColor(state.HealthColors.GM_PCNames, off, disable) + ';" href="!aura gmpc ?{Setting|Yes|No|Off}"&gt;' + state.HealthColors.GM_PCNames + '&lt;/a&gt;&lt;br&gt;' + 'GM Sees all NPC Names: &lt;a ' + style + 'background-color:' + ButtonColor(state.HealthColors.GM_NPCNames, off, disable) + ';" href="!aura gmnpc ?{Setting|Yes|No|Off}"&gt;' + state.HealthColors.GM_NPCNames + '&lt;/a&gt;&lt;br&gt;' + HR + 'PC Sees all PC Names: &lt;a ' + style + 'background-color:' + ButtonColor(state.HealthColors.PCNames, off, disable) + ';" href="!aura pcpc ?{Setting|Yes|No|Off}"&gt;' + state.HealthColors.PCNames + '&lt;/a&gt;&lt;br&gt;' + 'PC Sees all NPC Names: &lt;a ' + style + 'background-color:' + ButtonColor(state.HealthColors.NPCNames, off, disable) + ';" href="!aura pcnpc ?{Setting|Yes|No|Off}"&gt;' + state.HealthColors.NPCNames + '&lt;/a&gt;&lt;br&gt;' + HR + 'Aura Size: &lt;a ' + style + ' href="!aura size ?{Size?|0.7}"&gt;' + state.HealthColors.AuraSize + '&lt;/a&gt;&lt;br&gt;' + 'One Offs: &lt;a ' + style + 'background-color:' + (state.HealthColors.OneOff !== true ? off : "") + ';" href="!aura ONEOFF"&gt;' + (state.HealthColors.OneOff !== true ? "No" : "Yes") + '&lt;/a&gt;&lt;br&gt;' + 'FX: &lt;a ' + style + 'background-color:' + (state.HealthColors.FX !== true ? off : "") + ';" href="!aura FX"&gt;' + (state.HealthColors.FX !== true ? "No" : "Yes") + '&lt;/a&gt;&lt;br&gt;' + 'HealFX Type: &lt;a ' + fxStyle + 'background-color:#' + state.HealthColors.HealFX + ';" href="!aura HEAL ?{FX Type?|glow-holy}"&gt;' + state.HealthColors.HealFX + '&lt;/a&gt;&lt;br&gt;' + 'HurtFX Type: &lt;a ' + fxStyle + 'background-color:#' + state.HealthColors.HurtFX + ';" href="!aura HURT ?{FX Type?|splatter-blood}"&gt;' + state.HealthColors.HurtFX + '&lt;/a&gt;&lt;br&gt;' + 'DeathSFX: &lt;a ' + style + ' href="!aura deadfx ?{Sound Name?|' + state.HealthColors.auraDeadFX + '}"&gt;' + FX + '&lt;/a&gt;&lt;br&gt;' + HR + listFXButton + Update + '&lt;/div&gt;'); }, //OFF BUTTON COLORS------------ ButtonColor = function (state, off, disable) { var color; if(state == "No") color = off; if(state == "Off") color = disable; return color; }, //CHECK INSTALL &amp; SET STATE------------ checkInstall = function () { log('-=&gt;' + ScriptName + ' v' + version + ' [Updated: ' + Updated + ']&lt;=-'); if(!_.has(state, 'HealthColors') || state.HealthColors.schemaVersion !== schemaVersion) { log('&lt;' + ScriptName + ' Updating Schema to v' + schemaVersion + '&gt;'); state.HealthColors = {schemaVersion: schemaVersion}; state.HealthColors.version = version; } //CHECK STATE VALUES if(_.isUndefined(state.HealthColors.auraColorOn)) state.HealthColors.auraColorOn = true; //global on or off if(_.isUndefined(state.HealthColors.auraBar)) state.HealthColors.auraBar = "bar1"; //bar to use if(_.isUndefined(state.HealthColors.auraTint)) state.HealthColors.auraTint = false; //use tint instead? if(_.isUndefined(state.HealthColors.auraPercPC)) state.HealthColors.auraPercPC = 100; //precent to start showing PC if(_.isUndefined(state.HealthColors.auraPerc)) state.HealthColors.auraPerc = 100; //precent to start showing NPC //----------------- if(_.isUndefined(state.HealthColors.PCAura)) state.HealthColors.PCAura = true; //show players Health? if(_.isUndefined(state.HealthColors.NPCAura)) state.HealthColors.NPCAura = true; //show NPC Health? if(_.isUndefined(state.HealthColors.auraDeadPC)) state.HealthColors.auraDeadPC = true; //show dead X status PC if(_.isUndefined(state.HealthColors.auraDead)) state.HealthColors.auraDead = true; //show dead X status NPC //----------------- if(_.isUndefined(state.HealthColors.GM_PCNames)) state.HealthColors.GM_PCNames = "Yes"; //show GM PC names? if(_.isUndefined(state.HealthColors.PCNames)) state.HealthColors.PCNames = "Yes"; //show players PC Names? //----------------- if(_.isUndefined(state.HealthColors.GM_NPCNames)) state.HealthColors.GM_NPCNames = "Yes"; //show GM NPC names? if(_.isUndefined(state.HealthColors.NPCNames)) state.HealthColors.NPCNames = "Yes"; //show players NPC Names? //----------------- if(_.isUndefined(state.HealthColors.AuraSize)) state.HealthColors.AuraSize = 0.7; //set aura size? if(_.isUndefined(state.HealthColors.FX)) state.HealthColors.FX = true; //set FX ON/OFF? // Updated defaults for FX types (using DeathTracker FX names) if(_.isUndefined(state.HealthColors.HealFX)) state.HealthColors.HealFX = "glow-holy"; //set Heal FX type if(_.isUndefined(state.HealthColors.HurtFX)) state.HealthColors.HurtFX = "splatter-blood"; //set Hurt FX type if(_.isUndefined(state.HealthColors.auraDeadFX)) state.HealthColors.auraDeadFX = 'None'; //Sound FX Name //TokenMod CHECK if('undefined' !== typeof TokenMod &amp;&amp; TokenMod.ObserveTokenChange) TokenMod.ObserveTokenChange(handleToken); var FXHurt = findObjs({_type: "custfx", name: "-DefaultHurt"}, {caseInsensitive: true})[0]; var FXHeal = findObjs({_type: "custfx", name: "-DefaultHeal"}, {caseInsensitive: true})[0]; //DEFAULT FX CHECK if(!FXHurt) { GMW("Creating Default Hurt FX"); var Hurt = { "maxParticles": 150, "duration": 50, "size": 10, "sizeRandom": 3, "lifeSpan": 25, "lifeSpanRandom": 5, "speed": 8, "speedRandom": 3, "gravity": {"x": 0.01, "y": 0.65}, "angle": 270, "angleRandom": 25, "emissionRate": 100, "startColour": [0, 0, 0, 0], "endColour": [0, 0, 0, 0] }; createObj('custfx', {name: "-DefaultHurt", definition: Hurt}); } if(!FXHeal) { GMW("Creating Default Heal FX"); var Heal = { "maxParticles": 150, "duration": 50, "size": 10, "sizeRandom": 15, "lifeSpan": 50, "lifeSpanRandom": 30, "speed": 0.5, "speedRandom": 2, "angle": 0, "angleRandom": 180, "emissionRate": 1000, "startColour": [0, 0, 0, 0], "endColour": [0, 0, 0, 0] }; createObj('custfx', {name: "-DefaultHeal", definition: Heal}); } }, //WHISPER GM------------ GMW = function (text) { var DIV = "&lt;div style='width: 100%; border-radius: 4px; box-shadow: 1px 1px 1px #707070; text-align: center; vertical-align: middle; padding: 3px 0px; margin: 0px auto; border: 1px solid #000; color: #000; background-image: -webkit-linear-gradient(-45deg, #a7c7dc 0%,#85b2d3 100%);"; var MSG = DIV + "'&gt;&lt;b&gt;" + text + "&lt;/b&gt;&lt;/div"; sendChat('HealthColors', "/w GM " + MSG); }, //OUTSIDE CALL------------ UpdateToken = function (obj, prev) { if (obj.get("type") === "graphic") handleToken(obj, prev); else GMW("Script sent non-Token to be updated!"); }, //REGISTER TRIGGERS------------ registerEventHandlers = function () { on('chat:message', handleInput); on("change:token", handleToken); on('add:token', function (t) { _.delay(() =&gt; { let token = getObj('graphic', t.id), prev = JSON.parse(JSON.stringify(token)); handleToken(token, prev, "YES"); }, 400); }); //register this script to SmartAoE to handle linked bar hp changes if('undefined' !== typeof SmartAoE &amp;&amp; SmartAoE.ObserveTokenChange){ SmartAoE.ObserveTokenChange(function(obj, prev){ handleToken(obj, prev, "NO"); }); }; }; //RETURN OUTSIDE FUNCTIONS------------ return { GMW: GMW, Update: UpdateToken, CheckInstall: checkInstall, RegisterEventHandlers: registerEventHandlers }; }()); //On Ready on('ready', function () { 'use strict'; HealthColors.GMW("API READY"); HealthColors.CheckInstall(); HealthColors.RegisterEventHandlers(); });
1770124369
Rogue
Pro
Marketplace Creator
Thanks for the response. I'm not sure what I am doing wrong but pasted it into a new ApiScript, deleted the old one. But still do not get the healing animation or the blood spatter.
Am out rn, but can look when I get home. I wonder if there was some setting up in-game iie in the Aura menu where you identify whether auras are shown at whatever percentage etc, I recall there being a place to identify the FX used.&nbsp;
1770142802

Edited 1770190835
OK, so I know I messed about with this a bit before seeking help and I set up two custom FX -DefaultHeal and -DefaultHurt Hurt is&nbsp;{ "angle": 270, "angleRandom": 25, "duration": 50, "emissionRate": 100, "endColour": [175, 0, 0, 0], "endColourRandom": [20, 0, 0, 0], "gravity": {"x":0.01, "y":0.65}, "lifeSpan": 25, "lifeSpanRandom": 5, "maxParticles": 150, "size": 10, "sizeRandom": 3, "speed": 8, "speedRandom": 3, "startColour": [175, 0, 0, 1], "startColourRandom": [20, 0, 0, 0] } and Heal is { "angle": 0, "angleRandom": 180, "duration": 50, "emissionRate": 1000, "endColour": [0, 75, 30, 0], "endColourRandom": [0, 20, 20, 0], "lifeSpan": 50, "lifeSpanRandom": 30, "maxParticles": 150, "size": 10, "sizeRandom": 15, "speed": 0.5, "speedRandom": 2, "startColour": [0, 35, 10, 1], "startColourRandom": [0, 10, 10, 0.25] } and !aura gives me this - the two buttons to be defined are shown with their default text to the side [edited for clarity]
1770147290

Edited 1770190890
So, because I love throwing the dice, I deleted -DefaultHeal as one of my custom FX and set it back up and lost the ability to get the heal effect.&nbsp; The old grey cells, they are working Hastings, no?&nbsp; You need to setup the two custom effects as I have listed them then: 1: Click the button labelled Custom FX ids you will get a list of IDs 2: cut n paste the heal one into the drop down that comes up when you run !aura&nbsp; -where I have the words glow-holy above 3: do the same for the hurt ID&nbsp; - where it says splatter-blood above game should give you a message about updated tokens That should see you right
1770155615
Rogue
Pro
Marketplace Creator
Thanks so much for your help it is working now. The heal is a bit different than what it used to be, as is the hurt. The heal has a holy glow instead of the green bubbles and the blood spatter looks like the character got hit by a shotgun blast at point blank range! Great stuff, thanks so much for your help!&nbsp;
1770189280

Edited 1770195134
Did you setup the DefaultHurt and DefaultHeal I posted and then find the CustomFX ids? Those have to be put in to replace glow-holy and splatter -blood, then you will have the old style effects
1770262365
Rogue
Pro
Marketplace Creator
I did cut and paste them in, I copied the hurt one provided and placed in Blood-Spatter, and then pasted the heal one in glow, but still get the glow animation and the blood spray.&nbsp;
1770268020

Edited 1770269688
how did you get the ids?
Just making sure this is clear, the -DefaultHeal and -DefaultHurt are Custom FX and need to be set up using the FX button on the left hand side of the VTT menu. If you are using the API I posted , this will not work with the original API, there is a button at the bottom labelled Custom FX IDs. This produces a menu that is easy to miss because it also reloads the !aura menu and so is pushed up the chat menu. It is those IDs that need to go in those drop downs. If successful you will see the IDs under those buttons as per my penultimate pic above
1770282228

Edited 1770328863
The instructions are a bit scattered now, let me see if I can bring it all together here Go to your game/ Settings/Mod(API) scripts Click New Script (1 in the image) Cut and paste the API I have in my first post here, give it a name and save it, make sure it is enabled Launch the game Go to Effects and +Custom Effect (2 and 3 respectively in the image) Copy and paste the healing custom effect I listed above, give it a name and save it, repeat for the hurt effect (4 in the image) You should now see those listed under Custom Effects in the drop down when choosing an effect and selecting Custom Go to chat and type !aura, you will get the menu shown at the end of my post containing the effects code Click Custom FX IDs (5 in the image) and the chat menu will post the aura menu again BUT above it will be a smaller menu with all your custom effects listed (second image in this post) Copy the heal effect ID and paste it in the drop down that appears when you click the button labelled 6 in the image Repeat for the hurt effect, clicking button labelled 7 You should now see the IDs listed under the buttons as per my image and that should be you ready to go
1770328668
Rogue
Pro
Marketplace Creator
ah okay, i missed a few steps it seems. I will try this tonight thank you.
1770330383
Rogue
Pro
Marketplace Creator
Yes, got it! Thanks for the extra indepth walk through. It is working great now. Originally I just entered !aura, brought up the chart and copied the Heal into the GlowFX area. And the Hurt copied and pasted into the HurtFX.&nbsp;
No problem - I had to really dredge my memory as I have only done it once, every game since has been based off the same template and works, I haven't given it a thought in ages : )