The leagues, phase 3: the character card, the honours collection, the skill trail
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
16bf5b9fed
commit
76d88030e5
11 files changed
+152
-17
No files matched your search
+28
@@ -491,6 +491,34 @@ zombie (now an occasional opponent, `TUNE.racketEvery`, not the every-game fixtu
|
||||
`RETURNED`, `DOUBLE KILL`) is a footnote to something you already watched happen. Sharing the loud
|
||||
FACE with the milestone cards is right; sharing their SIZE made every footnote read as a milestone.
|
||||
|
||||
## Session log: THE LEAGUES, PHASE 3 — the character card, badges, the skill trail (2026-08-29, STAGING ONLY)
|
||||
|
||||
Phase 3. STAGING ONLY, like 1 and 2.
|
||||
|
||||
- **THE CHARACTER CARD** (`#card`, main.buildCard): the splash's LEVEL STRIP is the door (tap it —
|
||||
it wears `cursor: pointer` and nothing else changed on the splash). Name as the screen title,
|
||||
the live sprite (drawLook, third canvas on refreshLook), the current league's crest + name in
|
||||
the league colour, LEVEL in Bangers over the gradient bar with "N XP · M TO LEVEL X", an
|
||||
HONOURS row, and THE LEDGER (two .figs rows off stats.read per mode: kills / multi-kills /
|
||||
deaths, best run / most felled / runs). EDIT PLAYER borrows the identity screen and returns to
|
||||
the card (`playerReturn`). Deviation from the plan: no death-screen entry — the death screen
|
||||
already carries the XP moment inline, and its tap is the restart.
|
||||
- **The honours row is a COLLECTION**: all five league shields plus the champion's laurel always
|
||||
visible, earned bright, unearned dark (`filter: grayscale brightness`) — the empty slots are
|
||||
the incentive. A shield is earned by FINISHING its league (being past it); league five's lights
|
||||
with the champion crown, since there is no league six to be past it.
|
||||
- **Badges rolled via OpenRouter** (one sheet on #FF00FF, cut by connected components + chroma
|
||||
key, 4x NEAREST downscale): `badge_l1..l5.png` (terracotta / slate / grass / navy-ice /
|
||||
marble-gold shields, each with the crossed-rackets motif and a chip of decay) + `badge_champ.png`
|
||||
(gold laurel + cup). DOM `<img>` only — not in SPR, nothing draws them on canvas yet.
|
||||
- **THE SKILL TRAIL**: `LEAGUES` rows carry `color` (each riding its court's palette), and the
|
||||
player's OWN sprint dust wears it — `dustPuff` grew an optional colour, the mover's emit passes
|
||||
`skillDust()`. League 1 keeps the shipped court dust: the tint itself is a progression reward.
|
||||
Read off the profile (not `G.league`), so the gore mode shows your colour too. The aura stays
|
||||
made of MOTION, never paint — the full-body glow idea was dropped against the painted-layer veto.
|
||||
- Pane-verified: card at league 5 (four bright shields, dark L5 + laurel, ledger numbers, edit
|
||||
round trip). Suite unchanged at 121 — the card is DOM, the dust is a colour.
|
||||
|
||||
## Session log: THE LEAGUES, PHASE 2 — bands, pace tiers, courts, the promotion (2026-08-29, STAGING ONLY)
|
||||
|
||||
Phase 2 of the plan. STAGING ONLY, like phase 1.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
+46
-4
@@ -174,7 +174,7 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
|
||||
/* ONE overlay, four panels, swapped by #intro[data-stage]. Keeping the backdrop and the card frame
|
||||
alive across every screen is the point — a screen that unmounts the whole overlay flashes the
|
||||
court through between menus. */
|
||||
#splash, #setup, #stats, #ranks, #newbest, #secret, #bosses, #stmode, #stsub, #bracket, #vs, #train, #player, #promo { display: none; }
|
||||
#splash, #setup, #stats, #ranks, #newbest, #secret, #bosses, #stmode, #stsub, #bracket, #vs, #train, #player, #promo, #card { display: none; }
|
||||
#intro[data-stage="splash"] #splash { display: flex; flex-direction: column; flex: 1; }
|
||||
/* flex COLUMN, not block: it is what lets the footer's margin-top:auto reach the bottom of a
|
||||
screen whose content does not fill it */
|
||||
@@ -190,6 +190,7 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
|
||||
#intro[data-stage="vs"] #vs,
|
||||
#intro[data-stage="player"] #player,
|
||||
#intro[data-stage="promo"] #promo,
|
||||
#intro[data-stage="card"] #card,
|
||||
#intro[data-stage="newbest"] #newbest { display: flex; flex-direction: column; flex: 1;
|
||||
animation: drop 0.3s ease-out; }
|
||||
/* the overlay is HIDDEN during play, not removed: a restart puts it straight back, and the
|
||||
@@ -274,14 +275,31 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
|
||||
image-rendering: pixelated; animation: drop 0.5s ease-out 0.5s backwards; }
|
||||
#prCourtName { margin: 0; font: 400 10px Silkscreen, monospace; color: var(--acid);
|
||||
letter-spacing: 1.5px; animation: drop 0.5s ease-out 0.62s backwards; }
|
||||
/* THE CHARACTER CARD (the leagues, phase 3): the player writ large — sprite, crest, level,
|
||||
honours, ledger. The honours row is a collection with visible empty slots: the unearned
|
||||
badges sit dark, which is the whole incentive. */
|
||||
#cdTop { display: flex; gap: 14px; align-items: flex-start; margin-top: 14px; }
|
||||
#cdLook { position: static; display: block; flex: none; margin: 0; width: auto; height: 200px;
|
||||
touch-action: auto; image-rendering: pixelated; }
|
||||
#cdMeta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
|
||||
#cdBadge { width: 56px; image-rendering: pixelated; }
|
||||
#cdLeague { font: 700 10px Silkscreen, monospace; text-decoration: none; letter-spacing: 1.5px; }
|
||||
#cdLevel { font: 400 30px Bangers, cursive; color: var(--cream); letter-spacing: 1.5px; }
|
||||
#cdXp { display: block; margin-top: 5px; font: 400 9px Silkscreen, monospace; color: var(--dim);
|
||||
text-decoration: none; letter-spacing: 1px; }
|
||||
#cdBadges { display: flex; gap: 10px; align-items: flex-end; }
|
||||
#cdBadges img { height: 46px; image-rendering: pixelated; }
|
||||
#cdBadges img.dark { filter: grayscale(1) brightness(0.3); }
|
||||
/* THE LEVEL STRIP: the one meta number over a thin bar, riding the splash foot. The fill colour
|
||||
is the acid accent for now; the leagues will hand it the skill colour in phase 3. */
|
||||
#xpRow { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; }
|
||||
#xpRow u { font: 700 9px Silkscreen, monospace; color: var(--cream); text-decoration: none;
|
||||
letter-spacing: 1px; white-space: nowrap; }
|
||||
#xpRow s { flex: 1; height: 6px; background: rgba(255,255,255,0.10); border: 1px solid var(--line);
|
||||
#xpRow { cursor: pointer; } /* the strip IS the door to the character card */
|
||||
#xpRow s, #cdBar s { flex: 1; height: 6px; background: rgba(255,255,255,0.10); border: 1px solid var(--line);
|
||||
text-decoration: none; display: block; }
|
||||
#xpRow s i { display: block; height: 100%; width: 0%;
|
||||
#cdBar s { height: 8px; }
|
||||
#xpRow s i, #cdBar s i { display: block; height: 100%; width: 0%;
|
||||
background: linear-gradient(90deg, #3f9560, var(--acid) 55%, #e8b23a);
|
||||
transition: width 0.4s ease; }
|
||||
/* KIT and SKIN: a row of colour squares, under a label that names whatever is selected. That is
|
||||
@@ -629,6 +647,30 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
|
||||
<button class="btn big" id="prGo">WALK ON</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- THE CHARACTER CARD (the leagues): tap the splash's level strip to open. Built by
|
||||
main.buildCard from the profile + stats; the honours row shows every badge slot, earned
|
||||
bright and unearned dark. -->
|
||||
<div id="card">
|
||||
<div class="hdr"><button class="chev" id="cdBack">‹</button><h2 id="cdName">YOUR PLAYER</h2></div>
|
||||
<div id="cdTop">
|
||||
<canvas id="cdLook" width="96" height="224"></canvas>
|
||||
<div id="cdMeta">
|
||||
<img id="cdBadge" alt="">
|
||||
<u id="cdLeague"></u>
|
||||
<b id="cdLevel">LEVEL 1</b>
|
||||
<div id="cdBar"><s><i id="cdFill"></i></s><u id="cdXp"></u></div>
|
||||
</div>
|
||||
</div>
|
||||
<h3>HONOURS<span>WIN THE CUP TO CLIMB</span></h3>
|
||||
<div id="cdBadges"></div>
|
||||
<h3>THE LEDGER<span>ALL TIME</span></h3>
|
||||
<div class="figs" id="cdFigs1"></div>
|
||||
<div style="height:8px"></div>
|
||||
<div class="figs" id="cdFigs2"></div>
|
||||
<div class="foot bare">
|
||||
<button class="btn sec" id="cdEdit">EDIT PLAYER<i>NAME · TOUR · COLOURS</i></button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- THE DRAW (cup mode only). SERVE UP lands here instead of on a court: the four rounds roll
|
||||
through their own band of the ladder and stop, and what you watched land is what walks on
|
||||
(main.js hands the settled rungs to startMatch). The rows are built in main.js from
|
||||
@@ -752,6 +794,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="src/main.js?v=313"></script>
|
||||
<script type="module" src="src/main.js?v=314"></script>
|
||||
</body>
|
||||
</html>
|
||||
+8
-5
@@ -875,12 +875,15 @@ export const DIFFS = [
|
||||
// `band` is [lo, hi] inclusive rungs. Court order deliberately rides the bounce table: clay is
|
||||
// the slowest surface for the slowest league, grass the first prestige, and the top of the club
|
||||
// plays on THE MEMBERS' GROUND. The pace tier is TUNE.leaguePace (gameplay.leaguePace()).
|
||||
// `color` is the league's SKILL COLOUR — the identity tint the meta game hands the player:
|
||||
// the sprint-dust trail (league 2 up; league 1 keeps the shipped court dust), the character card's
|
||||
// accent, the badge row. Each rides its court's own palette so the colour reads as belonging.
|
||||
export const LEAGUES = [
|
||||
{ id: 1, name: 'THE GRAVEYARD SHIFT', court: 'clay', band: [1, 4] },
|
||||
{ id: 2, name: 'THE CLUB STAFF', court: 'hard', band: [5, 8] },
|
||||
{ id: 3, name: 'THE OFFICIALS', court: 'grass', band: [9, 12] },
|
||||
{ id: 4, name: 'THE COACHING STAFF', court: 'gloom', band: [13, 15] },
|
||||
{ id: 5, name: 'THE HONOURS BOARD', court: 'members', band: [16, 18] },
|
||||
{ id: 1, name: 'THE GRAVEYARD SHIFT', court: 'clay', band: [1, 4], color: '#c4652f' },
|
||||
{ id: 2, name: 'THE CLUB STAFF', court: 'hard', band: [5, 8], color: '#4f7fc9' },
|
||||
{ id: 3, name: 'THE OFFICIALS', court: 'grass', band: [9, 12], color: '#4cae52' },
|
||||
{ id: 4, name: 'THE COACHING STAFF', court: 'gloom', band: [13, 15], color: '#8fd8ff' },
|
||||
{ id: 5, name: 'THE HONOURS BOARD', court: 'members', band: [16, 18], color: '#e8b23a' },
|
||||
];
|
||||
export const leagueOf = lg => LEAGUES[Math.min(LEAGUES.length, Math.max(1, lg | 0 || 1)) - 1];
|
||||
|
||||
|
||||
+10
-5
@@ -1,6 +1,6 @@
|
||||
// Game logic: ballistics, swings, serves, rules/scoring, AI, and the per-frame update.
|
||||
|
||||
import { TUNE, UI, bossArt, APPLAUSE_T, EATEN_BURST, EATEN_SUMMARY, COURT, CONTACT, VOLLEY, ZONE_DEPTH, HOME, P_BOUNDS, TOSS, SHOT_DEPTH, POSE_TIME, BOUNCE_IDLE, zombieH, Z_CHEST , WEAPONS, RACK_MAX , BARREL_WEAPONS, racketStage, matchWound, LADDER } from './config.js';
|
||||
import { TUNE, UI, bossArt, APPLAUSE_T, EATEN_BURST, EATEN_SUMMARY, COURT, CONTACT, VOLLEY, ZONE_DEPTH, HOME, P_BOUNDS, TOSS, SHOT_DEPTH, POSE_TIME, BOUNCE_IDLE, zombieH, Z_CHEST , WEAPONS, RACK_MAX , BARREL_WEAPONS, racketStage, matchWound, LADDER, LEAGUES } from './config.js';
|
||||
import { P, O, ball, score, crowd, G, court, tour, other, deuceSide, setupPoint, sendBoy, resetState } from './state.js';
|
||||
import { audio, pock, swish, whoosh, applause, voice, voiceSeq, sfx, aww, zombieMusic, zombieDuck, menuDuck, splat, shriek, boom } from './audio.js';
|
||||
import { haptic } from './haptics.js';
|
||||
@@ -8,7 +8,7 @@ import { axisX, axisZ, takeFlickAim, touchPX, resetInput } from './input.js';
|
||||
import { W } from './render.js'; // runtime-only cycle (render imports gameplay), same pattern as input/zombies
|
||||
import { updateDrill } from './drill.js';
|
||||
import { endRun, beginRun, MODE_CLASSIC } from './stats.js';
|
||||
import { award, beginRunXp } from './profile.js';
|
||||
import { award, beginRunXp, prof } from './profile.js';
|
||||
import { updateZombies, updateParts, spawnZombie, spawnRacketZombie, spawnMachine, spawnChapterBoss, zombies, gore, explode, meleeSwipe, extras, parts, pellets, shots, playerGore, eatenBleed, resetZombies , firePellet , spawnBarrel , fireBeam , pops, popText } from './zombies.js';
|
||||
import { proceedAfterClear, startDuel, startHorde, warnHorde, resolveInterlude, watchdog, updateBench, benchKey, tickMatchFall, placeReceiver } from './beats.js'; // runtime-only cycle: beats calls back into cheer/aside/endBurst/deliverTin/showModal/logSwing
|
||||
import { netSendShot, netSendToss, netTick, netJudging, netSendPoint, netSendFault, netClose } from './net.js'; // runtime-only cycle: net calls back into pointTo/fault/tossBall/showModal
|
||||
@@ -81,13 +81,18 @@ function praiseWord() {
|
||||
// grass, grit on the slab. Squarely inside the "blood, fire, smoke" procedural exemption; the ball's
|
||||
// bounce and the sidestep both kick it, which is what pins fast feet and fast balls to the ground.
|
||||
const DUST_COL = { grass: '#8fa06a', clay: '#c9895a', hard: '#8494a4' };
|
||||
function dustPuff(x, z, n = 5, sp = 1) {
|
||||
function dustPuff(x, z, n = 5, sp = 1, col = null) {
|
||||
for (let k = 0; k < n; k++) parts.push({
|
||||
x: x + (Math.random() * 2 - 1) * 0.15, y: 0.05, z: z + (Math.random() * 2 - 1) * 0.1,
|
||||
vx: (Math.random() * 2 - 1) * 1.2 * sp, vy: 0.5 + Math.random() * 0.9 * sp,
|
||||
vz: (Math.random() * 2 - 1) * 1.2 * sp,
|
||||
t: 0.25 + Math.random() * 0.2, spark: DUST_COL[court.id] || '#98948a' });
|
||||
t: 0.25 + Math.random() * 0.2, spark: col || DUST_COL[court.id] || '#98948a' });
|
||||
}
|
||||
// THE SKILL TRAIL (the leagues, phase 3): the player's OWN sprint dust wears the league colour —
|
||||
// the aura made of motion, never paint (the painted-layer veto). League 1 keeps the shipped court
|
||||
// dust: the tint itself is a progression reward. Read off the profile, not G.league, so the gore
|
||||
// mode shows your colour too.
|
||||
const skillDust = () => prof.lg > 1 ? (LEAGUES[prof.lg - 1] || LEAGUES[0]).color : null;
|
||||
|
||||
export function flickTarget(ch, aim) { // exported: render draws the live reticle with it
|
||||
const q = pullQuality(aim.mag), f = pullFrac(aim.mag);
|
||||
@@ -1930,7 +1935,7 @@ export function update(dt) {
|
||||
const pSpd = Math.hypot(P.vx, P.vz);
|
||||
if (TUNE.trailMin && pSpd > TUNE.trailMin
|
||||
&& (P.dustAcc = (P.dustAcc || 0) + pSpd * dt) > TUNE.runDustEvery) {
|
||||
P.dustAcc = 0; dustPuff(P.x, P.z, 2, 0.6);
|
||||
P.dustAcc = 0; dustPuff(P.x, P.z, 2, 0.6, skillDust());
|
||||
}
|
||||
}
|
||||
// ...and out of 'rally' he STANDS. 'run' is the one pose nothing else expires (expirePose only
|
||||
|
||||
+60
-3
@@ -257,7 +257,8 @@ for (const t of TOURS) {
|
||||
// way this can show a wrong colour is if the court would show it too.
|
||||
// The sprite sheets load asynchronously and the menu deliberately parks the game loop, so the first
|
||||
// draw can land before the art does: retry on a slow poll that stops itself the moment it succeeds.
|
||||
const lookCv = document.getElementById('look'), pLookCv = document.getElementById('pLook');
|
||||
const lookCv = document.getElementById('look'), pLookCv = document.getElementById('pLook'),
|
||||
cdLookCv = document.getElementById('cdLook');
|
||||
let lookPoll = 0;
|
||||
function refreshLook() {
|
||||
const t = TOURS.find(x => x.id === pickedTour) || TOURS[0];
|
||||
@@ -265,7 +266,7 @@ function refreshLook() {
|
||||
const s = SKINS.find(e => e.id === pickedSkin) || SKINS[0];
|
||||
// both live players — the setup screen's and the identity screen's — are the same man and must
|
||||
// move together; drawing to whichever is hidden is a no-op-cheap blit
|
||||
const ok = drawLook(lookCv, t, k, s) & drawLook(pLookCv, t, k, s);
|
||||
const ok = drawLook(lookCv, t, k, s) & drawLook(pLookCv, t, k, s) & drawLook(cdLookCv, t, k, s);
|
||||
clearTimeout(lookPoll);
|
||||
if (!ok) lookPoll = setTimeout(refreshLook, 200); // sprites still coming; ask again shortly
|
||||
}
|
||||
@@ -350,12 +351,16 @@ function buildPlayer() {
|
||||
refreshLook();
|
||||
}
|
||||
document.getElementById('pDice').addEventListener('click', () => { pName.value = profile.zombieName(); });
|
||||
document.getElementById('pBack').addEventListener('click', () => go('splash')); // setup stays open — it re-asks
|
||||
document.getElementById('pBack').addEventListener('click', () => {
|
||||
if (playerReturn === 'card') { playerReturn = null; buildCard(); go('card'); return; }
|
||||
go('splash'); // setup stays unset — it re-asks
|
||||
});
|
||||
document.getElementById('pGo').addEventListener('click', () => {
|
||||
// an emptied field is not a refusal to have a name — the die decides, like the prefill did
|
||||
stats.saveName(stats.tidyName(pName.value) || profile.zombieName());
|
||||
try { localStorage.setItem('tour', pickedTour); } catch {}
|
||||
profile.prof.setup = 1; profile.save(); profile.push();
|
||||
if (playerReturn === 'card') { playerReturn = null; buildCard(); go('card'); return; }
|
||||
buildTops(); go('mode');
|
||||
});
|
||||
pName.addEventListener('keydown', e => { if (e.key === 'Enter') document.getElementById('pGo').click(); });
|
||||
@@ -495,6 +500,58 @@ function buildTrain() {
|
||||
}
|
||||
document.getElementById('trBack').addEventListener('click', () => go('setup'));
|
||||
|
||||
// --- THE CHARACTER CARD (the leagues, phase 3). The splash's level strip is the door. The
|
||||
// honours row is a COLLECTION: every slot always visible, earned badges bright, the rest dark —
|
||||
// the empty slots are the incentive. The ledger reads the same stats module the BODY COUNT does.
|
||||
const fig = (label, val) => `<div class="fig"><b>${label}</b><i>${val}</i></div>`;
|
||||
function buildCard() {
|
||||
const lg = leagueOf(profile.prof.lg), pr = profile.progress();
|
||||
document.getElementById('cdName').textContent = stats.savedName() || 'THE WALK-ON';
|
||||
document.getElementById('cdBadge').src = `assets/badge_l${lg.id}.png?v=${SPRV}`;
|
||||
const el = document.getElementById('cdLeague');
|
||||
el.textContent = `LEAGUE ${lg.id} OF ${LEAGUES.length} — ${lg.name}`;
|
||||
el.style.color = lg.color;
|
||||
document.getElementById('cdLevel').textContent =
|
||||
'LEVEL ' + pr.level + (pr.need ? '' : ' · THE CAP');
|
||||
document.getElementById('cdFill').style.width = Math.round(pr.frac * 100) + '%';
|
||||
document.getElementById('cdXp').textContent = profile.prof.xp.toLocaleString('en-GB') + ' XP'
|
||||
+ (pr.need ? ' · ' + (pr.need - pr.into).toLocaleString('en-GB') + ' TO LEVEL ' + (pr.level + 1) : '');
|
||||
const row = document.getElementById('cdBadges');
|
||||
row.innerHTML = '';
|
||||
for (const l of LEAGUES) {
|
||||
const img = document.createElement('img');
|
||||
img.src = `assets/badge_l${l.id}.png?v=${SPRV}`;
|
||||
img.title = l.name;
|
||||
// a league's badge is EARNED by finishing it — winning its cup. Being past it means exactly
|
||||
// that; league five has no "past", so its shield lights with the champion's crown.
|
||||
img.className = l.id < profile.prof.lg || (l.id === LEAGUES.length && profile.prof.ch) ? '' : 'dark';
|
||||
row.appendChild(img);
|
||||
}
|
||||
const champ = document.createElement('img');
|
||||
champ.src = `assets/badge_champ.png?v=${SPRV}`;
|
||||
champ.title = 'CHAMPION OF THE DEAD CLUB';
|
||||
champ.className = profile.prof.ch ? '' : 'dark';
|
||||
row.appendChild(champ);
|
||||
const g = stats.read('all', undefined, stats.MODE_GORE),
|
||||
z = stats.read('all', undefined, stats.MODE_MATCH),
|
||||
c = stats.read('all', undefined, stats.MODE_CLASSIC);
|
||||
document.getElementById('cdFigs1').innerHTML =
|
||||
fig('KILLS', (g.kills + z.kills + c.kills).toLocaleString('en-GB'))
|
||||
+ fig('MULTI-KILLS', (g.multi + z.multi + c.multi).toLocaleString('en-GB'))
|
||||
+ fig('DEATHS', (g.deaths + z.deaths + c.deaths).toLocaleString('en-GB'));
|
||||
document.getElementById('cdFigs2').innerHTML =
|
||||
fig('BEST RUN', g.longest + ' G')
|
||||
+ fig('MOST FELLED', z.longest)
|
||||
+ fig('RUNS', (g.matches + z.matches + c.matches).toLocaleString('en-GB'));
|
||||
refreshLook();
|
||||
}
|
||||
document.getElementById('xpRow').addEventListener('click', () => { buildCard(); go('card'); });
|
||||
document.getElementById('cdBack').addEventListener('click', () => go('splash'));
|
||||
let playerReturn = null; // EDIT PLAYER borrows the identity screen and comes back to the card
|
||||
document.getElementById('cdEdit').addEventListener('click', () => {
|
||||
playerReturn = 'card'; buildPlayer(); go('player');
|
||||
});
|
||||
|
||||
// --- THE PROMOTION CEREMONY (the leagues). beats.cupWon parks it in the profile module; the tap
|
||||
// off the cup summary lands here (maybeRestart) before the title screen. The court tile IS the
|
||||
// reward on screen; the name prompt, if the run also earned one, queues behind the ceremony.
|
||||
|
||||
Reference in new issue
Block a user