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

How to autofill a field by table lookup of attribute

1586107739

Edited 1586108103
Hey folks, me again.  Back with another question. In the section below you'll see two attributes, physical_strength_score, and melee_damage_bonus. <input class="ability" name="attr_physical_strength_score" type="number" value='0'> <input class="" name="attr_melee_damage_bonus" type="number" value='0'> According to the rules of the game, the  melee_damage_bonus  is determined by looking up, in a table, the  melee_damage_bonus that corresponds to the  physical_strength_score.  Here's that table: attr_physical_strength_score attr_melee_damage_bonus 1 to 5 -4 6 to 10 -3 11 to 15 -2 16 to 20 -1 21 to 25 -1 26 to 35 -1 36 to 40 -1 41 to 45 0 46 to 50 0 51 to 55 0 56 to 60 1 61 to 65 1 66 to 70 2 71 to 75 3 76 to 85 3 86 to 90 4 91 to 95 5 96 to 100 6 101 to 110 7 111 to 120 8 121 to 130 9 131 to 140 10 141 to 150 11 151 to 160 12 161 to 170 14 171 to 180 15 181 to 190 16 191 to 200 17 201 to 210 18 211 to 220 19 Lets just say that the asymmetry of this table is included so that the only answer is a table lookup, even though I just wish that were true.  How would I write a table lookup function for this? I could probably edit any table lookup function so that it fits my purpose.  I just haven't found an example that works. Thank you for reading = ).
1586108104

Edited 1586108302
Andreas J.
Forum Champion
Sheet Author
Translator
You need to have the table inside a codeblock or something, it's unreadable right now. Wow one second Look at Feast of legends sheet, you could use it as an template.
1586113107

Edited 1586113196
Thank you for responding = ). Looking at the provided example, I've written a solution that has a problem.  It doesn't work.  It's not that the values are wrong, rather there are none.  No matter how I edit the attr_physical_strength_score field, the field just remains blank.  I haven't determined the issue yet.  I'm hoping someone else can see it. Here are the fields that hold the values: <div class="pss backgroundColor section"> <input class="ability" name="attr_physical_strength_score" type="number" value='0'> </div> <div class="dm backgroundColor section"> <div class="fieldLabel section">Melee Dmg.</div> <input class="" name="attr_melee_damage_bonus" type="number" disabled="true"> </div> And, this is the solution I wrote: <script type="text/worker"> const int = score => parseInt(score, 10) || 0; const stats = ["attr_physical_strength_score"]; stats.forEach(stat => { on(`change:${stat}`, () => { getAttrs([stat], values => { const attr_physical_strength_score = int(values[stat]); console.log(attr_physical_strength_score); let attr_melee_damage_bonus = 0; if (attr_physical_strength_score <= 5) attr_melee_damage_bonus = "-4"; else if (attr_physical_strength_score <= 10) attr_melee_damage_bonus = "-3"; else if (attr_physical_strength_score <= 15) attr_melee_damage_bonus = "-2"; else if (attr_physical_strength_score <= 40) attr_melee_damage_bonus = "-1"; else if (attr_physical_strength_score <= 55) attr_melee_damage_bonus = "0"; else if (attr_physical_strength_score <= 65) attr_melee_damage_bonus = "1"; else if (attr_physical_strength_score <= 70) attr_melee_damage_bonus = "2"; else if (attr_physical_strength_score <= 85) attr_melee_damage_bonus = "3"; else if (attr_physical_strength_score <= 90) attr_melee_damage_bonus = "4"; else if (attr_physical_strength_score <= 95) attr_melee_damage_bonus = "5"; else if (attr_physical_strength_score <= 100) attr_melee_damage_bonus = "6"; else if (attr_physical_strength_score <= 110) attr_melee_damage_bonus = "7"; else if (attr_physical_strength_score <= 120) attr_melee_damage_bonus = "8"; else if (attr_physical_strength_score <= 130) attr_melee_damage_bonus = "9"; else if (attr_physical_strength_score <= 140) attr_melee_damage_bonus = "10"; else if (attr_physical_strength_score <= 150) attr_melee_damage_bonus = "11"; else if (attr_physical_strength_score <= 160) attr_melee_damage_bonus = "12"; else if (attr_physical_strength_score <= 170) attr_melee_damage_bonus = "14"; else if (attr_physical_strength_score <= 180) attr_melee_damage_bonus = "15"; else if (attr_physical_strength_score <= 190) attr_melee_damage_bonus = "16"; else if (attr_physical_strength_score <= 200) attr_melee_damage_bonus = "17"; else if (attr_physical_strength_score <= 210) attr_melee_damage_bonus = "18"; else attr_melee_damage_bonus = "19"; setAttrs({ [`attr_melee_damage_bonus`]: attr_melee_damage_bonus }); }); }); }); </script> I have two different <script type="text/worker"></script> sections.  I don't think that's an issue though.
1586115168

