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:
xcdoge authored and sganggs committed 2026-10-08 19:30:36 +08:00
1 parent d7c665dbf6
commit b4bc89ad4e
39 files changed
+836 -252

No files matched your search

+14 -2
View File
@@ -106,9 +106,21 @@ test('fuzz: 200 random battles on real data run to completion with invariants',
const r = b.result();
stats[r.reason]++;
for (const [pid, pp] of Object.entries(r.perPlayer)) {
assert.ok(pp.killed <= pp.total || kind === 'unite', `${pid} killed ≤ total`);
// the capsule's own pair: `total` counts only the enemies this field scheduled (`inTotal`), and its numerator
// never exceeds it. `killed` deliberately keeps the `counted` reading — a runtime split child / summon knocked
// down counts there — so `killed > total` is legal since PR #157's capsule semantics (a 4-磨砻 round killed 4
// plus a child reads 5/4 on nothing but `killed/total`; the capsule reads resolved/total = 4/4)
assert.ok(pp.killedInTotal <= pp.total, `${pid} killedInTotal ≤ total`);
assert.ok(pp.resolved <= pp.total, `${pid} resolved ≤ total`);
for (const k of ['damageDealt', 'healingDone', 'bossDamage']) assert.ok(Number.isFinite(pp[k]) && pp[k] >= 0, `${k} finite`);
if (r.reason === 'cleared' && kind === 'normal') assert.equal(pp.killed + pp.leaked.filter((l) => l.counted).length, pp.total, 'every counted enemy killed or leaked');
// the capsule identity: every one of the field's own enemies is 已解决 — knocked down (killedInTotal) or leaked
// (leakedInTotal). It replaces the old `killed + counted leaks = total`, which mixed the counted reading with the
// scheduled denominator and no longer holds (killed counts runtime children, total does not)
if (r.reason === 'cleared' && kind === 'normal') {
assert.ok(pp.killed + pp.leaked.filter((l) => l.counted).length >= pp.total, 'every counted enemy killed or leaked');
assert.equal(pp.killedInTotal + pp.leakedInTotal, pp.total, 'the capsule is full: killedInTotal + leakedInTotal = total');
assert.equal(pp.resolved, pp.total, 'a cleared normal field resolves its own list');
}
}
JSON.stringify(r);
}