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

Detecting whether handlebarchange triggered from an increase or decrease

I'm implementing a script to handle bloodied and death marker tokens, and I've got it working nicely.  I then started making it automatically display some blood fx when bloodied, which also works great... except it would be nice to be able to have a different fx display when HEALING, as opposed to taking damage. Here's my full code: /* global TokenMod */ on('ready',()=>{ // CONFIGURE const bar = 3; const bloodied = "bloodied::3239204"; const dying = "dying::3239210" const dead = "dead::3239207"; const fx_sparks_id = findObjs({_type: "custfx", name: "metal_sparks"})[0].id; const fx_blood_id = findObjs({_type: "custfx", name: "bloodsplat"})[0].id; // no edit below here // const unpackSM = (stats) => stats.split(/,/).reduce((m,v) => { let p = v.split(/@/); p[0]=p[0].toLowerCase(); let n = parseInt(p[1] || '0', 10); if(p[0].length) { m[p[0]] = Math.max(n, m[p[0]] || 0); } return m; },{}); const packSM = (o) => Object.keys(o) .map(k => ('dead' === k || true === o[k] || o[k]<1 || o[k]>9) ? k : `${k}@${parseInt(o[k])}` ).join(','); const handleBarChange = (obj) => { const bv = parseFloat(obj.get(`bar${bar}_value`)); const bm = parseFloat(obj.get(`bar${bar}_max`)); if(Number.isNaN(bm)){ return; } let sm = unpackSM(obj.get('statusmarkers')); if(bv > (bm / 2) && bv < bm) { spawnFx(obj.get('left'), obj.get('top'), fx_sparks_id); } if(bv <= (bm / 2) && bv > 0) { sm[bloodied] = true; spawnFx(obj.get('left'), obj.get('top'), fx_blood_id); } else{ delete sm[bloodied]; } if(bv > (0 - (bm / 2)) && bv <= 0) { sm[dying] = true; spawnFx(obj.get('left'), obj.get('top'), 'glow-death'); } else{ delete sm[dying]; } if(bv <= (0 - (bm / 2)) ) { sm[dead] = true; spawnFx(obj.get('left'), obj.get('top'), 'bomb-death'); } else { delete sm[dead]; } obj.set({ statusmarkers: packSM(sm) }); }; on(`change:graphic:bar${bar}_value`, handleBarChange); if('undefined' !== typeof TokenMod && TokenMod.ObserveTokenChange){ TokenMod.ObserveTokenChange(handleBarChange); } }); What would I do in order to have this detect whether the player decreased to bar's value, or decreased it?  As far as I can tell, I only seem to be able to detect what the CURRECT bar value is, not what triggered the change.
1622878389
GiGs
Pro
Sheet Author
API Scripter
token bars have a prev property, so you can check the new value against the old value, and thereby detect if it want up (current > prev) or down (current < prev). You'll want to change this line const handleBarChange = (obj) => { to const handleBarChange = (obj, prev) => { You then get the previous value with something like const prevHp = +prev[ "bar1 _value" ] || 0; You'll have to change that to the correct bar value.
That works wonderfully, thanks!  If you don't mind adding to my education though, I'm confused what the "|| 0;" portion of that line is doing.  I mean, I know that the || operator is a logical or, and returns true or false... but prevHp is correctly getting set to the previous bar value, and not a boolean... so what's going on?
1622889053
GiGs
Pro
Sheet Author
API Scripter
There's a surprising number of things to explain here. First, the expression starts with a +. const prevHp = +prev[ "bar1 _value" ] The + there coerces the value into a number. It's exactly the same as writing const prevHp = Number(prev[ "bar1 _value" ]) However, if bar1 contained a string (and also, if empty IIRC), this would produce an error. So you need to make sure its a number, and not an error. Javascript has the concept of truthiness - each value is either truthy or falsy. For the purposes of this situation, a truthy value is one that resolves correctly, and is not an error. A falsy value is an error. So if the bar contains a number, the result of the above expression is truthy, and if it does not, it errors out and so is falsy. Now, in javascript, a boolean OR expression stops at the first truthy value. and || is OR. So this: const value = something || somethingelse; says value is something OR somethingelse . if something is truthy, the expression stops there and value is set to something . If something is falsy, javascript looks to the other value, and if that is truthy, it accepts that. (If both are falsy, you get an error, and you'll need to handle that). So, getting back to our expression: const prevHp = +prev[ "bar1 _value" ] || 0; This says prevHp is if bar1_value is a number, set prevHP to that value. Bit if its not a number, set it to 0. To cut a long story short, the ||0 construct is a very common way to set default values in javascript. You know that if the bit before || is an error, it will take the second value (the default value). I set 0 as the default value here - that won't always be appropriate. Maybe you want to set it to something like 1000. Maybe you don't want to set a default value at all, but want to do handle the error directly. But it is a very useful technique to have in your toolbox.
1622896616
timmaugh
Pro
API Scripter
Something else to remember is that the prev object is a simple JavaScript object, with all of the properties and values accessible right off the root object, without needing to us get(...).
1622903748
The Aaron
Roll20 Production Team
API Scripter
Just a minor correction, a chain of || (or) operations returns the first truthy value or the last falsy value, not an error.  
1622943539
GiGs
Pro
Sheet Author
API Scripter
yes, I was keeping it simple for this particular case, since that falsy value will be an error.
1622945820

Edited 1622945845
So, what I'm seeing is that this isn't a logical OR, like I'm used to in C++, but more like the "? :" operator in that language?
1622946193
The Aaron
Roll20 Production Team
API Scripter
Yeah, it's kind of like a chain of ternary operators: let foo = bar || baz || 0; auto foo = (!!bar ? bar : (!!baz ? baz : 0));