feedback5 WE2: effects, reward pools and 机变 cards that grant a random operator also draw the player's 自选 pieces (#9)
「自选干员放入后模拟中的补给池随机范围也将被相应扩大」: player/diy.js diyStockEntries (every slotted piece with copies left; the roll's own tier rules, no 调度中心 gate) joins effectsMeta ctx.rollChess / ctx.rollPool (spDraft rollPool extra + chessOf: bonds through the player's view) and the 驰援 fallback in choices.js. Granted from the player's own stock (poolOf). Docs: META, PLAYING. Golden: no scenario moved.
This commit is contained in:
1 parent
7a3d53faf6
commit
7b83028139
7 files changed
+124
-11
No files matched your search
@@ -482,9 +482,13 @@ function applyDefault(m, ps, card) {
|
||||
handled = true;
|
||||
break;
|
||||
case 'single_special_choice_gain_bond_chess': {
|
||||
// the player's 自选 stock joins the draw, its bonds read through the player's view (player/diy.js diyStockEntries)
|
||||
const pgd = ps.gd || gd;
|
||||
const hasBond = (cid) => { const c = pgd.chess(cid); return !!(c && Array.isArray(c.bonds) && c.bonds.includes(bs.bond)); };
|
||||
for (let i = 0; i < count; i++) {
|
||||
const id = m.pool.roll(m.rngMeta, { maxTier: Math.max(1, ps.shop.level), filter: (cid) => { const c = gd.chess(cid); return !!(c && Array.isArray(c.bonds) && c.bonds.includes(bs.bond)); } })
|
||||
|| m.pool.roll(m.rngMeta, { maxTier: 6, filter: (cid) => { const c = gd.chess(cid); return !!(c && Array.isArray(c.bonds) && c.bonds.includes(bs.bond)); } });
|
||||
const extra = typeof ps.diyStockEntries === 'function' ? ps.diyStockEntries() : null;
|
||||
const id = m.pool.roll(m.rngMeta, { maxTier: Math.max(1, ps.shop.level), filter: hasBond, extra })
|
||||
|| m.pool.roll(m.rngMeta, { maxTier: 6, filter: hasBond, extra });
|
||||
if (id) ps.acquireChess(id, { source: 'choice' });
|
||||
}
|
||||
handled = true;
|
||||
|
||||
@@ -544,20 +544,30 @@ export function makeCtx(m, ps, source, hook, ev = null) {
|
||||
});
|
||||
return p ? view(p) : null;
|
||||
},
|
||||
/** Random chess id from the shared pool (copy-weighted). opts: { maxTier, tier, bond, filter(id) } */
|
||||
/**
|
||||
* Random chess id from the shared pool (copy-weighted) — and the player's own 自选 stock (player/diy.js
|
||||
* diyStockEntries, 0.2.0: 「自选干员放入后模拟中的补给池随机范围也将被相应扩大」). opts: { maxTier, tier, bond, filter(id) };
|
||||
* bonds are read through the player's data view (a slotted slot: its operator's).
|
||||
*/
|
||||
rollChess: (opts = {}) => {
|
||||
const f = (id) => {
|
||||
if (opts.bond) { const c = gd.chess(id); if (!c || !Array.isArray(c.bonds) || !c.bonds.includes(opts.bond)) return false; }
|
||||
return typeof opts.filter === 'function' ? !!opts.filter(id) : true;
|
||||
};
|
||||
return m.pool.roll(m.rngMeta, { maxTier: Number.isInteger(opts.maxTier) ? opts.maxTier : 6, tier: Number.isInteger(opts.tier) ? opts.tier : null, filter: f });
|
||||
const extra = typeof ps.diyStockEntries === 'function' ? ps.diyStockEntries() : null;
|
||||
return m.pool.roll(m.rngMeta, { maxTier: Number.isInteger(opts.maxTier) ? opts.maxTier : 6, tier: Number.isInteger(opts.tier) ? opts.tier : null, filter: f, extra });
|
||||
},
|
||||
rollItem: (opts = {}) => m.rollItemId(opts),
|
||||
/**
|
||||
* Roll a choices.json pool: equip pools → { kind: 'item', id }; chess pools (items / weighted / shopEligible with
|
||||
* tier, minTier, bond, golden) → { kind: 'chess', id, golden } (a pool chess needs a free copy). null when empty.
|
||||
*/
|
||||
rollPool: (poolId, opts = {}) => m.rollPool(poolId, { shopLevel: ps.shop.level, ...opts }),
|
||||
rollPool: (poolId, opts = {}) => m.rollPool(poolId, {
|
||||
shopLevel: ps.shop.level,
|
||||
// a shared-pool draw also takes the player's 自选 stock, its bonds read through the player's view (rollChess)
|
||||
extra: typeof ps.diyStockEntries === 'function' ? ps.diyStockEntries() : null, chessOf: (id) => gd.chess(id),
|
||||
...opts,
|
||||
}),
|
||||
/**
|
||||
* Run another owned chess's 特质 of `eventType` now (SERVER_GAIN / SERVER_PREP_START / SERVER_PREP_FIN /
|
||||
* SERVER_CHESS_SOLD / SERVER_REFRESH_SHOP). opts.asUid: run them as if they belonged to that piece. Returns the
|
||||
|
||||
@@ -152,9 +152,11 @@ export class MatchSpDraft {
|
||||
* Roll a choices.json pool (ctx.rollPool). Equip pools → rollItemId. Chess pools: an `items` (uniform) or `weighted`
|
||||
* list — only chess with a free pool copy (or outside the pool) qualify — else a copy-weighted draw from the shared
|
||||
* pool filtered by `tier` / `minTier` / `maxTier` (number or 'shopLevel') / `bond`; `golden: true` yields the elite id.
|
||||
* `extra` (the drawing player's 自选 stock, player/diy.js diyStockEntries) joins that shared-pool draw, `chessOf` reads the
|
||||
* bonds (the player's data view: a slotted slot's operator) — 0.2.0 WE2.
|
||||
* @returns {{ kind: 'item'|'chess', id: string, golden?: boolean } | null}
|
||||
*/
|
||||
rollPool(poolId, { shopLevel = 6 } = {}) {
|
||||
rollPool(poolId, { shopLevel = 6, extra = null, chessOf = null } = {}) {
|
||||
const pools = this.gd.choices.pools && typeof this.gd.choices.pools === 'object' ? this.gd.choices.pools : {};
|
||||
const p = typeof poolId === 'string' && Object.hasOwn(pools, poolId) ? pools[poolId] : null;
|
||||
if (!p || typeof p !== 'object') return null;
|
||||
@@ -181,10 +183,12 @@ export class MatchSpDraft {
|
||||
const maxTier = p.maxTier === 'shopLevel' ? lvl : Number.isInteger(p.maxTier) ? p.maxTier : 6;
|
||||
const minTier = Number.isInteger(p.minTier) ? p.minTier : 1;
|
||||
const bond = typeof p.bond === 'string' ? p.bond : null;
|
||||
const recOf = typeof chessOf === 'function' ? chessOf : (cid) => this.gd.chess(cid);
|
||||
id = this.pool.roll(rng, {
|
||||
tier: Number.isInteger(p.tier) ? p.tier : null,
|
||||
maxTier,
|
||||
filter: (cid, e) => e.tier >= minTier && (!bond || (Array.isArray(this.gd.chess(cid)?.bonds) && this.gd.chess(cid).bonds.includes(bond))),
|
||||
filter: (cid, e) => e.tier >= minTier && (!bond || (Array.isArray(recOf(cid)?.bonds) && recOf(cid).bonds.includes(bond))),
|
||||
extra,
|
||||
});
|
||||
}
|
||||
if (!id) return null;
|
||||
|
||||
@@ -25,7 +25,11 @@
|
||||
// shop's chess slots and the reward offers' temporary refreshes [ASSUMED] — weighted like any chess of its tier, once
|
||||
// the 调度中心 has reached the slot's shopLevel (activity_table shopLevelDisplayDataDict lists the tier-5 slots at
|
||||
// level 5 and the tier-6 slots at level 6; PRTS 帮助 "仅在调度中心等级 ≥ 干员所在等阶"). The price is the slot's (any
|
||||
// chess of its tier: 4). Effects that grant a random operator from the shared pool never draw it.
|
||||
// chess of its tier: 4).
|
||||
// * random grants (diyStockEntries, 0.2.0 WE2 #9): an effect, reward or 机变 card that grants this player a random
|
||||
// operator from the pool draws its stock too — 「自选干员放入后模拟中的补给池随机范围也将被相应扩大」 (bilibili), "调度中心
|
||||
// 随机资源的范围将被扩大" (PRTS 新手教程) — under the roll's own tier rules (the effect's tier / maxTier: no 调度中心 gate,
|
||||
// as for a preset chess) and filters (bonds read through the player's data view).
|
||||
// Installed on PlayerState.prototype by server/match/PlayerState.js (a method container: never instantiated; `this` is
|
||||
// the player state).
|
||||
|
||||
@@ -204,6 +208,17 @@ export class PlayerDiy {
|
||||
return out.length ? out : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The stock entries a random grant of this player draws besides the shared pool (see the header): every slotted piece
|
||||
* with copies left, whatever the 调度中心 level (the roll's own tier rules apply), or null (none).
|
||||
* @returns {Array<[string, { cap: number, left: number, tier: number, shopLevel: number }]> | null}
|
||||
*/
|
||||
diyStockEntries() {
|
||||
if (!this.diyStock || !this.diyStock.entries.size) return null;
|
||||
const out = [...this.diyStock.entries].filter(([, e]) => e.left > 0);
|
||||
return out.length ? out : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The 自选 pick a chess id (normal or elite) of this player fields — its slot's — or null (not a slotted slot).
|
||||
* @param {string} id
|
||||
|
||||
Reference in new issue
Block a user