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:
1 parent
812bea3234
commit
dbfd085493
5 files changed
+34
-130
No files matched your search
+6
-7
@@ -354,9 +354,9 @@ export function watchdog(dt) {
|
||||
// the match mode ends. Regicide is inherited for free: smashing the ball into the body still wounds
|
||||
// it, and killing it outright wins the game early (killZombie fires resolveInterlude('P'), which
|
||||
// lands in matchGameWon via the empty-court check).
|
||||
// `draw` is the bracket screen's settled rungs, one per cup round (main.buildBracket). It is
|
||||
// optional and null means "roll each round as it comes", which is what the mode did before the
|
||||
// screen existed and is still what the #cup back door gets.
|
||||
// `draw` is an optional pre-settled list of rungs, one per cup round — null (the normal case
|
||||
// since the bracket screen was deleted, 2026-08-29) means "roll each round as it comes". The
|
||||
// parameter stays: the suite uses it to pin the validation below.
|
||||
// `train` (2026-08-28) is a RUNG NUMBER and turns the run into the TRAINING COURT: that one
|
||||
// opponent, one game at a time, nothing banked. The ladder is parked — d.opp never advances, a
|
||||
// felled body walks straight back on, and bleeding out costs a modal instead of the run. All of
|
||||
@@ -395,7 +395,7 @@ export function startMatch(cup = false, draw = null, train = 0) {
|
||||
} else if (cup && !G.seen.cup) {
|
||||
G.seen.cup = true;
|
||||
showModal({ title: 'THE TOURNAMENT', color: UI.hot,
|
||||
body: ['FOUR ROUNDS UP THE DEAD HIERARCHY',
|
||||
body: ["UP YOUR LEAGUE'S DEAD HIERARCHY — THE FINAL IS SET",
|
||||
'ITS POINTS DRAW BLOOD — ' + TUNE.matchPlayerHp + ' AND YOU ARE EATEN'] });
|
||||
} else if (!cup && !train && !G.seen.match) {
|
||||
G.seen.match = true;
|
||||
@@ -414,9 +414,8 @@ export function startMatch(cup = false, draw = null, train = 0) {
|
||||
|
||||
// The round's rung, drawn from its band. d.opp carries it so matchFoe, the ladder speed dials and
|
||||
// the felled arithmetic all read the drawn rung with no cup-awareness of their own.
|
||||
// A DRAW MADE ON SCREEN IS THE DRAW THAT IS PLAYED. When the bracket screen settled the rungs they
|
||||
// arrive here as cup.draw and this simply reads them off — rolling again would mean the faces the
|
||||
// player watched land had nothing to do with what walks on, which is worse than showing nothing.
|
||||
// A PASSED DRAW IS THE DRAW THAT IS PLAYED (it once arrived from the bracket screen; the suite
|
||||
// still passes one) — this reads it off rather than rolling again.
|
||||
// Guarded on the band all the same: a saved or hand-passed draw that names a rung this round does
|
||||
// not contain falls back to an honest roll rather than dealing the champion in round one.
|
||||
function cupDraw() {
|
||||
|
||||
+12
-77
@@ -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();
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user