// Briefing — INFO_CHECK "1/2 确认本局信息" (research 06 §4.1, D1): enemy leader (silhouette, name, // abilities), stage (+ its pool: 战场固定 / 战场随机(共N张)), 特训敌人 factions (icon, name, description), 核心盟约 / 附加盟约 rows of bond discs // (disabled bonds greyed with the banned-member badge), 本局禁用干员 avatars, difficulty tag, the ready // count x/N with person pips, the 准备就绪 button (g.infoReady) and the countdown. import { useState } from '../../vendor/hooks.module.js'; import { html, Button, Icon, MicroLabel, BondDisc, Tooltip } from '../ui/components.js'; import { useGameData, Img, UnitThumb, RichText } from '../ui/gameComponents.js'; import { StepHeader, ExitModal } from '../ui/matchChrome.js'; import { LoadoutButton } from './loadout.js'; import { actions } from '../ui/gameActions.js'; import { factionTypes, bannedPerBond, sortedPlayers, phaseTotalSeconds, disabledBondSets, briefingBondTip } from '../ui/gameLogic.js'; import { bondIconUrl, enemyIconUrl, factionIconUrl } from '../ui/assetUrls.js'; import { useStore } from '../store.js'; import { data } from '../data.js'; const cx = (...p) => p.flat().filter(Boolean).join(' '); function BondRow({ title, micro, bonds, sets, perBond }) { const m = data.get('assets'); return html`

${title}<${MicroLabel}>${micro}

${bonds.map((b) => { // greyed: the drawn set D (still activatable, roster incomplete) and the mode's static inactive bonds const state = sets.off.has(b.bondId) ? 'off' : sets.drawn.has(b.bondId) ? 'drawn' : null; const off = !!state; const bannedN = perBond.get(b.bondId) || 0; const tip = briefingBondTip(b.name, state, bannedN); return html`<${Tooltip} key=${b.bondId} text=${tip}>
0 && 'is-partial')}> <${BondDisc} name=${b.name} icon=${bondIconUrl(m, b.bondId)} active=${!off} disabled=${off} tier=${off ? 0 : (b.thresholds?.length || 1)} maxTier=${Math.max(1, b.thresholds?.length || 1)} size="md" /> ${bannedN > 0 ? html`<${Icon} name="user" />${bannedN}` : null}
`; })}
`; } /** INFO_CHECK screen. */ export function BriefingScreen() { const pub = useStore((s) => s.match.public); const myId = useStore((s) => s.me.playerId); const solo = useStore((s) => s.room?.mode === 'solo') || String(pub?.modeId || '').includes('single'); const gd = useGameData(); const [exit, setExit] = useState(false); const [busy, setBusy] = useState(false); if (!pub) return null; const players = sortedPlayers(pub); const me = players.find((p) => p.playerId === myId); const readyN = players.filter((p) => p.ready).length; const mode = gd.config?.modes?.[pub.modeId]; const sets = disabledBondSets(pub, mode?.inactiveBondIds); const bonds = gd.list('bonds').sort((a, b) => (a.bondOrder ?? 0) - (b.bondOrder ?? 0) || (a.identifier ?? 0) - (b.identifier ?? 0)); const core = bonds.filter((b) => b.isCore); const addon = bonds.filter((b) => !b.isCore); const banned = (Array.isArray(pub.bannedChess) ? pub.bannedChess : []).filter((id) => gd.chess(id)); banned.sort((a, b) => (gd.chess(a)?.tier ?? 0) - (gd.chess(b)?.tier ?? 0)); const perBond = bannedPerBond(bonds, banned); const boss = pub.bossId ? gd.boss(pub.bossId) : null; const bossEnemy = boss ? gd.enemy(boss.enemyKey) : null; const stage = pub.stageId ? gd.stage(pub.stageId) : null; // the mode's battlefield pool (config.json modes[].stages): 标准 is always 战场#01, 险境+ draw one at random const poolN = Array.isArray(mode?.stages) ? mode.stages.length : 0; const pool = poolN > 1 ? `战场随机(共${poolN}张)` : poolN === 1 ? '战场固定' : ''; const types = factionTypes(pub.factions); const factions = gd.factions?.types || {}; const m = gd.m; const ready = async () => { if (busy || me?.ready) return; setBusy(true); await actions.infoReady(); setBusy(false); }; return html`
<${StepHeader} step=${1} of=${2} title="确认本局信息" micro="BRIEFING // INFO CHECK" pub=${pub} total=${phaseTotalSeconds(pub, gd.config)} onExit=${() => setExit(true)} />
<${MicroLabel} tone="gold">ENEMY LEADER // 敌方领袖
${bossEnemy ? html`<${Img} src=${enemyIconUrl(m, boss.enemyKey)} class="brief-boss__sil" fallback=${html`?`} />` : html`?`}

${boss?.name || bossEnemy?.name || '未知领袖'}

第 ${mode?.bossRound ?? pub.lastRound ?? 14} 回合 · 最终攻势 ${Array.isArray(boss?.abilities) && boss.abilities.length ? html`
    ${boss.abilities.slice(0, 3).map((a, i) => html`
  • <${RichText} text=${a} />
  • `)}
` : null}
<${MicroLabel}>BATTLEFIELD${pool ? html`${pool}` : null} <${Icon} name="rook" />${stage?.name || pub.stageId || '—'}

特训敌人<${MicroLabel}>SPECIAL ENEMIES

${types.length ? types.map((t) => html`
<${Img} src=${factionIconUrl(m, factions[t]?.icon)} /> ${factions[t]?.name || t}${factions[t]?.desc || ''}
`) : html`

本局没有特训敌人

`}
<${BondRow} title="核心盟约" micro="CORE BONDS" bonds=${core} sets=${sets} perBond=${perBond} /> <${BondRow} title="附加盟约" micro="ADD-ON BONDS" bonds=${addon} sets=${sets} perBond=${perBond} />

灰色:部分盟约所含干员阵容不完整(仍可通过其他盟约的干员或装备激活)${sets.off.size ? ',或本模式禁用' : ''} · <${Icon} name="user" />该盟约中无法出现的干员数

本局禁用干员<${MicroLabel}>BANNED OPERATORS${banned.length}

${banned.length ? html`
${banned.map((id) => html`<${UnitThumb} key=${id} kind="chess" id=${id} size="sm" dim=${true} />`)}
` : html`

本局没有禁用干员

`}
<${ExitModal} open=${exit} onClose=${() => setExit(false)} solo=${solo} />
`; }