Achievements page
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f6951b0f12
commit
a05530b802
5 changed files with 152 additions and 4 deletions
|
|
@ -13,6 +13,7 @@ let skew = 0; // server clock minus client clock, seconds
|
|||
let page = decodeURIComponent(location.hash.slice(1)) || remember("page") || "town";
|
||||
let selected = null; // bank item
|
||||
let dollPick = null; // equipment slot shown on the character sheet
|
||||
let achPick = null; // achievement chip spelled out: "section.card.entry"
|
||||
let orderTab = "take"; // work orders: for you, all open, yours
|
||||
let draft = null; // a work order being written
|
||||
let seenOrders = null; // order ids already known, so only new ones toast
|
||||
|
|
@ -374,7 +375,8 @@ function sidebar() {
|
|||
${nav("notes", "📰", "Patch notes", "", notesUnread() ? `<span class="badge">new</span>` : "", notesUnread() ? `What's new: ${C.patch_notes[0].title}` : "")}
|
||||
<div class="navhead">You</div>
|
||||
${nav("character", cls.icon, "Character", `${skillOf("combat").icon} ${me.levels.combat}`, "", `Combat level ${me.levels.combat}`)}
|
||||
${nav("bank", "🏦", "Bank", `${me.slots_used}/${me.slots}`, "", `${me.slots_used} of ${me.slots} bank slots used`)}`;
|
||||
${nav("bank", "🏦", "Bank", `${me.slots_used}/${me.slots}`, "", `${me.slots_used} of ${me.slots} bank slots used`)}
|
||||
${achievementsNav(me)}`;
|
||||
let group = null;
|
||||
for (const skill of C.skills) {
|
||||
if (skill.class && skill.class !== me.cls) continue;
|
||||
|
|
@ -462,7 +464,7 @@ function pageHtml() {
|
|||
}
|
||||
if (page.startsWith("character:")) return characterSheet(page.slice(10));
|
||||
if (page === "character") return characterSheet(S.uid);
|
||||
return ({ town, council, orders, board, roster, notes, bank }[page] || town)();
|
||||
return ({ town, council, orders, board, roster, notes, bank, achievements }[page] || town)();
|
||||
}
|
||||
|
||||
// Recipe input as "have / need"; without `have`, just the quantity.
|
||||
|
|
@ -2328,6 +2330,40 @@ function loop() {
|
|||
requestAnimationFrame(loop);
|
||||
}
|
||||
|
||||
// --- achievements ----------------------------------------------------------
|
||||
// A record of what's left to unlock, read off what you already have. Tap a chip for what it is.
|
||||
|
||||
const tally = (entries) => [entries.filter((e) => e.done).length, entries.length];
|
||||
|
||||
function achievementsNav(me) {
|
||||
const [have, need] = tally(me.achievements.flatMap((s) => s.cards.flatMap((c) => c.entries)));
|
||||
return nav("achievements", "🏆", "Achievements", `${have}/${need}`, "", `${have} of ${need} unlocked`);
|
||||
}
|
||||
|
||||
function achievements() {
|
||||
const sections = S.me.achievements, all = sections.flatMap((s) => s.cards.flatMap((c) => c.entries));
|
||||
const [have, need] = tally(all);
|
||||
return `<div class="panel"><h2>Achievements <span class="ach-count">${have} / ${need}</span></h2>
|
||||
<div class="bar gold thick"><span style="width:${have / need * 100}%"></span></div></div>`
|
||||
+ sections.map((s, si) => {
|
||||
const [sh, sn] = tally(s.cards.flatMap((c) => c.entries));
|
||||
return `<h3 class="section-title">${esc(s.name)} <span class="ach-count">${sh} / ${sn}</span></h3>
|
||||
<div class="grid">${s.cards.map((c, ci) => achCard(c, `${si}.${ci}`)).join("")}</div>`;
|
||||
}).join("");
|
||||
}
|
||||
|
||||
function achCard(card, key) {
|
||||
const [have, need] = tally(card.entries);
|
||||
const pick = achPick?.startsWith(key + ".") ? card.entries[Number(achPick.split(".")[2])] : null;
|
||||
const icon = (e) => e.colour ? `<span class="swatch" style="background:${e.colour}"></span>` : glyph(e.glyph, e.tint);
|
||||
const chips = card.entries.map((e, i) => `<button class="ach ${e.done ? "done" : ""} ${e.held ? "held" : ""} ${pick === e ? "on" : ""}" data-ach="${key}.${i}"
|
||||
title="${esc(`${e.name}${e.tip ? ` · ${e.tip}` : ""}`)}" aria-label="${esc(e.name)}">${icon(e)}</button>`).join("");
|
||||
return `<div class="panel ach-card ${have === need ? "full" : ""}"><h2>${esc(card.name)} <span class="ach-count">${have} / ${need}</span></h2>
|
||||
<div class="bar gold"><span style="width:${have / need * 100}%"></span></div>
|
||||
<div class="ach-chips">${chips}</div>
|
||||
${pick ? `<p class="small ach-line">${pick.done ? "✓" : "🔒"} <b>${esc(pick.name)}</b>${pick.tip ? ` <span class="muted">· ${esc(pick.tip)}</span>` : ""}</p>` : ""}</div>`;
|
||||
}
|
||||
|
||||
// --- events ---------------------------------------------------------------
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
|
|
@ -2626,3 +2662,7 @@ document.addEventListener("visibilitychange", () => { if (!document.hidden) refr
|
|||
}, 500);
|
||||
requestAnimationFrame(loop);
|
||||
})();
|
||||
if (d.ach) {
|
||||
achPick = achPick === d.ach ? null : d.ach;
|
||||
return render();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue