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

[HELP] Sheet Worker: Silent Mode not working?

1569467005
Finderski
Pro
Sheet Author
Compendium Curator
I have this sheet worker I'm working on, but the silent doesn't seem to be working... Essentially, when I enter a number in the bottom field, if the die type is already a d4 and the number is a negative number, it should not change the die type, and instead, set the negative number back to 0 and do it silently.  However, it doesn't appear to be working, because as the animated image shows, the d4 becomes a d6, which means the sheet worker is getting triggered because of the 0. Here's the code: traits.forEach(traits => { on(`change:${traits}_delta`, function(eventInfo) { let trait = traits; console.log(`^o^ Delta changed for ${trait} ^o^`); trait = trait.replace(':','_'); console.log("trait = "+trait); getAttrs([trait, `${trait}_old`, `${trait}mod`, `${trait}_delta`], v => { let tRank = parseInt(v[`${trait}`])||0; let tMod = parseInt(v[`${trait}mod`])||0; let tDelta = parseInt(v[`${trait}_delta`])||0; let newtDelta, oldRankVal; (tDelta === 0 ? newtDelta = tDelta - eventInfo.previousValue : newtDelta = tDelta); console.log(`^^^ ${trait} Rank: ${tRank}, Mod: ${tMod}, Delta: ${tDelta}, New Delta: ${newtDelta} ^^^`); //Is the Delta something other than 0 if(newtDelta !== 0) { let counter = Math.abs(newtDelta); if(newtDelta > 0) { //Increase console.log(`--- Increasing ${trait} ---`); if(tRank === 4 && tMod === -2) { //Check if skill is unskilled //unskilled counter = counter - 1; tMod = 0; } for(let i = counter; i > 0; i--) { if(tRank === 12) { tMod += 1; } else { tRank += 2; } } } else { //Decrease console.log(`--- Decreasing ${trait} ---`); if(tRank === 4) { //Rank is already 4 before decreasing...don't allow this tDelta = 0; } else { //Rank was not 4 before decreasing... for(let i = counter; i > 0; i--) { if(tRank === 4) { console.log(`Die Type is already 4, can't go any lower`); tRank = tRank; } else { if(tRank === 12 && tMod > 0) { //Something like Professional or Expert Edge, need to reduce positive modifier first tMod = tMod - 1; } else { //No positive modifier on rank, so reduce the die type tRank = tRank - 2; } } } } } } const sAttRank = trait, sAttMod = trait + 'mod', sAttDelta = `${trait}_delta`; let sattrs = {}; sattrs[sAttDelta]=tDelta; sattrs[`silent`] = true; setAttrs(sattrs); sattrs = {}; sattrs[sAttRank]=tRank; sattrs[sAttMod]=tMod; setAttrs(sattrs); }); }); }); I have also tried: sattrs(sAttDelta,{silent:true}); and that didn't work, either... Thoughts?
1569481346

Edited 1569486041
GiGs
Pro
Sheet Author
API Scripter
I dont have time to study the code, but I did spot an error on the first line traits.forEach(traits => { on(`change:${traits}_delta`, function(eventInfo) { let trait = traits; I assume traits is defined somehwere else. This first line should be traits.forEach(trait => { Or literally anything else but traits . When the forEach loop runs, it loops through the traits array, and sets the current item to trait .  When you use traits.forEach(trait => { you are essentially doing this for(var i=0; i < traits.length; i++) {     let trait = traits[i]; (Not exactly, but close enough.) This part (trait => { is equivalent to let trait = traits[i]; By having them both the same name, I'm surprised it works at all, but I'd expect it to cause weird errors at least.  So with a proper variable defined on the first line you don't need the third line. Those three lines would be replaced with: traits.forEach(trait => { on(`change:${trait}_delta`, function(eventInfo) { The other uses of trait  look correct from a quick scan. Also late in the script: sattrs[`silent`] = true; This isnt right. Nor is this: sattrs(sAttDelta,{silent:true}); Don't try to set silent as part of the sattrs variable. When you're doing that, you are just creating an attribute on the character sheet called silent, and setting its value to true. Do this instead setAttrs(sattrs,{silent:true}); Edit:  also that big if statement in the centre  where you create a counter, looks like very fragile code to me. The section where you create a counter, use it as the basis of a loop while also incrementing it elsewhere, and also duplicating the bulk of the code in the if and also the else section. I dont understand what you're doing there, but it looks like an error could easily creep into there and be very hard to debug. There's probably a much better way to do that section if you describe the logic in detail.
1569487090
Finderski
Pro
Sheet Author
Compendium Curator
Thanks, GiGs...I meant to include: setAttrs(sattrs,{silent:true}); Because I'd tried that as well. Silent doesn't seem to be doing anything...or rather it still triggers. Anyway, to get us all on the same page, I modified my code to match the above. To help (I hope), I'm also going to include the HTML portion sheet worker: //Create Trait values for rank and display hidden fields const traits = ['agility','smarts','spirit','strength','vigor','fighting','academicsskill','athletics','battle','boating','climbing','commonknowledge','driving','electronics','faith','focus','gambling','guts','hacking','healing','intimidation','investigation','language','lockpicking','notice','occult','performance','persuasion','piloting','psionics','repair','research','riding','ritual','science','shooting','spellcasting','stealth','streetwise','survival','swimming','taunt','throwing','thievery','tracking','weirdscience','repeating_skills:skillnamerank','pastrength','rastrength']; traits.forEach(trait => { //Should trigger second     on(`change:${trait} change:${trait}mod`, function(eventInfo) {        console.log(`+++ Change Detected for ${trait} +++`);        console.log("Trait triggering update: " + eventInfo.sourceAttribute);        //let trait = traits;        console.log("trait = "+trait);        console.log("Check for repeating: "+trait.slice(0,6));        /*if (trait.slice(0,5) === 'repeating') {            traitcheck = `repeating_skills_${traits}`;        }*/        trait = trait.replace(':','_');        console.log("trait = "+trait);        getAttrs([trait, `${trait}mod`, `${trait}_delta`], v => {            console.log("intMod will == "+v[`${trait}mod`]);                 console.log("Delta will == "+v[`${trait}_delta`]);                 let tDelta = v[`${trait}_delta`];                 tDelta = parseInt(tDelta)||0;                 let tDie = parseInt(v[trait])||0;                 console.log(`^^^ Delta: ${tDelta}, tDie: ${tDie} ^^^`);                 let tRank = '1d';                 let tDisplay = (tDelta !== 0 ? "*d" : "d");            let intMod = v[`${trait}mod`];                 intMod = parseInt(intMod)||0;            tRank += v[trait]+'!';            tDisplay += v[trait];            if(intMod > 0) {                     console.log("Mod is > 0...use +");     tRank += '+'+intMod+'[trait]';     tDisplay += '+' + intMod;     }                 else if(intMod < 0) {                     console.log("Mod is < 0...use -");     tRank += intMod+'[trait]';     tDisplay += intMod;                 }                 else {console.log("Mod is 0...don't do anything");}            const sAttRank = trait + '_rank', sAttDisplay = trait + '_display';     const sattrs = {};     sattrs[sAttRank]=tRank;     sattrs[sAttDisplay]=tDisplay;     setAttrs(sattrs);        });    }); });     //Do the Delta thing here...     //Set the actual trait and trait mod fields...this is needed so things like Vigor and Parry update if the appropriate trait is boosted/lowered     traits.forEach(trait => {         on(`change:${trait}_delta`, function(eventInfo) {             //let trait = traits;             console.log(`^o^ Delta changed for ${trait} ^o^`);             trait = trait.replace(':','_');        console.log("trait = "+trait);             getAttrs([trait, `${trait}_old`, `${trait}mod`, `${trait}_delta`], v => {                 let tRank = parseInt(v[`${trait}`])||0;                 let tMod = parseInt(v[`${trait}mod`])||0;                 let tDelta = parseInt(v[`${trait}_delta`])||0;                 let newtDelta, oldRankVal;                 (tDelta === 0 ? newtDelta = tDelta - eventInfo.previousValue : newtDelta = tDelta);                 console.log(`^^^ ${trait} Rank: ${tRank}, Mod: ${tMod}, Delta: ${tDelta}, New Delta: ${newtDelta} ^^^`);                 //Is the Delta something other than 0                 if(newtDelta !== 0) {                     let counter = Math.abs(newtDelta);                     if(newtDelta > 0) {                         //Increase                         console.log(`--- Increasing ${trait} ---`);                         if(tRank === 4 && tMod === -2) { //Check if skill is unskilled                             //unskilled                             counter = counter - 1;                             tMod = 0;                         }                         for(let i = counter; i > 0; i--) {                             if(tRank === 12) {                                 tMod += 1;                             }                             else {                                 tRank += 2;                             }                         }                     }                     else {                         //Decrease                         console.log(`--- Decreasing ${trait} ---`);                         if(tRank === 4) { //Rank is already 4 before decreasing...don't allow this                             tDelta = 0;                         }                         else { //Rank was not 4 before decreasing...                             for(let i = counter; i > 0; i--) {                                 if(tRank === 4) {                                     console.log(`Die Type is already 4, can't go any lower`);                                     tRank = tRank;                                 }                                 else {                                     if(tRank === 12 && tMod > 0) {                                         //Something like Professional or Expert Edge, need to reduce positive modifier first                                         tMod = tMod - 1;                                     }                                     else {                                         //No positive modifier on rank, so reduce the die type                                         tRank = tRank - 2;                                     }                                 }                             }                         }                     }                 }                 const sAttRank = trait, sAttMod = trait + 'mod', sAttDelta = `${trait}_delta`;     let sattrs = {};                 sattrs[sAttDelta]=tDelta;                 setAttrs(sattrs,{silent:true});                 sattrs = {};     sattrs[sAttRank]=tRank;     sattrs[sAttMod]=tMod;     setAttrs(sattrs);                              });         });     }); There are actually two sheet workers which use the same const array. I bolded the key lines where each start, just to make it a little clearer to see.  The first array (the one that would trigger most frequently) doesn't key off a change to delta, and the second only triggers on a change to delta.  In the second, that's also why I do two setAttrs calls, so I can set silently the delta trait before triggering the other changes that would trigger the first sheet worker. And here's the HTML: <div class='sheet-basetrait'> <input class="sheet-deltabutton" type="hidden" name="attr_agility_delta" value="0" /> <button class="sheet-traitbutton sheet-traitflexattbutton" type='roll' name='roll_tAgilityRoll' title="@{tAgilityRoll}" value='@{agilitybutton}' data-i18n="agility"> Agility</button> <input type="hidden" name="attr_agilitybutton" value="@{whisperagility} &{template:roll} @{rolltAgility} @{setmodsenc} @{showtraitmods}" /> <span><select name="attr_agility" title="@{agility}" class="sheet-traitdie" value="4"> <option value="4">d4</option> <option value="6">d6</option> <option value="8">d8</option> <option value="10">d10</option> <option value="12">d12</option> </select>+</span> <input class="sheet-otraitmod" type="number" name="attr_agilitymod" title="@{agilitymod}" value="0" /> <input class='sheet-moremods' type='checkbox' name='attr_showAgMod' /><span>y</span> <div class='sheet-basetrait sheet-traitmodplus'> <hr class="sheet-modsection"> <input class='sheet-whispercheck' type='checkbox' value='/w gm' name='attr_whisperagility' /> <span class='sheet-ModDesc' data-i18n="whisper-roll-to-gm">Whisper roll to GM</span><br /> <select name="attr_agwilddie" title="@{agwilddie}" class="sheet-traitdie" value="6"> <option value="4">d4</option> <option value="6">d6</option> <option value="8">d8</option> <option value="10">d10</option> <option value="12">d12</option> </select> <input type='text' class='sheet-ModDesc' name='attr_agwilddieinfo' placeholder='Standard Wild Die die type' data-i18n-placeholder="standard-wild-die-type" /><br /> <hr class="sheet-modsection"> <input type='text' class='sheet-ModDesc' name='attr_agModType' placeholder='Modifier due to edges, hindrances, etc' data-i18n-placeholder="att-mod-description" /> +<input class="sheet-otraitmod" type="number" name="attr_agrollMod" title="@{agrollMod}" value="0" /><br /> <label class="sheet-delta" data-i18n="die-step-delta">Increase/Decrease die type by number of steps</label><input class="sheet-otraitmod" style="border-bottom: 1px solid black;" type="number" name="attr_agility_delta" title="@{agility_delta}" value="0" /> </div> <input type='hidden' name='attr_agility_rank' value='1d4!' /> <input type='hidden' name='attr_agility_display' value='1d4' /> <input type='hidden' name='attr_rolltAgility' value='{{name=@{character_name} }} {{trait=^{agility}}} {{skill_rank=@{agility_display} }} {{skill_roll=[[@{agility_rank} + @{agrollMod}+ @{ModSumEnc}[Wounds, Fatigue, Encumbrance, Distracted] + @{traitmods} ]] }} {{mook=[[1d0+@{wdNum}]]}} {{wild_die=[[ 1d@{agwilddie}! + @{agilitymod} + @{agrollMod} + @{ModSumEnc}[Wounds, Fatigue, Encumbrance] + @{traitmods} ]]}}' /> </div>
1569487875
GiGs
Pro
Sheet Author
API Scripter
Can you describe what the sheet workers  purpose is, to give some background rather than trying to figure it all out from the code? Include what the different roles trait, traitmod, trait_old, traitrank, and trait_delta serve.  I suspect you have a setup here to track changes to an attribute, that might be a bit more convoluted than needed.
1569487961
Finderski
Pro
Sheet Author
Compendium Curator
GiGs said: Edit:  also that big if statement in the centre  where you create a counter, looks like very fragile code to me. The section where you create a counter, use it as the basis of a loop while also incrementing it elsewhere, and also duplicating the bulk of the code in the if and also the else section. I dont understand what you're doing there, but it looks like an error could easily creep into there and be very hard to debug. There's probably a much better way to do that section if you describe the logic in detail. Sure, the basic mechanic is you have a trait (Agility, Smarts, Spirit, Strength, Vigor, a bunch of skills, etc) which are ranked by die type, the lowest of which is d4 (d4-2 being considered Unskilled), the max of which is d12, but could be d12+#.  Generally speaking, the only time you should have a trait that is d?+? would be unskilled or when your die type is maxed out to d12. There are powers that allow one to boost (or decrease) a Trait's die type temporarily.  In either case, it's a die type that's boosted/lowered, except when Unskilled (d4-2) or Maxed (d12+). So, If boosted, I need to check to see if the die type is d12 before I increase it, and if it is d12, then I need to increase the modifier (example, d12 trait being boosted 2 steps would become d12+2, where a trait that is d8 being boosted twice would become d12). A weirdness is if I'm boosting an Unskilled (d4-2) trait, I first need make it skilled (d4) before boosting further.  So, if I were to boost an unskilled trait twice, the progression would be: d4-2 => d4 => d6. So, that's why I have to figure out of I'm Increasing or Decreasing the trait first, so I can check both of those scenarios. When a person resets (i.e. the trait becomes unboosted or unlowered, returning to normal), my anticipation is people are going to to want to just type 0 (also, I have CSS to give visual cues to indicate a trait is temporarily modified), so I'll need to undo what was done previously, so if I lowered a trait, when I set it to 0, I just do the reverse of what was done before. So, that's also why I decided it would be easier to watch for a decrease where the die type is d4 already and not really change anything, but set the delta back to 0 silently, so as not to trigger the sheet worker again.
1569488390

Edited 1569488457
GiGs
Pro
Sheet Author
API Scripter
Just noticed this:  In the second, that's also why I do two setAttrs calls, so I can set silently the delta trait before triggering the other changes that would trigger the first sheet worker. This almost certainly wont work the way you expect. There's no guarantee that the second setAttrs will actually fire after the first - you have no way to predict which one will trigger first. In situations like this, you are better off not using silent:true , and breaking the function into two separate sheet workers if possible. The first worker sets one set of attributes, then any attributes dependent on the attributes just set will trigger their own sheet workers. That's the only way I know of (because Promises are not supported in sheet workers) to trigger multiple setAttrs in the order you actually want them to go off - put them in separate sheet workers. Whatever you do, you need to reconstruct that worker to only need one setAttrs statement - multiple workers will not reliably trigger in the desired order. 
1569488401
Finderski
Pro
Sheet Author
Compendium Curator
GiGs said: Can you describe what the sheet workers  purpose is, to give some background rather than trying to figure it all out from the code? Include what the different roles trait, traitmod, trait_old, traitrank, and trait_delta serve.  I suspect you have a setup here to track changes to an attribute, that might be a bit more convoluted than needed. trait = Agility, Smarts, etc (will be a number that represents the die type...4, 6, 8, etc) traitmod = the modifier to the trait (eg. d4-2, the -2 is the trait mod) trait_old should be removed...it was an idea I'd been batting around, but realized it wouldn't work... trait_delta = the number of steps the trait is to be boosted/lowered by. Should always be an integer, can be positive or negative. And I don't doubt your last assessment...LOL I'm an impatient person and usually set out to code the solution and once I'm in the middle of it, realize it's not as straight forward as I thought when I started. I can think of at least two other ways to handle this, but none of them would be ideal, because of the way the Traits themselves impact other aspects of the character.  For example, if I boost Vigor, my Toughness (think AC for D&D...it's not exact corollary, but close enough) also increases. So, if possible, I'd like to account for that if I can.
1569488715
Finderski
Pro
Sheet Author
Compendium Curator
GiGs said: Just noticed this:  In the second, that's also why I do two setAttrs calls, so I can set silently the delta trait before triggering the other changes that would trigger the first sheet worker. This almost certainly wont work the way you expect. There's no guarantee that the second setAttrs will actually fire after the first - you have no way to predict which one will trigger first. In situations like this, you are better off not using silent:true , and breaking the function into two separate sheet workers if possible. The first worker sets one set of attributes, then any attributes dependent on the attributes just set will trigger their own sheet workers. That's the only way I know of to trigger multiple setAttrs in the order you actually want them to go off - put them in separate sheet workers. Whatever you do, you need to reconstruct that worker to only need one setAttrs statement - multiple workers will not reliably trigger in the desired order.  Well...that sucks. I realized that if they were different async things, but they are both in the same one and so I thought they'd trigger in the order presented, since they are both after all the other work is done...meaning, by the time we get to them, I've already gone through my if statements and for loops, etc.  :-/ Oh well...live and learn. I'll give that approach a shot.  Still not sure why silent isn't working at all, though...even if it's triggering out of order... :-/
1569488819

Edited 1569488901
GiGs
Pro
Sheet Author
API Scripter
Finderski said: And I don't doubt your last assessment...LOL I'm an impatient person and usually set out to code the solution and once I'm in the middle of it, realize it's not as straight forward as I thought when I started. I can think of at least two other ways to handle this, but none of them would be ideal, because of the way the Traits themselves impact other aspects of the character.  For example, if I boost Vigor, my Toughness (think AC for D&D...it's not exact corollary, but close enough) also increases. So, if possible, I'd like to account for that if I can. I havent studied your last couple of posts, just wanted to address this. What's wrong with use sheet workers to respond to Vigor changing to recalculate Toughness? There are times when using silent:true  is a bad idea. It's perfectly fine to have a chain reaction of sheet workers, each changing in turn (as long as you avoid circular logic). For instance, in D&D style games, increasing CON would change the CON Mod. That would then change all skills dependent on COn, HP, save mod, and anything else dependent on CON. If a character had any abilities based on a skill that used CON, the change in that skill would then trigger those sheet workes to update those abilities. So if you construct your sheet carefully, you can manage chain reactions like this to simplify sheet worker construction, and avoid async pitfalls, because this guarantees workers will be triggered in the correct order.
1569489093
GiGs
Pro
Sheet Author
API Scripter
Finderski said: Well...that sucks. I realized that if they were different async things, but they are both in the same one and so I thought they'd trigger in the order presented, since they are both after all the other work is done...meaning, by the time we get to them, I've already gone through my if statements and for loops, etc.  :-/ Oh well...live and learn. I'll give that approach a shot.  Still not sure why silent isn't working at all, though...even if it's triggering out of order... :-/ That's an understandable assumption. I made the same assumption myself too. I expect most people will stumble across this when first encountering async processes. 
1569489156

Edited 1569489191
Finderski
Pro
Sheet Author
Compendium Curator
GiGs said: Finderski said: And I don't doubt your last assessment...LOL I'm an impatient person and usually set out to code the solution and once I'm in the middle of it, realize it's not as straight forward as I thought when I started. I can think of at least two other ways to handle this, but none of them would be ideal, because of the way the Traits themselves impact other aspects of the character.  For example, if I boost Vigor, my Toughness (think AC for D&D...it's not exact corollary, but close enough) also increases. So, if possible, I'd like to account for that if I can. I havent studied your last couple of posts, just wanted to address this. What's wrong with use sheet workers to respond to Vigor changing to recalculate Toughness? There are times when using silent:true  is a bad idea. It's perfectly fine to have a chain reaction of sheet workers, each changing in turn (as long as you avoid circular logic). For instance, in D&D style games, increasing CON would change the CON Mod. That would then change all skills dependent on COn, HP, save mod, and anything else dependent on CON. If a character had any abilities based on a skill that used CON, the change in that skill would then trigger those sheet workes to update those abilities. So if you construct your sheet carefully, you can manage chain reactions like this to simplify sheet worker construction, and avoid async pitfalls, because this guarantees workers will be triggered in the correct order. That's exactly what I'm wanting to do...the only thing I want to trigger silently is the changing of delta, because I don't want to trigger delta again.  What I mean is this... First Delta change = -1 The rank is already d4, so I don't want to change anything and I want to reset the delta to 0 without triggering the sheet worker again, because triggering it again would no increase the trait by 1 (undoing what was done before), and now increasing a trait that wasn't decreased to begin with. Make sense?
1569489962
GiGs
Pro
Sheet Author
API Scripter
Finderski said: GiGs said: Finderski said: And I don't doubt your last assessment...LOL I'm an impatient person and usually set out to code the solution and once I'm in the middle of it, realize it's not as straight forward as I thought when I started. I can think of at least two other ways to handle this, but none of them would be ideal, because of the way the Traits themselves impact other aspects of the character.  For example, if I boost Vigor, my Toughness (think AC for D&D...it's not exact corollary, but close enough) also increases. So, if possible, I'd like to account for that if I can. I havent studied your last couple of posts, just wanted to address this. What's wrong with use sheet workers to respond to Vigor changing to recalculate Toughness? There are times when using silent:true  is a bad idea. It's perfectly fine to have a chain reaction of sheet workers, each changing in turn (as long as you avoid circular logic). For instance, in D&D style games, increasing CON would change the CON Mod. That would then change all skills dependent on COn, HP, save mod, and anything else dependent on CON. If a character had any abilities based on a skill that used CON, the change in that skill would then trigger those sheet workes to update those abilities. So if you construct your sheet carefully, you can manage chain reactions like this to simplify sheet worker construction, and avoid async pitfalls, because this guarantees workers will be triggered in the correct order. That's exactly what I'm wanting to do...the only thing I want to trigger silently is the changing of delta, because I don't want to trigger delta again.  What I mean is this... First Delta change = -1 The rank is already d4, so I don't want to change anything and I want to reset the delta to 0 without triggering the sheet worker again, because triggering it again would no increase the trait by 1 (undoing what was done before), and now increasing a trait that wasn't decreased to begin with. Make sense? I see. I dont have time to study the code right now, but I'm wondering if there might be a way to deal with this use the eventInfo properties to identify the trigger, and end the function. But that's just spitballing without examining the code. I'll try to find time to look at the code and explanations later, and see if i can suggest a solution. trait_delta = the number of steps the trait is to be boosted/lowered by. Should always be an integer, can be positive or negative. I might figure this out when studying the code, but is there are reason you are doing this as as a loop, and not simply adding the delta directly? You could have an array of the valid sequences like const validranks = ['d4-2','d4','d6', 'd8', 'd10', 'd12', 'd12+1', 'd12+2', /* etc */] then find the index of the current value, add delta to the index, then use  validranks [newindex] , and get the new attribute.
1569490799
GiGs
Pro
Sheet Author
API Scripter
Just had a thought <label class="sheet-delta" data-i18n="die-step-delta">Increase/Decrease die type by number of steps</label><input class="sheet-otraitmod" style="border-bottom: 1px solid black;" type="number" name="attr_agility_delta" title="@{agility_delta}" value="0" /> I'm suspecting you would be better off using this as a select instead of an input, with a predefined range of numbers - the valid changes. Then you can ensure it is presented as the change from normal, and dont need to worry about using "0" with two different meanings. If someone gets +1 and then +2, let them pick the +3 dropdown. And dont try to calculate cumulative changes, just always have delta modify from the base, not from the last score. Thus +1 is always +1 over the base. If this isn't how it works already, then I've misunderstood, but I'm having to rush and throwing this thought out there before I go.
1569499293
Finderski
Pro
Sheet Author
Compendium Curator
Yeah, I was considering something like that...If nothing else, this conversation has given me some things to try.  Thanks for your help GiGs, and if you have other ideas/thoughts, I'm always happy to hear them. :)
1569510757
Finderski
Pro
Sheet Author
Compendium Curator
Ok, so I changed the code around to this: traits.forEach(trait => { on(`change:${trait}_delta`, function(eventInfo) { console.log(`^o^ Delta changed for ${trait} ^o^`); trait = trait.replace(':','_'); console.log("trait = "+trait); getAttrs([trait, `${trait}mod`, `${trait}_base`, `${trait}mod_base`], function(v) { let tRank = parseInt(v[`${trait}`])||0; let tMod = parseInt(v[`${trait}mod`])||0; let tDelta = parseInt(eventInfo.newValue)||0; let prevDelta = parseInt(eventInfo.previousValue)||0; let tRankBase = v[`${trait}_base`]; let tModBase = v[`${trait}mod_base`]; const sAttRankBase = trait + '_base', sAttRankModBase = trait + 'mod_base', sAttRank = trait, sAttMod = trait + 'mod'; const sattrs = {}; let counter = Math.abs(tDelta); console.log(`+++ Rank/Base: ${tRank}/${tRankBase}, Mod/Base: ${tMod}/${tModBase}, Delta: ${tDelta}, Prev Delta: ${prevDelta}, `); //Check if previous Delta was 0, if so, will want to set base before changing anything if(prevDelta === 0) { //set the base values to the current values of the trait and mod console.log("^^^ Setting the Bases ^^^"); sattrs[sAttRankBase] = tRank; sattrs[sAttRankModBase] = tMod; } // Boosting/Lowering Trait or resetting to base? if(tDelta === 0) { console.log("--- Resetting stats to base ---"); sattrs[sAttRank] = tRankBase; sattrs[sAttMod] = tModBase; } else if(tDelta > 0) { console.log("+++ Boosting a Trait +++"); ((tRank === 4 && tMod === -2) ? (tMod = 0, counter = counter -1) : counter = counter); console.log(`+++ tRank: ${tRank}, tMod: ${tMod}, counter: ${counter}`); for(let i = counter; i > 0; i--) { if(tRank === 12) { console.log("+++ Rank is maxed...Boosting the Modifier +++"); tMod += 1; } else { console.log("+++ Boosting Die Type +++"); tRank += 2; } } sattrs[sAttRank] = tRank; sattrs[sAttMod] = tMod; } else { console.log("--- Lowering a Trait ---"); for(let i = counter; i > 0; i--) { if(tRank === 4) { console.log("--- Rank is already 4, breaking the loop ---"); break; } ((tRank === 12 && tMod > 0) ? tMod = tMod - 1 : tRank = tRank - 2); } sattrs[sAttRank] = tRank; sattrs[sAttMod] = tMod; } setAttrs(sattrs); }); }); }); It works, does what I expect it to, now the only problem is if the die starts at d4 and they try to decrease the attribute, the script works (meaning it breaks the for loop and sets the rank as 4, because a temp change is registered the chat output has the correct notation (I add an * the chat display), but when I set it back to 0, the * doesn't go away. :( I'm guessing it's because the change to the trait isn't registering as a change, because trait was already a d4...is that a valid assumption?
1569513063
Finderski
Pro
Sheet Author
Compendium Curator
Ok, I think I have it all sorted now. I just added delta to the watch list in the first sheet worker so we can get rid of the * when the trait die doesn't change.
1569542854
GiGs
Pro
Sheet Author
API Scripter
I'm glad you have it sorted. I can't promise to leave well alone, though, and might come back and ask more questions and suggest an alternative approach when i understand what's going on fully.  In the meantime, I suggest changing this else if(tDelta > 0) { console.log("+++ Boosting a Trait +++"); ((tRank === 4 && tMod === -2) ? (tMod = 0, counter = counter -1) : counter = counter); console.log(`+++ tRank: ${tRank}, tMod: ${tMod}, counter: ${counter}`); for(let i = counter; i > 0; i--) { if(tRank === 12) { console.log("+++ Rank is maxed...Boosting the Modifier +++"); tMod += 1; } else { console.log("+++ Boosting Die Type +++"); tRank += 2; } } sattrs[sAttRank] = tRank; sattrs[sAttMod] = tMod; } else { console.log("--- Lowering a Trait ---"); for(let i = counter; i > 0; i--) { if(tRank === 4) { console.log("--- Rank is already 4, breaking the loop ---"); break; } ((tRank === 12 && tMod > 0) ? tMod = tMod - 1 : tRank = tRank - 2); } sattrs[sAttRank] = tRank; sattrs[sAttMod] = tMod; } to this else {     tRank = Math.max(4, tRank + counter *2 + tMod *2);     if(tRank > 12) {         tMod = (tRank-12)/2;         tRank = 12;     } else { tMod = 0; } } This assumes the rule is as follows:  You get +/-2 die step foreach mod, and cant drop below 4, and cant go above 12. If above 12, and die steps get converted into +1. If you can go below 4, the first line and last would need changing. But it looks like it stops at d4, so the above should work. In situations like this, its best to convert die type and mod onto a single value, apply the modifiers to that value, then convert them back into die type and modifier. It makes the code a lot simpler.
1569543022
GiGs
Pro
Sheet Author
API Scripter
Finderski said: I'm guessing it's because the change to the trait isn't registering as a change, because trait was already a d4...is that a valid assumption? That makes sense to me.
1569543914
GiGs
Pro
Sheet Author
API Scripter
As an aside, the way you use different indicators for each of your console statements is cool (+++, ---, ^^^, etc.). You might find this function useful const log = (title, text, color = 'green', headerstyle = 'font-size:14px;  font-weight:bold;', bodystyle = 'font-size:12px; font-weight:normal;') => {     let titleStyle = `color:${color}; ${headerstyle} text-decoration:underline;`;     let textStyle = `color:${color}; ${bodystyle}`;     const output = `%c${title}:%c ${text}`;     console.log(output,titleStyle,textStyle); }; Drop this into your script block at the top, then you can replace a console statements like this: console.log("+++ Rank is maxed...Boosting the Modifier +++"); with log("+++","Rank is maxed...Boosting the Modifier"); or log("Rank is Maxed","Boosting the Modifier","red"); or log("Ability Rank Worker","Rank is Maxed - Boosting the Modifier","blue"); These will print the log statement as normal, but by default the color will be green, making it much easier to stand out. And you can enter a third argument (like "red") to change the colour. It has to be a colour that is valid in a css color statement. You need to enter a title and text, the color is optional. If you're adventurous you can enter a 4th and 5th argument, to change the title and text style - any html style string is valid.
1569595444
Finderski
Pro
Sheet Author
Compendium Curator
GiGs said: I'm glad you have it sorted. I can't promise to leave well alone, though, and might come back and ask more questions and suggest an alternative approach when i understand what's going on fully.  In the meantime, I suggest changing this else if(tDelta > 0) { console.log("+++ Boosting a Trait +++"); ((tRank === 4 && tMod === -2) ? (tMod = 0, counter = counter -1) : counter = counter); console.log(`+++ tRank: ${tRank}, tMod: ${tMod}, counter: ${counter}`); for(let i = counter; i > 0; i--) { if(tRank === 12) { console.log("+++ Rank is maxed...Boosting the Modifier +++"); tMod += 1; } else { console.log("+++ Boosting Die Type +++"); tRank += 2; } } sattrs[sAttRank] = tRank; sattrs[sAttMod] = tMod; } else { console.log("--- Lowering a Trait ---"); for(let i = counter; i > 0; i--) { if(tRank === 4) { console.log("--- Rank is already 4, breaking the loop ---"); break; } ((tRank === 12 && tMod > 0) ? tMod = tMod - 1 : tRank = tRank - 2); } sattrs[sAttRank] = tRank; sattrs[sAttMod] = tMod; } to this else {     tRank = Math.max(4, tRank + counter *2 + tMod *2);     if(tRank > 12) {         tMod = (tRank-12)/2;         tRank = 12;     } else { tMod = 0; } } This assumes the rule is as follows:  You get +/-2 die step foreach mod, and cant drop below 4, and cant go above 12. If above 12, and die steps get converted into +1. If you can go below 4, the first line and last would need changing. But it looks like it stops at d4, so the above should work. In situations like this, its best to convert die type and mod onto a single value, apply the modifiers to that value, then convert them back into die type and modifier. It makes the code a lot simpler. Cool.  I'll give it a try. :) GiGs said: As an aside, the way you use different indicators for each of your console statements is cool (+++, ---, ^^^, etc.). You might find this function useful const log = (title, text, color = 'green', headerstyle = 'font-size:14px;  font-weight:bold;', bodystyle = 'font-size:12px; font-weight:normal;') => {     let titleStyle = `color:${color}; ${headerstyle} text-decoration:underline;`;     let textStyle = `color:${color}; ${bodystyle}`;     const output = `%c${title}:%c ${text}`;     console.log(output,titleStyle,textStyle); }; Drop this into your script block at the top, then you can replace a console statements like this: console.log("+++ Rank is maxed...Boosting the Modifier +++"); with log("+++","Rank is maxed...Boosting the Modifier"); or log("Rank is Maxed","Boosting the Modifier","red"); or log("Ability Rank Worker","Rank is Maxed - Boosting the Modifier","blue"); These will print the log statement as normal, but by default the color will be green, making it much easier to stand out. And you can enter a third argument (like "red") to change the colour. It has to be a colour that is valid in a css color statement. You need to enter a title and text, the color is optional. If you're adventurous you can enter a 4th and 5th argument, to change the title and text style - any html style string is valid. And thanks for that tip, too. That'll definitely come in handy.