feedback1 gaps: the client-result layer bound counts the lineup's layer traits

With the bots' new band picks the full-match suite's coop/FUNNY/107
reached a 6-谢拉格 freeze board at R12 whose honest +112 谢拉格 layers passed
the flat 60 + 4*round = 108, so the server rejected the client and
re-simulated (SP_VERIFY=all agrees with the client on all 57 battles).

validateClientResult now adds, per bond, what the player's IN_BATTLE layer
traits can add to it: each trait of its units and each one their ADD_BOND
traits hand out (once per operator), up to the per-battle cap the sim
applies; a trait without a cap, or a 魔王, leaves the bond bounded only by
the room under 999. Other bonds keep the flat bound. DESIGN §14 / §20.12 /
§21.26, META and the CHANGELOG say so; tests pin the R12 board and the
capped, handed-out and 魔王 cases.
This commit is contained in:
sganggs committed 2026-10-03 15:25:48 +08:00
1 parent 1ea3e93de2
commit cef6b219f9
5 files changed
+102 -11

No files matched your search

+3 -1
View File
@@ -555,7 +555,9 @@ Any `choice:` handler whose EffectRef reuses its own key must guard like this (o
`layerGainRoom` — `PlayerState.addLayers` (all prep-side gains: 特质, items, bands, 机变 cards, bonds; `ctx.addLayers`),
the SETTLE of the in-battle gains and the battle's own live copy (`Battle.addLayers`, SIM.md §6); a gain at the cap
adds 0 and dispatches no onLayers. The client-result check bounds a reported gain by the room left from the bond's
starting layers (`fields.js validateClientResult`, 'layer bound'); `invariants.js` flags a bond above the cap. The
starting layers and by 60 + 4·round plus what the player's IN_BATTLE layer 特质 can add to that bond (their per-battle
caps; an uncapped trait leaves only the room — `fields.js layerAllowanceOf`, DESIGN §21.26) (`validateClientResult`,
'layer bound'); `invariants.js` flags a bond above the cap. The
bond strip, its popup, the effect text and the detail card show the server's capped count. The dev tools' direct
writes (`tools/matchrun.mjs --layers N`, `tools/balance.mjs applyBoard`) stop at the cap too.
* **Waves**: waves.js header (stage/factions/boss per match, faction replacement per round with `k` copies, scaling by