排行榜改造+Boss挑战一命制
- 排行榜30秒自动刷新(进入页面已刷新,定时器仅home界面生效,刷新不闪屏) - boss榜不再统计累计击坠:改为Boss挑战(rush)击败过的不同Boss数/总数(11),按mode=rush+win=1去重stage;rush局stage记录Boss索引 - Boss挑战一命制:startRushGo强制lives=1/maxLives=1,掉落与拾取加命均以maxLives为上限,中途无法再加命 - 排行榜文案:Boss挑战tab/Boss列头
This commit is contained in:
parent
559e70fac5
commit
4e41ee2bef
@ -49,10 +49,10 @@
|
|||||||
<div class="h3" style="color:var(--cyan);letter-spacing:3px">— 全服排行榜 TOP 100 —</div>
|
<div class="h3" style="color:var(--cyan);letter-spacing:3px">— 全服排行榜 TOP 100 —</div>
|
||||||
<div class="lb-tabs">
|
<div class="lb-tabs">
|
||||||
<button data-s="endless" class="on">无尽最高分</button>
|
<button data-s="endless" class="on">无尽最高分</button>
|
||||||
<button data-s="boss">击坠Boss</button>
|
<button data-s="boss">Boss挑战</button>
|
||||||
<button data-s="codex">图鉴收集</button>
|
<button data-s="codex">图鉴收集</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="lb-row lb-head"><span>#</span><span>飞行员</span><span>击坠</span><span>图鉴</span><span>无尽最高</span></div>
|
<div class="lb-row lb-head"><span>#</span><span>飞行员</span><span>Boss</span><span>图鉴</span><span>无尽最高</span></div>
|
||||||
<div class="lb-list" id="lb-list"></div>
|
<div class="lb-list" id="lb-list"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" style="margin-bottom:2%">
|
<div class="row" style="margin-bottom:2%">
|
||||||
|
|||||||
@ -1,6 +1,13 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
/* ================= 飞行员大厅(主页):排行榜 + 图鉴展柜背景 ================= */
|
/* ================= 飞行员大厅(主页):排行榜 + 图鉴展柜背景 ================= */
|
||||||
let LB_SORT = "endless";
|
let LB_SORT = "endless";
|
||||||
|
let LB_T = 0; // 排行榜自动刷新定时器
|
||||||
|
|
||||||
|
/* 排行榜 30 秒自动刷新(进入页面时 enterHome 已刷新一次) */
|
||||||
|
function lbAutoRefresh() {
|
||||||
|
if (LB_T) return;
|
||||||
|
LB_T = setInterval(() => { if (UI === "home") buildLeaderboard(LB_SORT); }, 30000);
|
||||||
|
}
|
||||||
|
|
||||||
/* 图鉴已收集数(只统计合法 key) */
|
/* 图鉴已收集数(只统计合法 key) */
|
||||||
function codexCount() {
|
function codexCount() {
|
||||||
@ -21,6 +28,7 @@ async function enterHome() {
|
|||||||
/* status===0 网络抖动:沿用现有数据,不踢出 */
|
/* status===0 网络抖动:沿用现有数据,不踢出 */
|
||||||
buildHomeStats();
|
buildHomeStats();
|
||||||
buildLeaderboard(LB_SORT);
|
buildLeaderboard(LB_SORT);
|
||||||
|
lbAutoRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildHomeStats() {
|
function buildHomeStats() {
|
||||||
@ -42,17 +50,19 @@ document.querySelectorAll(".lb-tabs button").forEach((b) => {
|
|||||||
|
|
||||||
async function buildLeaderboard(sort) {
|
async function buildLeaderboard(sort) {
|
||||||
const list = $("lb-list");
|
const list = $("lb-list");
|
||||||
list.innerHTML = '<div class="lb-empty">载入中...</div>';
|
if (!list.children.length) list.innerHTML = '<div class="lb-empty">载入中...</div>'; // 首次/空态才显示载入,自动刷新不闪屏
|
||||||
const r = await NET.api("/api/leaderboard?sort=" + sort, "GET");
|
const r = await NET.api("/api/leaderboard?sort=" + sort, "GET");
|
||||||
if (!r.ok) { list.innerHTML = '<div class="lb-empty">载入失败</div>'; return; }
|
if (!r.ok) { list.innerHTML = '<div class="lb-empty">载入失败</div>'; return; }
|
||||||
const rows = r.data.rows || [];
|
const rows = r.data.rows || [];
|
||||||
list.innerHTML = "";
|
list.innerHTML = "";
|
||||||
if (!rows.length) { list.innerHTML = '<div class="lb-empty">虚位以待</div>'; return; }
|
if (!rows.length) { list.innerHTML = '<div class="lb-empty">虚位以待</div>'; return; }
|
||||||
const meName = NET.user && NET.user.username;
|
const meName = NET.user && NET.user.username;
|
||||||
|
const bossTotal = r.data.bossTotal || 11;
|
||||||
rows.forEach((row, i) => {
|
rows.forEach((row, i) => {
|
||||||
const d = document.createElement("div");
|
const d = document.createElement("div");
|
||||||
d.className = "lb-row" + (meName && row.username === meName ? " me" : "");
|
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)];
|
const bossCell = sort === "boss" ? row.bossKills + "/" + bossTotal : String(row.bossKills); // boss 榜显示“击败几个/总共几个”
|
||||||
|
const cells = [String(i + 1), row.username, bossCell, row.codexN + "/" + r.data.codexTotal, String(row.endlessHigh)];
|
||||||
for (const c of cells) {
|
for (const c of cells) {
|
||||||
const s = document.createElement("span");
|
const s = document.createElement("span");
|
||||||
s.textContent = c; // textContent 防注入
|
s.textContent = c; // textContent 防注入
|
||||||
|
|||||||
@ -376,6 +376,8 @@ function startRushGo(i,build){
|
|||||||
G.drones={};build.d.forEach(k=>G.drones[k]=2);G.droneLoadout=build.d.slice();
|
G.drones={};build.d.forEach(k=>G.drones[k]=2);G.droneLoadout=build.d.slice();
|
||||||
G.xpNeed=1e9; // 挑战模式无升级打断
|
G.xpNeed=1e9; // 挑战模式无升级打断
|
||||||
G.rushIdx=i;G.rushT0=0;
|
G.rushIdx=i;G.rushT0=0;
|
||||||
|
G.stage=i; // 排行榜统计:rush 局 stage 记录 Boss 索引(0~10)
|
||||||
|
G.lives=1;G.stat.maxLives=1; // BOSS 挑战一命制:掉落/拾取心均以 maxLives 为上限,中途无法再加命
|
||||||
UI="play";show("");acc=0;
|
UI="play";show("");acc=0;
|
||||||
MUS.start(true);
|
MUS.start(true);
|
||||||
banner("BOSS 挑战 — "+BOSSES[i].name,"#ff5566",130);
|
banner("BOSS 挑战 — "+BOSSES[i].name,"#ff5566",130);
|
||||||
|
|||||||
@ -194,15 +194,25 @@ function me(req, res, ctx) {
|
|||||||
|
|
||||||
/* ---------- GET /api/leaderboard?sort=endless|boss|codex ---------- */
|
/* ---------- GET /api/leaderboard?sort=endless|boss|codex ---------- */
|
||||||
const LB_COLS = { endless: "endless_high", boss: "boss_kills", codex: "codexN" };
|
const LB_COLS = { endless: "endless_high", boss: "boss_kills", codex: "codexN" };
|
||||||
|
const BOSS_TOTAL = 11; // 与 js/enemies.js BOSSES 数量同步
|
||||||
function leaderboard(req, res, ctx, _body, query) {
|
function leaderboard(req, res, ctx, _body, query) {
|
||||||
const col = LB_COLS[(query && query.get("sort")) || ""] || "endless_high";
|
const sort = (query && query.get("sort")) || "";
|
||||||
/* col 来自上方白名单映射,非用户输入直接拼接 */
|
const bossSort = sort === "boss";
|
||||||
const rows = db.prepare(`
|
/* boss 榜:不统计累计击坠,改为 BOSS 挑战(rush)模式下击败过几个不同 Boss(去重)/ 总共 Boss 数 */
|
||||||
|
const rows = bossSort ? db.prepare(`
|
||||||
|
SELECT u.username AS username,
|
||||||
|
(SELECT COUNT(DISTINCT r.stage) FROM runs r
|
||||||
|
WHERE r.user_id=u.id AND r.mode='rush' AND r.win=1 AND r.stage BETWEEN 0 AND 10) AS bossKills,
|
||||||
|
s.endless_high AS endlessHigh,
|
||||||
|
(SELECT COUNT(*) FROM codex_unlocks c WHERE c.user_id=u.id) AS codexN
|
||||||
|
FROM users u JOIN user_stats s ON s.user_id=u.id
|
||||||
|
ORDER BY bossKills DESC, u.id ASC LIMIT 100`).all()
|
||||||
|
: db.prepare(`
|
||||||
SELECT u.username AS username, s.boss_kills AS bossKills, s.endless_high AS endlessHigh,
|
SELECT u.username AS username, s.boss_kills AS bossKills, s.endless_high AS endlessHigh,
|
||||||
(SELECT COUNT(*) FROM codex_unlocks c WHERE c.user_id=u.id) AS codexN
|
(SELECT COUNT(*) FROM codex_unlocks c WHERE c.user_id=u.id) AS codexN
|
||||||
FROM users u JOIN user_stats s ON s.user_id=u.id
|
FROM users u JOIN user_stats s ON s.user_id=u.id
|
||||||
ORDER BY ${col} DESC, u.id ASC LIMIT 100`).all();
|
ORDER BY ${LB_COLS[sort] || "endless_high"} DESC, u.id ASC LIMIT 100`).all();
|
||||||
return ctx.ok({ rows, codexTotal: CODEX_TOTAL, sort: col });
|
return ctx.ok({ rows, codexTotal: CODEX_TOTAL, bossTotal: BOSS_TOTAL, sort });
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- POST /api/run ----------
|
/* ---------- POST /api/run ----------
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user