The cup board: the league ranks, the level breaks the tie

Oliver wanted to rank the level a league was taken at. The challenge held: xp
comes only from playing, so a board that rewards a low level rewards not
playing — it would pay you to avoid the three rooms the season leans on. It
also inverts every other number in the game, freezes after five entries, and
makes the player who played more look worse.

So the league ranks and the level decides between everyone who got equally far,
where "lower is better" reads naturally. BOARDS.u carries subLow; server
rank_key is the other half, and the same key decides whether a submission beats
the row already standing. The level is written once at the promotion — before
the league moves, because it is the level that WON the cup — mirrored like the
rest of the profile, and inscribed under the shield it belongs to. Earned
shields smoulder while they are on screen: five CSS embers each, no loop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-31 15:51:38 +02:00
1 parent e96b4374d8
commit 80eb60d181
8 files changed
+226 -40

No files matched your search

+19 -4
View File
@@ -27,10 +27,10 @@ const KEY = 'splatterProfile';
// 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 cleanCups = (c, cap = 9) => {
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); }
for (let l = 1; l <= 5; l++) { const v = c[l] | 0; if (v > 0) out[l] = Math.min(cap, v); }
return out;
};
@@ -40,10 +40,11 @@ function load() {
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,
cups: cleanCups(p.cups), out: Math.max(0, Math.min(99, p.out | 0)) };
cups: cleanCups(p.cups), at: cleanCups(p.at, 50),
out: Math.max(0, Math.min(99, p.out | 0)) };
}
} catch {}
return { v: 1, xp: 0, lg: 1, ch: 0, setup: 0, cups: {}, out: 0 };
return { v: 1, xp: 0, lg: 1, ch: 0, setup: 0, cups: {}, at: {}, out: 0 };
}
export const prof = load();
@@ -131,6 +132,16 @@ export function bonus() {
// 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;
// THE INSCRIPTION (2026-08-31, the cup board): the level you were when you took a league's cup.
// It is what the cup board breaks its ties on and what a badge on the card says under it — the
// same cup taken with fewer buffs is the better win. Written once, at the promotion, and never
// overwritten: a league is taken once.
export const cupAt = lg => prof.at[lg] | 0;
export function recordCupWin(lg, level) {
if (!(lg >= 1 && lg <= 5) || !(level > 0) || prof.at[lg]) return;
prof.at[lg] = Math.min(LEVEL_CAP, level);
save();
}
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);
@@ -185,6 +196,10 @@ export async function pull() {
if (v > cupBest(l)) prof.cups[l] = Math.min(9, v);
}
prof.out = prof.out || Math.max(0, Math.min(99, p.out | 0));
for (let l = 1; l <= 5; l++) { // the inscription, never overwritten
const v = p.at && p.at[l] | 0;
if (v > 0 && !prof.at[l]) prof.at[l] = Math.min(LEVEL_CAP, v);
}
runFrom = levelAt(prof.xp); // the adopted xp is history, not this run's delta
save();
}