feedback7 UIBACK: the top-bar capsule counts like the official — resolved = killed + leaked among the enemies the round scheduled (opening 0/3, a leak 1/3, a kill 2/3, the splitter 3/3); a split child, a summon and a boss summon are in neither number but still cost LP and break 完美作战 (PR #308 by @xcdoge, the capsule half of PR #157 — authored by them: the sim / protocol / HUD hunks applied as reviewed): inTotal / killedInTotal / leakedInTotal / resolved, b.snap / BattleResult / b.progress (optional field) / m.public progress carry resolved, killed may exceed total (validation bounds it by the content-spawn allowance); dropped the PR's stray design-doc line — it had replaced the S→C b.end bullet of docs/design/network.md, which is back; the 联防 live-counter change mark follows the enemy list now that a spawn no longer moves total (uniteLeftMark + test); golden: only total / players.*.total / snaps move, outcomes bit-identical — roster 23 (roster-002 003 007 008 009 010 011 012 013 015 017 018 020 023 024 025 026 027 037 045 047 048 049), bonds 2 (bond-maniShip-low, bond-soloShip-high), fields 11 (boss-boss_1 3 5 pair+solo, boss-boss_6-solo, hidden-boss_8 10 pair+solo), diy 11 (diy-036 040 056 062 068 073 083 091 095 114 115), matches 12 (solo-FUNNY-1 NORMAL-1 HARD-1 ABYSS-1 ABYSS-2, coop2-NORMAL-3 coop2-HARD-4 coop3-ABYSS-5 coop4-ABYSS-7 coop2-NORMAL-8-serverrun solo-HARD-9-boosted coop2-NORMAL-70-diy: the total column of 36 round rows), standins unchanged
This commit is contained in:
1 parent
d7c665dbf6
commit
b4bc89ad4e
39 files changed
+836
-252
No files matched your search
+22
-4
@@ -262,7 +262,8 @@ export function uniteLeft(battle) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress numbers of a battle for b.progress / the teammates' waiting UI: game time, kills, total, counted leaks
|
||||
* Progress numbers of a battle for b.progress / the teammates' waiting UI: game time, kills, total, the capsule's
|
||||
* `resolved` (this field's own scheduled enemies knocked out or leaked — Battle.resolved), counted leaks
|
||||
* (normal / unite), the boss pool damage of this field and — unite fields — `left` (uniteLeft: each leaker's enemies
|
||||
* still standing).
|
||||
*/
|
||||
@@ -273,10 +274,14 @@ export function battleProgress(battle) {
|
||||
for (const k of Object.keys(pp)) for (const l of pp[k].leaked || []) if (l && l.counted !== false) leaks++;
|
||||
const pool = battle && battle.sharedBoss;
|
||||
const gt = Number(battle && battle.time) || 0;
|
||||
const total = Math.max(0, Math.trunc(Number(battle && battle.total) || 0));
|
||||
const out = {
|
||||
gt: Math.round(gt * 1000) / 1000,
|
||||
killed: Math.max(0, Math.trunc(Number(battle && battle.killed) || 0)),
|
||||
total: Math.max(0, Math.trunc(Number(battle && battle.total) || 0)),
|
||||
total,
|
||||
// `null` (never 0) when the battle cannot report it: a display replica / a stand-in must not look like "0 resolved"
|
||||
// (a `0` from here would defeat every `resolved ?? killed` fallback of the HUD)
|
||||
resolved: numberOrNull(battle && battle.resolved, total),
|
||||
leaks,
|
||||
bossDmg: pool && Number.isFinite(pool.cum) ? pool.cum : 0,
|
||||
done: !!(battle && battle.finished),
|
||||
@@ -288,6 +293,14 @@ export function battleProgress(battle) {
|
||||
return out;
|
||||
}
|
||||
|
||||
/** A finite, non-negative integer (never above `cap`), else null — a value the HUD may fall back from. */
|
||||
function numberOrNull(v, cap = Infinity) {
|
||||
if (v == null) return null; // Number(null) === 0: a battle without the counter (a stand-in) must not read as "0"
|
||||
const n = Number(v);
|
||||
if (!Number.isFinite(n)) return null;
|
||||
return Math.max(0, Math.min(cap, Math.trunc(n)));
|
||||
}
|
||||
|
||||
const r4 = (v) => Math.round((Number(v) || 0) * 1e4) / 1e4;
|
||||
const modsKey = (m) => (m && typeof m === 'object' ? JSON.stringify(Object.keys(m).filter((k) => m[k] !== undefined).sort().map((k) => [k, m[k]])) : '');
|
||||
|
||||
@@ -348,7 +361,9 @@ export function compactResult(res) {
|
||||
for (const [k, v] of Object.entries(p.layerGains || {}).slice(0, 40)) if (isKey(k) && fnum(v) > 0) layerGains[k] = Math.min(1e4, fnum(v));
|
||||
const total = Math.max(0, Math.trunc(fnum(p.total)));
|
||||
perPlayer[pid] = {
|
||||
killed: Math.min(total, Math.max(0, Math.trunc(fnum(p.killed)))),
|
||||
// `killed` keeps the sim's reading (every counted knock-out, runtime splits / summons included) and is deliberately
|
||||
// NOT clamped to `total`: the denominator counts only the round's own scheduled enemies (Battle.resolved)
|
||||
killed: Math.max(0, Math.trunc(fnum(p.killed))),
|
||||
total,
|
||||
leaked: cap(p.leaked, 400).filter((l) => l && isKey(l.enemyKey)).map((l) => {
|
||||
const o = { enemyKey: l.enemyKey, mods: compactMods(l.mods), lpr: Math.max(0, Math.min(1000, fnum(l.lpr, 1))), sourcePlayerId: keyOr(l.sourcePlayerId), tag: typeof l.tag === 'string' && l.tag.length <= 16 ? l.tag : null, counted: l.counted !== false };
|
||||
@@ -373,6 +388,9 @@ export function compactResult(res) {
|
||||
taken: Math.max(0, Math.round(fnum(u.taken))), attacks: Math.max(0, Math.trunc(fnum(u.attacks))),
|
||||
})),
|
||||
};
|
||||
// the HUD capsule's numerator (or absent for a result that has none: the teammate UI falls back to `killed`)
|
||||
const resolved = Number.isFinite(p.resolved) ? Math.max(0, Math.min(total, Math.trunc(p.resolved))) : null;
|
||||
if (resolved != null) perPlayer[pid].resolved = resolved;
|
||||
}
|
||||
const out = {
|
||||
reason: ['cleared', 'timeout', 'forced'].includes(r.reason) ? r.reason : 'forced',
|
||||
@@ -382,7 +400,7 @@ export function compactResult(res) {
|
||||
perPlayer,
|
||||
errors: Math.max(0, Math.min(1e9, Math.trunc(fnum(r.errors)))),
|
||||
};
|
||||
if (out.killed > out.total) out.killed = out.total;
|
||||
if (Number.isFinite(r.resolved)) out.resolved = Math.max(0, Math.min(out.total, Math.trunc(r.resolved)));
|
||||
if (Array.isArray(r.unspawned) && r.unspawned.length) {
|
||||
out.unspawned = cap(r.unspawned, 400).filter((u) => u && isKey(u.enemyKey)).map((u) => ({
|
||||
enemyKey: u.enemyKey, sourcePlayerId: keyOr(u.sourcePlayerId), tag: typeof u.tag === 'string' && u.tag.length <= 16 ? u.tag : null,
|
||||
|
||||
Reference in new issue
Block a user