Thank you all for the responses, I went back and reworked it as a sheet worker> Sheet worker: // Common parser function function parseDamageString(damageString, prefix) { const updates = {}; const match = damageString.match(/^(\d+)[dD](\d+)([+\-]\d+)?$/); if (match) { const numDice = parseInt(match[1], 10) || 0; const diceSize = parseInt(match[2], 10) || 0; const bonus = parseInt(match[3] || "0", 10) || 0; updates[`${prefix}_damage_numdice`] = numDice; updates[`${prefix}_damage_dicesize`] = diceSize; updates[`${prefix}_damage_bonus`] = bonus; } else { updates[`${prefix}_damage_numdice`] = 0; updates[`${prefix}_damage_dicesize`] = 0; updates[`${prefix}_damage_bonus`] = 0; } return updates; } // Auto-calculate damage components for fixed weapon (weapon1_mdr) on("sheet:opened add:weapon1_mdr_damage change:weapon1_mdr_damage", function() { getAttrs(["weapon1_mdr_damage"], function(values) { const damageString = values.weapon1_mdr_damage || ""; const updates = parseDamageString(damageString, "weapon1_mdr"); setAttrs(updates); }); }); // Auto-calculate damage components for repeating weapons (repeating_weaponsmdr) - change only on("add:repeating_weaponsmdr change:repeating_weaponsmdr:weapondamage_mdr", function(eventInfo) { const repeatingId = eventInfo.sourceAttribute.match(/repeating_weaponsmdr_([^_]+)_/)[1]; getAttrs([`repeating_weaponsmdr_${repeatingId}_weapondamage_mdr`], function(values) { const damageString = values[`repeating_weaponsmdr_${repeatingId}_weapondamage_mdr`] || ""; const updates = parseDamageString(damageString, `repeating_weaponsmdr_${repeatingId}`); setAttrs(updates); }); }); // On sheet:opened, manually get all repeating rows on("sheet:opened", function() { getSectionIDs("repeating_weaponsmdr", function(ids) { if (ids.length === 0) return; const fields = ids.map(id => `repeating_weaponsmdr_${id}_weapondamage_mdr`); getAttrs(fields, function(values) { const updates = {}; ids.forEach(id => { const damageString = values[`repeating_weaponsmdr_${id}_weapondamage_mdr`] || ""; Object.assign(updates, parseDamageString(damageString, `repeating_weaponsmdr_${id}`)); }); if (Object.keys(updates).length > 0) { setAttrs(updates); } }); }); }); Hidden inputs for static weapon: <input type="hidden" name="attr_weapon1_mdr_damage_numdice" value="0" /> <input type="hidden" name="attr_weapon1_mdr_damage_dicesize" value="0" /> <input type="hidden" name="attr_weapon1_mdr_damage_bonus" value="0" /> <input type="hidden" name="attr_weapon1_mdr_strain" value="0" /> Static Weapon Roll: <button class='new-roll' type='roll' value='&{template:coc-attack-1} {{name=@{weapon1_mdr_name}}} {{modifier=@{dice_modifier_checkbox}}} {{success=[[@{weapon1_skill_mdr}+@{dice_modifier_checkbox}]]}} {{hard=[[floor((@{weapon1_skill_mdr} + @{dice_modifier_checkbox})/2)]]}} {{extreme=[[floor((@{weapon1_skill_mdr} + @{dice_modifier_checkbox})/5)]]}} {{malf=@{weapon1_mdr_malf}}} {{roll1=[[1d100]]}} {{damage=[[@{weapon1_mdr_damage}@{weapon1_mdr_db}]]}} {{extremedamage=[[(@{weapon1_mdr_damage_numdice}*@{weapon1_mdr_damage_dicesize})+@{weapon1_mdr_damage_bonus}]]}} {{strain=[[ @{weapon1_mdr_strain} + 0 ]]}}' name='roll_weapon1_mdr_attack' /> Hidden Inputs for repeating weapon: <input type="hidden" name="attr_damage_numdice" value="0" /> <input type="hidden" name="attr_damage_dicesize" value="0" /> <input type="hidden" name="attr_damage_bonus" value="0" /> <input type="hidden" name="attr_weaponstrain_mdr" value="0" /> Repeating Weapon Roll: <button class='new-roll' type='roll' value='&{template:coc-attack-1} {{name=@{weaponname_mdr}}} {{modifier=@{dice_modifier_checkbox}}} {{success=[[@{weaponskill_mdr}+@{dice_modifier_checkbox}]]}} {{hard=[[floor((@{weaponskill_mdr}+@{dice_modifier_checkbox})/2)]]}} {{extreme=[[floor((@{weaponskill_mdr}+@{dice_modifier_checkbox})/5)]]}} {{malf=@{weaponmalf_mdr}}} {{roll1=[[1d100]]}} {{damage=[[@{weapondamage_mdr}@{weapondb_mdr}]]}} {{extremedamage=[[(@{damage_numdice}*@{damage_dicesize})+@{damage_bonus}]]}} {{strain=[[ @{weaponstrain_mdr} + 0 ]]}}' name='roll_weaponskill_mdr_check' /> Roll Template: <!-- &{template:coc-attack-1} --------------------------------------------------------------------------------------------------------- --> <rolltemplate class="sheet-rolltemplate-coc-attack-1"> <table> <caption>{{name}} | {{modifier}}</caption> <tr><td class="template_label" data-i18n="value">Value:</td><td class="template_value">{{success}}/{{hard}}/{{extreme}}</td></tr> {{#malf}} <tr><td class="template_label" data-i18n="malf">Malf:</td><td class="template_value">{{malf}}</td></tr> {{/malf}} <tr><td class="template_label" data-i18n="rolled">Rolled:</td><td class="template_value">{{roll1}}</td></tr> <tr style="background:#BEBEBE;"> <td class="template_label" data-i18n="result">Result:</td> <!-- 01 is always Critical --> {{#rollTotal() roll1 1}} <td style="background:Lime;" class="template_value"><b data-i18n="critical">Critical</b></td> {{/rollTotal() roll1 1}} <!-- Is Success --> {{#rollBetween() roll1 2 success}} <!-- Is Standard --> {{#rollGreater() roll1 hard}} <td style="background:DarkGreen;" class="template_value" data-i18n="success">Success</td> {{/rollGreater() roll1 hard}} <!-- Is Hard or Extreme --> {{#rollBetween() roll1 2 hard}} <!-- Is Hard --> {{#rollGreater() roll1 extreme}} <td style="background:Green;" class="template_value" data-i18n="hard">Hard</td> {{/rollGreater() roll1 extreme}} <!-- Is Extreme --> {{#rollBetween() roll1 2 extreme}} <td style="background:LightGreen;" class="template_value"><b data-i18n="extreme">Extreme</b></td> {{/rollBetween() roll1 2 extreme}} {{/rollBetween() roll1 2 hard}} {{/rollBetween() roll1 2 success}} <!-- Is Not Success --> {{#rollGreater() roll1 success}} <!-- Is skill >= 50 --> {{#rollGreater() success 49}} <!-- Is Fumble --> {{#rollTotal() roll1 100}} <td style="background:Red;" class="template_value"><b data-i18n="fumble">Fumble</b></td> {{/rollTotal() roll1 100}} <!-- Is Fail --> {{#rollLess() roll1 100}} <td style="background:Crimson;" class="template_value" data-i18n="fail">Fail</td> {{/rollLess() roll1 100}} {{/rollGreater() success 49}} <!-- Is skill < 50 --> {{#rollLess() success 50}} <!-- Is Fumble --> {{#rollGreater() roll1 95}} <td style="background:Red;" class="template_value"><b data-i18n="fumble">Fumble</b></td> {{/rollGreater() roll1 95}} <!-- Is Fail --> {{#rollLess() roll1 96}} <td style="background:Crimson;" class="template_value" data-i18n="fail">Fail</td> {{/rollLess() roll1 96}} {{/rollLess() success 50}} {{/rollGreater() roll1 success}} </tr> <tr> <td class="template_label" data-i18n="dam">Dam:</td><td class="template_value">{{damage}}</td> </tr> <!-- Only show Extreme Damage on Critical or Extreme --> {{#rollTotal() roll1 1}} <tr> <td class="template_label" data-i18n="extremedamage">Extreme Dam:</td><td class="template_value">{{extremedamage}}</td> </tr> {{/rollTotal() roll1 1}} {{#rollBetween() roll1 2 extreme}} <tr> <td class="template_label" data-i18n="extreme-damage">Extreme Dam:</td><td class="template_value">{{extremedamage}}</td> </tr> {{/rollBetween() roll1 2 extreme}} {{#^rollTotal() strain 0}} <tr> <td class="template_label" data-i18n="strain">Strain:</td><td class="template_value">{{strain}}</td> </tr> {{/^rollTotal() strain 0}} </table> </rolltemplate>