The whites take a wash, the friend brings their own colours, and the menu shows the man

Three things off the back of the picker.

THE LIVE PLAYER on the setup screen is the real sprite through the real tint, not
a mock-up of the pick — so the menu cannot promise a colour the court will not
keep. It redraws on every tap of a tour, a kit or a skin.

THE WOMEN'S TOUR IS NO LONGER SAT OUT. Her set is drawn head to toe in whites, so
there was no hue to rotate — the answer is not a dye but a WASH: the pick laid
over her whites at a low saturation with the lightness kept, which is how you dye
a white kit in life and gives rose, powder blue, mint, lilac. Her hair and skin
fall out of it on lightness alone, which is exactly what a dye could not manage.

THE FRIEND ACROSS THE NET now wears what they picked on their own phone. Their
look crosses on pairing, and since the opponent art is red rather than blue the
kit rides its own hue arc — safe there for the one reason it would not be on the
player's own sheets: the opponent sprites carry no drawn blood. An older build
simply never sends it and the opponent draws as before; the match still plays.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-15 15:23:34 +02:00
1 parent 1daa3e9d6a
commit b5838b2b24
6 files changed
+194 -64

No files matched your search

+17 -12
View File
@@ -8,7 +8,7 @@ import { P, O, ball, score, G, setupPoint, selectCourt, selectTour, selectKit, s
import { update, restartRun, keyPressed, solveShot, inServeBox, inCourt, forceZombies, startGore, splatPoint, deliverTin, selectWeapon, grantWeapon, showModal, dismissModal, flickTarget, dragServe, toggleTestMode } from './gameplay.js';
import { startDuel, resolveInterlude, startBossFight, endBossFight, startDrill, endDrill, startMatch, endMatch, startBench, endBench, FALL, benchFall, startNetVs } from './beats.js';
import { netConnect, netHooks } from './net.js';
import { fitViewport, render, proj, RES, SPRV, LOAD, SPR } from './render.js';
import { fitViewport, render, proj, RES, SPRV, LOAD, SPR, drawLook } from './render.js';
import { voice, ambient, menuMusic, menuDuck } from './audio.js';
import { zombies, spawnZombie, spawnRacketZombie, spawnMachine, spawnChapterBoss, piles, gore, parts, pellets, extras, shots, pops, explode, hurtPlayer, killPlayer , spawnBarrel } from './zombies.js';
import { cv } from './dom.js';
@@ -186,20 +186,24 @@ for (const t of TOURS) {
b.addEventListener('click', () => {
pickedTour = t.id;
for (const el of tourList.children) el.classList.toggle('on', el === b);
kitRowFor(t);
refreshLook();
summary();
});
tourList.appendChild(b);
}
// A TOUR PLAYED IN WHITES HAS NO KIT TO DYE (see TOURS.kit), and a row of swatches that silently
// does nothing is worse than no row — you tap all six and conclude the feature is broken. The row
// goes dead and the header says why, in the same slot that names the colour when it is live.
function kitRowFor(t) {
const off = t.kit === false;
document.getElementById('kitRow').classList.toggle('dead', off);
if (off) document.getElementById('kitName').textContent = 'PLAYED IN WHITES';
else document.getElementById('kitName').textContent =
(KITS.find(e => e.id === pickedKit) || KITS[0]).name;
// THE LIVE PLAYER, redrawn on every tap of a tour, a kit or a skin. It draws the REAL sprite through
// the REAL tint (drawLook), so there is no second recolour to keep in step with the first — the only
// way this can show a wrong colour is if the court would show it too.
// The sprite sheets load asynchronously and the menu deliberately parks the game loop, so the first
// draw can land before the art does: retry on a slow poll that stops itself the moment it succeeds.
const lookCv = document.getElementById('look');
let lookPoll = 0;
function refreshLook() {
const t = TOURS.find(x => x.id === pickedTour) || TOURS[0];
const ok = drawLook(lookCv, t, KITS.find(e => e.id === pickedKit) || KITS[0],
SKINS.find(e => e.id === pickedSkin) || SKINS[0]);
clearTimeout(lookPoll);
if (!ok) lookPoll = setTimeout(refreshLook, 200); // sprites still coming; ask again shortly
}
// --- KIT and SKIN swatches, built from the tables. Same rule as the tour tiles: tapping selects and
@@ -219,6 +223,7 @@ const swatches = (rowId, nameId, table, keyName, get, set) => {
try { localStorage.setItem(keyName, e.id); } catch {}
for (const el of row.children) el.classList.toggle('on', el === b);
label.textContent = e.name;
refreshLook();
});
row.appendChild(b);
}
@@ -228,7 +233,7 @@ let pickedKit = remembered('kit') || KITS[0].id;
let pickedSkin = remembered('skin') || SKINS[0].id;
swatches('kitRow', 'kitName', KITS, 'kit', () => pickedKit, id => pickedKit = id);
swatches('skinRow', 'skinName', SKINS, 'skin', () => pickedSkin, id => pickedSkin = id);
kitRowFor(TOURS.find(t => t.id === pickedTour) || TOURS[0]); // a remembered women's tour comes up dead too
refreshLook();
// --- court rows, built from the table.
// The two meters come out of the court's OWN bounce numbers rather than a pair of hand-written