feedback7: merge fb7-ui-backlog — #229 device tooltips, #238 settings button in lobby / room, #138 准备 folds the shop, #120 in-match spectator roster (cap stays 2), PR #308 capsule counts (+ the shared-field progress fix), PR #333 empty new shop slot on 调度中心 upgrade
- Conflicts: the stats entry (merged fb7-stats) and the settings button both sit in the lobby / room top bars — both kept;
public/js/ui/settings.js (#321 diagnostics, voiceLang, SettingsButton); docs/PLAYING.md table rows resolved line by
line against the merge base (#368, #354, #333 edits kept); docs/SIM.md / design/network.md snapshot field lists
(resolved + ammo / wolves / neg / stand / standCut); design/client.md Screens line (#368's AI switch kept).
- Grok review: MERGE AFTER FIXES — the shared-field capsule finding fixed on the branch (1a880699).
- Golden: roster 23, bonds 2, fields 11, matches 18, diy 11 — #308 totals / snapshots and #333's shop RNG (union OK);
broad node --test 5473 (5472 pass, 0 fail, 1 skipped); lint 0 errors; typecheck; i18n strict clean.
This commit is contained in:
commit
dc609ea13f
71 files changed
+3016
-806
No files matched your search
+12
-3
@@ -40,7 +40,12 @@ const isUnitEnd = (u) => isPlain(u) && nullable(isUid)(u.uid) && isNum(u.hpPct,
|
||||
&& optional(isBool)(u.skillActive) && nullable(isId)(u.defId);
|
||||
const isUnitStat = (u) => isPlain(u) && nullable(isUid)(u.uid) && nullable(isId)(u.defId) && optional((v) => isStr(v, 16))(u.kind)
|
||||
&& isStat(u.dmg) && isStat(u.kills) && isStat(u.heal) && isStat(u.taken) && isStat(u.attacks);
|
||||
const isPerPlayer = (p) => isPlain(p) && isInt(p.killed, 0, 1e5) && isInt(p.total, 0, 1e5) && p.killed <= p.total
|
||||
const isPerPlayer = (p) => isPlain(p) && isInt(p.killed, 0, 1e5) && isInt(p.total, 0, 1e5)
|
||||
// `resolved` = the HUD capsule's numerator of this player's own field (the round's own scheduled enemies knocked out
|
||||
// or leaked: server/sim/battle/deploy.js killedInTotal / leakedInTotal, Battle.resolved). `killed` counts every counted
|
||||
// knock-out — a runtime split child / summon too — and may therefore exceed `total`, which counts only the round's own
|
||||
// scheduled enemies (server/match/fields.js validateClientResult bounds it against maxTotal instead).
|
||||
&& optional((x) => isInt(x, 0, 1e5))(p.resolved)
|
||||
&& isList(p.leaked, RESULT_LIMITS.leaked, isLeak) && isBool(p.perfect)
|
||||
&& isMap(p.layerGains, RESULT_LIMITS.layerGains, isId, (v) => isNum(v, 0, 1e4))
|
||||
&& isStat(p.coins) && isStat(p.damageDealt) && isStat(p.bossDamage) && isStat(p.healingDone) && isStat(p.deaths)
|
||||
@@ -56,6 +61,7 @@ const isUnspawned = (u) => isPlain(u) && isId(u.enemyKey) && nullable(isId)(u.so
|
||||
export function isBattleResult(v) {
|
||||
return isPlain(v) && ['cleared', 'timeout', 'forced'].includes(v.reason) && isNum(v.time, 0, 1e5)
|
||||
&& optional((x) => isInt(x, 0, 1e5))(v.killed) && optional((x) => isInt(x, 0, 1e5))(v.total)
|
||||
&& optional((x) => isInt(x, 0, 1e5))(v.resolved)
|
||||
&& isMap(v.perPlayer, RESULT_LIMITS.players, isId, isPerPlayer) && Object.keys(v.perPlayer).length > 0
|
||||
&& (v.unspawned === undefined || isList(v.unspawned, RESULT_LIMITS.unspawned, isUnspawned))
|
||||
&& optional((x) => isInt(x, 0, 1e9))(v.errors) && optional((x) => isNum(x, 0, BIG))(v.bossHpLeft);
|
||||
@@ -385,13 +391,16 @@ export const C2S = {
|
||||
|
||||
// client-side combat (DESIGN §14): the authoritative client of a field reports its battle; a 联防 field adds
|
||||
// `left` = { [leakerId]: its enemies still standing (unspawned, alive, or through again) } (server/sim/spec.js
|
||||
// uniteLeft; user playtest #6 item 7 — the leakers' live counter)
|
||||
// uniteLeft; user playtest #6 item 7 — the leakers' live counter). `resolved` = the HUD capsule's numerator: the
|
||||
// field's own scheduled enemies that were knocked out **or leaked** (official: 漏一个 1/3, 打死一个 2/3,
|
||||
// 打死会分裂的 3/3 — Battle.leakedInTotal; runtime splits / summons stay out of both parts of the capsule).
|
||||
'b.progress': {
|
||||
battleId: isId, gt: (v) => isNum(v, 0, 1e5), killed: (v) => isInt(v, 0, 1e5), total: (v) => isInt(v, 0, 1e5),
|
||||
resolved: (v) => isInt(v, 0, 1e5),
|
||||
leaks: (v) => isNum(v, 0, 1e6), bossDmg: (v) => isNum(v, 0, BIG),
|
||||
by: (v) => isMap(v, RESULT_LIMITS.players, isId, (x) => isNum(x, 0, BIG)), done: isBool,
|
||||
left: (v) => isMap(v, RESULT_LIMITS.players, isId, (x) => isInt(x, 0, 1e5)),
|
||||
$optional: ['leaks', 'bossDmg', 'by', 'done', 'left'],
|
||||
$optional: ['resolved', 'leaks', 'bossDmg', 'by', 'done', 'left'],
|
||||
},
|
||||
'b.result': { battleId: isId, result: isBattleResult },
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user