You might be able to do this easier by copying the repeatingSum code from the wiki (as suggested by Scott earlier in the thread). You'd copy the code from the wiki to the start of your script block: const repeatingSum = ( destinations , section , fields ) => { if (! Array . isArray ( destinations )) destinations = [ destinations . replace ( /\s/ g , '' ). split ( ',' )]; if (! Array . isArray ( fields )) fields = [ fields . replace ( /\s/ g , '' ). split ( ',' )]; getSectionIDs ( `repeating_ ${ section } ` , idArray => { const attrArray = idArray . reduce (( m , id ) => [... m , ...( fields . map ( field => `repeating_ ${ section } _ ${ id } _ ${ field } ` ))], []); getAttrs ([... attrArray ], v => { const getValue = ( section , id , field ) => v [ `repeating_ ${ section } _ ${ id } _ ${ field } ` ] === 'on' ? 1 : parseFloat ( v [ `repeating_ ${ section } _ ${ id } _ ${ field } ` ]) || 0 ; const commonMultipliers = ( fields . length <= destinations . length ) ? [] : fields . splice ( destinations . length , fields . length - destinations . length ); const output = {}; destinations . forEach (( destination , index ) => { output [ destination ] = idArray . reduce (( total , id ) => total + getValue ( section , id , fields [ index ]) * commonMultipliers . reduce (( subtotal , mult ) => subtotal * getValue ( section , id , mult ), 1 ), 0 ); }); setAttrs ( output ); }); }); }; You do not touch that code at all, just paste it into the start of your script block. Then to sum up each repeating section, create a worker following the instructions on the page. For your fieldsets above, that would look like: on ( 'change:repeating_equipment:quantity change:repeating_equipment:mass remove:repeating_equipment' , function () { repeatingSum ( "equipmentmass" , "equipment" ,[ "quantity" , "mass" ]); }); on ( 'change:repeating_kits:quantity change:repeating_equipment:mass remove:repeating_kits' , function () { repeatingSum ( "equipmentmass" , "kits" ,[ "quantity" , "mass" ]); }); Notice on the event line, this follows standard roll20 example syntax - include a change event for each relevant attribute, and a remove for the repeating section so it detects when the user deletes a row. Then call the function you have just added - first supply the attribute you want to save the total into, then the repeating section name (without the repeating_ part), and finally an array of the attributes inside the section you want to multiply together. You can repeat this process for every repeating section you want to sum up. I wrote this function because at the time I was having to sum up a lot of repeating sections, and I wanted a really simple way to do it over and over. Now I just plonk that function at the start of a code block, ignore it, and then create those 3 line workers when I need them. Finally if using multiple repeating sections, you need to add one more worker to add the totals together. There's lots of ways to do this, but following (almost) the roll20 example syntax, here's one: on ( 'change:kitsmass change:equipmentmass' , function () { getAttrs ([ 'kitsmass' , 'equipmentmass' ], function ( v ) { const kits = + v . kitsmass || 0 ; const equip = + v . equipmentmass || 0 ; const total = kits + equip ; setAttrs ({ totalmass : total }); }); }); Now this is less efficient than Scott's method, and relies on cascading events (one setattrs creating a change, which is then picked up by the change event in another worker), but if you dont go overboard with such things there's no reason this should be noticeable by the user. Putting it all together, your entire script block would look like: const repeatingSum = ( destinations , section , fields ) => { if (! Array . isArray ( destinations )) destinations = [ destinations . replace ( /\s/ g , '' ). split ( ',' )]; if (! Array . isArray ( fields )) fields = [ fields . replace ( /\s/ g , '' ). split ( ',' )]; getSectionIDs ( `repeating_ ${ section } ` , idArray => { const attrArray = idArray . reduce (( m , id ) => [... m , ...( fields . map ( field => `repeating_ ${ section } _ ${ id } _ ${ field } ` ))], []); getAttrs ([... attrArray ], v => { const getValue = ( section , id , field ) => v [ `repeating_ ${ section } _ ${ id } _ ${ field } ` ] === 'on' ? 1 : parseFloat ( v [ `repeating_ ${ section } _ ${ id } _ ${ field } ` ]) || 0 ; const commonMultipliers = ( fields . length <= destinations . length ) ? [] : fields . splice ( destinations . length , fields . length - destinations . length ); const output = {}; destinations . forEach (( destination , index ) => { output [ destination ] = idArray . reduce (( total , id ) => total + getValue ( section , id , fields [ index ]) * commonMultipliers . reduce (( subtotal , mult ) => subtotal * getValue ( section , id , mult ), 1 ), 0 ); }); setAttrs ( output ); }); }); }; on ( 'change:repeating_equipment:quantity change:repeating_equipment:mass remove:repeating_equipment' , function () { repeatingSum ( "equipmentmass" , "equipment" ,[ "quantity" , "mass" ]); }); on ( 'change:repeating_kits:quantity change:repeating_equipment:mass remove:repeating_kits' , function () { repeatingSum ( "kitsmass" , "kits" ,[ "quantity" , "mass" ]); }); on ( 'change:kitsmass change:equipmentmass' , function () { getAttrs ([ 'kitsmass' , 'equipmentmass' ], function ( v ) { const kits = + v . kitsmass || 0 ; const equip = + v . equipmentmass || 0 ; const total = kits + equip ; setAttrs ({ totalmass : total }); }); }); (Dont forget the starting and ending script lines.)