FirearmProcedure
FirearmProcedure is the concrete subclass of AbstractProcedure for firearm attacks.
It drives the entire ranged attack sequence: assembling dice pools, applying recoil/range modifiers, executing the roll, and exporting contest information for the defender.
Role in the system
- Attacker-side only. Represents the shooter’s action. The defender is usually a
DodgeProcedure. - Extended flow. In addition to the base roll lifecycle, firearm attacks manage recoil, ammo, range, and pre-computed attack contexts.
- Contest integration. Exports a responder prompt (
Dodge? Yes/No) and builds resistance-prep data if the attack succeeds. - Locking. Uses
lockPriority: "advanced"so only one firearm attack per actor runs at a time.
Responsibilities
- Precompute context.
- Call into
FirearmService.beginAttack()to snapshot plan/damage and ammo state. - Maintain
#attackCtxwith plan/damage/ammoId for later resolution.
- Call into
- Modifiers.
- Sync recoil modifiers (
syncRecoil) and reset recoil state (resetRecoil). - Apply range modifiers with
primeRangeForWeapon.
- Sync recoil modifiers (
- Execution.
- Standard roll lifecycle:
execute → onChallengeWillRoll → SR3ERoll.evaluate → onChallengeResolved. - On resolution, commits effects (ammo, recoil) and clears local contests.
- Standard roll lifecycle:
- Contest export.
exportForContest()builds defender prompt (kind:"dodge").- Includes attack plan, damage snapshot, TN base/modifiers, and prompt text.
- Resistance prep.
buildResistancePrep()returns a structure forResistanceProcedure, including base TN (attack power) and resistance modifiers.
Typical flow
- Setup. Attacker + weapon item bound.
- Precompute. Call
precompute()with situational data (rounds, ammo, tokens, range). - Compose. Recoil and range modifiers are upserted automatically.
- Execute. Attacker rolls, results published to chat/log.
- Contest. If targets are present,
exportForContest()builds a Dodge defense prompt. - Resolution. On success,
buildResistancePrep()creates the resistance step for the target.
State model (additions)
Besides the AbstractProcedure stores, FirearmProcedure introduces:
| Store/Field | Purpose |
|---|---|
weaponModeStore: Writable<string> | Tracks current fire mode (semiauto, burst, etc.). |
ammoAvailableStore: Writable<number> | Tracks remaining ammo in the weapon. |
#attackCtx (private) | Snapshot of plan/damage/ammo for resolution. |
#selectedPoolKey (private) | Override for which pool key contributes. |
Roll lifecycle
execute({ OnClose?, CommitEffects? })
├─ OnClose?.()
├─ baseRoll = SR3ERoll.create(buildFormula(true), { actor })
├─ onChallengeWillRoll({ baseRoll, actor })
├─ roll = await baseRoll.evaluate(this)
├─ await baseRoll.waitForResolution()
├─ CommitEffects?.()
├─ expire local contests (if any)
├─ Hooks.callAll("actorSystemRecalculated", actor)
├─ onChallengeResolved({ roll, actor }) → FirearmService.onAttackResolved
└─ return roll
API reference
Modifiers & recoil
resetRecoil()– Reset all recoil for the actor viaFirearmService.syncRecoil({ declaredRounds, ammoAvailable? })– Compute recoil modifier and updatetnModifiers.primeRangeForWeapon(attackerToken, targetToken, rangeShiftLeft?)– Compute and apply range modifiers.tnModifiers– Alias ofmodifiersArrayStorefor recoil/range.
Precompute & context
precompute({ declaredRounds?, ammoAvailable?, attackerToken?, targetToken?, rangeShiftLeft? })– Build plan/damage context for the shot and seed ammo/mode stores.weaponModeStore– Writable fire mode state.ammoAvailableStore– Writable ammo state.
Roll orchestration
async execute({ OnClose?, CommitEffects? })– Standard lifecycle; commits ammo/recoil effects and expires contests.async onChallengeResolved({ roll, actor })– If no#attackCtx, recomputes; then callsFirearmService.onAttackResolved.
Contest & resistance
getPrimaryActionLabel()– Returns “Fire [Weapon]” or generic fire label.getKindOfRollLabel()– Returns localized “Challenge” or “Roll”.exportForContest()– Exports contest payload (attacker, weapon, TNs, plan/damage, prompt for Dodge).getResponderPromptHTML(exportCtx)– Builds the Dodge prompt (Yes/No).buildDefenseProcedure(exportCtx, { defender, contestId })– Instantiates aDodgeProcedurefor the target.buildResistancePrep(exportCtx, { initiator, target })– Returns TN base (attack power) + resistance mods for damage soak.renderContestOutcome(exportCtx, ctx)– Custom contested outcome: attacker vs. defender with TN breakdown and pools.
Scope of this documentation
This page describes the attacker-side firearm flow.
Defender-side (DodgeProcedure) and damage resolution (ResistanceProcedure) are documented separately.