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
+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