feedback1c WK: 变形同构体 wearers in the bond popup's members and on their card

Player report: with 变形同构体 and the matching bond item the wearer gets the
bond's effect, but the bond's member count leaves the converted operator out.

The count that activates the bond already included the wearer on every server
path (bondsMeta.pieceBonds: prep count, views, battle input; support.unitBonds:
the battle). The client did not: the bond popup's member list (成员 x/y) and the
wearer's card read only the chess records' bonds, so the popup said 在场 3 but
成员 2/10 without the wearer, and the card had no chip for the bond.

- gameLogic.grantedBonds / pieceBondIds: the server's 变形同构体 rule on the
  client; bondMembers lists wearers (tagged 同构, one row per operator, on the
  board or owned), so 成员 x/y agrees with 在场.
- detailPanel: the card's chips include the granted bond (dashed, 同构).
- Teammates: UnitInfo carries an ally operator's item ids (sim unitInfo,
  Match.prepFieldMeta); ownerBoard / runner.ownerOps keep them.
- Tests: every pairing on real matches (prep, views, battle input, the real
  battle), bench vs board, half pairs, distinct members; the client rule
  against the server's; popup / card rendering.
This commit is contained in:
sganggs committed 2026-10-03 02:29:28 +08:00
1 parent 7f134737ce
commit 0c898bb524
13 files changed
+464 -34

No files matched your search

+4 -3
View File
@@ -45,8 +45,9 @@
// playtest #4 item 7). Read-only: it takes the stats the sim computed last (`unit._s`) and
// never makes the unit recompute them, so looking never changes the battle's floats.
// battleRunner.unitIdOf(uid, ownerId, fieldId?) → the id of an own board piece's unit in that battle | null
// battleRunner.ownerOps(ownerId, fieldId?) → [{ kind: 'op', ownerId, defId }] that player's operators in the battle on
// screen (a teammate's bond popup: the members in play, DESIGN §20.15) | []
// battleRunner.ownerOps(ownerId, fieldId?) → [{ kind: 'op', ownerId, defId, items? }] that player's operators in the
// battle on screen with their equipment (a teammate's bond popup: the members in play, DESIGN
// §20.15, 变形同构体 wearers included) | []
//
// createBattleRunner(deps) builds an instance with injectable net / store / clock / frame scheduler / sim loader
// (test/match/runner.test.js drives it under Node).
@@ -686,7 +687,7 @@ export function createBattleRunner(deps) {
if (!e || typeof ownerId !== 'string' || !ownerId || (fieldId != null && e.fieldId !== fieldId)) return [];
const list = Array.isArray(e.battle.allyUnits) ? e.battle.allyUnits : [];
return list.filter((u) => u && u.kind === 'op' && u.ownerId === ownerId && typeof u.defId === 'string')
.map((u) => ({ kind: 'op', ownerId, defId: u.defId }));
.map((u) => (Array.isArray(u.items) && u.items.length ? { kind: 'op', ownerId, defId: u.defId, items: [...u.items] } : { kind: 'op', ownerId, defId: u.defId }));
},
/** Re-show the current battle (the game screen remounted). */
reshow() { if (cur) show(cur); },