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

More sheetworker butchering: if, else if with 2 things that need to be true?

1594094240
Kraynic
Pro
Sheet Author
For Heroes Unlimited, there are 4 tiers of strength, which affect how much the character can lift and carry. Normal (strengthtoggle = 1, which is selected by default) where lift is always ps*20, but carry is ps*10 below 17 and ps*20 at 17 or higher. Extraordinary (strengthtoggle = 2) where lift is ps*200 and carry is ps*100 Superhuman (strengthtoggle = 3) where lift is ps*300 and carry is ps*200 Supernatural (strengthtoggle = 4) where lift is ps*400 and carry is ps*300 My current mangling of a simpler sheetworker from my Fantasy sheet looks like this: on("change:ps change:strengthtoggle sheet:opened", function () { getAttrs(['ps','strengthtoggle'], function (values) { const ps = parseInt(values['ps'])||0; const strengthtoggle = parseInt(values['strengthtoggle'])||0; let carry = 0; if(strengthtoggle >= 1 && ps < 17) carry = ps*10; else if(strengthtoggle >= 1 && ps > 16) carry = ps*20; else if(strengthtoggle >= 2) carry = ps*100; else if(strengthtoggle >= 3) carry = ps*200; else if(strengthtoggle >= 4) carry = ps*300; let lift = 0; if(strengthtoggle >= 1) lift = ps*20; else if(strengthtoggle >= 2) lift = ps*200; else if(strengthtoggle >= 3) lift = ps*300; else if(strengthtoggle >= 4) lift = ps*400; let ps_bonus = 0; if(ps > 15) ps_bonus = Math.round(ps -15); setAttrs({ lift: lift, carry: carry, ps_bonus: ps_bonus }); }); }); This does the switch just fine at ps 17, but doesn't adjust with the change of strengthtoggle.  I'm not getting any errors in the console when I change that value, so I am hoping someone here can point me in the right direction.
1594094472

Edited 1594094521
Kraynic
Pro
Sheet Author
And all it took was me posting this in public to realize I had greater than instead of less than in all of those checks...  *sigh* on("change:ps change:strengthtoggle sheet:opened", function () { getAttrs(['ps','strengthtoggle'], function (values) { const ps = parseInt(values['ps'])||0; const strengthtoggle = parseInt(values['strengthtoggle'])||0; let carry = 0; if(strengthtoggle <= 1 && ps < 17) carry = ps*10; else if(strengthtoggle <= 1 && ps > 16) carry = ps*20; else if(strengthtoggle <= 2) carry = ps*100; else if(strengthtoggle <= 3) carry = ps*200; else if(strengthtoggle <= 4) carry = ps*300; let lift = 0; if(strengthtoggle <= 1) lift = ps*20; else if(strengthtoggle <= 2) lift = ps*200; else if(strengthtoggle <= 3) lift = ps*300; else if(strengthtoggle <= 4) lift = ps*400; let ps_bonus = 0; if(ps > 15) ps_bonus = Math.round(ps -15); setAttrs({ lift: lift, carry: carry, ps_bonus: ps_bonus }); }); }); It is working, but if there is a better way to do this, let me know.
1594102269

