The draw screen retires: the league cup rolls inside the run, ENTER THE DRAW moves onto the setup button

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-29 16:46:34 +02:00
1 parent 812bea3234
commit dbfd085493
5 files changed
+34 -130

No files matched your search

+12 -77
View File
@@ -352,6 +352,7 @@ function buildLeaguePanel() {
// on the card now — the setup should show the league and who of it you have already beaten).
function syncSetup() {
const cupMode = pickedMode === 'cup', climbMode = pickedMode === 'zombie';
document.getElementById('cStart').textContent = cupMode ? 'ENTER THE DRAW' : 'SERVE UP';
document.getElementById('who').style.display = cupMode || climbMode ? 'none' : 'flex';
document.getElementById('lgPanel').style.display = cupMode || climbMode ? 'block' : 'none';
document.getElementById('s01').textContent =
@@ -466,82 +467,17 @@ for (const c of COURTS) {
// to the league's own court rather than serving up a court the player has not earned
if (!courtUnlocked(picked)) picked = leagueOf(profile.prof.lg).court;
// ---- THE DRAW (Oliver, 2026-08-15: "when starting the tournament there should be a view of the
// tournament hierarchy but only the finale is settled — the game against the champion... random
// browsing through the roster in the individual spots which begins fast, gets slower and then
// settles on a random character, so that every tournament is new").
//
// THE SCREEN IS THE DRAW, NOT A TEASER. `cupPicks` is what walks on: startMatch takes it and
// cupDraw reads it instead of rolling its own, so the face you watched land in ROUND ONE is the
// body across the net. A screen that showed a different draw from the one being played would be
// worse than no screen — it would teach the player that the ceremony is a lie.
//
// The roll is one recursive setTimeout per row whose gap grows with p^2 — fast, then visibly
// slowing, then stopped. No rAF: the menu deliberately parks the game loop (see menuUp), and three
// staggered timers are the whole animation.
const cupRows = document.getElementById('cupRows'), cupGo = document.getElementById('cupGo');
let cupPicks = null, cupSpins = [];
// THE DRAW SCREEN IS GONE (2026-08-29, Oliver: "das ist doch jetzt eigentlich obsolet"). It was
// built for the 18-rung ladder, where four bands rolling out of a deep hat was a ceremony worth a
// screen; a league cup shuffles 2-3 faces the setup's league panel already shows face-up. The
// shuffle itself survives INSIDE the run (cupDraw rolls without replacement, the final settled)
// and each round still announces itself on the walk-on modal — only the screen is deleted. The
// cup's big button says ENTER THE DRAW (syncSetup), which is all the ritual the moment needs.
// The screen's mechanics live in git history (like the lob) if the ceremony is ever asked back.
// the portrait: every family's own head crop (assets/_heads.py), the club pro's included — the
// same file the in-play walk-on card uses, so the draw and the court show the same face
// same file the in-play walk-on card uses, so the picker and the court show the same face
const foeArt = f => `assets/z_${f.fam}head.png?v=${SPRV}`;
function buildBracket() {
for (const t of cupSpins) clearTimeout(t);
cupSpins = [];
const R = cupRoundsFor(profile.prof.lg);
// WITHOUT REPLACEMENT, like cupDraw: a league band is 3-4 rungs, so the non-final rounds are a
// shuffle of the sub-band — every tournament a new order, no body dealt twice, the final settled
cupPicks = [];
const used = new Set();
for (const r of R) {
const pool = r.band.filter(x => !used.has(x));
const pick = (pool.length ? pool : r.band)[Math.floor(Math.random() * (pool.length ? pool : r.band).length)];
used.add(pick); cupPicks.push(pick);
}
// the header counts the league's own rounds (a 3-rung league plays three)
document.querySelector('#bracket h3').firstChild.nodeValue =
R.length === 4 ? 'FOUR ROUNDS' : 'THREE ROUNDS';
cupRows.innerHTML = '';
cupGo.disabled = true;
document.getElementById('brState').textContent = 'DRAWING…';
const lg = leagueOf(profile.prof.lg);
document.getElementById('brSum').innerHTML =
`<span>ONLY THE FINAL WAS EVER SETTLED</span><span>${lg.name} · ${
(COURTS.find(c => c.id === lg.court) || COURTS[0]).name}</span>`;
R.forEach((r, i) => {
const fixed = r.band.length === 1; // the final: one rung, nothing to roll
const row = document.createElement('div');
row.className = 'cupRow' + (fixed ? ' fin set' : '');
row.innerHTML = `<u>${r.name}</u><img alt=""><b></b><i>${
r.need === 1 ? 'ONE GAME' : r.need + ' GAMES'}</i>`;
cupRows.appendChild(row);
const img = row.querySelector('img'), nm = row.querySelector('b');
const show = n => { const f = matchFoe(n); img.src = foeArt(f); nm.textContent = f.name; };
if (fixed) return show(cupPicks[i]);
const t0 = performance.now(), len = 1500 + i * 550; // 1.5 / 2.05 / 2.6 s — they land in order
(function roll() {
const p = Math.min(1, (performance.now() - t0) / len);
if (p >= 1) {
show(cupPicks[i]);
row.classList.add('set');
if (cupRows.querySelectorAll('.set').length === R.length) {
cupGo.disabled = false;
document.getElementById('brState').textContent = 'THE DRAW IS MADE';
}
return;
}
show(r.band[Math.floor(Math.random() * r.band.length)]);
cupSpins.push(setTimeout(roll, 45 + 330 * p * p));
})();
});
}
document.getElementById('brBack').addEventListener('click', () => {
for (const t of cupSpins) clearTimeout(t); // a screen you walked out of must stop spinning
cupSpins = [];
go('setup');
});
document.getElementById('cupGo').addEventListener('click', () => start('cup'));
// ---- THE TRAINING PICKER (Oliver, 2026-08-28: "ein Trainingsbereich — Auswahl des Gegners, ein
// Spiel, tap to replay, bis man keine Lust mehr hat"). The whole ladder face-up, one tile per rung,
// wearing the same z_*head crop the draw and the walk-on wear. Tap = start — the wizard's own
@@ -747,9 +683,9 @@ function start(modeId = pickedMode) {
G.diff = G.classic ? (DIFFS.find(d => d.id === pickedDiff) || DIFFS[1]) : null;
if (modeId === 'gore') startGore(); // no tennis prologue: the mode you picked is the mode you get
if (modeId === 'zombie') { intoSplatter(); startMatch(); }
// ...and the cup carries the draw the bracket screen just made. Null (the #cup back door) still
// means "roll it yourself", which is what the mode did before the screen existed.
if (modeId === 'cup') { intoSplatter(); startMatch(true, cupPicks); }
// the cup rolls its own draw per round (cupDraw, without replacement) — the bracket screen
// that used to settle it on-screen is gone (2026-08-29, see the foeArt note above).
if (modeId === 'cup') { intoSplatter(); startMatch(true); } // cupDraw shuffles per round
// training: the picked rung rides the match machinery with the ladder parked (beats.startMatch)
if (modeId === 'train') { intoSplatter(); startMatch(false, null, trainRung); }
}
@@ -840,7 +776,6 @@ nbName.addEventListener('keydown', e => { if (e.key === 'Enter') document.getEle
// SERVE UP starts the run — except in the cup, where the draw has to be made first. That screen
// carries its own start button, so this stays the one place a run begins from the setup screen.
document.getElementById('cStart').addEventListener('click', () => {
if (pickedMode === 'cup') { buildBracket(); go('bracket'); return; }
if (pickedMode === 'train') { go('train'); return; } // the picker starts it — tap advances
start();
});