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

Update repeating repeating rows from external source

1641321167

Edited 1641322194
Short version: I need to dynamically update an integer that increases a player's chance to hit an enemy with a weapon. Long version: I have a repeating section called repeating_weapons  and in each row, there's a select with options for weapontype .  There's also a hidden input called weaponmod . The weapontype options are things like Pistol, SMG, Shotgun and so on. The weaponmod input is an integer that is the sum of a character stat (like Dexterity or Reflex) and a character skill (like Handguns). A single skill (like Handguns) may encompass multiple weapontype options (like Pistol and SMG). A single skill's total is held in an attribute called something like Total_Handguns and is the sum of the number of skill points invested (an attribute called LVL_Handguns), any bonus to that skill (an attribute called Misc_Handguns) and the stat tied to that skill (an attribute called Dexterity or Reflex). So, the Total_Handguns skill is updated whenever the LVL_Handguns is updated or whenever the Misc_Handguns is updated or whenever Dexterity is updated. I need to update the weaponmod input throughout the repeating_weapons section for each row that has a weapontype input that is encompassed by the weapons skill that is being changed. This is the weapon skill... <input type="number" name="attr_Total_Handgun" value="@{Misc_Handgun}+@{LVL_Handgun}+@{Reflex}" disabled="true" /> This is the repeating_weapons section with a default value of Total_Melee skill... <fieldset class="repeating_weapons"> <div class="flex-table"> <input type="hidden" name="attr_WeaponMod" value="@{Total_Melee}"> I know I would need to use getSectionIDs to for loop through all the rows and update weaponmod accordingly and I'm assuming I'd use .includes() to simplify it but I can't get through function without it feeling like some Frankenstein's monster patched together.  Is there an elegant way to do this? Thanks!
1641324306
GiGs
Pro
Sheet Author
API Scripter
there is, but i cant do the typing because my right arm is in a sling. If you post your frankencode, it will be easier to fix that than type it all from scratch. That said, sheet workers cant work with aotocalc attributes, so you would need to recalculate your total_hsndgunvalue in the worker, or replace the autocalc with a separate worker calculating it.
Sorry about your arm!  Wishing you a speedy recovery and thanks for your help on this and across many other posts (some code below is yours!). Here's my frankencode! on("change:total_handgun change:total_melee", function(eventInfo) { const skill = eventInfo.sourceAttribute.split('_')[1]; const baseskill = "LVL_" + skill; const miscskill = "Misc_" + skill; const refskills = ["LVL_Melee"]; const dexskills = ["LVL_Handguns"]; getAttrs([ baseskill, miscskill, "Dexterity", "Reflex" ], function(values) { console.log(values); getSectionIDs("repeating_weapons", function(idarray) { let rows = {}; for (let i = 0; i < idarray.length; i++) { // let weapontype = need to get the weapontype in this row // if (["Pistol","SMG"].includes(weapontype)) { // need to parseInt and calculate all necessary values // need to set weaponmod with something like rows['repeating_weapons_' + idarray[i] + '_WeaponMod'] = totalskill); // setAttrs({ all my stuff }); //}; }; }); }) });
1641329499

Edited 1641330236
GiGs
Pro
Sheet Author
API Scripter
I do see problems. I'm not sure why refskills and dexskills are arrays.Also the first line refers to total values, but the change event asks of a skill value - i take it this is to switch between melee and handgun? This is one way to do that, but I am more partial to the Universal Sheet Worker approach (see wiki), where you have a ['melee', 'handgun'] array and it creates a separate worker for each. Also, whicheveer method is used, I;d rename Level_Handguns to Level_handgun, so you can replace refskills and dexskills with a single attribute, and build its name the same way: const whichSkills = ['LVL_' + skill ]; But the main problem you have is the way getSectionIDs is used. Basically everyone tries it like this at first, because the way you have to do it is counter-intuitive. You are going to do something with the attributes inside the repeating section, so you will need to grab their values with getAttrs. That means you need to do the getSectionIDs before getAttrs, and have a loop where you build the attribute names (just the strings of their names, not their values) in the section you will need later, and then add that to the getAttrs. Then have another loop under getAttrs, where you go through the section (using the idarray created in the earlier getSectionIDs), and then do the analysis you need. I'll post some code in a bit.
1641330139

