Let the player choose a court before the match

Three courts, picked on a second start-screen stage: CENTRE COURT (grass),
TERRE ROUGE (clay) and THE SLAB (hard). A court is a row in config.COURTS and
four PNGs — render() never learns their names.

Each row carries two palettes, because every court still rots: what "drained"
means on orange clay is not what it means on green lawn. Mow stripes became a
flag rather than a colour — recolouring the lawn and leaving the bands on still
read as grass. Bounce is two numbers copied into TUNE on selection, so the three
bounce sites in gameplay.js and the T panel stay untouched: grass skids low and
fast, clay sits up and drags, hard is the old baseline.

Per-court crowd sheets and ad strips. Each court's clap frame is generated from
its OWN seated sheet, not from x_crowd2 — pairing one court's crowd with
another's applause cross-fades between two different crowds.

The picker is a second panel in the existing #intro overlay, rows built from the
table. Last pick is remembered and comes up pre-highlighted; 1..N or Enter on a
keyboard.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-01 10:25:30 +02:00
1 parent 6378ff2a1b
commit fa30fb94c4
15 files changed
+166 -36

No files matched your search

+12 -1
View File
@@ -1,6 +1,6 @@
// All mutable game state in one place, plus the point-reset that re-arms it.
import { HOME, BOY_ENTER, TUNE, COURT } from './config.js';
import { HOME, BOY_ENTER, TUNE, COURT, COURTS } from './config.js';
import { gore } from './zombies.js'; // runtime-only cycle (zombies imports state): sendBoy reads gore
// to decide whether a mopping round is worth walking out for
@@ -11,6 +11,17 @@ export const ball = { x: 0, y: 1, z: 20, vx: 0, vy: 0, vz: 0, g: 9.2,
export const score = { pts: [0, 0], games: [0, 0], server: 'P' }; // pts index 0=P 1=O
export const crowd = { cheer: 0, dots: [] }; // dots are (re)built by render.buildCrowd
// The court you picked on the start screen. Everything visual reads `court` directly; the two
// bounce numbers are COPIED INTO TUNE instead, so the T panel still edits the live physics and
// gameplay's three bounce sites stay untouched.
export let court = COURTS[0];
export function selectCourt(id) {
court = COURTS.find(c => c.id === id) || COURTS[0];
TUNE.bounceY = court.bounceY; TUNE.bounceXZ = court.bounceXZ;
try { localStorage.setItem('court', court.id); } catch {} // private mode: a forgotten pick is fine
return court;
}
// everything that used to be loose top-level lets
export const G = {
mode: 'tennis', // tennis | transition | splatter