THE SEASON, phases 1-4: the front door is the fixture, and the club remembers
The tournament is the canonical path, so the game finally says so. The splash's primary button names the next cup fixture and enters the draw; the poster wall moved one tap down and deals three named rooms (the season, the training, out of competition) with the cup at the top. Two profile fields remember every attempt — rounds ever reached per league, and the body that put you out — so a lost cup is a line on the board instead of a null event, and the training court offers that body first, marked. The promotion names what waits in the new league. Overlays consolidated in the same pass: three modal drawers became one box with a masthead, hairline-separated rows and a real footer button (any tap still dismisses), and the run-end summary wears the same box — headline, xp, mark, and the fixture with ENTER THE DRAW beside PLAY AGAIN. The cup's own exit is a ceremony now: OUT IN THE QUARTER-FINAL, your best standing beside it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
063b01d2a5
commit
5c7521f867
10 files changed
+603
-204
No files matched your search
+38
-2
@@ -21,15 +21,29 @@ import { myId, savedName, saveName } from './stats.js';
|
||||
|
||||
const KEY = 'splatterProfile';
|
||||
|
||||
// THE CLUB REMEMBERS THE ATTEMPTS (2026-08-31, THE SEASON). Two small fields carry the whole
|
||||
// record: `cups` is league -> how many rounds you have ever reached in its cup (1 = round one,
|
||||
// rounds.length = you took the final), and `out` is the rung of the body that put you out last.
|
||||
// That is what turns a lost cup from a null event into a line on the board — and what lets the
|
||||
// training court offer the one that beat you. Bounded on load like everything else that comes
|
||||
// back off a device.
|
||||
const cleanCups = c => {
|
||||
const out = {};
|
||||
if (c && typeof c === 'object')
|
||||
for (let l = 1; l <= 5; l++) { const v = c[l] | 0; if (v > 0) out[l] = Math.min(9, v); }
|
||||
return out;
|
||||
};
|
||||
|
||||
function load() {
|
||||
try {
|
||||
const p = JSON.parse(localStorage.getItem(KEY) || 'null');
|
||||
if (p && typeof p === 'object') {
|
||||
return { v: 1, xp: Math.max(0, p.xp | 0), lg: Math.min(5, Math.max(1, p.lg | 0 || 1)),
|
||||
ch: p.ch ? 1 : 0, setup: p.setup ? 1 : 0 };
|
||||
ch: p.ch ? 1 : 0, setup: p.setup ? 1 : 0,
|
||||
cups: cleanCups(p.cups), out: Math.max(0, Math.min(99, p.out | 0)) };
|
||||
}
|
||||
} catch {}
|
||||
return { v: 1, xp: 0, lg: 1, ch: 0, setup: 0 };
|
||||
return { v: 1, xp: 0, lg: 1, ch: 0, setup: 0, cups: {}, out: 0 };
|
||||
}
|
||||
|
||||
export const prof = load();
|
||||
@@ -111,6 +125,19 @@ export function bonus() {
|
||||
// quality is centre-normalised, so the same ms error scores higher
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- the cup record ----
|
||||
// How far you have ever got in a league's cup, and who ended the last attempt. Written by the two
|
||||
// places a cup run can end (zombies.killPlayer, beats.cupWon) and read by the summary, the league
|
||||
// panel and the training court. A record only ever moves FORWARD — an early exit after a deep run
|
||||
// does not erase the deep run, it just is not news.
|
||||
export const cupBest = (lg = prof.lg) => prof.cups[lg] | 0;
|
||||
export function recordCup(lg, reached, rung = 0) {
|
||||
if (!(lg >= 1 && lg <= 5) || reached < 1) return;
|
||||
if (reached > cupBest(lg)) prof.cups[lg] = Math.min(9, reached);
|
||||
if (rung) prof.out = rung; // the LAST one to put you out, deep run or not
|
||||
save();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- the promotion ----
|
||||
// A cup win that moved the league parks its ceremony here (beats.cupWon writes, main.maybeRestart
|
||||
// consumes once the summary is tapped away). Module-local and consumed-on-read, the same shape as
|
||||
@@ -118,6 +145,9 @@ export function bonus() {
|
||||
let promo = null;
|
||||
export const setPromo = p => { promo = p; };
|
||||
export function takePromo() { const p = promo; promo = null; return p; }
|
||||
// ...and a PEEK, for the summary: a won cup parks a ceremony, and the handover has to point at
|
||||
// that instead of at the next draw. Never consumes — main.maybeRestart is the only consumer.
|
||||
export const hasPromo = () => !!promo;
|
||||
|
||||
// ---------------------------------------------------------------- the mirror ----
|
||||
// POST is fire-and-forget with keepalive so the pagehide path can use the same call. The server
|
||||
@@ -149,6 +179,12 @@ export async function pull() {
|
||||
prof.lg = Math.min(5, Math.max(prof.lg, p.lg | 0 || 1));
|
||||
prof.ch = prof.ch || (p.ch ? 1 : 0);
|
||||
prof.setup = prof.setup || (p.setup ? 1 : 0);
|
||||
// the cup record comes back with the xp it was earned beside — merged forward, never down
|
||||
for (let l = 1; l <= 5; l++) {
|
||||
const v = p.cups && p.cups[l] | 0;
|
||||
if (v > cupBest(l)) prof.cups[l] = Math.min(9, v);
|
||||
}
|
||||
prof.out = prof.out || Math.max(0, Math.min(99, p.out | 0));
|
||||
runFrom = levelAt(prof.xp); // the adopted xp is history, not this run's delta
|
||||
save();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user