Training pays a quarter, and the level bar wears its endpoints

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-30 15:58:34 +02:00
1 parent 7d39032907
commit a38c804069
6 files changed
+37 -10

No files matched your search

+1 -1
View File
@@ -390,7 +390,7 @@ export function startMatch(cup = false, draw = null, train = 0) {
G.seen.train = true;
showModal({ title: 'THE TRAINING COURT', color: UI.hot,
body: ['ONE BODY, ONE GAME AT A TIME',
'FELL IT — OR BLEED OUT — AND IT COMES BACK', 'NOTHING IS BANKED HERE'] });
'FELL IT — OR BLEED OUT — AND IT COMES BACK', 'NO RUN IS BANKED — REPS PAY QUARTER XP'] });
} else if (cup && !G.seen.cup) {
G.seen.cup = true;
showModal({ title: 'THE TOURNAMENT', color: UI.hot,
+5 -1
View File
@@ -526,6 +526,8 @@ function buildCard() {
el.style.color = lg.color;
document.getElementById('cdLevel').textContent =
'LEVEL ' + pr.level + ' OF ' + profile.LEVEL_CAP;
document.getElementById('cdFrom').textContent = pr.level;
document.getElementById('cdTo').textContent = pr.need ? pr.level + 1 : 'MAX';
// both bars sweep from empty to their mark (the 0.7s eased transition in the CSS)
for (const [id, w] of [['cdFill', Math.round(pr.frac * 100)],
['cdCareerFill', Math.min(100, Math.round(profile.prof.xp / profile.xpFor(profile.LEVEL_CAP) * 100))]]) {
@@ -635,7 +637,7 @@ function summary() {
`<span>${name} · ${t.name.replace(' SINGLES', '')} · ${c.name}${cupMode
? ' · LEAGUE ' + lg.id : ''}</span>`
// training banks nothing, so there is no mark to beat and the footer must not invent one
+ `<span>${m.id === 'train' ? 'NOTHING AT STAKE — JUST REPS'
+ `<span>${m.id === 'train' ? 'NO RUN, NO DEATH — REPS PAY ¼ XP'
: best ? best + unit + ' TO BEAT' : 'FIRST RUN'}</span>`;
}
@@ -652,6 +654,8 @@ function refreshSplash() {
document.getElementById('plBadge').src = `assets/badge_l${lg.id}.png?v=${SPRV}`;
document.getElementById('plName').textContent = stats.savedName() || 'YOUR PLAYER';
document.getElementById('plLv').textContent = 'LEVEL ' + pr.level + ' · LEAGUE ' + lg.id;
document.getElementById('plFrom').textContent = pr.level;
document.getElementById('plTo').textContent = pr.need ? pr.level + 1 : 'MAX';
document.getElementById('plFill').style.width = Math.round(pr.frac * 100) + '%';
document.getElementById('plGoal').textContent = profile.prof.ch
? 'CHAMPION OF THE DEAD CLUB — DEFEND THE NAME'
+6 -2
View File
@@ -72,11 +72,15 @@ export function beginRunXp() { runXp = 0; runFrom = levelAt(prof.xp); }
export const runDelta = () => ({ xp: runXp, from: runFrom, to: levelAt(prof.xp) });
// ONE guard for every no-stakes mode, in the shared function — a call site cannot forget it.
const muted = () => G.drill || G.bench || G.testMode || (G.match && G.match.train);
// The training court left this list 2026-08-29 (Oliver: zero pay made it feel pointless in a
// meta game): it pays A QUARTER now — reps count, the real court stays strictly 4x better, and
// the no-permadeath grind can never be the optimal one.
const muted = () => G.drill || G.bench || G.testMode;
export function award(kind, n = 1) {
if (muted()) return 0;
const amt = (XP[kind] || 0) * n;
let amt = (XP[kind] || 0) * n;
if (G.match && G.match.train) amt = Math.round(amt / 4);
if (!amt) return 0;
const before = levelAt(prof.xp);
prof.xp += amt; runXp += amt;