"use strict"; /* ================= 飞行员大厅(主页):排行榜 + 图鉴展柜背景 ================= */ let LB_SORT = "endless"; let HOME_SHOW = null; /* 图鉴已收集数(只统计合法 key) */ function codexCount() { let n = 0; for (const k in SAVE.codex) if (SAVE.codex[k] && (WEAPONS[k] || SUBS[k] || DRONES[k] || PASSIVES[k])) n++; return n; } async function enterHome() { G = null; UI = "home"; rollHomeShow(); show("o-home"); /* 刷新账号数据(stats/codex),再渲染面板与排行榜 */ const r = await NET.api("/api/me", "GET"); if (r.ok) NET._apply(r.data); else if (r.status === 401) { NET.user = null; UI = "auth"; show("o-auth"); return; } buildHomeStats(); buildLeaderboard(LB_SORT); } function buildHomeStats() { const s = NET.stats || { bossKills: 0, endlessHigh: 0 }; const nm = NET.user ? NET.user.username : "--"; $("home-stats").textContent = `${nm} · 击坠Boss ${s.bossKills} · 图鉴 ${codexCount()}/${NET.codexTotal} · 无尽最高 ${s.endlessHigh}`; } /* ---------- 排行榜 ---------- */ document.querySelectorAll(".lb-tabs button").forEach((b) => { b.onclick = () => { LB_SORT = b.dataset.s; document.querySelectorAll(".lb-tabs button").forEach((x) => x.classList.toggle("on", x === b)); SFX.pick(); buildLeaderboard(LB_SORT); }; }); async function buildLeaderboard(sort) { const list = $("lb-list"); list.innerHTML = '
载入中...
'; const r = await NET.api("/api/leaderboard?sort=" + sort, "GET"); if (!r.ok) { list.innerHTML = '
载入失败
'; return; } const rows = r.data.rows || []; list.innerHTML = ""; if (!rows.length) { list.innerHTML = '
虚位以待
'; return; } const meName = NET.user && NET.user.username; rows.forEach((row, i) => { const d = document.createElement("div"); d.className = "lb-row" + (meName && row.username === meName ? " me" : ""); const cells = [String(i + 1), row.username, String(row.bossKills), row.codexN + "/" + r.data.codexTotal, String(row.endlessHigh)]; for (const c of cells) { const s = document.createElement("span"); s.textContent = c; // textContent 防注入 d.appendChild(s); } list.appendChild(d); }); } /* ---------- 大厅背景:随机军械展柜 + 随机刷怪巡游 ---------- */ const HOME_MOB_TYPES = ["scout", "weaver", "kami", "splitter", "mine", "gunship", "sniper"]; function rollHomeShow() { HOME_SHOW = { m: shuffle(Object.keys(WEAPONS)).slice(0, 3), s: shuffle(Object.keys(SUBS)).slice(0, 3), d: shuffle(Object.keys(DRONES)).slice(0, 2), t: 0, spawnT: 20, mobs: [], }; } /* 由 render() 在 UI==="home" 时每帧调用(dt=1) */ function drawHomeShowcase(dt) { if (!HOME_SHOW || HOME_SHOW.t > 1800) rollHomeShow(); // 30 秒重抽一轮 const hs = HOME_SHOW; hs.t += dt; /* 展柜:3主武+3副武+2僚机,两排漂浮 */ const items = [ ...hs.m.map((k) => ({ d: WEAPONS[k] })), ...hs.s.map((k) => ({ d: SUBS[k] })), ...hs.d.map((k) => ({ d: DRONES[k] })), ]; ctx.textAlign = "center"; items.forEach((it, i) => { const col = i % 4, row = (i / 4) | 0; const x = W / 2 + (col - 1.5) * 56; const y = 118 + row * 52 + Math.sin(hs.t * 0.03 + i * 1.7) * 2.5; const img = it.d.icon ? ICONS[it.d.icon] : SPR[it.d.spr]; if (img) { ctx.globalAlpha = 0.85; ctx.drawImage(img, x - img.width * 1.5, y - img.height * 1.5, img.width * 3, img.height * 3); ctx.globalAlpha = 1; } ctx.font = "6px 'Press Start 2P',monospace"; ctx.fillStyle = "#7f8cb8"; ctx.fillText(it.d.name, x, y + 22); }); /* 随机刷怪:从顶部飘入,正弦摆动 */ hs.spawnT -= dt; if (hs.spawnT <= 0 && hs.mobs.length < 8) { hs.spawnT = rndi(50, 110); const ty = pick(HOME_MOB_TYPES), elite = Math.random() < 0.2; const spr = SPR[(elite ? "e_" : "") + ty] || SPR[ty] || SPR.scout; hs.mobs.push({ x: rnd(20, W - 20), y: -16, vy: rnd(0.25, 0.6), ph: rnd(0, TAU), amp: rnd(6, 26), spr, sc: elite ? 1.8 : 1.3, t: 0 }); } for (const m of hs.mobs) { m.t += dt; m.y += m.vy * dt; const mx = m.x + Math.sin(m.t * 0.02 + m.ph) * m.amp; ctx.globalAlpha = 0.8; ctx.drawImage(m.spr, mx - (m.spr.width * m.sc) / 2, m.y - (m.spr.height * m.sc) / 2, m.spr.width * m.sc, m.spr.height * m.sc); ctx.globalAlpha = 1; } hs.mobs = hs.mobs.filter((m) => m.y < H + 24); }