Edited 1586115294
Kraynic
Pro
Sheet Author
I think your problem is the disabled="true".  If I remember correctly, sheetworkers can't interact with disabled inputs.  Try changing it to readonly: <input class="" name="attr_melee_damage_bonus" type="number" readonly> Edit:  Or hidden, if you don't want this displayed.
I do want it displayed.  I changed it to: <input class="" name="attr_melee_damage_bonus" type="number" readonly> Unfortunately, while there is a value there now, it is not dependent on the value in attr_physical_strength_score.
1586117177

Edited 1586117255
Kraynic
Pro
Sheet Author
I'm not a good one to be looking over scripts (I have to ask for help often when doing anything with sheetworkers), but you might want to go through your script and strip out all the attr_ parts of your attributes.  I think you need to put in attribute names that match whatever would go inside a macro attribute call:  @{"whatever would be here"}.  So, while your html is attr_melee_damage_bonus, the script should be referencing melee_damage_bonus (I think).
1586118385
Andreas J.
Forum Champion
Sheet Author
Translator
If you look at the sheet, you notice that the mentioned attributes are stored as hidden inputs just above the sheetworker, and then the parts taht display them are just span elements.
No worries Kraynic.  I appreciate any response = ) I'd only noticed part of that.  Let me see what I can do with that information.
I made what I think is the change you suggested.  See my changes below: <div class="pss backgroundColor section"> <input class="field ability" name="attr_physical_strength_score" type="number" value='0'> </div> <div class="dm backgroundColor section"> <div class="fieldLabel section">Melee Dmg.</div> <input name="attr_melee_damage_bonus" type="hidden" value="0"> <span class="field derived" name="attr_melee_damage_bonus"></span> </div> Unfortunately,  attr_melee_damage_bonus  is still independent of  attr_physical_strength_score .  In fact, there's no way to change the value of  attr_melee_damage_bonus .
1586123848

Edited 1586124273
admiralnlson
Sheet Author
Try replacing setAttrs({ [`attr_melee_damage_bonus`]: attr_melee_damage_bonus }); with setAttrs({ melee_damage_bonus: attr_melee_damage_bonus }); The attr_ prefix should not be used in sheet workers. See&nbsp; <a href="https://wiki.roll20.net/Sheet_Worker_Scripts#Functions" rel="nofollow">https://wiki.roll20.net/Sheet_Worker_Scripts#Functions</a>
1586124268

