Watching a teammate shows their hand, 临时整备区, equipment, strategy and effects (#129)
The prep scout of another player's board carries their 整备区 hand and 临时整备区 as units on the bench rows (like the own prep bench), the equipped items of their operators, their strategy in the drawer and their effects column (the official mode shows a teammate's hand too). The scout signature includes the hand / temp slots, so a moved card refreshes the watcher. Closes #128. Contributed by @2321Robin.
This commit is contained in:
1 parent
bd892a4dd6
commit
bce182703b
15 files changed
+521
-20
No files matched your search
@@ -629,6 +629,8 @@ export function resolveDetail(target, pieces) {
|
||||
const u = target.unit || {};
|
||||
const own = Number.isInteger(u.uid) ? pieces?.get(u.uid) : null;
|
||||
if (u.side === 'enemy') { const en = data.lookup('enemies', u.defId); return en ? { type: 'enemy', enemy: en, unitId: u.id } : null; }
|
||||
// a hand item on a scouted prep board (m.field units, kind 'item'): the item's own card
|
||||
if (u.kind === 'item') { const it = data.lookup('items', u.defId); return it ? { type: 'item', item: it } : null; }
|
||||
const c = data.lookup('chess', u.defId);
|
||||
if (c) return { type: 'chess', chess: c, piece: own?.piece || null, unitId: u.id, unitItems: Array.isArray(u.items) ? u.items : null };
|
||||
const t = data.lookup('tokens', u.defId);
|
||||
|
||||
@@ -59,19 +59,20 @@ function EnemiesTab({ pub, priv, onEnemy }) {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function InfoTab({ pub, priv, onChess }) {
|
||||
function InfoTab({ pub, priv, onChess, bandId = null, bandOwner = null }) {
|
||||
const { bonds, banned, perBond, stateOf } = matchInfoModel(pub, {
|
||||
bonds: data.list('bonds'), chess: (id) => data.lookup('chess', id), mode: data.get('config')?.modes?.[pub?.modeId],
|
||||
});
|
||||
const disabled = new Set(bonds.filter((b) => stateOf(b.bondId)).map((b) => b.bondId));
|
||||
const band = priv?.bandId ? data.lookup('bands', priv.bandId) : null;
|
||||
// while scouting a teammate's prep board the drawer shows THEIR 策略 in place of one's own (user playtest #2 item 2)
|
||||
const band = (bandId || priv?.bandId) ? data.lookup('bands', bandId || priv.bandId) : null;
|
||||
const stage = pub?.stageId ? data.lookup('stages', pub.stageId) : null;
|
||||
const withBans = bonds.filter((b) => disabled.has(b.bondId) || (perBond.get(b.bondId) || 0) > 0)
|
||||
.sort((a, b) => (disabled.has(b.bondId) - disabled.has(a.bondId)) || ((perBond.get(b.bondId) || 0) - (perBond.get(a.bondId) || 0)));
|
||||
return html`<div class="edrawer__body">
|
||||
${band ? html`<div class="iband">
|
||||
<${BandIcon} bandId=${band.bandId} size="md" />
|
||||
<div><${MicroLabel} tone="mint">STRATEGY // 我的策略</${MicroLabel}><b>${band.name} <small class="t-lo">${band.effectName}</small></b>
|
||||
<div><${MicroLabel} tone="mint">STRATEGY // ${bandOwner ? `${bandOwner} 的策略` : '我的策略'}</${MicroLabel}><b>${band.name} <small class="t-lo">${band.effectName}</small></b>
|
||||
<${RichText} text=${band.descRaw || band.desc} class="iband__desc" /></div>
|
||||
</div>` : null}
|
||||
${stage ? html`<p class="istage"><${Icon} name="rook" />战场:<b>${stage.name || stage.id}</b></p>` : null}
|
||||
@@ -88,14 +89,17 @@ function InfoTab({ pub, priv, onChess }) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ tab:'enemies'|'info', onTab:(t:string)=>void, pub:any, priv:any, onClose:Function, onEnemy:(key:string, count:number)=>void, onChess:(id:string)=>void }} props
|
||||
* @param {{ tab:'enemies'|'info', onTab:(t:string)=>void, pub:any, priv:any, onClose:Function, onEnemy:(key:string, count:number)=>void, onChess:(id:string)=>void,
|
||||
* bandId?: string|null, bandOwner?: string|null }} props
|
||||
* bandId / bandOwner: while scouting a teammate's prep board, the watched player's 策略 (m.public players[].bandId)
|
||||
* replaces one's own in the 本局信息 tab (game.js scoutBandId; user playtest #2 item 2)
|
||||
*/
|
||||
export function EnemyDrawer({ tab, onTab, pub, priv, onClose, onEnemy, onChess }) {
|
||||
export function EnemyDrawer({ tab, onTab, pub, priv, onClose, onEnemy, onChess, bandId = null, bandOwner = null }) {
|
||||
return html`<div class="edrawer brackets" role="dialog" aria-label=${tab === 'info' ? '本局信息' : '敌方情报'}>
|
||||
<div class="edrawer__top">
|
||||
<${Tabs} size="sm" value=${tab} onChange=${onTab} items=${[{ id: 'info', label: '本局信息' }, { id: 'enemies', label: '敌方情报' }]} />
|
||||
<button type="button" class="edrawer__close tapx" aria-label="关闭" onClick=${onClose}><${Icon} name="close" /></button>
|
||||
</div>
|
||||
${tab === 'info' ? html`<${InfoTab} pub=${pub} priv=${priv} onChess=${onChess} />` : html`<${EnemiesTab} pub=${pub} priv=${priv} onEnemy=${onEnemy} />`}
|
||||
${tab === 'info' ? html`<${InfoTab} pub=${pub} priv=${priv} onChess=${onChess} bandId=${bandId} bandOwner=${bandOwner} />` : html`<${EnemiesTab} pub=${pub} priv=${priv} onEnemy=${onEnemy} />`}
|
||||
</div>`;
|
||||
}
|
||||
@@ -150,6 +150,13 @@ export function boardTileOf(field, r, c) {
|
||||
return [r - BOSS_ROW_SHIFT, field === 'bossR' ? MAX_COL - c : c];
|
||||
}
|
||||
|
||||
/** The band (策略) a player picked, from m.public.players[].bandId (Match.js marksPublic) — the detail card shows it
|
||||
* on a teammate's unit (user playtest #2 item 2: watching a teammate revealed nothing about their 策略). */
|
||||
export function ownerBandId(pub, ownerId) {
|
||||
const p = Array.isArray(pub?.players) ? pub.players.find((x) => x && x.playerId === ownerId) : null;
|
||||
return typeof p?.bandId === 'string' && p.bandId ? p.bandId : null;
|
||||
}
|
||||
|
||||
/** Banner shown when a phase starts: { title, sub?, tone } or null. */
|
||||
export function phaseBanner(phase, pub) {
|
||||
const r = int(pub?.round, 0);
|
||||
|
||||
Reference in new issue
Block a user