Skip to content

Attacks should broadcast Anti-Armor so the defender can apply it #191

Description

@nmbradley

§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

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.
  • Since Merge PC and NPC onto one unprefixed attribute namespace #90 the NPC sheet shares repeating_attacks; say whether NPC attacks broadcast AA too.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    1e1e RulesetminorWorks, but wrong or awkward

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions