The Boss That Farms Your Kills
The Necrolord used to be a boss with a timer: it died, waited, and stood back up. Mechanically that is a health bar with extra steps, and it never made you play differently. This week it was rebuilt around two damage-driven mechanics that punish exactly the thing a tower defense player does best, which is killing a lot of things quickly in one spot. That rework needed a zombie, so zombie became a general-purpose enemy modifier first.
Zombie is a modifier, not an enemy type
Zombie is applied with the same dot notation as the damage-type immunity variants: splitter.zombie is a splitter that happens to be a zombie. It is orthogonal to enemy type, so every enemy in the game has a zombie form for free.
A zombie renders in grayscale, is immune to every status effect, walks at 75% of its base speed, uses none of its base enemy's special mechanics, and has a 25% chance to rise again at 35% HP when it dies. Every special-mechanic site in the codebase gates on a single isZombie predicate, which means abilities I add next month are automatically suppressed on the zombie form without me remembering to do it. Grayscale is pure presentation: desaturated copies of the enemy textures are built once at init. Replicated in co-op snapshots, and exposed through dbg.spawn so I can conjure one instantly.
The Necrolord, rebuilt
Base HP went from 3500 to 10500, and the timed self-resurrection was replaced by two mechanics that both feed off your own damage:
- Lifesteal. It heals 35% of all damage dealt to nearby non-zombie enemies inside
lifestealRadius. Applied fromdealDamageagainst a per-frame cache of Necrolord entity ids, so it costs nothing when there is no Necrolord on the board. - Reanimation. Every three nearby enemies that die raises one back as a half-HP zombie of the type that died. The kill counter lives in
Enemy.auxTimer.
Zombies neither feed the drain nor get reanimated, which is what stops the loop from being infinite. The reanimation counter originally only advanced on direct tower kills, which meant a splash-heavy build never triggered it; it now advances on nearby deaths from any source, direct hits, splash and damage over time alike. The pickup reach is 50% wider than the heal radius, so it raises corpses from further out than it drains. All the arithmetic sits in pure helpers in lib/necrolord.ts, test-driven, and the old recentDeaths queue is gone.
What this does to play: dumping your whole defense into the pack around the boss is now the worst move available. It heals, then it raises what you killed.
Dying twice on purpose
The boss also cheats death twice, at 25% and then 10% of max HP, tracked in Enemy.bossRevivesUsed. Getting the feel right took three passes.
First version: it popped back up instantly, which looked like a bug. Now a mid-battle death starts a two second animation, four red-pulse cycles of 500ms each, during which the boss is fully invulnerable and untargetable by towers. The purple resurrection ring grows and the new resurrect sound plays when the animation ends and it actually rises, not before.
Second pass fixed the details that broke the illusion: it kept walking the path while "dead", and beam towers kept their lock on a target that was not there. It now freezes in place and drops the beam lock.
Third: every boss final death (the real one) now triggers a heavy camera shake at 0.9, so the moment lands.
Zombification happens in place
The first reanimation implementation spawned a new zombie entity at the death position. That reads as a substitution, not a transformation: the enemy blinks out and a gray one blinks in.
Now the dying enemy enters a one second in-place zombification transition. It freezes on the path and fades from full color to grayscale via a two-pass draw (the colored sprite, then a gray overlay at increasing alpha). During the window towers cannot directly target it, but AoE splash can still reach and kill it, which is the counterplay: you have a second to deny the raise. If it survives, it converts in place, at reduced speed and with any shield stripped.
That replaced a pile of state: the spawn-at-death call, a markReanimated/wasReanimated/clearReanimated set, and a wall-clock animation tracker, all gone in favor of a single zombifyTimer field that both the sim systems and the renderer read directly, serialized in the snapshot so co-op agrees. Enemies elected for reanimation also skip the normal death particle burst, since they are not dying, and the new zombie plays a 500ms white-flash-to-gray transition on arrival.
Golden Shield on a clock
The Golden Shield boss used to drop its shield in response to hits, which meant a high fire-rate build stripped it instantly and a slow build never got through. It now runs a timed cycle: shielded, then exposed for 1.5 seconds (down from 3 after playtesting), regardless of what you are shooting. Both states got dedicated sprite sheets, which shipped with the two PNGs assigned to the wrong filenames, so it rendered transparent while shielded and opaque while exposed. Exactly backwards, and obvious the moment someone played it.
Shieldbearers, Aegis, and a warning
Three smaller boss and elite fixes:
- Shieldbearer regen used to accumulate every frame regardless of combat, so its shield regrew while you were shooting it. Any hit taken, absorbed or on real HP, now resets the regen timer: it only regrows a layer after a few seconds free of incoming damage.
- The Aegis shield ring was a flat circle. It is now 1.5 world units across, starting at 4 design-pixels of thickness and losing one pixel every 2 seconds of its 8 second window, so the ring visibly thins as the shield expires. On each regain, a large 3.5 unit ring contracts to the target size over half a second as a signal.
- A boss incoming banner. When a boss (or the wyrm) enters the stage, "!! BOSS INCOMING !!" flashes in red-orange under the wave banner, 0.4s on and 0.4s off, three times. It is driven by a
bossAlertUntiltimestamp on the game state, synced through co-op snapshots like the wave announcement. Bosses are also drawn in a separate pass after regular enemies now, so they are never hidden under the crowd they arrived with.
The five original bosses are slowly all becoming this: a mechanic that punishes one specific habit, rather than a big health bar.
Next: two new towers and a cooldown on being on fire.