Three more chapters, and at game 100 the champion returns everything

The roster ran out at chapter 6 and then repeated itself; game 70 got the
groundskeeper again, bigger. bossArt() now walks nine designs, one per chapter,
and hands out THE CHAMPION on every tenth — the floor(ch/10) term takes his
chapters back out of the count so chapter 11 opens the second lap on the
groundskeeper rather than skipping him.

  70 THE STRINGER — leather apron, bandoliers of gut string, racket frames on
     his back. He takes your lane and puts two dead-straight ones on it.
  80 THE TOURNAMENT DIRECTOR — blazer, lanyard, radio. `adds` is new: he calls
     stewards onto the court while you fight him, which is the one thing a boss
     fight could not do before, since the stage is cleared for it.
  90 THE STRAWBERRY SELLER — tray of cream, apron soaked red, ladle. A tank
     that sprays four at once and then comes for you.
 100 THE CHAMPION — torn whites, a laurel of strapping tape, the trophy still
     in one fist. `rally`: anything under splatter quality comes straight back
     at your head, so he is the one body you have to out-HIT rather than
     out-shoot. `phases` lays three rows over his own as his health falls — he
     holds the baseline and rallies, then runs the line drilling volleys, then
     drops to a charge — and each turn is an event: cry, shake, the stand up.

Thirty-six frames through assets/_regen.py, the mascot's three-batch recipe
(2 stride, 3 wounds, 4 throws). The trap that cost the re-rolls: a throw batch
references its own wound frames, so a wounds batch that fails leaves the throw
sheet drawn against the SEED — two of the four came back half groundskeeper.
Wounds first, verify, then throws.

And the physio, who Oliver reported "does basically nothing but move towards
the net": he kept 4.2 of every 6.3 m he charged, so the fight was always over
before he arrived. `withdraw` is his own number now (0.2) and he charges half
again as fast — measured, he is on top of you in 11 s instead of never — and he
drills three balls a cycle on the way in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-09 16:08:57 +02:00
1 parent f4c6f408e7
commit 04ee0174ce
42 files changed
+353 -72

No files matched your search

+12 -5
View File
@@ -194,7 +194,7 @@ export function proj(x, y, z) {
// Asset cache-buster — bump with main.js?v=N (see the img.src note below). EXPORTED because the
// menu screens hang <img> tags on the same files, and two copies of this number is one copy too
// many: the one that does not get bumped is the one that serves a cached 404.
export const SPRV = 87;
export const SPRV = 88;
// The boot bar in main.js watches this. Nothing here CHANGES when things load — every sprite was
// already requested at import — it just makes the wait visible and holds the menu back until the
// last sheet has landed. See the onerror note below for the other half of "sometimes missing".
@@ -214,12 +214,17 @@ for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','
'z_boss1','z_boss2','z_bossw1','z_bossw2','z_bossw3', // the CHAPTER BOSS: 2-frame stride + three wound stages (arm off -> ribs out -> headless)
'z_bosst0','z_bosst1','z_bosst2','z_bosst3', // ...and each of those four states mid-THROW (windT)
'z_mach1','z_mach2','z_machw1','z_machw2', // the ball machine: idle, firing, dented, split open
'z_judge1','z_judge2','z_judgew','z_judget','z_judgewt', // boss design 2 (chapter 2, 8, ...)
'z_chair1','z_chair2','z_chairw','z_chairt','z_chairwt', // boss design 3 (chapter 3, 9, ...)
// designs 4-6, each with the full set the groundskeeper has: 2 stride, 3 wounds, 4 throws
'z_judge1','z_judge2','z_judgew','z_judget','z_judgewt', // boss design 2 (chapter 2, then the second lap)
'z_chair1','z_chair2','z_chairw','z_chairt','z_chairwt', // boss design 3 (chapter 3, then the second lap)
// designs 4-9 and the final boss, each with the full set the groundskeeper has: 2 stride, 3 wounds, 4 throws
'z_coach1','z_coach2','z_coachw1','z_coachw2','z_coachw3','z_coacht0','z_coacht1','z_coacht2','z_coacht3',
'z_physio1','z_physio2','z_physiow1','z_physiow2','z_physiow3','z_physiot0','z_physiot1','z_physiot2','z_physiot3',
'z_mascot1','z_mascot2','z_mascotw1','z_mascotw2','z_mascotw3','z_mascott0','z_mascott1','z_mascott2','z_mascott3',
// designs 7-9 and THE CHAMPION (the final boss, every tenth chapter — see bossArt)
'z_string1','z_string2','z_stringw1','z_stringw2','z_stringw3','z_stringt0','z_stringt1','z_stringt2','z_stringt3',
'z_dir1','z_dir2','z_dirw1','z_dirw2','z_dirw3','z_dirt0','z_dirt1','z_dirt2','z_dirt3',
'z_berry1','z_berry2','z_berryw1','z_berryw2','z_berryw3','z_berryt0','z_berryt1','z_berryt2','z_berryt3',
'z_champ1','z_champ2','z_champw1','z_champw2','z_champw3','z_champt0','z_champt1','z_champt2','z_champt3',
// the late roster: ball boy (3 hp, 2 skins), bouncer (6 hp, 3), roller man (9 hp, 4).
// Every skin has its …b stride twin, so a wounded body keeps walking (see ZWOUND).
'z_e1','z_e2','z_e3','z_e4','z_ew','z_ewb','z_ew2','z_ew2b',
@@ -624,7 +629,9 @@ function drawZombie(zb) {
// that paces or hops sideways would slide across the court with its feet frozen. (zb.z is the
// fallback so a boss spawned by an older path still animates.)
const walked = (zb.dist ?? zb.z) / TUNE.bruteStride;
const wanted = zb.windT > 0 ? A.throws[Math.min(idx, A.throws.length - 1)]
// retT is the CHAMPION'S RETURN — the same throw frame, held briefly, so a ball he sends back
// has a stroke behind it instead of arriving out of a body that never moved.
const wanted = zb.windT > 0 || zb.retT > 0 ? A.throws[Math.min(idx, A.throws.length - 1)]
: idx ? A.wounds[idx - 1]
: A.walk[stepFrame(walked, 2)];
// a design whose sheet has not been generated (or has not loaded) degrades to design 1 rather