Edited 1641330221
GiGs
Pro
Sheet Author
API Scripter
Also remember this will cause your worker to always fail: <input type="number" name="attr_Total_Handgun" value="@{Misc_Handgun}+@{LVL_Handgun}+@{Reflex}" disabled="true" /> Sheet workers dont see values in autocalcs, they just see the expression, @{Misc_Handgun}+@{LVL_Handgun}+@{Reflex} , a string which never changes. So your sheet needs to change that to a sheet worker, or your section worker needs to bypass it and use the core attributes directly (and hope they aren't also autocalcs). Whats the calculation for Total_Melee. Also are they are any other attack values, like Rifles or Unarmed?
1641330342
GiGs
Pro
Sheet Author
API Scripter
In your loop you have this: // if (["Pistol","SMG"].includes(weapontype)) { // need to parseInt and calculate all necessary values // need to set weaponmod with something like rows['repeating_weapons_' + idarray[i] + '_WeaponMod'] = totalskill); // setAttrs({ all my stuff }); What necessary values do you need to collect?
1641330872

Edited 1641330909
I made refskills and dexskills arrays because they contain many skills.&nbsp; For brevity, I didn't list them all, but Reflex covers Melee, MartialArts and Brawling.&nbsp; Dexterity covers Handguns, ShoulderArms, HeavyWeapons and so on. I set the first line to total_skill values because if someone changed LVL_skill, Dexterity or Misc_skill, I would want the sheet worker to trigger so I could update weaponmod. I'll take a stab at the Universal Sheet Worker approach with an array and a forEach loop. The nested getAttrs description makes sense, but it&nbsp; felt&nbsp; like more processing than was necessary.&nbsp; I'll lean into it! The calculation for Total_Melee (and every other skill) is built as Misc_skill + LVL_skill + some governing character stat like Dexterity.&nbsp; I'm not sure why. It's an older sheet that I just started working on.&nbsp; The core attributes, however, are direct inputs that I can parseInt on and calculate as necessary.&nbsp; The sheet author is already doing that elsewhere in the sheet worker, but only for when the weapontype changes and he/she still doesn't account for any Misc_skill bonuses. Here are some of the combat skills:&nbsp; <a href="https://github.com/Roll20/roll20-character-sheets/blob/master/CyberpunkRED_raycw/cyberpunkred-raycw.html#L492" rel="nofollow">https://github.com/Roll20/roll20-character-sheets/blob/master/CyberpunkRED_raycw/cyberpunkred-raycw.html#L492</a> Here's the repeating_weapons section:&nbsp; <a href="https://github.com/Roll20/roll20-character-sheets/blob/master/CyberpunkRED_raycw/cyberpunkred-raycw.html#L949" rel="nofollow">https://github.com/Roll20/roll20-character-sheets/blob/master/CyberpunkRED_raycw/cyberpunkred-raycw.html#L949</a> &nbsp; Here's where the sheet worker kind of updates the weaponmod attribute if the weapontype changes:&nbsp; <a href="https://github.com/Roll20/roll20-character-sheets/blob/master/CyberpunkRED_raycw/cyberpunkred-raycw.html#L2531" rel="nofollow">https://github.com/Roll20/roll20-character-sheets/blob/master/CyberpunkRED_raycw/cyberpunkred-raycw.html#L2531</a> Thanks!
GiGs said: In your loop you have this: // if (["Pistol","SMG"].includes(weapontype)) { // need to parseInt and calculate all necessary values // need to set weaponmod with something like rows['repeating_weapons_' + idarray[i] + '_WeaponMod'] = totalskill); // setAttrs({ all my stuff }); What necessary values do you need to collect? I need to collect the new values for: LVL_skill, Misc_skill and whatever character stat (could be Dexterity or Reflex) is associated with that skill. For handguns, that would be: LVL_handguns, Misc_Handguns and Dexterity. For martial arts, that would be: LVL_martial, Misc_martial and Reflex. Once I have all those values, I can just add them up and set weaponmod equal to that value.&nbsp; I'm just trying to do it efficiently so I'm not computing a bunch of stuff on every row that I don't need to compute. So I think I need to getSectionIDs and go through to determine the weapontype and then determine the skill and character stat that is associated with that weapontype.&nbsp; Sound right?
1641331475
GiGs
Pro
Sheet Author
API Scripter
applebaggins said: The calculation for Total_Melee (and every other skill) is built as Misc_skill + LVL_skill + some governing character stat like Dexterity.&nbsp; I'm not sure why. It's an older sheet that I just started working on.&nbsp; The core attributes, however, are direct inputs that I can parseInt on and calculate as necessary.&nbsp; The sheet author is already doing that elsewhere in the sheet worker, but only for when the weapontype changes and he/she still doesn't account for any Misc_skill bonuses. Remember every attribute you want must be included in the getStats, otherwise the worker won'tsee them and their values are always 'undefined'.
GiGs said: applebaggins said: The calculation for Total_Melee (and every other skill) is built as Misc_skill + LVL_skill + some governing character stat like Dexterity.&nbsp; I'm not sure why. It's an older sheet that I just started working on.&nbsp; The core attributes, however, are direct inputs that I can parseInt on and calculate as necessary.&nbsp; The sheet author is already doing that elsewhere in the sheet worker, but only for when the weapontype changes and he/she still doesn't account for any Misc_skill bonuses. Remember every attribute you want must be included in the getStats, otherwise the worker won'tsee them and their values are always 'undefined'. Yup!&nbsp; I'm tracking you there.&nbsp; I know all the attributes I need - just have to figure out the best way to put them together, but maybe I'm also being a little too nitpicky about how it all comes together.
1641331634
GiGs
Pro
Sheet Author
API Scripter
That sheet has a serious case of divitus! (google it). But you dont need to fix that if your goal is just to fix an issue or two.
1641331690
GiGs
Pro
Sheet Author
API Scripter
applebaggins said: Yup!&nbsp; I'm tracking you there.&nbsp; I know all the attributes I need - just have to figure out the best way to put them together, but maybe I'm also being a little too nitpicky about how it all comes together. You can never be too nitpciky with programming. Generally, the nitpickier, the better.
GiGs said: That sheet has a serious case of divitus! (google it). But you dont need to fix that if your goal is just to fix an issue or two. LOL!&nbsp; I did Google this and got a great laugh out of it.&nbsp; :D&nbsp; I am far less skilled than the original author, but am trying to fix a thing or two and add a thing or two for a campaign I just started.
1641333135

Edited 1641336151
GiGs
Pro
Sheet Author
API Scripter
Here's a Universal Sheet Worker to replace all the autocalcs for calculating the totals. This will make your repeating section possible, and generally improve yoiur sheet. (Honestly, it would be better to do this as single worker, but the code is a bit more complex, and it's not going to make much difference as a forEach loop). You need to do 2 things for this to work (listed below code). // create an array listing ALL the skills and the stat they use. Use only lower case. const skill_stats = { &nbsp; &nbsp; archery : ' reflex ', &nbsp; &nbsp; autofire : ' reflex ', &nbsp; &nbsp; handgun : 'reflex ', } // note you could do this indexing by stat instead of skill, and that could be more efficient // but the code ius a lot easier to write this way, and the efficieny loss doesn't matter. // now create a universal sheet worker to calculate the totals in response to changes: Object . keys ( skill_stats ). forEach ( skill =&gt; { &nbsp; &nbsp; // create the variables for the relevant attributes &nbsp; &nbsp; const baseskill = "lvl_" + skill ; &nbsp; &nbsp; const miscskill = "misc_" + skill ; &nbsp; &nbsp; const stat = skill_stats [ skill ]; &nbsp; &nbsp; on ( `change: ${ baseskill } change: ${ miscskill } change: ${ stat } ` , function () { &nbsp; &nbsp; &nbsp; &nbsp; getAttrs ([ baseskill , miscskill , stat ], function ( values ) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const base = parseInt ( values [ baseskill ]) || 0 ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const misc = parseInt ( values [ miscskill ]) || 0 ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const stat = parseInt ( values [ stat ]) || 0 ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const total = base + misc + stat ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs ({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [ 'total_' + skill ]: total &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; }); }); What you need to do: First, go through the sheet and on the Total_[attribute] lines, replace disabled=true with readonly . Second, in the above code there's this object variable const skill_stats = { &nbsp; &nbsp; archery: reflex, &nbsp; &nbsp; autofire: reflex, &nbsp; &nbsp; handgun: reflex, } Simply expand it with every attribute name, and the stat it uses. You'll notice my code uses entirely lower case attribute names. Roll20 is case insenstitive except in one place, the on(change) line, where everything must be lower case. So its always best in your sheet workers to use entirely lower case. PS: also make sure the total skill names match just by adding total_ to the start. The worker above assumes that. That worked for all the ones i looked at.
Mister Wizard!&nbsp; That looks awesome - thanks much.&nbsp; Just to be clear (and using Handgun as an example), I'm going to take all instances of: &lt;input type="number" name="attr_Total_Handgun" value="@{Misc_Handgun}+@{LVL_Handgun}+@{Reflex}" disabled="true" /&gt; and turn them into this: &lt;input type="number" name="attr_Total_Handgun" value="0" readonly="true" /&gt; I'm assuming I need to set the value part to 0 and let the universal sheet worker handle the rest?&nbsp; Or do I not even need to change the value part in the code?
1641333889
GiGs
Pro
Sheet Author
API Scripter
You dont have to change the value part, the sheet worker will overwrite it. But you can change it to ="0" for neatness. When I'm modifying an existing sheet I normally don't bother, to save on typing. I'm honestly not sure if readonly=true works (it probably does), I always just use readonly alone like: &lt;input type="number" name="attr_Total_Handgun" value="0" readonly &gt;
1641334008
GiGs
Pro
Sheet Author
API Scripter
That said it's probablky a good idea to change one line: &nbsp; &nbsp; on(`change:${baseskill} change:${miscskill} change:${stat} sheet:opened`, function() { To make sure all values get updated when the sheets are being used. If you are starting a new game and don't have pre-existing characters, don't add that though, since it'll make sheets opening a little bit slower.
1641335770
GiGs
Pro
Sheet Author
API Scripter
Does this line in the repeating section not do what you need, and if so what's the problem with it? &lt; input type =" hidden " name =" attr_WeaponMod " value =" @{Total_Melee} " &gt; Is the problem that it always uses the Total_Melee score?
GiGs said: Does this line in the repeating section not do what you need, and if so what's the problem with it? &lt; input type =" hidden " name =" attr_WeaponMod " value =" @{Total_Melee} " &gt; Is the problem that it always uses the Total_Melee score? Everything updates properly if you change the weapontype to something else and change it back, but it doesn't update itself if you update a skill associated to the weapon.&nbsp; WeaponMod works, but it only updates when the Weapontype gets changed.
1641336197
GiGs
Pro
Sheet Author
API Scripter
In my earlier code, i had a mistake: I left off the quotes around reflex in this section: const skill_stats = { &nbsp; &nbsp; archery: 'reflex', &nbsp; &nbsp; autofire: 'reflex', &nbsp; &nbsp; handgun: 'reflex', }
1641336874
GiGs
Pro
Sheet Author
API Scripter
applebaggins said: GiGs said: Does this line in the repeating section not do what you need, and if so what's the problem with it? &lt; input type =" hidden " name =" attr_WeaponMod " value =" @{Total_Melee} " &gt; Is the problem that it always uses the Total_Melee score? Everything updates properly if you change the weapontype to something else and change it back, but it doesn't update itself if you update a skill associated to the weapon.&nbsp; WeaponMod works, but it only updates when the Weapontype gets changed. That sounds like you need to add a couple more attributes to the on(change) line, like adding: change:repeating_weapons:weaponmod change:repeating_weapons:weapontype That would look like on ( `change:total_handgun change:total_melee change:repeating_weapons:weaponmod change:repeating_weapons:weapontype sheet:opened` , function ( eventInfo ) { The skills is not as straightforward. You'll need to have some way to index weapon types and the skill used by them, usually using an object like: const weapon_skills = { &nbsp;&nbsp;&nbsp; pistol: handgun, &nbsp;&nbsp;&nbsp; smg: handgun, &nbsp;&nbsp;&nbsp;&nbsp;/* all the other options */ } How do you need to use the skill?
1641337301

Edited 1641338004
GiGs
Pro
Sheet Author
API Scripter
I havent written the repeating section code, because I'm not clear what exactly you want it to do or which attributes are needed. Can you describe that in as much detail as possible, ignoring our prior conversation?
1641338707
GiGs
Pro
Sheet Author
API Scripter
Looking through the workers section, I guess you are tryng to fix the worker that starts line 2531?
GiGs said: I havent written the repeating section code, because I'm not clear what exactly you want it to do or which attributes are needed. Can you describe that in as much detail as possible, ignoring our prior conversation? Sure! Consider the repeating_weapons row below: The Type &nbsp;is a dropdown in which you can select many different weapon types. This field is known as repeating_weapons_RowID_weapontype . There's also a hidden value called repeating_weapons_RowID_weaponmod &nbsp;and it's comprised three addends: a base skill, a bonus to that skill and a physical stat associated with that skill.&nbsp; The value of repeating_weapons_RowID_weaponmod &nbsp;needs to be updated dynamically whenever one of the three addends is updated. We'll use Pistol as an example.&nbsp; Anytime the repeating_weapons_RowID_weapontype &nbsp;is set to Pistol, the repeating_weapons_RowID_weaponmod &nbsp;for that row is the sum of the following addends: the base level of the Handgun skill (called LVL_Handgun) the bonus level of the Handgun skill (called Misc_Handgun) the Reflex stat (called simply Reflex) I need to dynamically update the repeating_weapons_RowID_weaponmod &nbsp;value anytime one of the addends is updated. To further complicate matters, the weapon types are not 1:1 with skills and physical stats.&nbsp; Consult the following table: Weapon Type Skill Used Physical Stat Used Brawling Brawling Dexterity Martial Arts Martial Dexterity Melee Melee Dexterity Pistol Handgun Reflex SMG Handgun Reflex SMG (Autofire) Autofire Reflex Assault Rifle ShoulderArms Reflex Shotgun (Slug) ShoulderArms Reflex AR (Autofire) Autofire Reflex Sniper Rifle ShoulderArms Reflex Bow/Crossbow Archery Reflex Grenade Launcher HeavyArms Reflex Rocket Launcher HeavyArms Reflex
GiGs said: Looking through the workers section, I guess you are tryng to fix the worker that starts line 2531? I'm happy to expand on that worker.&nbsp; Currently, that worker only executes when the weapontype is changed, though.&nbsp; I'd like to have a worker that executes any time one of the components/addends listed above are updated.
1641339995
GiGs
Pro
Sheet Author
API Scripter
Does the Total_ version of the weapon skillsinclude the attribute, so its always made up of the LVL + Misc + stat?
1641340111

Edited 1641340136
GiGs said: Does the Total_ version of the weapon skillsinclude the attribute, so its always made up of the LVL + Misc + stat? Yes, the Total_skill attribute is always made up of LVL_skill + Misc_skill + whatever stat is associated with that skill.
1641345503

Edited 1641356691
GiGs
Pro
Sheet Author
API Scripter
That was a great description. Here's a replacement for that sheet worker, that sets the weaponmod attribute for each row in the repeating section, and is triggered when the total_attribute changes (which means also the lvl_, misc_, and dex or reflex stats), and also triggers when weapon type is changed. This assumes you have set up the previous code to create the total_ skills (or, better, the code in the next post). const weapon_skills = [ "archery" , "handgun" , "heavyarms" , "shoulderarms" , "brawling" , "martial" , "melee" , &nbsp; "autofire" ]; const weapon_skills_changes = weapon_skills . map ( skill =&gt; 'change:total_' + skill ). join ( ' ' ); on ( ` ${ weapon_skills_changes } change:repeating_weapons:weapontype` , function ( ) { &nbsp; &nbsp; getSectionIDs ( "repeating_weapons" , function ( idarray ) { &nbsp; &nbsp; &nbsp; &nbsp; const sectionNames = []; &nbsp; &nbsp; &nbsp; &nbsp; idarray . forEach ( id =&gt; sectionNames . push ( `repeating_weapons_ ${ id } _weapontype` )); &nbsp; &nbsp; &nbsp; &nbsp; getAttrs ([ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ... sectionNames , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ... weapon_skills . map ( skill =&gt; 'total_' + skill ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ], function ( values ) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console . log ( values ); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const output = {}; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const weapontype_skill = { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Brawling : 'brawling' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Martial Arts" : 'martial' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Melee : "melee" , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Pistol : 'handgun' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SMG : 'handgun' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "SMG (Autofire)" : 'autofire' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Assault Rifle" : 'shoulderarms' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Shotgun (Slug)" : 'shoulderarms' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "AR (Autofire)" : 'autofire' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Sniper Rifle" : 'shoulderarms' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Bow/Crossbow" : 'archery' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Grenade Launcher" : 'heavyarms' , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Rocket Launcher" : 'heavyarms' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; idarray . forEach ( id =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const wtype = values [ `repeating_weapons_ ${ id } _weapontype` ]; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const skill = weapontype_skill [ wtype ]; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const weaponmod = parseInt ( values [ 'total_' + skill ]) || 0 ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output [ `repeating_weapons_ ${ id } _weaponmod` ]= weaponmod ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs ( output ); &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; }); }); There isn't any documentation, because I'm about at my limit of typing for a bit. But I have broken the code down into steps. If you dont follow any of it (or it doesn't work! I havent tested it so they might be syntax errors), ask away. Note: this wont calculate the values till you change and one attribute that goes into any of the total_ values, or any one&nbsp; weapontype (including adding a new weapon). Once you change one of those values, it will calculate all values correctly.
1641346376

Edited 1641366526
GiGs
Pro
Sheet Author
API Scripter
And here's a replacement for the earlier total_ calculation, that is more efficient. const all_skills = { &nbsp; &nbsp; trading : 'cool' , &nbsp; &nbsp; concentration : 'willpower' , &nbsp; &nbsp; concealreveal : 'intelligence' , &nbsp; &nbsp; lipreading : 'intelligence' , &nbsp; &nbsp; perception : 'intelligence' , &nbsp; &nbsp; tracking : 'intelligence' , &nbsp; &nbsp; athletics : 'dexterity' , &nbsp; &nbsp; contortionist : 'dexterity' , &nbsp; &nbsp; dance : 'dexterity' , &nbsp; &nbsp; endurance : 'willpower' , &nbsp; &nbsp; torturedrugs : 'willpower' , &nbsp; &nbsp; stealth : 'dexterity' , &nbsp; &nbsp; &nbsp; &nbsp; driveland : '' , &nbsp; &nbsp; pilotsea : '' , &nbsp; &nbsp; riding : '' , &nbsp; &nbsp; accounting : '' , &nbsp; &nbsp; animalhandling : '' , &nbsp; &nbsp; bureaucracy : '' , &nbsp; &nbsp; business : '' , &nbsp; &nbsp; composition : '' , &nbsp; &nbsp; criminology : '' , &nbsp; &nbsp; cryptography : '' , &nbsp; &nbsp; deduction : '' , &nbsp; &nbsp; education : '' , &nbsp; &nbsp; gamble : '' , &nbsp; &nbsp; streetslang : '' , &nbsp; &nbsp; languagea : '' , &nbsp; &nbsp; languageb : '' , &nbsp; &nbsp; librarysearch : '' , &nbsp; &nbsp; yourhome : '' , &nbsp; &nbsp; localexperta : '' , &nbsp; &nbsp; localexpertb : '' , &nbsp; &nbsp; sciencea : '' , &nbsp; &nbsp; scienceb : '' , &nbsp; &nbsp; tactics : '' , &nbsp; &nbsp; wilderness : '' , &nbsp; &nbsp; brawling : 'dexterity' , &nbsp; &nbsp; evasion : '' , &nbsp; &nbsp; melee : 'dexterity' , &nbsp; &nbsp; acting : '' , &nbsp; &nbsp; instrumenta : '' , &nbsp; &nbsp; instrumentb : '' , &nbsp; &nbsp; archery : '' , &nbsp; &nbsp; handgun : 'reflex' , &nbsp; &nbsp; shoulderarms : 'reflex' , &nbsp; &nbsp; bribery : '' , &nbsp; &nbsp; conversation : '' , &nbsp; &nbsp; humanperception : '' , &nbsp; &nbsp; interrogation : '' , &nbsp; &nbsp; persuasion : '' , &nbsp; &nbsp; personalgrooming : '' , &nbsp; &nbsp; streetwise : '' , &nbsp; &nbsp; wardrobe : 'cool' , &nbsp; &nbsp; avtech : 'technique' , &nbsp; &nbsp; basictech : 'technique' , &nbsp; &nbsp; cybertech : 'technique' , &nbsp; &nbsp; firstaid : 'technique' , &nbsp; &nbsp; forgery : 'technique' , &nbsp; &nbsp; lvtech : 'technique' , &nbsp; &nbsp; paintdrawsculpt : 'technique' , &nbsp; &nbsp; photographyfilm : 'technique' , &nbsp; &nbsp; picklock : 'technique' , &nbsp; &nbsp; pickpocket : 'technique' , &nbsp; &nbsp; svtech : 'technique' , &nbsp; &nbsp; weaponstech : 'technique' , &nbsp; &nbsp; pilotair : '' , &nbsp; &nbsp; martial : 'dexterity' , &nbsp; &nbsp; autofire : 'reflex' , &nbsp; &nbsp; heavyarms : 'reflex' , &nbsp; &nbsp; demolitions : 'technique' , &nbsp; &nbsp; electronicssecurity : 'technique' , &nbsp; &nbsp; paramedic : 'technique' , &nbsp; &nbsp; charismaticimpact : '' , &nbsp; &nbsp; interface : '' , &nbsp; &nbsp; fieldexpertise : '' , &nbsp; &nbsp; upgradeexpertise : '' , &nbsp; &nbsp; fabricationexpertise : '' , &nbsp; &nbsp; inventionexpertise : '' , &nbsp; &nbsp; surgery : '' , &nbsp; &nbsp; pharmaceuticals : '' , &nbsp; &nbsp; cryosystem : '' , &nbsp; &nbsp; credibility : '' , &nbsp; &nbsp; teamwork : '' , &nbsp; &nbsp; backup : '' , &nbsp; &nbsp; operator : '' , &nbsp; &nbsp; moto : '' , }; const all_skills_lvl_misc = []; Object . keys ( all_skills ). forEach ( skill =&gt; all_skills_lvl_misc . push ( &nbsp; &nbsp; &nbsp; &nbsp; "lvl_" + skill , &nbsp; &nbsp; &nbsp; &nbsp; "misc_" + skill )); const all_skills_lvl_misc_changes = all_skills_lvl_misc . map ( skill =&gt; `change: ${ skill } ` ). join ( ' ' ); const stats_lower = [ "intelligence" , "reflex" , "dexterity" , "technique" , "cool" , "willpower" , "luck" , "movement" , "body" , "empathy" ]; const stats_changes = stats_lower . map ( stat =&gt; `change: ${ stat . toLowerCase () } ` ). join ( ' ' ); on ( ` ${ all_skills_lvl_misc_changes } ${ stats _changes} sheet:opened` , function () { &nbsp; &nbsp; getAttrs ([... stats _lower. map ( stat =&gt; stat . toLowerCase ()), ... all_skills_lvl_misc ], function ( values ) { &nbsp; &nbsp; &nbsp; &nbsp; const output = {}; &nbsp; &nbsp; &nbsp; &nbsp; Object . keys ( all_skills ). forEach ( skill =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // create the variables for the relevant attributes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const base = parseInt ( values [ "lvl_" + skill ]) || 0 ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const misc = parseInt ( values [ "misc_" + skill ]) || 0 ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const stat = parseInt ( values [ all_skills [ skill ]]) || 0 ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const total = base + misc + stat ; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output [ 'total_' + skill ] = total ; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; setAttrs ( output ); &nbsp; &nbsp; }); }); &nbsp; This assumes you have followed one previous requirement: changed all the total_ attributes from disable=true to readonly. It also requires that you fill in the attribute for each skill in that first all_skills variable. I've done a bunch of them. Some skills have no stat (like cryosystem and credibility). Leave the value: ''. This will calculate the stat at 0. Note that any skill you dont change disabled="true" to readonly will still work as an autocalc, so if you only changed the weapon skills listed in the previous post, this would work fine for getting the repeating section worker to work properly, and you could update the worker above with other skills as and when you have time.
1641355286

Edited 1641355965
GiGs
Pro
Sheet Author
API Scripter
There were a couple of typos in the above code and I've corrected them.
1641358671
GiGs
Pro
Sheet Author
API Scripter
Oh, I just realised what you meant when you said earlier you needed to change weapon type then change it back. The fix for that is this: &lt; select name = "attr_Weapontype" class = "Weapontype" &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "-" selected &gt;(Choose) &lt;/ option &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; &lt; option value = "Brawling" &gt; Brawling &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "Martial Arts" &gt; Martial Arts &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "Melee" &gt; Melee &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "Pistol" &gt; Pistol &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "SMG" &gt; SMG &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "SMG (Autofire)" &gt; SMG (Autofire) &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "Shotgun (Slug)" &gt; Shotgun (Slug) &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "Assault Rifle" &gt; Assault Rifle &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "AR (Autofire)" &gt; AR (Autofire) &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "Sniper Rifle" &gt; Sniper Rifle &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "Bow/Crossbow" &gt; Bow/Crossbow &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "Grenade Launcher" &gt; Grenade Launcher &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt; option value = "Rocket Launcher" &gt; Rocket Launcher &lt;/ option &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/ select &gt; add that first option line. This means that by default a weapon type isnt set, and players have to choose one, and when they do, it triggers the sheet worker. adding the selected keyword to brawling probabky works as well, as on the next line, but I prefer the above approach. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;option value="Brawling" selected &gt;Brawling&lt;/option&gt; This sets Brawling as a default value, and whenever you add a new weapon, the brawling value will be calculated.
Thanks a MILLION!&nbsp; I'll get started on this stuff today and let you know!
Worked like a charm!&nbsp; Thanks again - check your email!
1641403636
GiGs
Pro
Sheet Author
API Scripter
Thank you :)