Polish round: modal system, softened palette, pixel font, and the 14 plan items
The three foundations first, since everything else leans on them:
- G.modal is the only thing that stops the world. update() early-returns on it
so no zombie steps, no ball flight, no spawn timers run while a popup is on
screen — you can read it without being eaten. Dismissal swallows the gesture;
the pointerdown dismisser is registered only on pointer:fine, because on touch
pointerdown beats touchstart and a shared handler cleared the modal and then
served with the same thumb.
- UI in config.js is the accent palette. The arcade primaries were shouting over
the artwork; the gore reds deliberately stay loud.
- Every canvas font string now goes through F(). Bare `monospace` resolved to
Courier — a slab serif — which was the "generic serif" bug, not taste.
Then: weapons are only ever WON. deliverTin() has exactly one caller now
(resolveInterlude('P')); the old game schedule calls the DUEL instead, fired off
proceedAfterClear() where the court is guaranteed empty. Four popups (splatter
tutorial with a generated illustration, first duel, weapon received, horde),
wCap 9 with the tin amounts tunable, a 5-hp brute that comes apart over four
wound skins, fire that ignites the neighbours and chains outward, a three-stage
death where you become the biggest gore mound on the court, and a 7s changeover
with a ball boy who finally has a mop.
New art: assets/logo.png, x_howto, z_gw2-4, x_boymop1-4, plus assets/_key.py for
standalone art (chroma-key + crop, no frame splitting, no forced sprite height).
Benchmarks re-run and holding: CPU returns 23/24 serves, 30 human-tapped points
= 50 hits / 0 whiffs, 26 simulated games with no exceptions.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5faaa99467
commit
a09a5d7559
23 files changed
+392
-103
No files matched your search
@@ -30,7 +30,8 @@ export const TUNE = {
|
||||
zSpawnStep: 0.22, // spawn-gap reduction per finished game
|
||||
zMax: 3, // shamblers on court in game 1 (cap grows +1 per game to zMaxCap; 0 = spawns off, for tests)
|
||||
zMaxCap: 14, // absolute shambler cap
|
||||
changeoverT: 4.5, // s the changeover breather lasts (after odd games, as the rules demand)
|
||||
changeoverT: 7.0, // s the changeover breather lasts (after odd games, as the rules demand)
|
||||
boyMopSpeed: 4.0, // m/s a MOPPING ball boy crosses at (a fetching one still sprints at 7.5)
|
||||
gameBeatT: 1.6, // s the game-end beat lasts on even (non-changeover) games
|
||||
eatenR: 0.9, // m a shambler must close to eat you — matches the visual sprite overlap
|
||||
zSnap: 0.9, // m of lateral slack at zero range — the aim cone's base width (fat-thumb forgiveness)
|
||||
@@ -62,10 +63,15 @@ export const TUNE = {
|
||||
backstopPop: 1.8, // m/s of lift off the fence, so the rebound travels back instead of dying at the net posts
|
||||
meleeCool: 1.0, // s between racket swishes — melee is the panic button, not the default
|
||||
zPierce: 0.75, // pace a ball keeps after a splatter — hot balls plow through lined-up pairs
|
||||
ballChangeFirst: 3, // game of the first new-balls delivery (real rule: 7, then every 9 — too sparse here)
|
||||
ballChangeEvery: 4, // games between deliveries after the first
|
||||
// The schedule calls the DUEL, not the tin: weapons are only ever won, but a duel comes round
|
||||
// on its own so there is always a chance at one. Fires off the next hand-cleared wave.
|
||||
duelFirst: 2, // game after which the first scheduled sudden-death duel is called
|
||||
duelEvery: 3, // games between scheduled duels after the first
|
||||
bombMax: 3, // bomb balls in a fresh tin
|
||||
wCap: 3, // per-type cap on the courtside rack — tins accumulate, but only so many
|
||||
tinTriples: 3, // triple-serves in a fresh tin
|
||||
tinFlames: 3, // flame balls in a fresh tin
|
||||
tinGuns: 1, // machine-gun charges in a fresh tin
|
||||
wCap: 9, // per-type cap on the courtside rack — tins accumulate, but only so many
|
||||
rackH: 22, // px height of the bottom weapon rack (feel knob: how much court it covers)
|
||||
bombRadius: 2.5, // m blast radius of a bomb ball
|
||||
hordeLen: 12, // s a horde wave lasts
|
||||
@@ -76,8 +82,14 @@ export const TUNE = {
|
||||
runnerSpeed: 3.2, // runner ('f') speed multiplier over the shamble
|
||||
runnerVMax: 4.2, // hard runner speed cap — the late-game ramp must stay humanly reactable
|
||||
shamblerHp: 2, // splat-quality hits a classic shambler ('a'/'b') soaks before it dies — only the runner ('f') is still one-shot glass
|
||||
// fire: the flame ball no longer just kills what it touches, it starts an epidemic.
|
||||
burnTime: 3.0, // s a body burns before the fire goes out
|
||||
burnDps: 2.0, // hp lost per second while burning — burnTime*burnDps must exceed bruteHp or tanks walk out of the fire
|
||||
burnSpread: 1.3, // m — a burning body ignites anything this close, every frame it burns
|
||||
burnIgniteR: 2.6, // m — the flame ball's ignition radius around the body it kills
|
||||
burnPanic: 1.0, // walk-speed multiplier while burning (1 = off; crank it for panicked sprinting)
|
||||
setCardT: 2.0, // s the centered SET card holds (the 'kurze unterbrechung' before the horde)
|
||||
bruteHp: 2, // splat-quality hits (or pellets) a brute ('g') soaks before it dies
|
||||
bruteHp: 5, // splat-quality hits (or pellets) a brute ('g') soaks before it dies — one wound skin per stage
|
||||
shieldDown: 1.5, // s a shield zombie's ('s') chair stays dropped after a block — the kill window
|
||||
meleeRange: 1.7, // m — a racket swish cleaves shamblers this close to you
|
||||
racketHp: 3, // splat-quality hits a racket zombie (mini-boss) takes before it dies
|
||||
@@ -88,6 +100,17 @@ export const TUNE = {
|
||||
killPips: 1, // splatter: show the kills-to-next-point pips on the scoreboard
|
||||
};
|
||||
|
||||
// the death animation's timeline, in seconds of G.eatenT. A: thrash · B: you burst into gore
|
||||
// · C: the summary fades in. The restart tap is gated past the whole thing so a panic tap
|
||||
// during the burst can't skip it.
|
||||
export const EATEN_BURST = 0.5, EATEN_SUMMARY = 1.6, EATEN_RESTART = 2.2;
|
||||
|
||||
// UI accent colours, one place so the whole HUD can be re-tuned at once. Deliberately
|
||||
// desaturated from the original arcade primaries: they were shouting over the artwork.
|
||||
// (NOT the gore — blood and piles keep their loud reds; only text and interactive UI.)
|
||||
export const UI = { hot: '#d9705f', warm: '#e0cc72', pick: '#cbd06a', cream: '#e8e8dc',
|
||||
dim: '#8fa0b8', bad: '#a34a42', ball: '#dbe063' };
|
||||
|
||||
export const COURT = { L: 23.77, W: 8.23, dblW: 10.97, netZ: 11.885, netH: 0.914, netW: 10.06 };
|
||||
COURT.svcFar = COURT.netZ - 6.4; // far service line
|
||||
COURT.svcNear = COURT.netZ + 6.4; // near service line
|
||||
|
||||
Reference in new issue
Block a user