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 .
×

Spacemaster Stats - Sheetworker to calculate total stat bonus - Advice requested.

I'm trying to get 10 stats each with 3 subvalues to add those values to get the total bonus. I'm not a coder, but I felt like I was onto something here. It doesn't seem to work, though. Could anyone take a look as see if I missed something, or maybe tell me if this is a no-go?  <script type="text/worker">     const stats = ["co", "ag", "sd", "me", "re", "st", "qu", "pr", "em", "in"];     stats.forEach(stat => {     on("change:${stat} sheet:opened", function() {     getAttrs(["${stat}_norm","${stat}_race", "${stat}_back"], function(values) {     let stat_norm = parseInt(values.${stat}_norm,10)||0;     let stat_race = parseInt(values.${stat}_race,10)||0;     let stat_back = parseInt(values.${stat}_back,10)||0;     let stat_bonus = stat_norm + stat_race + stat_back;     setAttrs({     [`${stat}_bonus`]: stat_bonus     });     });     });     }); </script>
I took out all the variables and just tried to do one stat. It almost works, but for some reason the 'on change:co'  portion only happens if I make two changes. It does the math right, and updates the field, but I have to change it, leave the field, and then change it again. The on sheet:opened  works fine. I've tried looking through the forums, but everyone's use cases seem so specific to what they are trying to do. I'm not above making a sheet worker for each stat, instead of one worker for all stats, but it's no good if it doesn't work in real time. <script type="text/worker"> on("change:co sheet:opened", function() { getAttrs(['co_norm','co_race','co_back'], function(values) { let stat_norm = parseInt(values.co_norm,10)||0; let stat_race = parseInt(values.co_race,10)||0; let stat_back = parseInt(values.co_back,10)||0; let stat_bonus = stat_norm + stat_race + stat_back; setAttrs ({ [`co_bonus`]: stat_bonus }); }); }); </script>
1588631493
GiGs
Pro
Sheet Author
API Scripter
The mistake in your first worker is this section      let stat_norm = parseInt(values.${stat}_norm,10)||0;     let stat_race = parseInt(values.${stat}_race,10)||0;     let stat_back = parseInt(values.${stat}_back,10)||0; It should be      let stat_norm = parseInt(values[`${stat}_norm`])||0;     let stat_race = parseInt(values[`${stat}_race`])||0;     let stat_back = parseInt(values[`${stat}_back`])||0; Notice the format for those is the same as in the setAttrs statement which is correct [`${stat}_bonus`]: stat_bonus You need the square brackets and quotes (notice they are backticks: `, not single quotes ' or double quotes " - for this use, you must use the correct quote type).  For the second worker, the only thing that stands out to me is this part: setAttrs ({ [`co_bonus`]: stat_bonus }); In this instance, where you are using the actual name and not a variable which stands in for the name, you shouldnt be using the square brackets, and the quotes are optional. This should work: setAttrs ({ co_bonus: stat_bonus });
1588632161
GiGs
Pro
Sheet Author
API Scripter
In the first worker, the ON(change) and getAttrs line are also incorrect. whenever you have ${} inside a string, you have to use backticks. Here's the complete worker: const stats = ['co', 'ag', 'sd', 'me', 're', 'st', 'qu', 'pr', 'em', 'in']; stats.forEach(stat => {     on(`change:${stat} sheet:opened`, function () {         getAttrs([`${stat}_norm`, `'${stat}_race`, `${stat}_back`], function (values) {             let stat_norm = parseInt(values[`${stat}_norm`]) || 0;             let stat_race = parseInt(values[`${stat}_race`]) || 0;             let stat_back = parseInt(values[`${stat}_back`]) || 0;             let stat_bonus = stat_norm + stat_race + stat_back;             setAttrs({                 [`${stat}_bonus`]: stat_bonus             });         });     }); });
Okay, so after finding the errant quote in your version, it does work to update all the values, but still requires me to make two changes. And, both changes have to be to the same attribute. If I increase attr_co such that the value should update, it doesn't do anything. If I increment it again. or set it back to what it was, it makes the change it should have made on the last change.  If I change the value of attr_co and then change anything else, nothing happens to the calculated value until I come back and change attr_co again, other than opening the sheet, which seems to work fine.         <label>Constitution</label> <input type="number" name="attr_co" > <input type="number" name="attr_co_pot" > <input type="number" name="attr_co_dev" readonly > <input type="number" name="attr_co_norm" readonly value="0" > <input type="number" name="attr_co_race" readonly value="0" > <input type="number" name="attr_co_back" value="0" > <input type="number" name="attr_co_bonus" value="0" readonly >
1589685325

Edited 1589690778
GiGs
Pro
Sheet Author
API Scripter
What was the errant quote in my version, btw? ( Edit:  i found it! wow, that was hard to spot, lol.) You mention changing co, but now that i look at the sheet worker, I'm not seeing how that actually affects the bonus. The bonus looks like its calculated purely from the co_norm, co_race, and co_back stats. That being the case, the change line needs adjusting to this:  on(`change: ${stat}_norm change:${stat}_race change:${stat}_back sheet:opened`, function () { I dont see how the base co stat is involved here. Do you have any other sheet workers that use it? If so, it's possible they should be combined with this one.
Sorry, I should have pointed out the errant quote's location instead of being mysterious about it. 'co' is one of the const values, and it's the 'on change' trigger. There is another sheet worker that determines the co_norm value, and another that determines the co_race value. The co_back is value is manually provided by the user. So, with those determined, the goal is to make it so that when 'co' is changed, it triggers the script to update co_bonus. This has made me realize that the co_bonus value needs to be updated anytime co_norm, co_race or co_back are changed, rather than when co is changed, since not every step of change to a stat's raw value changes it's bonus.  Here are my worker scripts. Can I just jam all these into one script section? I'm not really sure how the logic would work out trying to combine them. <script type="text/worker"> //Normal Stat Bonus Calculator const int = score => parseInt(score, 10) || 0; // Auto-calculates & updates 'Stat Bonus' based on changes to corresponding 'Base Stat', // If the Base stat is less than 20, the sheet sets the bonus to "-2" const stats = ["co", "ag", "sd", "me", "re", "st", "qu", "pr", "em", "in"]; stats.forEach(stat => { on(`change:${stat}`, () => { getAttrs([stat], values => { const stat_base = int(values[stat]); console.log(stat_base); let stat_norm = 0; if (stat_base >= 103) stat_bonus = "35"; else if (stat_base >= 102) stat_norm = "35"; else if (stat_base >= 101) stat_norm = "30"; else if (stat_base >= 100) stat_norm = "25"; else if (stat_base >= 98) stat_norm = "20"; else if (stat_base >= 96) stat_norm = "15"; else if (stat_base >= 90) stat_norm = "10"; else if (stat_base >= 75) stat_norm = "5"; else if (stat_base >= 20) stat_norm = "0"; else stat_norm = "-2"; setAttrs({ [`${stat}_norm`]: stat_norm }); }); }); }); </script> <script type="text/worker"> //Race stat bonus table on("change:race sheet:opened", function () { getAttrs(['race'], function(values) { const races = { 'Human': {st_race: 5, qu_race: 0, pr_race: 0, in_race: 0, em_race: 0, co_race: 0, ag_race: 0, sd_race: 5, me_race: 0, re_race: 0, hitdietype: 'd8'}, 'Neo-Human': {st_race: 5, qu_race: 5, pr_race: 5, in_race: 5, em_race: 5, co_race: 5, ag_race: 5, sd_race: 5, me_race: 5, re_race: 5, hitdietype: 'd8'}, 'Humanoid I': {st_race: 10, qu_race: 0, pr_race: -10, in_race: 0, em_race: 0, co_race: 10, ag_race: -5, sd_race: -15, me_race: -5, re_race: -5, hitdietype: 'd10'}, 'Humanoid II': {st_race: -10, qu_race: 10, pr_race: -5, in_race: 0, em_race: 0, co_race: 0, ag_race: 10, sd_race: -20, me_race: 0, re_race: 0, hitdietype: 'd10'}, 'Humanoid III': {st_race: -10, qu_race: 0, pr_race: 0, in_race: 10, em_race: 10, co_race: -5, ag_race: 0, sd_race: -5, me_race: 5, re_race: 10, hitdietype: 'd8'}, 'Transhuman I': {st_race: 20, qu_race: -5, pr_race: 10, in_race: 0, em_race: -10, co_race: 20, ag_race: -5, sd_race: -5, me_race: -5, re_race: -10, hitdietype: 'd10+1'}, 'Transhuman II': {st_race: 0, qu_race: 15, pr_race: -5, in_race: 15, em_race: -5, co_race: -5, ag_race: 20, sd_race: -5, me_race: 10, re_race: 5, hitdietype: 'd10'}, 'Transhuman III': {st_race: -5, qu_race: 0, pr_race: 0, in_race: 5, em_race: 0, co_race: -5, ag_race: 0, sd_race: -5, me_race: 15, re_race: 15, hitdietype: 'd8'}, 'Transhuman IV': {st_race: -5, qu_race: -5, pr_race: 5, in_race: 5, em_race: 5, co_race: -5, ag_race: 0, sd_race: 30, me_race: 5, re_race: -10, hitdietype: 'd8'}, 'Transhuman V': {st_race: 15, qu_race: 15, pr_race: 15, in_race: 10, em_race: 0, co_race: 20, ag_race: 15, sd_race: 5, me_race: 15, re_race: 10, hitdietype: 'd10+1'}, 'Transhuman VI': {st_race: 10, qu_race: 10, pr_race: 10, in_race: 10, em_race: 5, co_race: 10, ag_race: 10, sd_race: 20, me_race: 10, re_race: 10, hitdietype: 'd10'}, 'Transhuman VII': {st_race: 25, qu_race: 15, pr_race: 15, in_race: -5, em_race: 5, co_race: 25, ag_race: 15, sd_race: 10, me_race: 0, re_race: -5, hitdietype: 'd10+2'}, 'Transhuman VIII': {st_race: 10, qu_race: 5, pr_race: 5, in_race: 10, em_race: 15, co_race: 0, ag_race: 10, sd_race: 15, me_race: 5, re_race: 10, hitdietype: 'd10'}, 'Transhuman IX': {st_race: 5, qu_race: 0, pr_race: 10, in_race: 20, em_race: 20, co_race: 0, ag_race: 0, sd_race: 30, me_race: 30, re_race: 20, hitdietype: 'd8'}, 'Transhuman X': {st_race: 5, qu_race: 10, pr_race: 5, in_race: 30, em_race: 0, co_race: 5, ag_race: 20, sd_race: 5, me_race: 15, re_race: 20, hitdietype: 'd8'}, 'Transhuman XI': {st_race: 5, qu_race: 10, pr_race: 0, in_race: 20, em_race: 10, co_race: 5, ag_race: 5, sd_race: 10, me_race: 25, re_race: 15, hitdietype: 'd8'}, 'Transhuman XII': {st_race: 15, qu_race: 10, pr_race: 15, in_race: 5, em_race: 10, co_race: 20, ag_race: 10, sd_race: 20, me_race: 15, re_race: 10, hitdietype: 'd10+1'}, 'Replicant Type I': {st_race: 20, qu_race: 20, pr_race: 0, in_race: 0, em_race: 0, co_race: 10, ag_race: 20, sd_race: -10, me_race: 0, re_race: 0, hitdietype: 'd10+2'}, 'Replicant Type II': {st_race: 0, qu_race: 0, pr_race: -10, in_race: -5, em_race: 20, co_race: 0, ag_race: 20, sd_race: -20, me_race: 0, re_race: 20, hitdietype: 'd10'}, 'Replicant Type III': {st_race: 0, qu_race: 0, pr_race: 10, in_race: 5, em_race: 0, co_race: 0, ag_race: 0, sd_race: -10, me_race: 20, re_race: 10, hitdietype: 'd8'}, 'Replicant Type IV': {st_race: 5, qu_race: 5, pr_race: 20, in_race: -10, em_race: 10, co_race: 5, ag_race: 5, sd_race: -20, me_race: -10, re_race: -10, hitdietype: 'd10'}, 'Replicant Type V': {st_race: 0, qu_race: 0, pr_race: -10, in_race: -15, em_race: -20, co_race: 0, ag_race: 0, sd_race: -20, me_race: -20, re_race: -20, hitdietype: 'd8'}, 'Altha': {st_race: 15, qu_race: 15, pr_race: 20, in_race: 5, em_race: 10, co_race: 20, ag_race: 15, sd_race: 20, me_race: 15, re_race: 15, hitdietype: 'd10'}, 'Idorians': {st_race: -10, qu_race: 10, pr_race: -5, in_race: 0, em_race: 0, co_race: 0, ag_race: 10, sd_race: -20, me_race: 0, re_race: 0, hitdietype: 'd10'}, 'Snee': {st_race: 30, qu_race: 20, pr_race: 20, in_race: 0, em_race: -20, co_race: 20, ag_race: 10, sd_race: 0, me_race: -5, re_race: 5, hitdietype: 'd20'}, 'Aoemarans': {st_race: -90, qu_race: -60, pr_race: -50, in_race: 10, em_race: 30, co_race: 10, ag_race: -5, sd_race: 10, me_race: 15, re_race: 10, hitdietype: 'd4'}, 'Trilopters': {st_race: 20, qu_race: 10, pr_race: -15, in_race: -10, em_race: 10, co_race: 5, ag_race: 10, sd_race: -5, me_race: 0, re_race: 5, hitdietype: 'd8'}, 'Areed': {st_race: 10, qu_race: 5, pr_race: -10, in_race: -10, em_race: 10, co_race: 5, ag_race: 10, sd_race: -10, me_race: 0, re_race: -5, hitdietype: 'd10'}, } let race = values.race; if (!races.hasOwnProperty( race )) { console.log("Error: The item " + race + " is not found within the race Object."); return; } setAttrs({ "co_race": races[race].co_race, "ag_race": races[race].ag_race, "sd_race": races[race].sd_race, "me_race": races[race].me_race, "re_race": races[race].re_race, "st_race": races[race].st_race, "qu_race": races[race].qu_race, "pr_race": races[race].pr_race, "em_race": races[race].em_race, "in_race": races[race].in_race, "hitdietype": races[race].hitdietype }); }); }); </script> <script type="text/worker"> //Total stat bonus calculator const stats = ['co', 'ag', 'sd', 'me', 're', 'st', 'qu', 'pr', 'em', 'in']; stats.forEach(stat => { on(`change:${stat} sheet:opened`, function () { getAttrs([`${stat}_norm`, `${stat}_race`, `${stat}_back`], function (values) { let stat_norm = parseInt(values[`${stat}_norm`]) || 0; let stat_race = parseInt(values[`${stat}_race`]) || 0; let stat_back = parseInt(values[`${stat}_back`]) || 0; let stat_bonus = stat_norm + stat_race + stat_back; setAttrs({ [`${stat}_bonus`]: stat_bonus }); }); }); }); </script>
1589769212

Edited 1589769284
GiGs
Pro
Sheet Author
API Scripter
Yes, you can combine them into one script block, and in deed you should. While having the workers in separate blocks does work, roll20 updates have broken this functionality before and might do it again, so its best to have all your sheet workers in one script block. If you try the last suggestion i posted, changing this line on(`change:${stat} sheet:opened`, function () { to this on(`change: ${stat}_norm change:${stat}_race change:${stat}_back sheet:opened`, function () { you should get that section working. Also the end of your race worker can be simplified. Note that races[race] will look something like this (picking one entry at random): {st_race: 5, qu_race: 10, pr_race: 5, in_race: 30, em_race: 0, co_race: 5, ag_race: 20, sd_race: 5, me_race: 15, re_race: 20, hitdietype: 'd8'} And set Attrs expects data to be in this format: {attribute_name: value, attribute_name: value, attribute_name} So its already in the right format to be sent to setAttrs. Your attribute names are correct, so you can do this:         let race = values.race; if (!races.hasOwnProperty( race )) { console.log("Error: The item " + race + " is not found within the race Object."); return; } setAttrs(races[race]);
You've been amazingly helpful. I'll spend some time working on this soon and let you know how it turns out. Thanks!
1589777522
GiGs
Pro
Sheet Author
API Scripter
You're welcome :) One thing: when you combine them into script block, you'll have two of these lines: const stats = ['co', 'ag', 'sd', 'me', 're', 'st', 'qu', 'pr', 'em', 'in']; Remove the second one. 
And, that did the trick for combining all the scripts into one block. Now my worker can pick the normal bonus based on the stat value, the race bonus based on race, and total the race, normal and background bonuses automatically, as well as assigning the development points for each stat's base value. Six weeks ago when I started working on this I thought this was way over my head. Now I see that it's just a little over my head. Thanks! I'll have some other questions, but I'll start new threads for those. I think we can say this one is solved. For the edification of anyone else working on Rolemaster style stats, here is my worker script. <script type="text/worker"> //Stat bonus tables and calculations const int = score => parseInt(score, 10) || 0; // Auto-calculates & updates 'Stat Bonus' based on changes to corresponding 'Base Stat', // If the Base stat is less than 20, the sheet sets the bonus to "-2" const stats = ["co", "ag", "sd", "me", "re", "st", "qu", "pr", "em", "in"]; stats.forEach(stat => { on(`change:${stat}`, () => { getAttrs([stat], values => { const stat_base = int(values[stat]); console.log(stat_base); let stat_norm = 0; if (stat_base >= 103) stat_norm = "40"; else if (stat_base >= 102) stat_norm = "35"; else if (stat_base >= 101) stat_norm = "30"; else if (stat_base >= 100) stat_norm = "25"; else if (stat_base >= 98) stat_norm = "20"; else if (stat_base >= 96) stat_norm = "15"; else if (stat_base >= 90) stat_norm = "10"; else if (stat_base >= 75) stat_norm = "5"; else if (stat_base >= 20) stat_norm = "0"; else stat_norm = "-2"; setAttrs({ [`${stat}_norm`]: stat_norm }); }); }); }); on("change:race sheet:opened", function () { getAttrs(['race'], function(values) { const races = { 'Human': {st_race: 5, qu_race: 0, pr_race: 0, in_race: 0, em_race: 0, co_race: 0, ag_race: 0, sd_race: 5, me_race: 0, re_race: 0, hitdietype: 'd8'}, 'Neo-Human': {st_race: 5, qu_race: 5, pr_race: 5, in_race: 5, em_race: 5, co_race: 5, ag_race: 5, sd_race: 5, me_race: 5, re_race: 5, hitdietype: 'd8'}, 'Humanoid I': {st_race: 10, qu_race: 0, pr_race: -10, in_race: 0, em_race: 0, co_race: 10, ag_race: -5, sd_race: -15, me_race: -5, re_race: -5, hitdietype: 'd10'}, 'Humanoid II': {st_race: -10, qu_race: 10, pr_race: -5, in_race: 0, em_race: 0, co_race: 0, ag_race: 10, sd_race: -20, me_race: 0, re_race: 0, hitdietype: 'd10'}, 'Humanoid III': {st_race: -10, qu_race: 0, pr_race: 0, in_race: 10, em_race: 10, co_race: -5, ag_race: 0, sd_race: -5, me_race: 5, re_race: 10, hitdietype: 'd8'}, 'Transhuman I': {st_race: 20, qu_race: -5, pr_race: 10, in_race: 0, em_race: -10, co_race: 20, ag_race: -5, sd_race: -5, me_race: -5, re_race: -10, hitdietype: 'd10+1'}, 'Transhuman II': {st_race: 0, qu_race: 15, pr_race: -5, in_race: 15, em_race: -5, co_race: -5, ag_race: 20, sd_race: -5, me_race: 10, re_race: 5, hitdietype: 'd10'}, 'Transhuman III': {st_race: -5, qu_race: 0, pr_race: 0, in_race: 5, em_race: 0, co_race: -5, ag_race: 0, sd_race: -5, me_race: 15, re_race: 15, hitdietype: 'd8'}, 'Transhuman IV': {st_race: -5, qu_race: -5, pr_race: 5, in_race: 5, em_race: 5, co_race: -5, ag_race: 0, sd_race: 30, me_race: 5, re_race: -10, hitdietype: 'd8'}, 'Transhuman V': {st_race: 15, qu_race: 15, pr_race: 15, in_race: 10, em_race: 0, co_race: 20, ag_race: 15, sd_race: 5, me_race: 15, re_race: 10, hitdietype: 'd10+1'}, 'Transhuman VI': {st_race: 10, qu_race: 10, pr_race: 10, in_race: 10, em_race: 5, co_race: 10, ag_race: 10, sd_race: 20, me_race: 10, re_race: 10, hitdietype: 'd10'}, 'Transhuman VII': {st_race: 25, qu_race: 15, pr_race: 15, in_race: -5, em_race: 5, co_race: 25, ag_race: 15, sd_race: 10, me_race: 0, re_race: -5, hitdietype: 'd10+2'}, 'Transhuman VIII': {st_race: 10, qu_race: 5, pr_race: 5, in_race: 10, em_race: 15, co_race: 0, ag_race: 10, sd_race: 15, me_race: 5, re_race: 10, hitdietype: 'd10'}, 'Transhuman IX': {st_race: 5, qu_race: 0, pr_race: 10, in_race: 20, em_race: 20, co_race: 0, ag_race: 0, sd_race: 30, me_race: 30, re_race: 20, hitdietype: 'd8'}, 'Transhuman X': {st_race: 5, qu_race: 10, pr_race: 5, in_race: 30, em_race: 0, co_race: 5, ag_race: 20, sd_race: 5, me_race: 15, re_race: 20, hitdietype: 'd8'}, 'Transhuman XI': {st_race: 5, qu_race: 10, pr_race: 0, in_race: 20, em_race: 10, co_race: 5, ag_race: 5, sd_race: 10, me_race: 25, re_race: 15, hitdietype: 'd8'}, 'Transhuman XII': {st_race: 15, qu_race: 10, pr_race: 15, in_race: 5, em_race: 10, co_race: 20, ag_race: 10, sd_race: 20, me_race: 15, re_race: 10, hitdietype: 'd10+1'}, 'Replicant Type I': {st_race: 20, qu_race: 20, pr_race: 0, in_race: 0, em_race: 0, co_race: 10, ag_race: 20, sd_race: -10, me_race: 0, re_race: 0, hitdietype: 'd10+2'}, 'Replicant Type II': {st_race: 0, qu_race: 0, pr_race: -10, in_race: -5, em_race: 20, co_race: 0, ag_race: 20, sd_race: -20, me_race: 0, re_race: 20, hitdietype: 'd10'}, 'Replicant Type III': {st_race: 0, qu_race: 0, pr_race: 10, in_race: 5, em_race: 0, co_race: 0, ag_race: 0, sd_race: -10, me_race: 20, re_race: 10, hitdietype: 'd8'}, 'Replicant Type IV': {st_race: 5, qu_race: 5, pr_race: 20, in_race: -10, em_race: 10, co_race: 5, ag_race: 5, sd_race: -20, me_race: -10, re_race: -10, hitdietype: 'd10'}, 'Replicant Type V': {st_race: 0, qu_race: 0, pr_race: -10, in_race: -15, em_race: -20, co_race: 0, ag_race: 0, sd_race: -20, me_race: -20, re_race: -20, hitdietype: 'd8'}, 'Altha': {st_race: 15, qu_race: 15, pr_race: 20, in_race: 5, em_race: 10, co_race: 20, ag_race: 15, sd_race: 20, me_race: 15, re_race: 15, hitdietype: 'd10'}, 'Idorians': {st_race: -10, qu_race: 10, pr_race: -5, in_race: 0, em_race: 0, co_race: 0, ag_race: 10, sd_race: -20, me_race: 0, re_race: 0, hitdietype: 'd10'}, 'Snee': {st_race: 30, qu_race: 20, pr_race: 20, in_race: 0, em_race: -20, co_race: 20, ag_race: 10, sd_race: 0, me_race: -5, re_race: 5, hitdietype: 'd20'}, 'Aoemarans': {st_race: -90, qu_race: -60, pr_race: -50, in_race: 10, em_race: 30, co_race: 10, ag_race: -5, sd_race: 10, me_race: 15, re_race: 10, hitdietype: 'd4'}, 'Trilopters': {st_race: 20, qu_race: 10, pr_race: -15, in_race: -10, em_race: 10, co_race: 5, ag_race: 10, sd_race: -5, me_race: 0, re_race: 5, hitdietype: 'd8'}, 'Areed': {st_race: 10, qu_race: 5, pr_race: -10, in_race: -10, em_race: 10, co_race: 5, ag_race: 10, sd_race: -10, me_race: 0, re_race: -5, hitdietype: 'd10'}, } let race = values.race; if (!races.hasOwnProperty( race )) { console.log("Error: The item " + race + " is not found within the race Object."); return; } setAttrs(races[race]); }); }); stats.forEach(stat => { on(`change:${stat} change:${stat}_norm change:${stat}_race change:${stat}_back sheet:opened`, function () { getAttrs([`${stat}_norm`, `${stat}_race`, `${stat}_back`], function (values) { let stat_norm = parseInt(values[`${stat}_norm`]) || 0; let stat_race = parseInt(values[`${stat}_race`]) || 0; let stat_back = parseInt(values[`${stat}_back`]) || 0; let stat_bonus = stat_norm + stat_race + stat_back; setAttrs({ [`${stat}_bonus`]: stat_bonus }); }); }); }); stats.forEach(stat => { on(`change:${stat}`, () => { getAttrs([stat], values => { const stat_base = int(values[stat]); console.log(stat_base); let stat_dev = 0; if (stat_base >= 103) stat_dev = "11"; else if (stat_base >= 102) stat_dev = "11"; else if (stat_base >= 101) stat_dev = "10"; else if (stat_base >= 100) stat_dev = "10"; else if (stat_base >= 95) stat_dev = "9"; else if (stat_base >= 85) stat_dev = "8"; else if (stat_base >= 75) stat_dev = "7"; else if (stat_base >= 60) stat_dev = "6"; else if (stat_base >= 40) stat_dev = "5"; else if (stat_base >= 25) stat_dev = "4"; else if (stat_base >= 15) stat_dev = "3"; else if (stat_base >= 5) stat_dev = "2"; else if (stat_base >= 1) stat_dev = "1"; else stat_dev = "1"; setAttrs({ [`${stat}_dev`]: stat_dev }); }); }); }); </script>
1589864832
GiGs
Pro
Sheet Author
API Scripter
Great! And yes, it looks overwhelming at first, but each step is a small step, and before you know it, you can do so much.