Edited 1594110754
GiGs
Pro
Sheet Author
API Scripter
You can do that easier. Notice that there is a direct relationship between the strength toggle (2-4) and the multiplier (200 - 400), and the carry is 100 * (toggle-1) with special handling at toggle 1. First lets simplify (which is programmer-speak for "make more complicated") this bit:             let ps_bonus = 0; if(ps > 15) ps_bonus = Math.round(ps -15); We can use the ternary operator to set this in one line. The ternary operator is a fancy if statement, you do the if after the equals sign like this:             const ps_bonus = (ps > 15) ? Math.round(ps -15) : 0; This looks complicated, but is actually pretty simple. It follows this form:             const VARIABLE_NAME = (IF STATEMENT) ? (VALUE IF TRUE) : (VALUE IF FALSE); That structure is excellent when you have an if statement with two possible values. You can just do it in a single line. The question mark and colon divide it up into three sections - the test, the true value, and the false value. I wanted to explain that because I'll be using it again. So lets assume the toggle is 2 or higher. We can do the carry and lift like this:         if(strengthtoggle >= 2) lift = ps * strengthtoggle * 100;         if(strengthtoggle >= 2) carry = ps * (strengthtoggle-1) * 100;         Lets make that strengthtoggle name shorter to make it easier          if(s_toggle >= 2) lift = ps * s_toggle * 100;         if(s_toggle >= 2) carry = ps * (s_toggle -1) * 100; We can turn the above into a ternary operator, like so         const lift = (s_toggle >= 2) ? (ps * s_toggle * 100) : WHAT GOES HERE;         const carry = (s_toggle >= 2) ? (ps * (s_toggle -1) * 100) : WHAT GOES HERE; Notice we have just moved the if statement to the right side of the equal sign. Now the WHAT GOES HERE is where we put when  s_toggle  is not 2 or more, in otherwords when it is 1. For lift that is simple:         const lift = (s_toggle >= 2) ? (ps * s_toggle * 100) : (ps * 20); When  s_toggle  is 1, lift is PS *20, and when it is 2 or higher, it is PS *  s_toggle  * 100. That handles it, You dont actually need the brackets around the sections above. I did them that way to make it clear where each section starts and ends. This is fine too:         const lift = s_toggle >= 2 ? ps * s_toggle * 100 : ps * 20; But you might find the previous version more readable. Carry is a bit more complicated, because it has two possibilities. Lets make a ternary operator for that:         const carry = (ps < 17) ? (ps * 10) : (ps * 20); Another way of writing that would be  const carry = ps * 10 * (ps > 16 ? 2 : 1); You can use ternary operators like this within other arithematic. The above are true only when  s_toggle  is 1.  Here's the clever bit (and also the reason I went to such lengths to explain the ternary operator) - we can put brackets around that entire thing, and put in the false statement of the previous ternary operator, like so:         const carry = s_toggle >= 2 ? ps * (s_toggle -1) * 100 : (ps < 17 ? ps * 10 : ps * 20); Yes, you can nest ternary operators inside each other. Or the alternate version:         const carry = s_toggle >= 2 ? ps * (s_toggle -1) * 100 : (ps * 10 * (ps > 16 ? 2 : 1)); This looks really complex, but remember to use the question mark and colon as separators, and look at each of those parts separately. So we have:         const carry =             s_toggle >= 2              ?             ps * (s_toggle -1) * 100             :             (ps * 10 * (ps > 16 ? 2 : 1)); Notice how similar this is to a more traditional version: let carry = 0; if( s_toggle >= 2) {     carry =  ps * (s_toggle -1) * 100 ; else {     carry =  (ps * 10 * (ps > 16 ? 2 : 1)); } The ternary operator allows for much more compact code, and once you are familiar with the layout (remember the ? and : are dividers) it's just as easy to read. One last thing, these statements: s_toggle >= 2  are a bit overkill. We know  s_toggle  is an integer, it cannot have values between one and 2, so we can instead use: s_toggle > 1  Putting it all together we get on("change:ps  change:strengthtoggle sheet:opened", function () {     getAttrs(['ps',' strengthtoggle '], function (values) {         const ps = parseInt(values.ps)||0;         const s_toggle = parseInt(values. strengthtoggle )||0;         const lift = s_toggle > 1 ? ps * s_toggle * 100 : ps * 20;         const carry = s_toggle > 1 ? ps * (s_toggle -1) * 100 : ps * 10 * (ps > 16 ? 2 : 1);         const ps_bonus = ps > 15 ? Math.round(ps -15) : 0;         setAttrs({             lift, carry, ps_bonus         });     }); }); I made two other minor changes here. Notice the way you get the values. You can use the values.ps syntax instead of values['ps']  when the name doesnt contain any invalid javascript characters (mainly the dash). You couldnt do this for an attribute named  strength-toggle , but strengthtoggle and strength_toggle are both fine. Also in setAttrs, you had             setAttrs({ lift: lift, carry: carry, ps_bonus: ps_bonus }); There's nothing wrong with this - it's the accepted way to do it. But when the variable has exactly the same name as the attribute it is setting (and it has to be an exact match), you can reduce it to this             setAttrs({ lift, carry, ps_bonus }); or even             setAttrs({ lift, carry, ps_bonus }); In javascript, linebreaks are always optional. We use them only to break the code up to make it more readable.  One last thing: do you really need Math.round on that ps_bonus? Since ps is always an integer, its always a whole number. Can ps be fractional? In which case change this line          const   ps_bonus  =  ps  >  15  ?  Math . round ( ps  - 15 ) :  0 ; to         const ps_bonus = ps > 15 ? ps -15 : 0; Actually another and probably better way to write this is         const ps_bonus = Math.max(ps -15, 0); Math.max takes the larger of the numbers supplied (working just like the kh operator in roll20).  Hope this helps!
1594132514
Kraynic
Pro
Sheet Author
Thanks!  I'll try to wrap my brain around that so that I can re-mangle it for use elsewhere.  :p I don't remember why there is the math.round for ps_bonus in my Fantasy sheet (since this is just an altered sheetworker from there).  I should probably go back and do a little cleanup editing on that sheet as well soon.
1594187385
GiGs
Pro
Sheet Author
API Scripter
If it helps, just focus on this part: GiGs  said: This looks complicated, but is actually pretty simple. It follows this form:             const VARIABLE_NAME = (IF STATEMENT) ? (VALUE IF TRUE) : (VALUE IF FALSE); and here is a part of the previous post with simplified (and incorrect) math so it isnt as distracting, to illustrate the parts in action:         const carry = s_toggle > 1 ? ps * 100 : ps * 10; This looks really complex, but remember to use the question mark and colon as separators, and look at each of those parts separately. So we have:         const carry =             s_toggle > 1              ?             ps * 100             :             ps * 10 ; Notice how similar this is to a more traditional version: let carry = 0; if( s_toggle > 1) {     carry =  ps * 100 ; else {     carry =  ps * 10; } The ternary operator allows for much more compact code, and once you are familiar with the layout (remember the ? and : are dividers) it's just as easy to read.