Revert splatter rapid-fire serve; fix horde pose + re-trigger

Oliver's feedback on the feel pass:

1. Rapid-fire serving was way too easy. Reverted splatter serving to the
   proper model: a tap does the toss ritual (apex timing = quality), a
   flick is a quick aimed serve. Dropped the multi-ball barrage and
   removed the extraBalls plumbing (array, update, render, hooks). Melee
   swish and zombie homing stay. If multi-ball is wanted back, it should
   require a proper serve per ball.
2. The player was stuck in the serve/swing pose when a horde started
   (the triggering shot's pose lingered) — startHorde now clears it.
3. A horde re-triggered immediately: machine-gun kills scored points, so
   games were won mid-horde and the next kill after it ended won another
   game → instant new horde. A horde is now survival: it doesn't score
   (splatPoint skipped while G.horde), so it can't chain. After a horde
   you must win a full game again to summon the next.

Verified via window.T: a tap tosses (not an instant serve) and the full
toss→serve→rally completes; melee still kills adjacent shamblers; pose is
idle/-1 at horde start; no scoring during a horde and the next kill after
scores 15 without restarting it; tennis 11/12, bomb consume, homing all
still green; no console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 4.8 committed 2026-07-12 00:28:10 +02:00
1 parent 38035738ac
commit bfaafe6727
4 files changed
+25 -49

No files matched your search

+2 -4
View File
@@ -4,7 +4,7 @@ import { cv, ctx } from './dom.js';
import { TUNE, COURT, PLAYER_H, BOY_H, UMP_H, BOUNCE_IDLE, SPRITE_H } from './config.js';
import { P, O, ball, score, crowd, G } from './state.js';
import { predictLanding } from './gameplay.js';
import { zombies, gore, piles, parts, pellets, extraBalls } from './zombies.js';
import { zombies, gore, piles, parts, pellets } from './zombies.js';
// ---------------------------------------------------------------- palette ----
// tennis palette -> drained splatter palette; the transition lerps between them
@@ -304,8 +304,6 @@ export function render() {
const by = Math.abs(Math.sin(G.idleT * BOUNCE_IDLE.tempo)) * BOUNCE_IDLE.apex;
drawBall(bx, by, sv.z);
}
// earlier serves still in flight (multi-ball barrage)
for (const b of extraBalls) drawBall(b.x, b.y, b.z, false, b.bomb);
// the match ball
if ((ball.active || G.phase === 'over') && !ball.collected) drawBall(ball.x, ball.y, ball.z, true, ball.bomb);
// splatter particles
@@ -351,7 +349,7 @@ export function render() {
ctx.fillStyle = '#f8e048'; ctx.font = 'bold 8px monospace';
const touch = matchMedia('(pointer: coarse)').matches;
const txt = G.mode === 'splatter'
? (touch ? 'TAP TO FIRE · FLICK TO AIM · SWISH TO MELEE' : 'SPACE FIRES · ARROWS AIM')
? (touch ? 'TAP TO SERVE · FLICK TO AIM · SWISH TO MELEE' : 'SPACE SERVES · ARROWS AIM')
: G.serveNum === 2 ? (touch ? 'SECOND SERVE — TAP' : 'SECOND SERVE — SPACE')
: (touch ? 'TAP TO TOSS, TAP TO SERVE' : 'SPACE TO TOSS, SPACE TO SERVE');
ctx.fillText(txt, W / 2, H - 16);