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 with a conditional sheetworker please

What I'm after is a numerical attribute ('counter') that, when pushed above or below specific but irregular thresholds, will change the value of another numerical attribute ('rating'). I.e. Counter = 0,1            Rating = 0 Counter = 2,3,4         Rating = 1 Counter = 5,6,7,8,9   Rating = 2 Counter = 10+           Rating = 3 Here's what I've got: <input type="number" name="attr_counter" min="0" /> <input type="number" name="attr_rating" min="0" /> <script type="text/worker"> on('change:counter', () => {     getAttrs(['counter', 'rating'], v=> {         let newcounter = parseInt(v.counter) || 0;         let newrating = parseInt(v.rating) || 0;             if(newcounter < 2) {                 newrating = 0;             }             if(newcounter > 1 && newcounter < 5) {                 newrating = 1;             }             if(newcounter > 4 && newcounter < 10) {                 newrating = 2;             }             if(newcounter > 9) {                 newrating = 3;             }         setAttrs({             rating: newrating         })     }) }); </script> Am I close, or on a very wrong track? Can anyone please advise?
1645274359

Edited 1645274459
GiGs
Pro
Sheet Author
API Scripter
Have you tried it? Your worker looks fine, but you can simplify that if statement with the else keyword, so that the comparison is only done one, and this simplifies your compasion.       on ( 'change:counter' , () => {             getAttrs ([ 'counter ], v => {                 let newcounter = parseInt ( v . counter ) || 0 ;                 let newrating ;                 if ( newcounter < 2 ) {                     newrating = 0 ;                 } else if ( newcounter < 5 ) {                     newrating = 1 ;                 } else if ( newcounter < 10 ) {                     newrating = 2 ;                 } else {                     newrating = 3 ;                 }                 setAttrs ({                     rating : newrating                 });             });         }); Notice in this method, the if statement has to be constructed in the order listed, with the lower values at the bottom. And the last comparison, else with no check, is just when all previous tests are not true, so it automatically catches all values over 9. I also added semi-colons where they should be, and removed the rating from getAttrs. You dont care what the old rating was, you are just setting a new one that is completely constructed within the worker. There are more compact ways to build this test, but this (and your original code) are both fine and do the job.
I had tried it, but forgot that the script worker doesn't kick in until the input is de-selected! So I got it right first time? Cool!! Thanks for the simplifying tip too, that will be really handy.
1645275521

Edited 1645281511
GiGs
Pro
Sheet Author
API Scripter
Here's a more compact version which uses some numerical analysis and functions you might not be aware of. I'll explain it afterwards. on ( 'change:counter' , () => {             getAttrs ([ 'counter' ], v => {                 let newcounter = parseInt ( v . counter ) || 0 ;                 let newrating = Math . min ( 3 , Math . max ( 0 , Math . ceil ( Math . sqrt ( newcounter )) - 1 )) ;                 setAttrs ({                     rating : newrating                 });             });         }); So first lets look at the numbers: Counter = 0,1            Rating = 0 Counter = 2,3,4         Rating = 1 Counter = 5,6,7,8,9   Rating = 2 Counter = 10+           Rating = 3 There is relationship here between most of the steps: 1/4/9 is what you get if you square the numbers 1/2/3. So if you take the squareroot of the numbers, and round up, you are almost there. 1 = 1, 4 = 2, 9 = 3. Just need to subtract 1. Math.sqrt() will take the square root of a number. Math.ceil will round a number up. So Math.ceil(Math.sqrt(number)) -1 will get most of the work done. Byut this doesnt account for numbers below 1, or numbers above 16 (which would calculate a result higher than 3). Luckily the Math.min() function will always take the lowest of numbers seperated by a comma (so Math.min(3,5,1) gives a 5result of 1), and Math.max() does the same but takes the highest. So we can use both of those: Math.max(0,Math.ceil(Math.sqrt(number)) -1) will never give a result lower than 0, and then Math.min(3, Math.max(0,Math.ceil(Math.sqrt(number)) -1)) will never give a number higher than 3. In conclusion, if you anaylse a sequence for patterns, you can often find a more compact way to build a sheet worker. But this is important to realise: you don't have to . The previous workers will do the job fine.
1645275650

Edited 1645275716
GiGs
Pro
Sheet Author
API Scripter
Aero said: I had tried it, but forgot that the script worker doesn't kick in until the input is de-selected! So I got it right first time? Cool!! Thanks for the simplifying tip too, that will be really handy. I think you can avoid this problem by setting a default value, like this: <input type="number" name="attr_counter" min="0" value="0" /> <input type="number" name="attr_rating" min="0" value="0"/> You should always set default values like this, especially if that attribute is going to be used in other calculations. And yes, got it first time. Breaking into javascript isnt the easiest thing so nice work :)
1645281542
GiGs
Pro
Sheet Author
API Scripter
I just realised I I included an incorrect variable name in my last code and have updated it.