Combo Kills & Kill Streaks
A single chain counter rewards uninterrupted offence. Every enemy kill increments game.killStreak, and the counter survives any shield-only hit. Two things break the chain: any hull damage (shield-bleed-through is never possible, so the chain only dies when HP actually drops) and a 2-second silence between kills.
Streak counter
- Increment site:
damageEnemyinengine/combat/damage.ts, inside the non-anchor / non-shared-health kill branch. - On every counted kill:
game.killStreak += 1,game.killStreakTimer = 2.0,game.bestStreakis updated if the new value beats it. - Decay:
bridge.tstickskillStreakTimereach frame; when it hits zero the streak and milestone index reset. - Break on hull:
damagePlayersetsgame.killStreak = 0andgame.lastStreakMilestone = -1wheneverhullDmg > 0. Pure shield absorption never touches those fields. - Anchors, shared-health boss bodies, and the boss kill itself route through separate signals and do not advance the streak counter.
Milestones
Defined in data/kill-streaks.ts as STREAK_MILESTONES. Each milestone fires once per streak — game.lastStreakMilestone stores the highest index already awarded so re-crossing thresholds inside the same chain is a no-op.
| Kills | Label | Bonus XP | Color |
|---|---|---|---|
| 10 | STREAK ×10 | 10 | #88ff88 |
| 25 | RAMPAGE ×25 | 30 | #ffff44 |
| 50 | MASSACRE ×50 | 80 | #ff8844 |
| 100 | UNSTOPPABLE ×100 | 200 | #ff44ff |
| 200 | GODLIKE ×200 | 500 | #44ffff |
Cumulative bonus XP for a full 200-kill chain: 820 XP (10 + 30 + 80 + 200 + 500). The loop in _checkStreakMilestone walks the table in order and breaks after the highest newly-reached milestone, so multi-step jumps (e.g. crossing 10 and 25 on consecutive frames) still award each tier on its own frame.
On-milestone effects
When a threshold fires, _checkStreakMilestone runs:
XpAccum.collect(m.bonusXp)— bonus XP routes through the standard XP accumulator and stacks with normal orb drops.Notifications.add(m.label, m.color)— banner text in the milestone color.Particles.burst(...)— celebratory spark burst at the enemy’s death position; particle count scales with milestone index (20 + i * 8), speed80 + i * 30, color parsed from the milestone hex.Juice.fire('elite_kill')— reuses the elite kill juice recipe.Sig.fire('kill_streak_milestone', 0, 0, m.killCount, 0, '')— broadcast for any effect-system listener.
HUD readout
engine/rendering/hud.ts draws a minimal label below the FPS counter once game.killStreak >= 5:
- Before the first milestone (5–9 kills): generic
N× STREAKtext inMedicalPalette.statusGood. - After a milestone fires: switches to
STREAK_MILESTONES[lastStreakMilestone].labeland.color, so the HUD tier-color matches the most recent threshold awarded.
No glow, no shake, no other on-screen flourish from the counter itself — the milestone banner + particle burst carry the celebration, the HUD label is just the running tally.
Related signals
kill_streak_milestone— fired on every milestone crossing (kill count in dxa slot).enemy_kill/tagged_kill— fired once per non-anchor, non-shared-body kill in the same branch that increments the streak.hull_damage— fired bydamagePlayerimmediately before the streak is wiped, so any consumer that wants to react to “chain broken” can listen for hull damage instead of polling the counter.