More Projectiles Fan
What it is
A legacy run-wide stack that adds extra shots to every weapon’s volley. The stack is tracked under the more_projectiles upgrade counter and clamped 0–20. Each weapon has its own step ladder; the bonus is added on top of the level-based base shot count. How those extra shots are arranged in space is per-weapon, not a single shared fan shape — most weapons send the extras at different enemies rather than fanning angularly, only a few weapons spread the extras as an angular cone or a fixed angular gap.
The step ladder
The getExtraProjectiles(weaponId, H) function reads H = upgradeCounts['more_projectiles'], clamps it to 0–20, and returns a weapon-specific bonus. Weapons not listed below ignore the stack entirely (barrier, fire-trail, defy, railgun-derivative weapons, and every legendary).
| Weapon | H0 | H1 | H2 | H3 | H4 | H5 | H6 | H7 | H8 | H9 | H10 | H11 | H12 | H13 | H14 | H15 | H16 | H17 | H18 | H19 | H20 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| rifle | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 5 | 5 | 5 |
| coilgun | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 5 | 5 |
| shotgun | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 5 | 5 | 5 |
| railgun | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 |
| missile | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 5 | 5 | 5 |
| lightning (chain jumps) | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 5 | 5 | 5 |
| revolver (burst rounds) | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 5 | 5 | 5 |
| cannon (shells per volley) | 0 | 1 | 1 | 2 | 2 | 2 | 3 | 3 | 3 | 4 | 4 | 4 | 5 | 5 | 5 | 6 | 6 | 6 | 7 | 7 | 7 |
| mortar (shells per volley) | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | 4 | 4 | 4 | 5 | 5 | 5 |
| disc (orbiting blades) | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 |
| flame (embers per fire) | 0 | 3 | 4 | 5 | 6 | 8 | 8 | 9 | 10 | 10 | 12 | 12 | 13 | 14 | 14 | 16 | 16 | 17 | 18 | 19 | 20 |
| sweep (orbiting blades) | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 3 | 3 |
| line (tesla pairs) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 |
| magnetar (tesla pairs) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 |
| fire-ring (orbiting blades) | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 3 | 3 |
| burst (rounds per coordinator) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 |
The bonus is added on top of the weapon’s base shot count regardless of weapon level. For weapons whose primary count is level-driven (a stepped table like shellCount, chainCount, burstPattern, bladeCount, emberCount, seekerCount, projectileCount), the per-H bonus is added after the level lookup resolves.
How the extras are arranged
The arrangement of extras depends on the weapon’s spread mode. The shot loop in the projectile firing path picks exactly one of four arrangements for each shot index i (0-based) of the total shot count.
| Arrangement | When it applies | Geometry |
|---|---|---|
| Multi-target | spreadDeg = 0 and perpendicularLayout = false | Each shot is aimed at a different enemy via the multi-target acquisition routine. No angular fan at all; the extras peel off toward whichever enemies are in range. |
| Random spread | spreadDeg > 0 and randomSpread = true | Each shot’s angle is aim + (rand − 0.5) × spreadDeg independently — the cone is filled chaotically. |
| Even angular fan | spreadDeg > 0 and randomSpread = false | Shots are evenly spaced across the full cone. For i in [0, count − 1], angle is aim + ((i / (count − 1)) − 0.5) × spreadDeg. The total cone width is spreadDeg; the per-shot angular gap is spreadDeg / (count − 1). |
| Perpendicular layout | perpendicularLayout = true | All shots travel along the aim direction; spawn positions are offset sideways along the perpendicular axis (see Perpendicular Layout concept). No angular fan. |
For homing weapons with no spread, extras get a tiny ±6 px perpendicular spawn jitter so the staggered launch reads as a salvo even though every missile still aims at its own assigned target.
Stagger delay between extras: 0 when perpendicular layout is on, 0 when angular spread is on (spreadDeg > 0), and otherwise staggerDelaySec or 0.1 s if unset. The first shot fires on the same frame as the fire event; extras chain at integer multiples of the delay.
Per-weapon spread values
Most weapons have spreadDeg = 0 and never produce an angular fan. The actual cone widths defined on weapon specs:
| Weapon | spreadDeg (total cone width) | Mode | Notes |
|---|---|---|---|
| rifle | 0 | Multi-target | Each extra shot aimed at a different enemy. Homing locks per shot. |
| coilgun | 0 | Multi-target | Same as rifle; targets unique enemies. |
| missile | 0 | Multi-target | Homing extras lock onto separate targets. |
| revolver | 55 | Even angular fan | Wide cone; spread is fixed regardless of shot count. |
| shotgun | 18 | Even angular fan | Auto-scales: at count > base the spread widens to keep the per-shot gap constant (see Spread scaling below). |
| cannon | 0 | Perpendicular layout | Positional spread, not angular — see Perpendicular Layout concept. |
| flame | 0 (coneWidth = 65°) | Random spread in cone | The flame stream uses coneWidth, not spreadDeg. Each ember picks a uniform random angle inside the cone plus an extra ±10° per-ember jitter. The cone widens with shot count (see below). |
| mortar | 0 | Multi-target shells | Arc shells; extras target unique enemies. |
| disc, sweep, fire-ring | 0 | Orbit | Extras are added as additional orbiting blades, not as a fan. |
| lightning | 0 | Chain | The bonus adds chain jumps to the single chain bullet, not extra bullets. |
| burst | 0 | Sequential burst | The bonus adds rounds to a sequential coordinator burst, not a fan. |
| line, magnetar | 0 | Tesla line pairs | The bonus adds whole tesla-line pairs at a fixed angular offset (see special cases below). |
| lgd_plasma_arc | 28 | Random spread in cone | Legendary plasma machine gun; random fill. |
| All other legendaries | 0 | Per-behavior | Each legendary’s behavior handler decides arrangement; most ignore more_projectiles. |
Spread scaling with shot count
Two weapons flag scaleSpreadWithCount = true: shotgun and flame. When set, the effective spread is spreadDeg × actualCount / baseCount, holding the per-shot angular gap constant. Examples:
| Weapon | Base count | Base spread | Count at H1 | Effective spread at H1 |
|---|---|---|---|---|
| Shotgun (L1) | 5 | 18° | 6 | 21.6° |
| Shotgun (L20) | 13 | 18° | 14 | 19.4° |
| Flame (L1) | 15 embers | 65° cone | 18 embers | 78° cone |
All other weapons with non-zero spread (revolver 55°, lgd_plasma_arc 28°) keep the cone width fixed regardless of count, so adding shots makes the volley denser, not wider.
Special cases
Barrier
The barrier’s max active arc count is fixed by weapon level alone: 1 arc at L1, 2 at L7, 3 at L13+. The barrier fire path explicitly ignores the more_projectiles stack — its custom code does not call getExtraProjectiles. New arcs spawn at the angle that maximizes distance to existing arcs, each arc spans about 100° of a circle around the ship, and the fire-rate cooldown is the regeneration bottleneck rather than the active cap.
Fire-trail
Fire-trail drops a single stationary damage zone at the ship’s position each fire event. It has no entry in the step table and ignores the stack — adding more_projectiles ranks produces no extra zones.
Tesla lines (line, magnetar)
Tesla-line weapons interpret each bonus as an additional whole line pair fired at a fixed angular offset of 15° between consecutive pairs, centered on the aim direction. The total number of line pairs is 1 + extraLines; pair li fires at offset −15° × (total − 1) / 2 + li × 15°. This is the only weapon family that uses a baked 15° angular fan — every other angular-fan weapon reads its spread from spreadDeg.
Cannon (perpendicular line)
Cannon adds shells to a perpendicular line, not a cone. The center of the line sits at the ship; shells are spaced 18 px apart along the axis perpendicular to aim. All shells travel along the same heading and land in a parallel line at the target. Cannon also rolls a 25% double-shot chance per fire — when it procs, the entire perpendicular volley fires twice.
Deployables that cap active count
Mortar, fire-ring, and a few other weapons enforce a max-active cap via maxActive. For those, more_projectiles raises the cap by the same step amount rather than adding shots to a single fire event. The fire still produces shellCount (or equivalent) shells per volley; the cap controls how many independent shells/zones can exist in the world at once.
Sources of stacks
The more_projectiles upgrade no longer appears on level-up reward cards. The only in-game source is the Echo Generator artifact, which adds 1 or more stacks when triggered.
EXTRACT-CANDIDATEs
EXTRACT-CANDIDATE: concepts/spread.md— A dedicated spread/cone concept page should consolidate the angular fan formula (t × spreadRad, withtin [−0.5, +0.5]), therandomSpreadvariant, thescaleSpreadWithCountrule, and contrast with perpendicular layout and multi-target acquisition.EXTRACT-CANDIDATE: concepts/multi-target-acquisition.md— The_multiTargetAnglespath used by everyspreadDeg = 0weapon deserves its own concept page covering target search, per-shot target assignment, and the 6 px perpendicular spawn jitter for homing salvos.EXTRACT-CANDIDATE: concepts/tesla-line.md— Already exists; should add the 15° per-pair fan offset and the1 + extraLinesformula explicitly.EXTRACT-CANDIDATE: concepts/horizontal-modifiers.md— Already exists; its More Projectiles table is the source of truth and this page consumes it. Cross-link.EXTRACT-CANDIDATE: weapons/shotgun.mdandweapons/flame.md— Per-weapon pages should call outscaleSpreadWithCountand walk through an example shot-count → effective-spread calculation.EXTRACT-CANDIDATE: weapons/barrier.mdandweapons/fire-trail.md— Per-weapon pages should explicitly note these two weapons ignore the more_projectiles stack.EXTRACT-CANDIDATE: artifacts/echo-generator.md— The only current source of more_projectiles stacks; should link back here for the step ladder consequences.