Add chapter bosses and a second damage channel; demote the racket zombie
Steps 4 and 5 of the late-game depth plan. The ranged channel. A rogue ball machine gets wheeled onto the far court every four games: it never walks, never crosses your baseline and never scores, so it is a standing threat you choose when to deal with — the target-priority decision the game was missing. Its shot is a real arc solved like a serve, not a flat bolt, so it reads coming in and the swing window has something to meet. Three outcomes: a swing inside the volley window returns it as your own ball flying up-court (an extras clone, so "a parry is a weapon" cost nothing to build), the panic swish bats it away, and letting it reach you costs blood. The swish path is load-bearing, not politeness: in pretoss the player is rooted and cannot swing at all. Contact still kills outright — that stays a separate channel, and killPlayer() is now the single death path for both causes so the run summary and the best-run write cannot drift. Health is drawn on the man: procedural spatter at fixed anchors, a live trickle, and a red wash from the screen edges. No bar. Healing is winning a duel, which finally gives the duel a reason to be wanted. Chapter bosses every ten games, with their own sheet — a colossal zombie groundskeeper hauling a ball hopper, coming apart through arm-off, ribs-out and headless-still-throwing. Chapter 1 is 10 hp and 2.7 m, chapter 4 is 34 hp and 3.67 m. It outranks the set and duel beats at a clear, because a boss walking into a standing wave is unreadable. And it fixes the economy: a chapter-4 boss costs 12 bombs or 100 rounds or 34 side balls against a per-type cap of 9, so no single weapon can take one and a banked mixed arsenal is mandatory. The racket zombie is demoted to an occasional opponent, as asked — appearing every won game is exactly why he read as the boss. Five silent bugs found on the way, all in HANDOFF: a blast deleted a 34 hp boss outright (isBoss() exists to stop that class recurring), the machine's hp did nothing because it fell through to the one-shot fallback, the boss both scored and fired its card, the machine gated the hand-clear, and a boss died with a shambler-sized gore burst. Tennis untouched: 30 tapped points still 50 hits / 0 whiffs. 45-game soak clean with all four chapters firing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ffac9b5512
commit
4a066e5cc6
14 files changed
+492
-131
No files matched your search
@@ -5,10 +5,10 @@
|
||||
|
||||
import { TUNE, COURT, UMP_H, UMP_X, EATEN_RESTART } from './config.js';
|
||||
import { P, O, ball, score, G, setupPoint } from './state.js';
|
||||
import { update, keyPressed, solveShot, inServeBox, inCourt, forceZombies, splatPoint, deliverTin, selectWeapon, showModal, dismissModal, startDuel, resolveInterlude, flickTarget } from './gameplay.js';
|
||||
import { update, keyPressed, solveShot, inServeBox, inCourt, forceZombies, splatPoint, deliverTin, selectWeapon, showModal, dismissModal, startDuel, resolveInterlude, flickTarget, startBossFight, endBossFight } from './gameplay.js';
|
||||
import { fitViewport, render, proj, RES } from './render.js';
|
||||
import { voice, ambient } from './audio.js';
|
||||
import { zombies, spawnZombie, piles, gore, parts, pellets, extras, explode } from './zombies.js';
|
||||
import { zombies, spawnZombie, spawnRacketZombie, spawnMachine, spawnChapterBoss, piles, gore, parts, pellets, extras, shots, explode, hurtPlayer, killPlayer } from './zombies.js';
|
||||
import { cv } from './dom.js';
|
||||
import './input.js';
|
||||
|
||||
@@ -58,6 +58,6 @@ cv.addEventListener('pointerdown', e => {
|
||||
requestAnimationFrame(frame);
|
||||
|
||||
// exposed for in-browser sanity checks and simulated playtests
|
||||
window.T = { TUNE, ball, P, O, score, G, zombies, spawnZombie, piles, gore, parts, pellets, extras, explode, splatPoint, solveShot, inServeBox, inCourt, proj, setupPoint, forceZombies, deliverTin, selectWeapon, showModal, dismissModal, startDuel, resolveInterlude, flickTarget,
|
||||
window.T = { TUNE, ball, P, O, score, G, zombies, spawnZombie, spawnRacketZombie, spawnMachine, spawnChapterBoss, piles, gore, parts, pellets, extras, shots, explode, hurtPlayer, killPlayer, splatPoint, solveShot, inServeBox, inCourt, proj, setupPoint, forceZombies, deliverTin, selectWeapon, showModal, dismissModal, startDuel, resolveInterlude, flickTarget, startBossFight, endBossFight,
|
||||
step: dt => update(dt), render, press: keyPressed,
|
||||
get phase() { return G.phase; }, set phase(v) { G.phase = v; } };
|
||||
Reference in new issue
Block a user