/**
* highscore.js
* High-score screen: displays final score(s), persists top-10 to localStorage,
* shows leaderboard, offers back-to-start button.
*
* show(names, scores, playerCount)
* names — string (1P) or array of strings (2P)
* scores — number (1P) or array of numbers (2P)
* playerCount — 1 or 2
*/
const HighScoreScreen = (() => {
const STORAGE_KEY = 'kidneylab_scores';
/* ── Persistence ─────────────────────────────────────────────── */
function loadScores() {
try {
return JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
} catch {
return [];
}
}
function saveScore(name, score) {
const scores = loadScores();
scores.push({ name: name.toUpperCase().slice(0, 12), score, date: new Date().toLocaleDateString() });
scores.sort((a, b) => b.score - a.score);
const top10 = scores.slice(0, 10);
localStorage.setItem(STORAGE_KEY, JSON.stringify(top10));
return top10;
}
/* ── Helpers ─────────────────────────────────────────────────── */
function rankLabel(rank) {
if (rank === 1) return '🏆 NEW HIGH SCORE!';
if (rank === 2) return '🥈 2nd place!';
if (rank === 3) return '🥉 3rd place!';
return `Rank #${rank}`;
}
function resultCardHTML(playerName, finalScore, scores, myRank) {
const isTop = myRank === 1;
return `
${rankLabel(myRank)}
${playerName.toUpperCase()}
${finalScore >= 0 ? finalScore : 0}
POINTS
`;
}
function tableHTML(scores, highlightNames, highlightScores) {
const rowsHTML = scores.map((s, i) => {
// highlight any entry that matches one of the just-played players
const isMe = highlightNames.some((n, ni) =>
s.name === n.toUpperCase().slice(0, 12) && s.score === highlightScores[ni]
);
return `
| ${i + 1} |
${s.name} |
${s.score} |
${s.date} |
`;
}).join('');
return `
HALL OF FAME
| # | NAME | SCORE | DATE |
${rowsHTML}
`;
}
/* ── Public show ─────────────────────────────────────────────── */
function show(names, scores, playerCount) {
// Normalise to arrays
const nameArr = Array.isArray(names) ? names : [names];
const scoreArr = Array.isArray(scores) ? scores : [scores];
const count = playerCount || nameArr.length;
// Switch screen
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
document.getElementById('highscore-screen').classList.add('active');
// Save all players' scores; last save wins for the leaderboard table
let leaderboard;
nameArr.forEach((n, i) => {
leaderboard = saveScore(n, scoreArr[i]);
});
// Build rank info for each player
const rankInfo = nameArr.map((n, i) => {
const rank = leaderboard.findIndex(
s => s.name === n.toUpperCase().slice(0, 12) && s.score === scoreArr[i]
) + 1;
return { name: n, score: scoreArr[i], rank };
});
render(rankInfo, leaderboard, nameArr, scoreArr);
}
function render(rankInfo, leaderboard, nameArr, scoreArr) {
const el = document.getElementById('highscore-screen');
// One result card per player
const cardsHTML = rankInfo.map(r =>
resultCardHTML(r.name, r.score, leaderboard, r.rank)
).join('');
// Cards side-by-side for 2P, centred for 1P
const cardsWrap = rankInfo.length > 1
? `${cardsHTML}
`
: cardsHTML;
el.innerHTML = `
GAME & WATCH
KIDNEY LAB
${cardsWrap}
${tableHTML(leaderboard, nameArr, scoreArr)}
`;
el.querySelector('#back-btn').addEventListener('click', () => {
IntroScreen.show();
});
}
return { show };
})();