Edited 1586124279
I made the change suggested: &lt;script type="text/worker"&gt; const int = score =&gt; parseInt(score, 10) || 0; const stats = ["attr_physical_strength_score"]; stats.forEach(stat =&gt; { on(`change:${stat}`, () =&gt; { getAttrs([stat], values =&gt; { const attr_physical_strength_score = int(values[stat]); console.log(attr_physical_strength_score); let attr_melee_damage_bonus = 0; if (attr_physical_strength_score &lt;= 5) attr_melee_damage_bonus = "-4"; else if (attr_physical_strength_score &lt;= 10) attr_melee_damage_bonus = "-3"; else if (attr_physical_strength_score &lt;= 15) attr_melee_damage_bonus = "-2"; else if (attr_physical_strength_score &lt;= 40) attr_melee_damage_bonus = "-1"; else if (attr_physical_strength_score &lt;= 55) attr_melee_damage_bonus = "0"; else if (attr_physical_strength_score &lt;= 65) attr_melee_damage_bonus = "1"; else if (attr_physical_strength_score &lt;= 70) attr_melee_damage_bonus = "2"; else if (attr_physical_strength_score &lt;= 85) attr_melee_damage_bonus = "3"; else if (attr_physical_strength_score &lt;= 90) attr_melee_damage_bonus = "4"; else if (attr_physical_strength_score &lt;= 95) attr_melee_damage_bonus = "5"; else if (attr_physical_strength_score &lt;= 100) attr_melee_damage_bonus = "6"; else if (attr_physical_strength_score &lt;= 110) attr_melee_damage_bonus = "7"; else if (attr_physical_strength_score &lt;= 120) attr_melee_damage_bonus = "8"; else if (attr_physical_strength_score &lt;= 130) attr_melee_damage_bonus = "9"; else if (attr_physical_strength_score &lt;= 140) attr_melee_damage_bonus = "10"; else if (attr_physical_strength_score &lt;= 150) attr_melee_damage_bonus = "11"; else if (attr_physical_strength_score &lt;= 160) attr_melee_damage_bonus = "12"; else if (attr_physical_strength_score &lt;= 170) attr_melee_damage_bonus = "14"; else if (attr_physical_strength_score &lt;= 180) attr_melee_damage_bonus = "15"; else if (attr_physical_strength_score &lt;= 190) attr_melee_damage_bonus = "16"; else if (attr_physical_strength_score &lt;= 200) attr_melee_damage_bonus = "17"; else if (attr_physical_strength_score &lt;= 210) attr_melee_damage_bonus = "18"; else attr_melee_damage_bonus = "19"; setAttrs({ 'melee_damage_bonus': attr_melee_damage_bonus }); }); }); }); &lt;/script&gt; Unfortunately, the issue still exists.&nbsp; Thanks for responding though = ).
There was a typo in my original answer. You should remove the single quotes around&nbsp; melee_damage_bonus
I made the change suggested: &lt;script type="text/worker"&gt; const int = score =&gt; parseInt(score, 10) || 0; const stats = ["attr_physical_strength_score"]; stats.forEach(stat =&gt; { on(`change:${stat}`, () =&gt; { getAttrs([stat], values =&gt; { const attr_physical_strength_score = int(values[stat]); console.log(attr_physical_strength_score); let attr_melee_damage_bonus = 0; if (attr_physical_strength_score &lt;= 5) attr_melee_damage_bonus = "-4"; else if (attr_physical_strength_score &lt;= 10) attr_melee_damage_bonus = "-3"; else if (attr_physical_strength_score &lt;= 15) attr_melee_damage_bonus = "-2"; else if (attr_physical_strength_score &lt;= 40) attr_melee_damage_bonus = "-1"; else if (attr_physical_strength_score &lt;= 55) attr_melee_damage_bonus = "0"; else if (attr_physical_strength_score &lt;= 65) attr_melee_damage_bonus = "1"; else if (attr_physical_strength_score &lt;= 70) attr_melee_damage_bonus = "2"; else if (attr_physical_strength_score &lt;= 85) attr_melee_damage_bonus = "3"; else if (attr_physical_strength_score &lt;= 90) attr_melee_damage_bonus = "4"; else if (attr_physical_strength_score &lt;= 95) attr_melee_damage_bonus = "5"; else if (attr_physical_strength_score &lt;= 100) attr_melee_damage_bonus = "6"; else if (attr_physical_strength_score &lt;= 110) attr_melee_damage_bonus = "7"; else if (attr_physical_strength_score &lt;= 120) attr_melee_damage_bonus = "8"; else if (attr_physical_strength_score &lt;= 130) attr_melee_damage_bonus = "9"; else if (attr_physical_strength_score &lt;= 140) attr_melee_damage_bonus = "10"; else if (attr_physical_strength_score &lt;= 150) attr_melee_damage_bonus = "11"; else if (attr_physical_strength_score &lt;= 160) attr_melee_damage_bonus = "12"; else if (attr_physical_strength_score &lt;= 170) attr_melee_damage_bonus = "14"; else if (attr_physical_strength_score &lt;= 180) attr_melee_damage_bonus = "15"; else if (attr_physical_strength_score &lt;= 190) attr_melee_damage_bonus = "16"; else if (attr_physical_strength_score &lt;= 200) attr_melee_damage_bonus = "17"; else if (attr_physical_strength_score &lt;= 210) attr_melee_damage_bonus = "18"; else attr_melee_damage_bonus = "19"; setAttrs({ melee_damage_bonus: attr_melee_damage_bonus }); }); }); }); &lt;/script&gt; Unfortunately, the issue still exists.&nbsp; Thanks again for responding though = ).
1586125741
Kraynic
Pro
Sheet Author
What I meant is that I don't think "attr_" should exist anywhere in your sheetworker.&nbsp; Your html has to use that to tell the Roll20 sandbox that it is creating an attribute.&nbsp; Outside of the html, you just refer to whatever comes after that prefix.&nbsp; So all of your "attr_physical_strength_score" and "attr_melee_damage_bonus" in the script need to have the "attr_" part removed and become "physical_strength_score" and "melee_damage_bonus". At least that is how everything is done in sheetworkers on my sheet.&nbsp; For instance, there is a Physical Strength attribute that is "attr_ps" in the html.&nbsp; It generates a damage bonus which is "attr_ps_bonus" in the html.&nbsp; In the sheetworker, it is just "ps" and "ps_bonus".
1586126144

