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
#attackCtx
with 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 ofmodifiersArrayStore
for 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 aDodgeProcedure
for 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.