engine/weapons

PURPOSE — Runtime firing system for the player ship: ticks cooldowns and warmup, resolves per-shot stats from weapon specs plus horizontal modifiers, dispatches to the appropriate fire path per weapon behavior/collision mode, spawns and updates in-flight projectiles, and applies on-hit / on-death behavior callbacks.

OWNS

  • Weapon instances on the player ship (cooldown timer, cooldown max, fire timer, warmup state, manual-trigger flag, per-slot fire/target mode, empower mult/shots, fire-flash latch).
  • Active player projectiles in the world (every bullet’s position, velocity, lifetime, hit set, behavior list, weapon-id back-reference, and all per-behavior bullet fields — homing target lock, boomerang return state, mine phase, burst coordinator state, orbit anchor, beam-decay timer, artillery telegraph, etc.).
  • Per-shot stat pipeline: scaling-curve level resolution, early-level damage and fire-rate nerfs, legendary baseline multiplier, fire-rate jitter, Star Power damage multiplier, empower decrement, fire-rate-driven cooldownMax derivation.
  • Weapon archetype registry (capability flags per weapon family).
  • Bullet behavior registry (named per-frame update / onHit / onDeath handlers attached to bullets via _behaviors).
  • Manual-fire flag (module-level latch read at bullet spawn so manual shots get a homing ramp-in).
  • Delayed-shot queue (staggered extra projectiles awaiting their fire moment).
  • Bullet recycle bin (allocation pool for spent bullet objects).

READS FROM

  • data/weapons for WeaponCoreSpec, WEAPON_MAP, scaling-curve / stepped-stat helpers, weapon damage multiplier, legendary baseline multiplier, extra-projectile resolution.
  • engine/core for ship state, world state, clock, canvas dimensions, camera, shared module-level game / ship references, set pool.
  • engine/core/spatial-grid (enemyGrid) for enemy broad-phase queries during targeting, homing, burst lock, mine trigger, AOE finish, and quad-burst hitscan scoring.
  • engine/player/states for the Star Power exclusive-state check.
  • Player upgrade counts on GameState for damage_<tag> / damage_all / more_projectiles horizontal modifiers.

PUSHES TO

  • engine/combat via damageEnemy (AOE finish, mine detonation, direct hitscan, ECHO casing-scatter) and applyChainExplosion.
  • engine/effects via spawnFlameZone and spawnDelayedAoE for flame-drop / plasma-fire / artillery zones.
  • engine/vfx for particles, post-FX rings, explosion FX, sonar rings, ship recoil and warmup anticipation, player glow.
  • engine/rendering camera (shake on fire / hit).
  • engine/audio weapon chimes per slot and damage tag.
  • engine/telemetry collector for weapon-hit records.

DOES NOT

  • Decide which weapon slot fires this frame or pick an aim angle for the orchestrator — the caller passes aimAngle and slotIndex. (The internal getAutoAimAngle helper is consumed only by the module’s own fire paths; the outer loop computes its own primary aim.)
  • Resolve hit detection or damage math on in-flight projectiles. Collisions and damage application live in engine/combat; this module only spawns the bullets and runs their per-frame behavior callbacks.
  • Apply damage filters, affixes, knockback, life steal, shield absorption, or boss caps — all of that lives downstream of damageEnemy.
  • Define weapon stats, scaling curves, archetypes by name, or legendary fusion pairs — those are data and live in data/weapons.
  • Own the in-game upgrade UI, weapon levelling, or rarity rolls — only consumes the resolved level and upgradeCounts.
  • Render projectiles, beams, telegraphs, or HUD indicators — only writes the state those renderers read.
  • Track player input or fire-mode toggles — only reads the _manualTrigger and fireMode fields set by the input layer.

Signals fired / Signals watched — none. The module talks to other systems by direct calls (combat, vfx, telemetry, audio, effects); it does not emit or subscribe to engine signals.

Entry points

  • WeaponManager.fire — per-frame fire attempt for one weapon slot; manages warmup, runs the stat pipeline, dispatches to the correct fire path.
  • WeaponManager.updateCooldowns — ticks every active weapon’s fire timer.
  • WeaponManager.spawnBullet — creates and registers an in-flight projectile from a resolved barrel descriptor.
  • WeaponManager.releaseBullet — returns a spent projectile to the recycle bin.
  • WeaponManager.getAutoAimAngle — internal targeting helper exposed for fire paths that re-aim per sub-shot.
  • WeaponManager.fireProjectiles / fireBeamTrace / fireChainArc / fireBurst / fireFireTrail / fireQuadHitscan / fireArcMortar / fireOrbit / fireFlameStream / fireConeBeamDot / fireLine / fireShieldArc / fireOrbitRing / fireBeamDecay / fireArtilleryRain / firePhoenixAura / fireCarpetBomber — the per-archetype/per-behavior fire paths dispatched from WeaponManager.fire.
  • WeaponManager.fireChoreography — fire-time VFX, recoil, shake, audio chime.
  • fireWeapon — module-level wrapper used by the engine harness.
  • addWeapon — attach a new weapon instance to a ship.
  • upgradeWeapon — bump a weapon’s level on the ship.
  • updateWeapons — per-frame top-level update of all weapons on a ship.
  • getWeaponStats — read-only lookup of a weapon’s current resolved stats.
  • getWeaponEffectiveRange — acquire-range query used by the auto-aim orchestrator; widens for area-mode weapons.
  • tickDelayedShots — drains the staggered extra-projectile queue once per frame.
  • setManualFireFlag — bridge-side latch toggled before a manual-mode fire so spawned bullets are tagged for homing ramp-in.
  • getEarlyLevelNerf / getPlayerFireRateNerf — exposed for callers that need to mirror the early-level taper.
  • getBulletBinSize — telemetry probe for recycle-bin occupancy.
  • WeaponArchetypes.register / .get / .can / .list / .getModEligibility — capability-flag registry for weapon families.
  • BulletBehaviors.register / .get / .updateBullet / .deathBullet / .hitBullet — registry and dispatcher for per-bullet behavior callbacks.
  • projectileArchetype / beamArchetype / shotgunArchetype / missileArchetype / burstArchetype / orbitWeaponArchetype / teslaArchetype / flakArchetype / lanceArchetype — compatibility lookups that return a registered archetype meta with a hardcoded fallback.

Pattern notes

  • Two parallel registries (WeaponArchetypes, BulletBehaviors) self-register at module load via top-level register() calls; consumers index them by string id rather than importing handlers directly.
  • Bullets carry their behavior list as a string array (_behaviors); the dispatcher walks it each frame / hit / death. New flight patterns are added by registering a behavior and tagging the spawn template — no changes to the bullet-update loop.
  • Fire dispatch is a flat if/else chain in WeaponManager.fire keyed first on def.behavior, then on def.collisionMode, defaulting to fireProjectiles. There is no behavior registry for fire paths — adding one requires editing the chain.
  • Manual-fire is communicated through a module-level latch (setManualFireFlag_nextFireIsManual) read at spawn time, rather than threaded through the fire signature.
  • Staggered extra projectiles use a module-level _delayedShots queue that the harness must drain via tickDelayedShots each frame.