feedback5 WK: 自选编队 on the server — room.diy { picks } (lenient: illegal picks dropped, only malformed input is BAD_MSG; stored per session / seat; a match takes the picks its seat had at the start, a change during a match is for the next one; welcome lists diyKitted), PlayerState.diy with the player's data view (a slotted DIY slot is its operator for every rule: bonds from its factions, no 特质, the pick's skill and module, the slot's tier / price / merge), a per-player stock per slotted piece (8 at tier 5, 5 at tier 6 [ASSUMED]; never in the shared pool; none when every bond of it is banned), DIY pieces in that player's shop rolls and reward offers once the 调度中心 reaches the slot's level, battleInput diy, m.private.diy / diyBanned, prep scouting and results name the operator, 信标 never sends a 自选 piece to a teammate [ASSUMED]

The owner's decisions of 2026-10-05 (picks, slots, shop per player, bans); research 0.2.0 §2. Golden unchanged (no scenario slots a DIY pick).
Tests: test/match/diy-shop.test.js (9), test/lobby-diy.test.js (4).
This commit is contained in:
sganggs committed 2026-10-05 23:35:01 +08:00
1 parent 742f478526
commit 4bee542e61
26 files changed
+1026 -105

No files matched your search

+12 -6
View File
@@ -77,13 +77,16 @@ export class PlayerBasics {
/**
* The skill index / module a chess record fights with under this player's loadout (DESIGN §16) — for a chess this
* player fields as its stand-in (0.2.0 补位) the stand-in's backup selection, whatever the loadout says.
* player fields as its stand-in (0.2.0 补位) the stand-in's backup selection, whatever the loadout says; for a slotted
* 自选 slot (0.2.0, player/diy.js) its pick's skill and module (the composed record's defaults — the loadout never names
* a DIY slot: shared/protocol.js checkLoadout).
*/
loadoutFor(chessRecord) {
if (this.fieldsStandIn(chessRecord)) {
return resolveLoadout(null, this.gd.standIn(chessRecord.chessId), (id) => this.gd.standIn(id) || this.gd.chess(id));
}
return resolveLoadout(this.loadout, chessRecord, (id) => this.gd.chess(id));
const rec = chessRecord && chessRecord.isDiy && typeof chessRecord.chessId === 'string' ? this.gd.chess(chessRecord.chessId) || chessRecord : chessRecord;
return resolveLoadout(this.loadout, rec, (id) => this.gd.chess(id));
}
/**
@@ -119,13 +122,16 @@ export class PlayerBasics {
/**
* The record this player's piece of chess record `rec` fights with (0.2.0 补位): the stand-in record
* (gd.standIn — the chess's identity, the stand-in's body) when the player fields its stand-in, else `rec` itself.
* Rules about the unit's body read it (placement class, summon / bot ranges, the scouting art); rules about the chess
* (price, bonds, 特质, merges, pools) keep reading gd.chess.
* (gd.standIn — the chess's identity, the stand-in's body) when the player fields its stand-in; for a DIY slot record
* the player's 自选 record of that slot (this.gd — a caller holding the match's own record of the slot gets the
* operator); else `rec` itself. Rules about the unit's body read it (placement class, summon / bot ranges, the
* scouting art); rules about the chess (price, bonds, 特质, merges, pools) keep reading gd.chess.
* @param {object|null} rec
*/
fieldRecord(rec) {
return rec && this.fieldsStandIn(rec) ? this.gd.standIn(rec.chessId) || rec : rec;
if (rec && this.fieldsStandIn(rec)) return this.gd.standIn(rec.chessId) || rec;
if (rec && rec.isDiy && !rec.diyFor && typeof rec.chessId === 'string') return this.gd.chess(rec.chessId) || rec;
return rec;
}
/**