You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
§28.3: "Weapons with Anti-Armor (AA) ignore and destroy armor whenever they hit." Note the second half of the same paragraph: "Some armor may have Damage Reduction (DR) which always reduces incoming Damage by the amount stated (even if the armor is destroyed, or if the weapon has Anti-Armor)." So AA skips the AP threshold and breaks the armour — but DR still applies first.
Why this needs broadcasting rather than a lookup
applyArmor has exactly one call site: applyDamage, reached only from the Take Damage button. Attacks never apply armour — rollAttack posts the damage roll and stops, because the target is a different character's sheet, which the attacker cannot write to.
So the defender's sheet resolves armour, and it knows nothing about the weapon that hit it. AA cannot be read from the attacker's row. The attack card has to carry it, and Take Damage has to ask for it.
Work
Structure the data. Add antiArmor: boolean to the Weapon type in src/game/data/weapons.ts and set it on the two weapons that have it — SK 109 Seeker Smart Rifle and Vibechete. Today AA exists only inside the free-text damage string ("4d10 DMG (Anti-Armor)"), which nothing can read — the same shape as the Damage Reduction gap fixed in Armor data has no Damage Reduction field, so DR is never populated #149.
Put it on the row. Add an attack_anti_armor field to repeating_attacks, written by the charactermancer from the weapon data alongside the rest of the attack row (src/ts/charactermancer/7-final.ts), and editable for hand-entered weapons.
Broadcast it.postAttackResult in src/ts/rules/checks.ts already posts the damage card on a hit. Include the attack's AA state in that card so the table can see it — the defender reads the card and applies what it says.
Ask for it. Take Damage already prompts for the damage number and type (?{Damage?|0}, damageTypeQuery()). Add an Anti-Armor question in the same query set, so the defender answers what the attacker's card told them.
Apply it.applyArmor(hit, armorPoints, damageReduction, antiArmor): DR still applies first, the AP threshold is skipped, and the armour is destroyed. One branch in an already-tested pure function.
Open question — magnitude
The book writes AA as a bare flag; neither AA weapon carries a number. This ticket implements a flag. If a numeric AA rating is wanted for homebrew, the same broadcast channel carries it and the applyArmor branch becomes a threshold rather than a skip — but that is a house rule, not 1e.
Constraints
Never use Promises or await in this legacy sheet's code. Roll20 unbinds the active character once a handler returns, so a promise continuation's setAttrs fails silently. Use its callbacks; only startRoll may be awaited.
The Take Damage roll must reach startRoll correctly — it reads state through a getAttrs callback and starts the roll inside it. Do not restructure that.
applyArmor and applyDamage are pure and well covered. Extend the tests rather than reshaping them: AA with DR, AA against zero AP, AA against armour that would otherwise absorb.
§28.3: "Weapons with Anti-Armor (AA) ignore and destroy armor whenever they hit." Note the second half of the same paragraph: "Some armor may have Damage Reduction (DR) which always reduces incoming Damage by the amount stated (even if the armor is destroyed, or if the weapon has Anti-Armor)." So AA skips the AP threshold and breaks the armour — but DR still applies first.
Why this needs broadcasting rather than a lookup
applyArmorhas exactly one call site:applyDamage, reached only from the Take Damage button. Attacks never apply armour —rollAttackposts the damage roll and stops, because the target is a different character's sheet, which the attacker cannot write to.So the defender's sheet resolves armour, and it knows nothing about the weapon that hit it. AA cannot be read from the attacker's row. The attack card has to carry it, and Take Damage has to ask for it.
Work
Structure the data. Add
antiArmor: booleanto theWeapontype insrc/game/data/weapons.tsand set it on the two weapons that have it — SK 109 Seeker Smart Rifle and Vibechete. Today AA exists only inside the free-textdamagestring ("4d10 DMG (Anti-Armor)"), which nothing can read — the same shape as the Damage Reduction gap fixed in Armor data has no Damage Reduction field, so DR is never populated #149.Put it on the row. Add an
attack_anti_armorfield torepeating_attacks, written by the charactermancer from the weapon data alongside the rest of the attack row (src/ts/charactermancer/7-final.ts), and editable for hand-entered weapons.Broadcast it.
postAttackResultinsrc/ts/rules/checks.tsalready posts the damage card on a hit. Include the attack's AA state in that card so the table can see it — the defender reads the card and applies what it says.Ask for it. Take Damage already prompts for the damage number and type (
?{Damage?|0},damageTypeQuery()). Add an Anti-Armor question in the same query set, so the defender answers what the attacker's card told them.Apply it.
applyArmor(hit, armorPoints, damageReduction, antiArmor): DR still applies first, the AP threshold is skipped, and the armour is destroyed. One branch in an already-tested pure function.Open question — magnitude
The book writes AA as a bare flag; neither AA weapon carries a number. This ticket implements a flag. If a numeric AA rating is wanted for homebrew, the same broadcast channel carries it and the
applyArmorbranch becomes a threshold rather than a skip — but that is a house rule, not 1e.Constraints
awaitin this legacy sheet's code. Roll20 unbinds the active character once a handler returns, so a promise continuation'ssetAttrsfails silently. Use its callbacks; onlystartRollmay be awaited.startRollcorrectly — it reads state through agetAttrscallback and starts the roll inside it. Do not restructure that.applyArmorandapplyDamageare pure and well covered. Extend the tests rather than reshaping them: AA with DR, AA against zero AP, AA against armour that would otherwise absorb.repeating_attacks; say whether NPC attacks broadcast AA too.