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:
1 parent
742f478526
commit
4bee542e61
26 files changed
+1026
-105
No files matched your search
+20
-10
@@ -12,7 +12,9 @@
|
||||
//
|
||||
// Rolls: each chess slot draws ONE copy uniformly from all remaining copies of eligible chess with tier ≤ shop level
|
||||
// ("copy-weighted"; duplicates within a roll allowed). The item slot picks a tier with the same tier shares, then a
|
||||
// uniform shop-eligible item of that tier (falling back to lower tiers).
|
||||
// uniform shop-eligible item of that tier (falling back to lower tiers). A roll may add entries outside the pool
|
||||
// (`extra`, after its own): one player's 自选 stock (0.2.0, player/diy.js diyRollEntries) — weighted by its copies like
|
||||
// any chess, drawn by that player's shop only.
|
||||
|
||||
/**
|
||||
* Per-match disabled bond set D and banned chess (research 01 A2): D = uniform sample of `core` core bonds and `addon`
|
||||
@@ -90,22 +92,30 @@ export class SharedPool {
|
||||
return k;
|
||||
}
|
||||
|
||||
/** Remaining copies of eligible chess (tier ≤ maxTier, or exactly `tier`). */
|
||||
_eligible({ maxTier = 6, tier = null, filter = null } = {}) {
|
||||
/**
|
||||
* Remaining copies of eligible chess (tier ≤ maxTier, or exactly `tier`): the pool's entries, then `extra` ([id, entry]
|
||||
* pairs of the same shape — a player's 自选 stock) under the same filters.
|
||||
*/
|
||||
_eligible({ maxTier = 6, tier = null, filter = null, extra = null } = {}) {
|
||||
const out = [];
|
||||
for (const [id, e] of this.entries) {
|
||||
if (e.left <= 0) continue;
|
||||
if (tier != null ? e.tier !== tier : e.tier > maxTier) continue;
|
||||
if (filter && !filter(id, e)) continue;
|
||||
out.push([id, e.left]);
|
||||
}
|
||||
const scan = (list) => {
|
||||
for (const [id, e] of list) {
|
||||
if (e.left <= 0) continue;
|
||||
if (tier != null ? e.tier !== tier : e.tier > maxTier) continue;
|
||||
if (filter && !filter(id, e)) continue;
|
||||
out.push([id, e.left]);
|
||||
}
|
||||
};
|
||||
scan(this.entries);
|
||||
if (extra) scan(extra);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy-weighted roll: one copy uniformly among remaining copies of eligible chess. Returns a base id or null.
|
||||
* @param {Function} rng
|
||||
* @param {{ maxTier?: number, tier?: number|null, filter?: (id: string, e: object) => boolean }} [opts]
|
||||
* @param {{ maxTier?: number, tier?: number|null, filter?: (id: string, e: object) => boolean,
|
||||
* extra?: Iterable<[string, { left: number, tier: number }]>|null }} [opts]
|
||||
*/
|
||||
roll(rng, opts = {}) {
|
||||
const el = this._eligible(opts);
|
||||
|
||||
Reference in new issue
Block a user