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

[Sheet Worker] Comparing two things

So I have a single characteristic box with several inputs in it (say strength, dexterity, etc).  I am setting up several other  characteristic boxes with modifiers.  When checkbox "A" is checked (and no others), only the modifiers of box "A" are used.  But I also want to be able to add boxes "B" and "C".  Activating an entire suite of modifiers with a single click, or turning them off.  I was shown how to do this on another sheet, I think, but I can't remember which that was.  Anyone got a clue how to do this?
1589840770
Finderski
Pro
Sheet Author
Compendium Curator
Here's a "simple" example for calculating things...I believe GiGs did a more elaborate example that may be more in line with what you want in the wiki...somewhere...? // Simple Sum function for Repeating Sections with Check Field function repeatingSimpleSumWCheck (section, field, destination, checkfield, checkvalue){ console.log("Made it repeatingSimpleSumWCheck"); console.log("checkvalue: "+checkvalue); let repSection = "repeating_"+section; getSectionIDs(repSection, function(idArray) { //Construct Array of fields to get attributes for... let sumFields = []; let checkFields = []; for (let a=0; a< idArray.length; a++) { sumFields[sumFields.length] = repSection + "_" + idArray[a] + "_" + field; checkFields[checkFields.length] = repSection + "_" + idArray[a] + "_" + checkfield; } console.log("List of IDs: "+idArray); console.log("List of Sum Fields: "+sumFields); console.log("List of check Fields: "+checkFields); getAttrs(sumFields, function(v) { getAttrs(checkFields, function(c) { console.log("%%% values of v: "+ JSON.stringify(v) +" %%%"); var sumTotal = 0; for(a=0; a<idArray.length; a++){ if (c[checkFields[a]] === checkvalue) { sumTotal += parseFloat(v[sumFields[a]]) || 0; console.log("$$$ sumTotal: " + sumTotal + " $$$"); } } var setSumValue = {}; setSumValue[destination]=sumTotal; setAttrs(setSumValue); }); }); }); } The bolded part is what will be relevant to you, I think.  Then depending on what you ultimately want to do it would be a series of if statements, or if/elseif/else statements, etc. For example, if they are all additive if A is checked +a, if B is checked +b, then a series of if statements would suffice. However, if A is one thing, but A+B is something completely different, then you'd need If/else(if) statements. A psuedo-code example of what I'm talking about about Additive Approach: let outcome = result; if (checkboxA === checkvalueA) { result = A; } if (checkboxB === checkvalueB) { result += B; //value could be AB or B at this point } if (checkboxC === checkvalueC) { result += C; //value could be AC, BC, ABC, or C at this point } Non-additive approach: let outcome = result; if (checkboxA === checkvalueA && checkboxB !== checkvalueB && checkboxC !== checkvalueC) { //only A is checked result = X; } else if (checkboxA === checkvalueA && checkboxB === checkvalueB && checkboxC !== checkvalueC) { //A and B are checked result = Y;  } else if (checkboxA === checkvalueA && checkboxB === checkvalueB && checkboxC === checkvalueC) { //A, B, and C are checked result = Z;  } else if (checkboxA === checkvalueA && checkboxB !== checkvalueB && checkboxC !== checkvalueC) { //A, and C are checked result = Q;  } else if (checkboxA !== checkvalueA && checkboxB === checkvalueB && checkboxC !== checkvalueC) { //only B is checked result = P;  } else if (checkboxA !== checkvalueA && checkboxB === checkvalueB && checkboxC !== checkvalueC) { //B and C are checked result = R;  } else if (checkboxA !== checkvalueA && checkboxB !== checkvalueB && checkboxC === checkvalueC) { //only C is checked result = S;  } else { result = T; } You can also use switch/case statements, but I find if/else statements a bit more explicit and less room for error, because of the way switches can fall through in unexpected ways. I hope this helps and is kind of what you were looking for?  
1589858089

