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 questions

1590342812
Joshua S.
Pro
Sheet Author
API Scripter
Basic questions: 1) how do I log to the console in a sheetworker? 2) is there a way to get attributes by class? 3) can I store a {key:value} object in an attribute? Details: Right now, I'm just trying to figure out how sheetworkers work. I don't have much javascript experience, but I have built a couple of API scripts. Right now I can't figure out if my sheetworker is even being triggered properly because I can't find the console. Eventually, what I want to do is have a script that grabs all the attributes that have a particular class, filter them based on a checkbox status, add them all up, and then update an attribute. I was thinking that a way to do this is to store a dictionary object in an attribute and any time an attribute with the appropriate class is changed or checked either update the appropriate key:value  if it already exists or add a new key:value  if it doesn't. Say that I have a really simple system where there are two front line values: attack and defense. Strength affects attack and Dexterity affects defense. You also have equipment that can affect either or both. Bob has Str=6, Dex=3, stored in attributes. He also has a chainmail shirt, great sword, spiked shield, and broadsword that are stored in a repeating field with checkboxes to indicate which items are equipped like this (with X representing checked and O representing unchecked): X 'chainmail shirt' 'Def+3' 'Att+0' O 'great sword' 'Def+1' 'Att+5' X 'broadsword' 'Def+1' 'Att+3' X 'spiked shield' 'Def+3' 'Att+1' When he drops his sword and shield and draws his great sword, I want the attack and defense values to automatically update. Same if he drinks a potion of increased strength. All basic stuff. I also need the solution to be fairly scalable because I will eventually have more than two front line values and far more than two attributes. Thanks for any help!
1590343562