Edited 1586126575
Huzzahh!!! Apologies for misreading your message Kraynic.&nbsp; I made the change you suggested, and it worked!&nbsp; Thank you everyone for your help (^.^). Here is the functional code = D. &lt;div class="pss backgroundColor section"&gt; &lt;input class="field ability" name="attr_physical_strength_score" type="number" value='0'&gt; &lt;/div&gt; &lt;div class="dm backgroundColor section"&gt; &lt;div class="fieldLabel section"&gt;Melee Dmg.&lt;/div&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;input name="attr_melee_damage_bonus" type="hidden" value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;span class="field derived" name="attr_melee_damage_bonus"&gt;&lt;/span&gt; &lt;/div&gt; &lt;script type="text/worker"&gt; const int = score =&gt; parseInt(score, 10) || 0; const stats = ["physical_strength_score"]; stats.forEach(stat =&gt; { on(`change:${stat}`, () =&gt; { getAttrs([stat], values =&gt; { const physical_strength_score = int(values[stat]); console.log(physical_strength_score); let melee_damage_bonus = 0; if (physical_strength_score &lt;= 5) melee_damage_bonus = "-4"; else if (physical_strength_score &lt;= 10) melee_damage_bonus = "-3"; else if (physical_strength_score &lt;= 15) melee_damage_bonus = "-2"; else if (physical_strength_score &lt;= 40) melee_damage_bonus = "-1"; else if (physical_strength_score &lt;= 55) melee_damage_bonus = "0"; else if (physical_strength_score &lt;= 65) melee_damage_bonus = "1"; else if (physical_strength_score &lt;= 70) melee_damage_bonus = "2"; else if (physical_strength_score &lt;= 85) melee_damage_bonus = "3"; else if (physical_strength_score &lt;= 90) melee_damage_bonus = "4"; else if (physical_strength_score &lt;= 95) melee_damage_bonus = "5"; else if (physical_strength_score &lt;= 100) melee_damage_bonus = "6"; else if (physical_strength_score &lt;= 110) melee_damage_bonus = "7"; else if (physical_strength_score &lt;= 120) melee_damage_bonus = "8"; else if (physical_strength_score &lt;= 130) melee_damage_bonus = "9"; else if (physical_strength_score &lt;= 140) melee_damage_bonus = "10"; else if (physical_strength_score &lt;= 150) melee_damage_bonus = "11"; else if (physical_strength_score &lt;= 160) melee_damage_bonus = "12"; else if (physical_strength_score &lt;= 170) melee_damage_bonus = "14"; else if (physical_strength_score &lt;= 180) melee_damage_bonus = "15"; else if (physical_strength_score &lt;= 190) melee_damage_bonus = "16"; else if (physical_strength_score &lt;= 200) melee_damage_bonus = "17"; else if (physical_strength_score &lt;= 210) melee_damage_bonus = "18"; else melee_damage_bonus = "19"; setAttrs({ melee_damage_bonus: melee_damage_bonus }); }); }); }); &lt;/script&gt;
1586126369