Edited 1590128151
GiGs
Pro
Sheet Author
API Scripter
Finderski said: Here's a "simple" example for calculating things... Coal Powered Puppet said: So I have a single characteristic box with several inputs in it (say strength, dexterity, etc).  I am setting up several other  characteristic boxes with modifiers.  When checkbox "A" is checked (and no others), only the modifiers of box "A" are used.  But I also want to be able to add boxes "B" and "C".  Activating an entire suite of modifiers with a single click, or turning them off.  I was shown how to do this on another sheet, I think, but I can't remember which that was.  Anyone got a clue how to do this? It would be easier if you used the actual names of attributes, it makes writing the code and giving explanations so much easier. When you use vague concepts, we have to guess what they might be, write code based on that guess work, then you have to look at the code and figure out how to adapt it back to what you need. Whereas if you used the actual attribute names and details, we could write the final code (while still explaining what it does), and you can just go and use it. Anyway, the basic principle is as follows: Before i start explaining, let me say that I use const and let in place of var , but if you aren't comfortable with those, just replace them both with var . They do the same job. Step 1: Create the Data Start by creating a data variable which contains all the attributes (their actual names on their sheet) and their values. For example, here's a hypothetical set of race modifiers: const modsbyrace = {     none: {strength_race_mod: 0, dexterity_race_mod: 0, intelligence_race_mod: 0, wisdom_race_mod: 0, charisma_race_mod: 0},     human: {strength_race_mod: 0, dexterity_race_mod: 0, intelligence_race_mod: 0, wisdom_race_mod: 0, charisma_race_mod: 0},     elf: {strength_race_mod: -1, dexterity_race_mod: 2, intelligence_race_mod: 2, wisdom_race_mod: -2, charisma_race_mod: 2},     halfling:  {strength_race_mod: -4, dexterity_race_mod: 4, intelligence_race_mod: 0, wisdom_race_mod: 0, charisma_race_mod: 2}, }; Notice the structure here. You have a set of outer { } brackets. Then you have a name for each set of modifiers, a colon, then another set of { } inside of which you have all that attribute names you want to assign, with their values. Each of the inner {} sets ends with a comma.  For best effects, the names for each data set (human, elf, halfling) should perfectly match the values in dropdown or whatever you are getting them from. Notice I have a "none" entry - it's a good idea with this approach to set up an entry for when the value isnt set. Also note that  strength_race_mod, dexterity_race_mod , etc are the attribute names exactly as they appear on the sheet.  You dont have to do this (sometimes you can't, like in a repeating section), but it makes the code much, much easier when you can, and that's what this example focuses on. Step 2: Set up the Input So lets say in the sheet we have a race selection dropdown that looks like this: <select name="attr_race">     <option value="none" selected>Choose a Race</option>     <option value="human" >Human</option>     <option value="elf">Elf</option>     <option value="halfling">Halfling</option> </select> Notice one of the entries is selected : that makes the process easier. It doesnt matter which is selected, just make sure one is. With that set, you can avoid having to handle certain errors in the sheet worker. Step 3: The Magic Happens Now the part of the sheet worker that does the magic. on('change:race', function() {     getAttrs(['race'], function(values) {         const race = values.race;         const updatemods =  modsbyrace[race];         setattrs(updatemods);     }); }); and there you have it. It's that simple. A Brief Aside to Explain How it Works The  modsbyrace[race]  part does the magic. You are looking in the modsbyrace data set, and picking the line that matches the race you want. You get a value like  {strength_race_mod: 0, dexterity_race_mod: 0, intelligence_race_mod: 0, wisdom_race_mod: 0, charisma_race_mod: 0} Now I want you to think about what happens when use setAttrs with multiple attributes. You do something like this: setAttrs( {           strength_race_mod: 0,      dexterity_race_mod: 0,      intelligence_race_mod: 0,      wisdom_race_mod: 0,      charisma_race_mod: 0 }); Now compare to the object you got from the modsbyrace object: they are identical if you ignore the linebreaks. And in javascript, linebreaks are optional. So the modsbyrace holds the data you need, in the perfect format to just send to setAttrs without further work. Thats why this technique is so powerful and simple. Using an Input instead of a Select Now, the version above is one you can use with a select , because you can make sure every option value in the select matches a name in the modsbyrace data. If you are using an input , where players might enter any words at all and you have to handle the possibility of data not matching, or you forget to include a selected option, you need to tweak it a bit. Something like: on('change:race', function() {     getAttrs(['race'], function(values) {         const race = values.race;         let updatemods = modsbyrace[race]' // set a default value first         if(modsbyrace.hasOwnProperty(race) {             // check if the race value actually exists in the data, and only if it does set the variable             updatemods = modsbyrace[race];             setattrs(updatemods);         }     }); }); And there you have it.  Where to put the Data Final note: You can include the modsbyrace data set in the sheet worker, or before it. I left it out of the sheet worker just for clarity of explaining the worker itself. If its data you might use in different sheet workers, keep it outside the sheet worker. Otherwise, put it inside the sheet worker after the getAttrs line but before the rest of the code. I hope this is a decent explanation and you can adapt it to your purpose. If you need more help, post the code you are working with and I'll show you how to make it work.
1589859203
vÍnce
Pro
Sheet Author
@GiGs; I could see this being used very easily to set buffs on sheets.  Very cool.
1589859410
GiGs
Pro
Sheet Author
API Scripter
An addendum that sometimes trips people up: If any of your attribute names have characters that aren't numbers, letters or underscores, you have to enclose them with quotes. for example: const modsbyrace = {     'no selection': {'strength-race-mod': 0},     human: {'strength-race-mod: 0},     elf: {'strength-race-mod: -1} }; Likewise if the attribute value is not a number, you need to put it in quotes: const modsbyrace = {     'no selection': {'strength-race-mod': 'N/A'},     human: {'strength-race-mod: 0},     elf: {'strength-race-mod: -1} };
1589859621
GiGs
Pro
Sheet Author
API Scripter
Vince said: @GiGs; I could see this being used very easily to set buffs on sheets.  Very cool. It's an incredibly useful technique. You can use it to create mini-compendiums in sheets, or use it for all sorts of lookup tables. You can probably replace any kind of if/else or switch structure that is being used to sort between different values and assign more than one thing with this technique. I've posted variants on it to a lot of threads over the last couple of years, but this might be best explanation of it so far.
1589892770

Edited 1589892840
GiGs
Pro
Sheet Author
API Scripter
I just realised I might have misread the original question. CPP, are you wanting to activate multiple sets of bonuses? That can be done too, but I'd need to know whether they are in a repeating section or not. Some details on the attribute names and how they are grouped would be helpful.
Its early for me, and the magic of my coffee is weak, so bear with me: The characteristics are named: attr_strength attr_perception attr_endurance attr_charisma attr_intelligence attr_agility attr_luck The first modifier block has each of the above named: attr_strength_mod_1 attr_perception_mod_1 attr_endurance_mod_1 attr_charisma_mod_1 attr_intelligence_mod_1 attr_agility_mod_1 attr_luck_mod_1 The second modifier block is like so: attr_strength_mod_2 attr_perception_mod_2 attr_endurance_mod_2 attr_charisma_mod_2 attr_intelligence_mod_2 attr_agility_mod_2 attr_luck_mod_2 And so on.  These are hidden in a collapsible field.  I was thinking five options are enough but maybe a repeating field would make more sense.  I dunno.  The caffeine isn't whispering any secrets right now.  And each group has a checkbox (or a two option radio button "on-and-off-switch" acting like a checkbox).  That is called: attr_altered_state_mod_1   When clicked, all of modifiers of its associated group of characteristics are applied.  Each group can be applied in any combination with any other group.  So you can have a power armor group that adds to strength and reduces dexterity, a cocaine group that adds to agility and reduces charisma, and a money group that increases luck.  If you are on cocaine and have money, click those two. Each of the modifiers are controlled by the player.  They name the group, and assign the modifiers.   Clear as mud?
1589893938
GiGs
Pro
Sheet Author
API Scripter
That's much clearer. Do you have a set of attributes to add hold the total of all modifiers (like strength_mod_total), or do they get added and subtracted directly to the main attribute scores?
attr_strength_mod attr_perception_mod attr_endurance_mod attr_charisma_mod attr_intelligence_mod attr_agility_mod attr_luck_mod No numbers, just mod.  This will be added to the base attribute
1589895954
GiGs
Pro
Sheet Author
API Scripter
As it happens I answered a question for exactly the same purpose yesterday, over here:&nbsp; <a href="https://app.roll20.net/forum/permalink/8688091/" rel="nofollow">https://app.roll20.net/forum/permalink/8688091/</a> Here's an adaptation of that code for your purpose, with the html i used to test it. So, I made this a repeating section, because that allows you to have any number of buffs. I can change it to a non-repeating section if you'd prefer. Notice that the attributes inside the repeating section use _mods , not _mod . This is for performance reasons: if you have a name outside of a repeating section that is identical to a name inside the repeating section, changes in the non-repeating attribute also trigger the other. This is best avoided. I have assumed the repeating section is called 'repeating_modifiers'. If its going to be a different name, find this line &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;mod_section_name&nbsp;=&nbsp;'modifiers';&nbsp;&nbsp;&nbsp;&nbsp; and change the 'modifiers' to whatever you want to use. Finally this code is not going to be easy reading. If its important to you to understand it (a very valid concern!), I am perfectly happy to rewrite it using more beginner-friendly functions, with more detailed instructions. (But I'll need to sleep first :)) Here we go: &lt;fieldset&nbsp;class="repeating_modifiers"&gt;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;type="checkbox"&nbsp;name="attr_altered_state_mod"&nbsp;value="1"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;name="attr_strength_mods"&nbsp;type="number"&nbsp;value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;name="attr_perception_mods"&nbsp;type="number"&nbsp;value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;name="attr_endurance_mods"&nbsp;type="number"&nbsp;value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;name="attr_charisma_mods"&nbsp;type="number"&nbsp;value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;name="attr_intelligence_mods"&nbsp;type="number"&nbsp;value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;name="attr_agility_mods"&nbsp;type="number"&nbsp;value="0"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;name="attr_luck_mods"&nbsp;type="number"&nbsp;value="0"&gt; &lt;/fieldset&gt; &lt;hr/&gt; &lt;input&nbsp;name="attr_strength_mod"&nbsp;type="number"&nbsp;value="0"&gt; &lt;input&nbsp;name="attr_perception_mod"&nbsp;type="number"&nbsp;value="0"&gt; &lt;input&nbsp;name="attr_endurance_mod"&nbsp;type="number"&nbsp;value="0"&gt; &lt;input&nbsp;name="attr_charisma_mod"&nbsp;type="number"&nbsp;value="0"&gt; &lt;input&nbsp;name="attr_intelligence_mod"&nbsp;type="number"&nbsp;value="0"&gt; &lt;input&nbsp;name="attr_agility_mod"&nbsp;type="number"&nbsp;value="0"&gt; &lt;input&nbsp;name="attr_luck_mod"&nbsp;type="number"&nbsp;value="0"&gt; &lt;script&nbsp;type="text/worker"&gt;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;// a shortcut function to avoid typing out parseInt all the time. &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;int&nbsp;=&nbsp;(value,&nbsp;error&nbsp;=&nbsp;0)&nbsp;=&gt;&nbsp;parseInt(value)&nbsp;||&nbsp;error; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;an&nbsp;array&nbsp;of&nbsp;the&nbsp;distinctive&nbsp;parts&nbsp;of&nbsp;each&nbsp;attribute&nbsp;name. &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;modifiers&nbsp;=&nbsp;['strength',&nbsp;'perception',&nbsp;'endurance',&nbsp;'charisma',&nbsp;'intelligence',&nbsp;'agility',&nbsp;'luck']; &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;mod_section_name&nbsp;=&nbsp;'modifiers';&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;a&nbsp;function&nbsp;to&nbsp;quickly&nbsp;build&nbsp;repeating&nbsp;section&nbsp;names,&nbsp;suitable&nbsp;for&nbsp;this&nbsp;worker. &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;section_field&nbsp;=&nbsp;(section,&nbsp;field,&nbsp;id&nbsp;=&nbsp;':')&nbsp;=&gt;&nbsp;`repeating_${section}${id&nbsp;===&nbsp;':'&nbsp;?&nbsp;id&nbsp;:&nbsp;`_${id}_`}${field}`; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;build&nbsp;the&nbsp;changes&nbsp;line,&nbsp;to&nbsp;account&nbsp;for&nbsp;the&nbsp;modifiers&nbsp;above. &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;buildChanges&nbsp;=&nbsp;modifiers.reduce((total,item)&nbsp;=&gt;&nbsp;`${total}&nbsp;change:${section_field('modifiers',&nbsp;item)}_mods`,''); &nbsp;&nbsp;&nbsp;&nbsp;on(`${buildChanges}&nbsp;change:repeating_modifiers:altered_state_mod&nbsp;remove:repeating_${mod_section_name}&nbsp;sheet:opened`,&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getSectionIDs(`repeating_${mod_section_name}`,&nbsp;idarray&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fieldnames&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;loop&nbsp;through&nbsp;idarray,&nbsp;and&nbsp;ccreate&nbsp;the&nbsp;repeating&nbsp;section&nbsp;attribute&nbsp;for&nbsp;each&nbsp;modifier&nbsp;attribute&nbsp;name &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray.forEach(id&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modifiers.forEach(mod&nbsp;=&gt;&nbsp;fieldnames.push(section_field(mod_section_name,&nbsp;`${mod}_mods`,&nbsp;id))); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fieldnames.push(section_field(mod_section_name,&nbsp;'altered_state_mod',&nbsp;id)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs(fieldnames,&nbsp;v&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;initialise&nbsp;the&nbsp;object&nbsp;used&nbsp;for&nbsp;output,&nbsp;with&nbsp;each&nbsp;total&nbsp;attribute&nbsp;set&nbsp;to&nbsp;a&nbsp;default&nbsp;value&nbsp;of&nbsp;0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;output&nbsp;=&nbsp;{}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modifiers.forEach(mod&nbsp;=&gt;&nbsp;output[`${mod}_mod`]&nbsp;=&nbsp;0); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;loop&nbsp;through&nbsp;idarray&nbsp;again &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray.forEach(id&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;check&nbsp;if&nbsp;this&nbsp;row&nbsp;is&nbsp;to&nbsp;be&nbsp;counted&nbsp;or&nbsp;not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;toggle&nbsp;=&nbsp;int(v[section_field(mod_section_name,&nbsp;'altered_state_mod',&nbsp;id)]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(toggle)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;add&nbsp;each&nbsp;modifier&nbsp;to&nbsp;the&nbsp;total&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modifiers.forEach(mod&nbsp;=&gt;&nbsp;output[`${mod}_mod`]&nbsp;=&nbsp;output[`${mod}_mod`]&nbsp;+&nbsp;int(v[section_field(mod_section_name,&nbsp;`${mod}_mods`,&nbsp;id)])); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(output); &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;
1589904534

Edited 1589906408
GiGs
Pro
Sheet Author
API Scripter
Here's a version of the previous sheet worker with all the time saving loops taken out, so it might be a bit more readable. &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;int&nbsp;=&nbsp;(value,&nbsp;error&nbsp;=&nbsp;0)&nbsp;=&gt;&nbsp;parseInt(value)&nbsp;||&nbsp;error; &nbsp;&nbsp;&nbsp;&nbsp;on(`change:repeating_modifiers:strength_mods&nbsp;change:repeating_modifiers:perception_mods&nbsp;change:repeating_modifiers:endurance_mods&nbsp;change:repeating_modifiers:charisma_mods&nbsp;change:repeating_modifiers:intelligence_mods&nbsp;change:repeating_modifiers:agility_mods&nbsp;change:repeating_modifiers:luck_mods&nbsp;change:repeating_modifiers:altered_state_mod&nbsp;remove:repeating_modifiers&nbsp;sheet:opened`,&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// with a repeating section you have to loop through every row of the section. This function gives you the id of each row. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getSectionIDs(`repeating_modifiers`,&nbsp;idarray&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fieldnames&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;loop&nbsp;through&nbsp;idarray,&nbsp;and&nbsp;create&nbsp;the&nbsp;repeating&nbsp;section&nbsp;attribute&nbsp;for&nbsp;each&nbsp;modifier&nbsp;attribute&nbsp;name &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;idarray.length;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fieldnames.push( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_altered_state_mod', &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_strength_mods', &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_perception_mods', &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_endurance_mods', &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_charisma_mods', &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_intelligence_mods', &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_agility_mods', &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_luck_mods' &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// the previous section created a fieldnames array, which contains every attribute's full name (including ids) on every row. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs(fieldnames,&nbsp;v&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;initialise&nbsp;the&nbsp;object&nbsp;used&nbsp;for&nbsp;output,&nbsp;with&nbsp;each&nbsp;total&nbsp;attribute&nbsp;set&nbsp;to&nbsp;a&nbsp;default&nbsp;value&nbsp;of&nbsp;0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;output&nbsp;=&nbsp;{"strength_mod":0,"perception_mod":0,"endurance_mod":0,"charisma_mod":0,"intelligence_mod":0,"agility_mod":0,"luck_mod":0}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;loop&nbsp;through&nbsp;idarray&nbsp;again &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(let&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;idarray.length;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;check&nbsp;if&nbsp;this&nbsp;row&nbsp;is&nbsp;to&nbsp;be&nbsp;counted&nbsp;or&nbsp;not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;toggle&nbsp;=&nbsp;int(v['repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_altered_state_mod']); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(toggle)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;add&nbsp;each&nbsp;modifier&nbsp;to&nbsp;the&nbsp;total&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.strength_mod&nbsp;=&nbsp;output.strength_mod&nbsp;+&nbsp;int(v['repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_strength_mods']); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.perception_mod&nbsp;=&nbsp;output.perception_mod&nbsp;+&nbsp;int(v['repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_perception_mods']); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.endurance_mod&nbsp;=&nbsp;output.endurance_mod&nbsp;+&nbsp;int(v['repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_endurance_mods']); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.charisma_mod&nbsp;=&nbsp;output.charisma_mod&nbsp;+&nbsp;int(v['repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_charisma_mods']); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.intelligence_mod&nbsp;=&nbsp;output.intelligence_mod&nbsp;+&nbsp;int(v['repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_intelligence_mods']); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.agility_mod&nbsp;=&nbsp;output.agility_mod&nbsp;+&nbsp;int(v['repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_agility_mods']); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.luck_mod&nbsp;=&nbsp;output.luck_mod&nbsp;+&nbsp;int(v['repeating_modifiers_'&nbsp;+&nbsp;idarray[i]&nbsp;+&nbsp;'_luck_mods']); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs(output); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;});
This, of course, works beautifully.&nbsp; Thank you all for your help!
1589938507
GiGs
Pro
Sheet Author
API Scripter
Sometimes I actually test the sheet workers before posting, hehe. You're welcome!