Edited 1590343617
I know very little, but I can answer your first question: console.log("====Look here"); You can put anything in the double quotes. I use the equal signs to help it stand out when scanning through the console log. It's also a good idea to use it to check variable values at different points in the script. console.log("==== str_mod: " + str_mod); That will report the value of a variable name "str_mod" to the console. Edit: Oh, and you can see the console by using F12 in your browser to call up the Dev Tools.
1590345931
GiGs
Pro
Sheet Author
API Scripter
Joshua S. said: Basic questions: 1) how do I log to the console in a sheetworker? 2) is there a way to get attributes by class? 3) can I store a {key:value} object in an attribute? As Rabulias says, you use console.log to log messages, and they get sent to the browser console, not the api console. You can't get attributes by class, at least if you are referring to the html class. The structure of a sheet - the html and css - are invisible to sheet workers. Sheet workers can only get attributes by using the getAttrs function (see wiki), which gets attributes on a javascript object. For example this: getAttrs(['strength', 'dexterity', function(values) { will give you the object values &nbsp;=&nbsp; {strength: "12", dexterity: "10"} &nbsp;(note that the attribute values are strings - that'll trip you up if you're not careful). You get the attributes as keys, and their scores as string values.&nbsp; For storing key:values &nbsp;in attributes, you can store anything in an attribute as long as you can handle it being converted into a string. The question to ask is why do you want to do this? When you get attributes in a sheet worker, they and their values are always key:value &nbsp;pairs already.&nbsp; Your specific situation: having a bunch of repeating section attributes that accumulate modifiers that apply to stats outside the repeating section(s) is definitely possible. Funnily enough I've posted a solution to a similar problem twice in the last couple of days. First though here's a post on the wiki that explains the basics of a sheet worker:&nbsp; <a href="https://wiki.roll20.net/Sheetworker_examples_for_Non-programmers#Sheet_Worker_Tutorial" rel="nofollow">https://wiki.roll20.net/Sheetworker_examples_for_Non-programmers#Sheet_Worker_Tutorial</a> Here's a post that explains how to handle race modifiers to stats, which isnt directly relevant, but illustrates how to store data in the character sheet and use that to apply modifiers to stats:&nbsp; <a href="https://app.roll20.net/forum/permalink/8691193/" rel="nofollow">https://app.roll20.net/forum/permalink/8691193/</a> And here's a post (and the one following) later in the same threa dwhich explains exactly what you want to do: have a repeating section which has a range of possible bonuses, that applies to things outside the repeating section:&nbsp; <a href="https://app.roll20.net/forum/permalink/8692631/" rel="nofollow">https://app.roll20.net/forum/permalink/8692631/</a>
1590427612
Joshua S.
Pro
Sheet Author
API Scripter
OK, found the console. GiG, I have taken your code and adapted it to my situation and it works. I even understand parts of it. Next question, suppose I have multiple repeating sections (lets call them 'equipment', 'passive_abilities and 'active_abilities'), each of which has items in it that could affect 'attack' or 'defense', as well as some non-repeating values that affect them. How would I deal with that? Code that I got working is below: &lt;div class="stats"&gt; &nbsp; &nbsp; &lt;label&gt;&lt;span class="labeltext"&gt;Strength: &lt;/span&gt;&lt;input type="number" value="0" name="attr_strength" /&gt;&lt;/label&gt; &nbsp; &nbsp; &lt;label&gt;&lt;span class="labeltext"&gt;Dexterity: &lt;/span&gt;&lt;input type="number" value="0" name="attr_dexterity" /&gt;&lt;/label&gt; &nbsp; &nbsp; &lt;label&gt;&lt;span class="labeltext"&gt;Attack: &lt;/span&gt;&lt;input type="number" value="0" name="attr_attack" /&gt;&lt;/label&gt; &nbsp; &nbsp; &lt;label&gt;&lt;span class="labeltext"&gt;Defense: &lt;/span&gt;&lt;input type="number" value="0" name="attr_defense" /&gt;&lt;/label&gt; &lt;/div&gt; &lt;div class="equip"&gt; &nbsp; &nbsp; &lt;span class="checkbox"&gt;&lt;/span&gt; &nbsp; &nbsp; &lt;label class="equipname"&gt;Equipment:&lt;/label&gt; &nbsp; &nbsp; &lt;label class="equipmod"&gt;+ATT:&lt;/label&gt; &nbsp; &nbsp; &lt;label class="equipmod"&gt;+DEF:&lt;/label&gt; &nbsp; &nbsp; &lt;fieldset class="repeating_equipment"&gt; &nbsp; &nbsp; &nbsp; &nbsp; &lt;input class="checkbox" type="checkbox" name="attr_equipment_altered_state_mod" value="1" /&gt; &nbsp; &nbsp; &nbsp; &nbsp; &lt;input class="equipname" type="text" name="attr_equip_name" /&gt; &nbsp; &nbsp; &nbsp; &nbsp; &lt;input class="equipmod" type='number' name='attr_equipment_attack_mods' /&gt; &nbsp; &nbsp; &nbsp; &nbsp; &lt;input class="equipmod" type="number" name='attr_equipment_defense_mods' /&gt; &nbsp; &nbsp; &lt;/fieldset&gt; &lt;/div&gt; &lt;script type="text/worker"&gt; &nbsp; &nbsp; const int = (value, error = 0) =&gt; parseInt(value) || error; &nbsp; &nbsp; const derived_stats = ['attack', 'defense']; &nbsp; &nbsp; const rep_section_name = 'equipment'; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; // a function to quickly build repeating section names, suitable for this worker. &nbsp; &nbsp;const section_field = (section, field, id = ':') =&gt; `repeating_${section}${id === ':' ? id : `_${id}_`}${section}_${field}`; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; // build the changes line, to account for the modifiers above. &nbsp; &nbsp; const buildChanges = derived_stats.reduce((total,item) =&gt; `${total} change:${section_field(rep_section_name, item)}_mods`,''); &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; on(`${buildChanges} change:repeating_equipment:equipment_altered_state_mod remove:repeating_${rep_section_name} sheet:opened`, () =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; getSectionIDs(`repeating_${rep_section_name}`, idarray =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(idarray + ' idarray'); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const fieldnames = []; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // loop through idarray, and create the repeating section attribute for each modifier attribute name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; idarray.forEach(id =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; derived_stats.forEach(mod =&gt; fieldnames.push(section_field(rep_section_name, `${mod}_mods`, id))); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fieldnames.push(section_field(rep_section_name, 'altered_state_mod', id)); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(section_field+' section_field'); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(buildChanges+ ' buildChanges'); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(fieldnames + ' fieldnames'); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getAttrs(fieldnames, v =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(v); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('v^') &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // initialise the object used for output, with each total attribute set to a default value of 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const output = {}; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; derived_stats.forEach(mod =&gt; output[`${mod}`] = 0); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // loop through idarray again &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; idarray.forEach(id =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // check if this row is to be counted or not &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; toggle = int(v[section_field(rep_section_name, 'altered_state_mod', id)]); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(v[section_field(rep_section_name, 'altered_state_mod', id)]); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(section_field(rep_section_name, 'altered_state_mod')); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(toggle+' '+id); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(toggle) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // add each modifier to the total&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; derived_stats.forEach(mod =&gt; output[`${mod}`] = output[`${mod}`] + int(v[section_field(rep_section_name, `${mod}_mods`, id)])); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('toggled'); &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; console.log(output); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('output^') &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs(output); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; }); &lt;/script&gt;
1590432292
GiGs
Pro
Sheet Author
API Scripter
Before I start, let me suggest changing the&nbsp; equipment_altered_state_mod attribute name to just&nbsp; equipment_toggle . Either one is as good as the other, but the meaning of the second is clearer IMO. Sp, there are two ways to deal with it. One thing to bear in mind is you should only have one sheet worker change a given attribute. So, dont have, for example, 3 different sheet workers all changing the same attribute. If you needed that kind of setup, the way to do it would be to create intermediate attributes to hold the 3 totals, and another sheet worker that watches those 3 attributes and adds them to the actual final total. So, with that in mind, the trickiest to write is to combine the three repeating section workers into a single sheet worker, in which you nest the getSectionIds function for each section inside each other, leading to getAttrs and setAttrs at the bottom of the chain. You have to be careful to name the array of ids for each section differently. Then you just collect all the modifiers together in the one worker and save them to final mod attributes. The second method is a bit less efficient, but easier to write (though does involve a fair bit of duplication): have a different sheet worker for each section, each of which saves the attributes to an intermediate set of totals. Then you have a final sheet worker which detects when any of the intermediate section totals changes, adds them together and adds them to final mod totals attributes. To save you the trouble, I've rewritten your worker as a three repeating section one. See next post.
1590432701

Edited 1590439841
GiGs
Pro
Sheet Author
API Scripter
Here's a sheet worker that calculates the ATT and DEF values. I created extra repeating sections - passives &nbsp;and actives . Obviously you can change those - just remember to change them in this line: &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;section_names&nbsp;=&nbsp;['equipment',&nbsp;'passives',&nbsp;'actives']; I also created an array to hold the attributes you want to use from outside the repeating section, like so &nbsp;&nbsp;const&nbsp;outside_attributes&nbsp;=&nbsp;['strength',&nbsp;'dexterity']; Just add as many attributes as you need, and the on(change) and getAttrs lines will automatically grab them. All you need to do is add the code inside the getAttrs function to use them how you want to. I added this at the end as an example: output.attack&nbsp;=&nbsp;output.attack&nbsp;+&nbsp;int(v.strength); output.defense&nbsp;=&nbsp;output.defense&nbsp;+&nbsp;int(v.dexterity); I've tested the sheet worker below to make sure it works. Enjoy! &lt;div&nbsp;class="stats"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;label&gt;&lt;span&nbsp;class="labeltext"&gt;Strength:&nbsp;&lt;/span&gt;&lt;input&nbsp;type="number"&nbsp;value="0"&nbsp;name="attr_strength"&nbsp;/&gt;&lt;/label&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;label&gt;&lt;span&nbsp;class="labeltext"&gt;Dexterity:&nbsp;&lt;/span&gt;&lt;input&nbsp;type="number"&nbsp;value="0"&nbsp;name="attr_dexterity"&nbsp;/&gt;&lt;/label&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;label&gt;&lt;span&nbsp;class="labeltext"&gt;Attack:&nbsp;&lt;/span&gt;&lt;input&nbsp;type="number"&nbsp;value="0"&nbsp;name="attr_attack"&nbsp;/&gt;&lt;/label&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;label&gt;&lt;span&nbsp;class="labeltext"&gt;Defense:&nbsp;&lt;/span&gt;&lt;input&nbsp;type="number"&nbsp;value="0"&nbsp;name="attr_defense"&nbsp;/&gt;&lt;/label&gt; &lt;/div&gt; &lt;hr&nbsp;/&gt; &lt;div&nbsp;class="equip"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;label&nbsp;class="equipname"&gt;Equipment:&lt;/label&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;fieldset&nbsp;class="repeating_equipment"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="checkbox"&nbsp;type="checkbox"&nbsp;name="attr_equipment_toggle"&nbsp;value="1"&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="equipname"&nbsp;type="text"&nbsp;name="attr_equipment_name"&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="equipmod"&nbsp;type='number'&nbsp;name='attr_equipment_attack_mods'&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="equipmod"&nbsp;type="number"&nbsp;name='attr_equipment_defense_mods'&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/fieldset&gt; &lt;/div&gt; &lt;hr&nbsp;/&gt; &lt;div&nbsp;class="equip"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;label&nbsp;class="equipname"&gt;Passive Abilities:&lt;/label&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;fieldset&nbsp;class="repeating_passives"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="checkbox"&nbsp;type="checkbox"&nbsp;name="attr_passives_toggle"&nbsp;value="1"&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="equipname"&nbsp;type="text"&nbsp;name="attr_passives_name"&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="equipmod"&nbsp;type='number'&nbsp;name='attr_passives_attack_mods'&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="equipmod"&nbsp;type="number"&nbsp;name='attr_passives_defense_mods'&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/fieldset&gt; &lt;/div&gt; &lt;hr&nbsp;/&gt; &lt;div&nbsp;class="equip"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;label&nbsp;class="equipname"&gt;Active Abilities:&lt;/label&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;fieldset&nbsp;class="repeating_actives"&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="checkbox"&nbsp;type="checkbox"&nbsp;name="attr_actives_toggle"&nbsp;value="1"&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="equipname"&nbsp;type="text"&nbsp;name="attr_actives_name"&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="equipmod"&nbsp;type='number'&nbsp;name='attr_actives_attack_mods'&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input&nbsp;class="equipmod"&nbsp;type="number"&nbsp;name='attr_actives_defense_mods'&nbsp;/&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/fieldset&gt; &lt;/div&gt; &lt;script&nbsp;type="text/worker"&gt; &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;const&nbsp;derived_stats&nbsp;=&nbsp;['attack',&nbsp;'defense']; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;an&nbsp;array&nbsp;of&nbsp;the&nbsp;repeating&nbsp;section&nbsp;names &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;section_names&nbsp;=&nbsp;['equipment',&nbsp;'passives',&nbsp;'actives']; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;an&nbsp;array&nbsp;of&nbsp;the&nbsp;attributes&nbsp;outside&nbsp;of&nbsp;the&nbsp;section&nbsp;you&nbsp;want&nbsp;to&nbsp;use. &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;outside_attributes&nbsp;=&nbsp;['strength',&nbsp;'dexterity']; &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}_`}${section}_${field}`; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;altered&nbsp;buildChanges,&nbsp;so&nbsp;now&nbsp;it&nbsp;is&nbsp;a&nbsp;function&nbsp;that&nbsp;can&nbsp;hanndle&nbsp;all&nbsp;3&nbsp;repeating&nbsp;sections &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;buildChanges&nbsp;=&nbsp;(section)&nbsp;=&gt;&nbsp;derived_stats.reduce((total,&nbsp;item)&nbsp;=&gt;&nbsp;`${total}&nbsp;change:${section_field(section,&nbsp;item)}_mods`,&nbsp;''); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;created&nbsp;3&nbsp;variables&nbsp;for&nbsp;the&nbsp;change:stuff&nbsp;line,&nbsp;to&nbsp;make&nbsp;that&nbsp;less&nbsp;of&nbsp;a&nbsp;chore&nbsp;to&nbsp;write&nbsp;and&nbsp;read &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;toggleChanges&nbsp;=&nbsp;section_names.map(section&nbsp;=&gt;&nbsp;`change:repeating_${section}:${section}_toggle`).join('&nbsp;'); &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;outsideChanges&nbsp;=&nbsp;outside_attributes.map(stat&nbsp;=&gt;&nbsp;`change:${stat}`).join('&nbsp;'); &nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;removeSections&nbsp;=&nbsp;section_names.map(section&nbsp;=&gt;&nbsp;`remove:repeating_${section}`).join('&nbsp;'); &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;on(`${toggleChanges}&nbsp;${outsideChanges}&nbsp;${buildChanges(section_names[0])}&nbsp;${buildChanges(section_names[1])}&nbsp;${buildChanges(section_names[2])}&nbsp;${toggleChanges}&nbsp;${removeSections}&nbsp;sheet:opened`,&nbsp;()&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;define&nbsp;the&nbsp;fieldnames&nbsp;outside&nbsp;the&nbsp;first&nbsp;getSectionIDs&nbsp;to&nbsp;make&nbsp;clear&nbsp;it&nbsp;doesnt&nbsp;belong&nbsp;to&nbsp;any&nbsp;of&nbsp;them &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fieldnames&nbsp;=&nbsp;[]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;notice&nbsp;the&nbsp;idarray&nbsp;array&nbsp;name&nbsp;has&nbsp;changed.&nbsp;It&nbsp;must&nbsp;be&nbsp;different&nbsp;in&nbsp;each&nbsp;getSectionIDs &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getSectionIDs(`repeating_${section_names[0]}`,&nbsp;idarray0&nbsp;=&gt;&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;loop&nbsp;through&nbsp;idarray0,&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;idarray0.forEach(id&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;derived_stats.forEach(mod&nbsp;=&gt;&nbsp;fieldnames.push(section_field(section_names[0],&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(section_names[0],&nbsp;'toggle',&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;getSectionIDs(`repeating_${section_names[1]}`,&nbsp;idarray1&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;loop&nbsp;through&nbsp;idarray1,&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;&nbsp;&nbsp;&nbsp;&nbsp;idarray1.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;derived_stats.forEach(mod&nbsp;=&gt;&nbsp;fieldnames.push(section_field(section_names[1],&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;fieldnames.push(section_field(section_names[1],&nbsp;'toggle',&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;getSectionIDs(`repeating_${section_names[2]}`,&nbsp;idarray2&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;loop&nbsp;through&nbsp;idarray2,&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idarray2.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;&nbsp;&nbsp;&nbsp;derived_stats.forEach(mod&nbsp;=&gt;&nbsp;fieldnames.push(section_field(section_names[2],&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;fieldnames.push(section_field(section_names[2],&nbsp;'toggle',&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;now&nbsp;we&nbsp;are&nbsp;ready&nbsp;to&nbsp;grab&nbsp;all&nbsp;the&nbsp;values&nbsp;from&nbsp;the&nbsp;character&nbsp;sheet &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;outside_attributes&nbsp;as&nbsp;an&nbsp;array&nbsp;of&nbsp;the&nbsp;attributes&nbsp;you&nbsp;want&nbsp;to&nbsp;usem&nbsp;that&nbsp;aren't&nbsp;in&nbsp;the&nbsp;repeating&nbsp;sections &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs([...fieldnames,&nbsp;...outside_attributes],&nbsp;v&nbsp;=&gt;&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;console.log(v); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log('v^'); &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;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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;derived_stats.forEach(mod&nbsp;=&gt;&nbsp;output[`${mod}`]&nbsp;=&nbsp;0); &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;loop&nbsp;through&nbsp;all&nbsp;3&nbsp;idarrays &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;first&nbsp;set&nbsp;up&nbsp;an&nbsp;array&nbsp;of&nbsp;arrays,&nbsp;to&nbsp;make&nbsp;the&nbsp;idearrays&nbsp;easy&nbsp;to&nbsp;access&nbsp;with&nbsp;an&nbsp;index &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;idarrays&nbsp;=&nbsp;[idarray0,&nbsp;idarray1,&nbsp;idarray2]; &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;[0,1,2].forEach(num&nbsp;=&gt;&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;now&nbsp;loop&nbsp;through&nbsp;each&nbsp;idarray,&nbsp;and&nbsp;get&nbsp;the&nbsp;various&nbsp;values&nbsp;and&nbsp;add&nbsp;them&nbsp;to&nbsp;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;&nbsp;&nbsp;&nbsp;&nbsp;idarrays[num].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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;toggle&nbsp;=&nbsp;int(v[section_field(section_names[num],&nbsp;'toggle',&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;if&nbsp;(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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;derived_stats.forEach(mod&nbsp;=&gt;&nbsp;output[`${mod}`]&nbsp;=&nbsp;output[`${mod}`]&nbsp;+&nbsp;int(v[section_field(section_names[num],&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;&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;&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;now&nbsp;handle&nbsp;the&nbsp;outsideattributes&nbsp;however&nbsp;you&nbsp;need&nbsp;to.&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.attack&nbsp;=&nbsp;output.attack&nbsp;+&nbsp;int(v.strength); &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.defense&nbsp;=&nbsp;output.defense&nbsp;+&nbsp;int(v.dexterity); &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;&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;}); &lt;/script&gt;
1590432918

Edited 1590439871
GiGs
Pro
Sheet Author
API Scripter
I only noticed after posting you had two extra repeating sections already names: passive_abilities and active_abilities You must not use those names . Repeating section names cannot contain underscores - you will find your code stops working. Dont use upper case letters either. You can use dashes, but you have to be careful with them, so better to avoid them. Call them passiveabilities / activeabilities &nbsp;or just passives / actives &nbsp;instead. I edited my previous post to use passives and actives, but of course you can change them.