Edited 1586126651
admiralnlson
Sheet Author
Ah yeah, missed the&nbsp; attr_physical_strength_score&nbsp; part, my bad. Kraynic is right, this had to go as well. const stats = ["physical_strength_score"]; Think of it this way: attributes are not prefixed by attr_ in the "Attributes &amp; Abilities" tab of your sheet, right? That's because attributes in the game's DB do not have these prefixes. Well, sheet workers work with the DB. The "attr_" prefix is only needed in HTML elements names so the Roll20 HTML parser can know that you want to link the element with an attribute.
1586127336
Kraynic
Pro
Sheet Author
Nice!
1586149850

Edited 1586150112
GiGs
Pro
Sheet Author
API Scripter
I'm arriving late, but I do have an optimisation suggestion for your worker. Does the strength ever go above 220? I'll post two version, one ofr if 220 is max, and one for if it goes above 220 and follows the same scale. But before I do that, your worker starts with stats.forEach, and you only need that if if you have a set of attributes which all follow the same rules. In your case, you only have one stat, so you dont need it. So here's an optimised version of your script: const&nbsp;int&nbsp;=&nbsp;score&nbsp;=&gt;&nbsp;parseInt(score)&nbsp;||&nbsp;0; on('change:physical_strength_score',&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;getAttrs(['physical_strength_score'],&nbsp;values&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;physical_strength_score&nbsp;=&nbsp;int(values[stat]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(physical_strength_score); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;melee_damage_bonus&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(physical_strength_score&nbsp;&lt;=&nbsp;15)&nbsp;melee_damage_bonus&nbsp;=&nbsp;Math.max(-4,&nbsp;Math.ceil(physical_strength_score/5)&nbsp;-5); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(physical_strength_score&nbsp;&lt;=&nbsp;40)&nbsp;melee_damage_bonus&nbsp;=&nbsp;-1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(physical_strength_score&nbsp;&lt;=&nbsp;55)&nbsp;melee_damage_bonus&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(physical_strength_score&nbsp;&lt;=&nbsp;65)&nbsp;melee_damage_bonus&nbsp;=&nbsp;1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(physical_strength_score&nbsp;&lt;=&nbsp;95)&nbsp;melee_damage_bonus&nbsp;=&nbsp;Math.ceil(physical_strength_score/5)&nbsp;-14; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(physical_strength_score&nbsp;&lt;=&nbsp;160)&nbsp;melee_damage_bonus&nbsp;=&nbsp;Math.ceil(physical_strength_score/10)&nbsp;-4; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;Math.min(19, Math.ceil(physical_strength_score/10)&nbsp;-3); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;melee_damage_bonus:&nbsp;melee_damage_bonus &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;}); }); A couple of things to note: when assigning the melee_damage_bonus there's no need to set it as a string (="3"), you j=should just set it as a number (=3). This allows you to perform arithmetic on it if you need to. The reason the Feast of Legends sheet uses quotes was because it wanted to include the + in the output, but you dont seem to have that. (Note to the sheet's author: eerily familiar code, i think i have seen code like that somewhere before... :) ) Your table does follow standard rules - there are sections where every 5 points gives +1, and sections where every 10 points gives +1. These are perfect opportunities to use arithmetic to reduce the number of rows you need to write. In the above code, Math.ceil() rounds up whatever is inside it, and Math.max says, "take the highest value". Since Math.max starts with -4, that calculation never results in a value below -4, thus making the bottom of the table worlk. Likewise at the other end, we have Math.min(19, a calculation),&nbsp; so that calculation never results in a value greater than 19. If strength can go above 220, then change this line &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;Math.min(19, Math.ceil(physical_strength_score/10)&nbsp;-3); to &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;Math.ceil(physical_strength_score/10); and it will work for any strength value. I do notice in your original chart there's no 13 value: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;141 to 150 11 151 to 160 12 161 to 170 14 171 to 180 15 Is that a mistake? the calculation would need tweaking slightly if so.
Hey GiGs, Thank you for your post.&nbsp; I had also noticed the missing 13 value.&nbsp; Unfortunately, I can't currently speak to whether that is a mistake.&nbsp; With my GM, for now, I'm assuming no.&nbsp; I've added it to the list of questions I have for him, that he doesn't yet have time to answer.&nbsp; I'm confident I could rework it to incorporate that change if needed. You said this was optimized.&nbsp; I haven't had time to look over this yet, but right now I'm seeing three changes. removing "forEach",&nbsp;presumably&nbsp;to reduce processing overhead removing quotation marks to allow for more utility reducing the number of "if else"s using math, also presumably to reduce processing overhead So far, my HTML is only 1500 lines.&nbsp; The character sheet is only about 10% complete though.&nbsp; I've seen them get to 20,000 lines.&nbsp; At what point would you say this kind of optimization is worth the sacrifice in ease of edit-ability?&nbsp; I ask because this game system is still in demo, and there are often rules changes.&nbsp; So I see the decision as a trade-off of processing speed vs editing speed.
1586293576

Edited 1586293692
Hi GiGs My variables have changed a bit since that post.&nbsp; I removed "_score" for instance. I attempted to take advantages of the changes you showed me, but it's not working.&nbsp; I wonder whether you see the issue(s). &nbsp;&nbsp;&nbsp;&nbsp;&lt;div class="pss backgroundColor section"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input class="field ability" name="attr_physical_strength" type="number" value='0' min='1' max='220'&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;div class="mg backgroundColor section"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div class="fieldLabel section"&gt;Melee Dmg&lt;/div&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input name="attr_melee_damage_adjustment" type="hidden" value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span class="field derived" name="attr_melee_damage_adjustment"&gt;&lt;/span&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt; &lt;script type="text/worker"&gt; &nbsp;&nbsp;&nbsp;&nbsp;const int = score =&gt; parseInt(score) || 0; &nbsp;&nbsp;&nbsp;&nbsp;on('change:physical_strength', () =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs(['physical_strength'], values =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const physical_strength = int(values[stat]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(physical_strength); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let melee_damage_adjustment = 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (physical_strength &lt;= 15) melee_damage_adjustment = Math.max(-4, Math.ceil(physical_strength_score/5) -5); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 40) melee_damage_adjustment = -1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 55) melee_damage_adjustment = 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 65) melee_damage_adjustment = 1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 95) melee_damage_adjustment = Math.ceil(physical_strength_score/5) -14; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 160) melee_damage_adjustment = Math.ceil(physical_strength_score/10) -4; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else Math.min(19, Math.ceil(physical_strength_score/10) -3); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; melee_damage_adjustment: melee_damage_adjustment &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;}); &lt;/script&gt;
1586321561
GiGs
Pro
Sheet Author
API Scripter
Timothy Z. said: Hey GiGs, Thank you for your post.&nbsp; I had also noticed the missing 13 value.&nbsp; Unfortunately, I can't currently speak to whether that is a mistake.&nbsp; With my GM, for now, I'm assuming no.&nbsp; I've added it to the list of questions I have for him, that he doesn't yet have time to answer.&nbsp; I'm confident I could rework it to incorporate that change if needed. You said this was optimized.&nbsp; I haven't had time to look over this yet, but right now I'm seeing three changes. removing "forEach",&nbsp;presumably&nbsp;to reduce processing overhead removing quotation marks to allow for more utility reducing the number of "if else"s using math, also presumably to reduce processing overhead So far, my HTML is only 1500 lines.&nbsp; The character sheet is only about 10% complete though.&nbsp; I've seen them get to 20,000 lines.&nbsp; At what point would you say this kind of optimization is worth the sacrifice in ease of edit-ability?&nbsp; I ask because this game system is still in demo, and there are often rules changes.&nbsp; So I see the decision as a trade-off of processing speed vs editing speed. It looks like you only have one sheet worker at present, so optimisation wont make much difference at all. In fact most optimisations really dont make that much difference except on the biggest sheets, or when you are starting from really inefficient code. I'm talking more from a design perspective - code like this is easier to edit. The few if/else lines you have, the better - it's always easier to edit&nbsp; less code. You just need to identify the patterns that make up the table and write the code.&nbsp; I was going to include an alternate method of getting the values that doesnt use if/else statements, and is much easier to edit later - if you're interested, prompt me and I'll ad it once I've fully woken up.
1586321721
GiGs
Pro
Sheet Author
API Scripter
Timothy Z. said: Hi GiGs My variables have changed a bit since that post.&nbsp; I removed "_score" for instance. I attempted to take advantages of the changes you showed me, but it's not working.&nbsp; I wonder whether you see the issue(s). &nbsp;&nbsp;&nbsp;&nbsp;&lt;div class="pss backgroundColor section"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input class="field ability" name="attr_physical_strength" type="number" value='0' min='1' max='220'&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;div class="mg backgroundColor section"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div class="fieldLabel section"&gt;Melee Dmg&lt;/div&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input name="attr_melee_damage_adjustment" type="hidden" value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span class="field derived" name="attr_melee_damage_adjustment"&gt;&lt;/span&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt; &lt;script type="text/worker"&gt; &nbsp;&nbsp;&nbsp;&nbsp;const int = score =&gt; parseInt(score) || 0; &nbsp;&nbsp;&nbsp;&nbsp;on('change:physical_strength', () =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs(['physical_strength'], values =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const physical_strength = int(values[stat]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(physical_strength); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let melee_damage_adjustment = 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (physical_strength &lt;= 15) melee_damage_adjustment = Math.max(-4, Math.ceil(physical_strength_score/5) -5); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 40) melee_damage_adjustment = -1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 55) melee_damage_adjustment = 0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 65) melee_damage_adjustment = 1; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 95) melee_damage_adjustment = Math.ceil(physical_strength_score/5) -14; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (physical_strength &lt;= 160) melee_damage_adjustment = Math.ceil(physical_strength_score/10) -4; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else Math.min(19, Math.ceil(physical_strength_score/10) -3); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; melee_damage_adjustment: melee_damage_adjustment &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;}); &lt;/script&gt; The problem is this line const&nbsp;physical_strength&nbsp;=&nbsp;int(values[stat]); Which was my mistake. I'm not sure how I left that in. That should be const &nbsp; physical_strength &nbsp;=&nbsp; int ( values. physical_strength);
Thanks for the correction GiGs.&nbsp; I'll make use of it as soon as I have time. I am interested in an alternative to if/then statements.&nbsp; I'm not sure what it would be though.
1586331849

Edited 1586332658
GiGs
Pro
Sheet Author
API Scripter
One approach that is very handy in place of if statements, when you are just returning a single value, is to convert the table to an array.&nbsp; The first thing to do is to convert your original table to a simple array. You had this: attr_physical_strength_score attr_melee_damage_bonus 1 to 5 -4 6 to 10 -3 11 to 15 -2 16 to 20 -1 21 to 25 -1 26 to 35 -1 36 to 40 -1 41 to 45 0 46 to 50 0 51 to 55 0 56 to 60 1 61 to 65 1 66 to 70 2 71 to 75 3 76 to 85 3 86 to 90 4 91 to 95 5 96 to 100 6 101 to 110 7 111 to 120 8 121 to 130 9 131 to 140 10 141 to 150 11 151 to 160 12 161 to 170 14 171 to 180 15 181 to 190 16 191 to 200 17 201 to 210 18 211 to 220 19 The left hand side follows a very predictable set of rules (every 5 points below 100, and 10 points after), so thats pretty easy to convert. First thing to do is get rid of the left side, so we are left with this array const melee_table = [-4, -3, -2, -1, -1, -1, -1, -1, 0, 0, 0, 1, 1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19]; Note that 26-35 doesnt follow the rest of the rules, so I added an extra -1 in the above so that there's one entry for every 5 points below 100. The same is true at 76-85. Note: With array notation, you can get something from an array by doing&nbsp; let something = array[3]; So in this case, we just need to divide the strength by 5 if its &lt; 100, by 10 if its over, and add a correction factor, then get that value from the array. Math.ceil() rounds up so we can get with 'row' of the table by using&nbsp; let row = Math.ceil(physical_strength/5); This will give us the row in the table for strength scores below 100.&nbsp; To get the 100 or above we need to divide by 10, and add a correction factor that makes the 100 value correct. The correction factor is 10, since 100/10 = 10, and we want it to equal 20. We could use a traditional if statement here (if strength/10, divide strength by 5, etc) but a ternary operator is perfect for replacing if statemnts that have only two options. A ternary operator looks like this let something = (if test) ? (value if true) : (value if false); You dont need to use brackets, they are just there to help identify the different sections of the expression. So in this case: let strength_factor = (strength &lt;100 ) ? Math.ceil(strength/5) : Math.ceil(strength / 10) +10; let strength_bonus = bonus_table[strength_factor -1]; The -1 on that last line is because arrays start at 0, not 1. array[3] would give us the 4th value, not the 3rd value (0, 1, 2, 3), so we have to reduce the result by 1 to match properly. Putting it all together, and combining a couple of lines gives us const melee_table = [-4, -3, -2, -1, -1, -1, -1, -1, 0, 0, 0, 1, 1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19]; const strength_bonus = bonus_table[((strength &lt;100 ) ? Math.ceil(strength/5) : Math.ceil(strength / 10) +10) -1]; That's a much better way to convert tables into javascript, if they follow identifiable rules, than long if/else statements. You do sometimes have to alter the table a bit to match - like the way i added an extra value in the 26-35 and 76-85 ranges to make sure the number of items was correct. Note: I used let sometimes and const others. const defines a variable that you cannot change (const stands for constant), and let defines a variable you can change (add to, subtract from, etc). You can just use let all the time without a problem,&nbsp; but if you know a variable is not meant to change, using const helps to avoid some errors.&nbsp; The important takeaway here: when converting a table from some source to a computer program, you should always look at the table and see if there is any repeating pattern there that you can use to simplify the data. ('Simplify' in programming terms, it doesnt always make it simple to read...)
1586378048

Edited 1586378232
Hey folks, I do my best to make it easier for anyone replying to my questions.&nbsp; So, I try to only include the relevant broken code.&nbsp; I currently have 35 sheetworkers on my 1600 line character sheet, and many more planned.&nbsp; They take up 70% of the lines, although your posts to this thread should help me reduce that significantly.&nbsp; Thanks for all your help. That array approach reminds me of strategies I've used in C++.&nbsp; I'm quite pleased to see it.&nbsp; I'm not as familiar with Javascript yet, but I'm working on it.&nbsp; I'm specifically interested in its limitations.&nbsp; Some of the things I'm planning to do with this character sheet should require more complex and creative approaches.&nbsp; I'm not ready to tackle them though, so I don't yet know how to describe what I mean.
1586382288
Andreas J.
Forum Champion
Sheet Author
Translator
Tim Z said: &nbsp;I'm not ready to tackle them though, so I don't yet know how to describe what I mean. That's the thing, you should describe what you want to happen , and not on how you think you might implement it. It can very well be that the best solution is constructed in a completely different way, and we send you down dead ends while helping you to implement what you think will work, instead of what you want to happen. This is generally known as the " XY Problem ".
1586413205

Edited 1586413314
GiGs
Pro
Sheet Author
API Scripter
Andreas J. said: That's the thing, you should describe what you want to happen , and not on how you think you might implement it. This is very good advice. There have been so many posts where I've been struggling to get an asker to explain what their problem is, while they are too focused on their chosen solution. When youre new, its hard to know the best way to do something, so its best to give an overview of what the problem is, as well as the ways you've tried to solve it.