I am following the RepeatingSum tutorial from the Roll20 wiki however when I paste it in, it doesn't calculate the total. Any help on what I am doing wrong would be appreciated. Duncman Here is my code <input type="radio" name="attr_tab1" class="sheet-tab sheet-tab1" value="1" title="Equipment" /><span title="Equipment"></span> </div> <div style="background-color: #ac6e73" class="sheet-tab-content sheet-tab1"> <br /> <label class="sheet-section_header">EQUIPMENT</label> <br /> <p style="font-weight:bold; width:54%; display:inline-block">Carried Equipment:</p> <p style="font-weight:bold;text-align:center;width:25%;display:inline-block">Worn/Carried</p> <p style="font-weight:bold;text-align:center;width: 10% ;display:inline-block">Enc:</p> <fieldset class="repeating_equipment" style="margin-top:-20px;"> <input style="display:inline-block; width: 55% ;" type="text" name="attr_equipment_type"/> <input style="display:inline-block; width: 25% ;" type="text" name="attr_equipment_location"/> <input style="display:inline-block; width: 4em ;" type="number" name="attr_equipment_weight"/> </fieldset> </div> <br /> <div> <label style="display:inline" class="sheet-attr_label">Encumburance Total:</label> <input style='width:5em;display:inline;' value="0" type="number" name="attr_enc_totalf"/> <input style='display:none' type="number" value="0" name="attr_enc_total"/> </div> </div> <script type="text/worker"> const repeatingSum = (destinations, section, fields, ...extras) => { const isNumber = value => parseFloat(value).toString() === value.toString(); const isOption = value => [...checks.valid, ...checks.roundtypes].includes(value); const isRounding = value => checks.roundtypes.includes(value); const isFraction = value => value.includes('/') && !(value.includes(',') || value.includes('|')); const getTrimmed = value => value.toLowerCase().replace(/\s/g, ''); const getRounded = (type, value, pow) => (Math[type](value * Math.pow(10, pow)) / Math.pow(10, pow)).toFixed(Math.max(0, pow)); const getFraction = (value) => /*{ console.log(`value: ${value}`); */ parseInt(value.split('/')[0]) / parseInt(value.split('/')[1]); const getMultiplier = (value, rounding = 1) => 'undefined' === typeof value ? (rounding ? 0: 1) : ( isNumber(value) ? parseFloat(value) : (isFraction(value) ? getFraction(value) : value)); if (!Array.isArray(destinations)) destinations = [getTrimmed(destinations)]; if (!Array.isArray(fields)) fields = [getTrimmed(fields)]; const fields_trimmed = fields.map(field => getTrimmed(field).split(':')[0]); const subfields = fields_trimmed.slice(0,destinations.length); const checks = { valid: ['multiplier'], roundtypes: ['ceil', 'round', 'floor'] }; let properties = {attributes: {}, options: {}}; extras.forEach(extra => { const [prop, v] = getTrimmed(extra).split(':'); const multiplier_maybe = getMultiplier(v, isRounding(prop)); const obj = isNumber(multiplier_maybe) ? subfields.reduce((obj,field) => { obj[field] = multiplier_maybe; return obj; },{}) : multiplier_maybe.split(',').reduce((obj, item) => { const [stat, value] = item.split('|'); const multiplier = getMultiplier(value, isRounding(prop)); obj[stat] = multiplier; return obj; }, {}); properties[isOption(prop) ? 'options' : 'attributes'][prop] = obj; }); getSectionIDs(`repeating_${section}`, idArray => { const attrArray = idArray.reduce((m, id) => [...m, ...(fields_trimmed.map(field => `repeating_${section}_${id}_${field}`))], []); getAttrs([...attrArray, ...Object.keys(properties.attributes)], 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.reduce((obj, destination, index) => { let sumTotal = idArray.reduce((total, id) => total + getValue(section, id, fields_trimmed[index]) * commonMultipliers.reduce((subtotal, mult) => subtotal * ((!mult.includes(':') || mult.split(':')[1].split(',').includes(fields_trimmed[index])) ? getValue(section, id, mult.split(':')[0]) : 1), 1), 0); sumTotal *= (properties.options.hasOwnProperty('multiplier') && Object.keys(properties.options.multiplier).includes(fields_trimmed[index])) ? (parseFloat(properties.options.multiplier[fields_trimmed[index]]) || 0): 1; sumTotal += Object.entries(properties.attributes).reduce((total, [key, value]) => total += (value.hasOwnProperty(fields_trimmed[index]) ? parseFloat(v[key] || 0) * (parseFloat(value[fields_trimmed[index]]) || 1): 0) , 0); checks.roundtypes.forEach(type => { if (properties.options.hasOwnProperty(type)) { if (Object.keys(properties.options[type]).includes(fields_trimmed[index])) { sumTotal = getRounded(type, sumTotal, (+properties.options[type][fields_trimmed[index]] || 0)); } else if (properties.options[type] == '0' || !isNaN(+properties.options[type] || 'x') ) { sumTotal = getRounded(type, sumTotal, +properties.options[type]); } } }); obj[destination] = sumTotal; return obj; }, {}); setAttrs(output); }); }); }; on("change:enc_totalf", function() { getAttrs(["enc_totalf"], function(values) { var fx = parseFloat(values.enc_totalf); fx = Math.round(fx,0); setAttrs({enc_total:fx}); }); }); on('change:repeating_equipment remove:repeating_equipment',function(){ repeatingSum('equipment','equipment_weight','enc_totalf'); });