I assumed getting the id of a section would not trigger anything but, there is all the code triggered on ( 'change:repeating_martialarts remove:repeating_martialarts change:repeating_weapon:repweapondef change:repeating_weapon:repweaponabi remove:repeating_weapon' , TAS . _fn ( updateParry )); on ( 'change:qc-parry' , TAS . _fn ( updateParry )); async function updateParry ( e ) { if ( e . sourceType !== "player" && e . triggerName !== 'wound-penalty' ) { if ( debug >= 2 ) TAS . debug ( `updateParry:: TRIGGER FROM SCRIPT => CANCEL` ); return ; } if ( debug >= 2 ) TAS . debug ( 'updateParry:: e=' + JSON . stringify ( e )); const setObj = await ParryUpdater . getUpdatedParryObj (); if ( debug >= 2 ) TAS . debug ( 'updateParry:: setObj=' , setObj ); setAttrs ( setObj ); } class ParryUpdater { #maIds ; #weaponIds ; constructor () {} async getAttrToBeRetrieved ( maIds , weaponIds ) { let time = new TimeCounter ( 'ParryUpdater::getAttrToBeRetrieved' ); if ( debug === 3 ) TAS . debug ( `ParryUpdater::getAttrToBeRetrieved maIds= ${ maIds } , weaponIds= ${ weaponIds } ` ); this . #maIds = maIds || await getSectionIDsAsync ( 'martialarts' ); time . lap ( 'after AWAIT getMA_ID' ); this . #weaponIds = weaponIds || await getSectionIDsAsync ( 'weapon' ); time . lap ( `after AWAIT getWEAP_ID, size= ${this . #weaponIds . length } ` ); TAS . debug ( `ParryUpdate::getAttrToBeRetrieved #weaponIds= ${ JSON . stringify ( this . #weaponIds ) } ` ); const attrList = [ 'qc' , 'brawl' , 'melee' , 'dexterity' , 'qc-parry' , 'max-ma' , ... defAddedAttrs ]; time . lap ( 'after constructing attrList' ); this . #maIds . forEach ( id => attrList . push ( `repeating_martialarts_ ${ id } _repmartialarts` )); time . lap ( 'after forEach on MA' ); this . #weaponIds . forEach ( id => attrList . push ( `repeating_weapon_ ${ id } _repweapondef` , `repeating_weapon_ ${ id } _repweaponabi` , `repeating_weapon_ ${ id } _repweaponparry` , `repeating_weapon_ ${ id } _repweaponparryspe` )); time . lap ( 'after forEach on WEAP' ); maAttrsArray . forEach ( attr => attrList . push ( attr )); time . lap ( 'after forEach on MA LIST' ); return attrList ; } updateObj ( values , toBeUpdated = {}) { const getFromUpdatedOrRetrieve = ( attrStr ) => ( toBeUpdated && attrStr in toBeUpdated ) ? toBeUpdated [ attrStr ] : values [ attrStr ]; let ma = 0 ; for ( const maName of maAttrsArray ) ma = Math . max ( ma , Number ( getFromUpdatedOrRetrieve ( maName ))); const dex = Number ( getFromUpdatedOrRetrieve ( 'dexterity' )), brawl = Number ( getFromUpdatedOrRetrieve ( 'brawl' )), melee = Number ( getFromUpdatedOrRetrieve ( 'melee' )), qcParry = Number ( getFromUpdatedOrRetrieve ( 'qc-parry' )), isQc = Number ( getFromUpdatedOrRetrieve ( 'qc' )), finalObj = JSON . parse ( JSON . stringify ( toBeUpdated )), addedDef = calcDefAddedAndSetOnslaughtApplied ( values , finalObj ), correspondingTable = { 'brawl' : brawl , 'melee' : melee }; for ( const maName of maAttrsArray ) correspondingTable [ maName ] = Number ( getFromUpdatedOrRetrieve ( maName )); if ( debug >= 2 ) TAS . debug ( `ParryUpdater:updateObj:: values= ${ JSON . stringify ( values ) } ` ); ma = this . #maIds . reduce (( acc , id ) => Math . max ( acc , Number ( getFromUpdatedOrRetrieve ( `repeating_martialarts_ ${ id } _repmartialarts` ))), ma ); if ( debug === 3 ) TAS . debug ( `ParryUpdater:updateObj:: Max MA= ${ ma } , isQc= ${ isQc } , qcParry= ${ qcParry } ` ); if ( debug === 3 ) TAS . debug ( 'ParryUpdater:updateObj:: Unarmed Parry calc:' , ( isQc ? qcParry : 'Math.ceil(' + dex + ' + ' + brawl + ') / 2)' )); var newParry = ( isQc ? qcParry : Math . ceil (( dex + brawl ) / 2 )); if ( debug === 3 ) TAS . debug ( 'ParryUpdater:updateObj:: Unarmed Parry w/specialty calc:' , ( isQc ? qcParry + 1 : 'Math.ceil(' + dex + ' + ' + brawl + ' + 1) / 2)' )); var newParrySpe = ( isQc ? qcParry + 1 : Math . ceil (( dex + brawl + 1 ) / 2 )); if ( debug === 3 ) TAS . debug ( `ParryUpdater:updateObj:: applying addedDef: ${ addedDef } ` ); newParry += addedDef ; newParrySpe += addedDef ; if ( debug === 3 ) TAS . debug ( 'ParryUpdater:updateObj:: setAttrs!parry=' + newParry + ', parry-specialty=' + newParrySpe ); verifyAndSetIfDifferent ( values , finalObj , 'parry' , newParry ); verifyAndSetIfDifferent ( values , finalObj , 'parry-specialty' , newParrySpe ); verifyAndSetIfDifferent ( values , finalObj , 'max-ma' , ma ); if ( debug === 3 ) TAS . debug ( 'ParryUpdater:updateObj:: Updating Weapon Parry value' ); for ( const id of this . #weaponIds ) { let def = getFromUpdatedOrRetrieve ( `repeating_weapon_ ${ id } _repweapondef` ) || 0 , abi = getFromUpdatedOrRetrieve ( `repeating_weapon_ ${ id } _repweaponabi` ) || 'brawl' ; const weapParry = abi === 'noParry' ? - 420 : Math . ceil (( dex + ( Object . keys ( correspondingTable ). includes ( abi ) ? correspondingTable [ abi ] : Number ( abi )) ) / 2 ) + Number ( def ) + addedDef ; const weapParrySpe = abi === 'noParry' ? - 420 : Math . ceil (( dex + ( Object . keys ( correspondingTable ). includes ( abi ) ? correspondingTable [ abi ] : Number ( abi )) + 1 ) / 2 ) + Number ( def ) + addedDef ; verifyAndSetIfDifferent ( values , finalObj , `repeating_weapon_ ${ id } _repweaponparry` , weapParry ); verifyAndSetIfDifferent ( values , finalObj , `repeating_weapon_ ${ id } _repweaponparryspe` , weapParrySpe ); } if ( debug >= 2 ) TAS . debug ( 'ParryUpdater:updateObj:: UPDATE WEAPONS PARRY' , finalObj ); return finalObj ; } async getUpdatedObj ( toBeUpdated = {}) { const values = await getAttrsAsync ( await this . getAttrToBeRetrieved ()); return this . updateObj ( values , toBeUpdated ); } static async getUpdatedParryObj ( toBeUpdated = {}) { return await new ParryUpdater (). getUpdatedObj ( toBeUpdated ); } } I also tried to remove the fieldset in the html, reflects in roll20 visually (no weapons anymore) but no change in script "lag"