// 机变 draft overlay (research 06 §4.4 / §11.5): family title | description, "倒计时结束后仍未选定将自动分配", // whose turn ("当前轮到你决策" / "{name} 正在决策…") with countdown, pick order with ✓ / ⌛ / … / door, // and a 3×2 grid (solo: 3 cards) of cards with icon, title, rich description, tier chip and the taker's // avatar badge. Clicking an available card on your turn sends g.choice. import { html, Icon, TierChip, Countdown, MicroLabel, Spinner } from './components.js'; import { Img, RichText, PlayerAvatar, GIcon } from './gameComponents.js'; import { itemIconUrl, enemyIconUrl, uiUrl } from './assetUrls.js'; import { richTextPlain } from './richText.js'; import { sortedPlayers } from './gameLogic.js'; import { data } from '../data.js'; const cx = (...p) => p.flat().filter(Boolean).join(' '); /** * Resolve an sp card to display fields. * @param {any} card normalised card ({ idx, takenBy, effectId?, itemId?, id?, name?, desc?, descRaw?, tier?, team?, enemyKey? }) * @param {string|null} family 'bounty'|'supply'|'shop'|'tactic' */ export function resolveSpCard(card, family) { const choices = data.get('choices'); const byEffect = (list, id) => (Array.isArray(list) && id ? list.find((x) => x && x.effectId === id) : null); const effectId = card.effectId || (!card.itemId && typeof card.id === 'string' && data.lookup('effects', card.id) ? card.id : null); const eff = effectId ? data.lookup('effects', effectId) : null; const itemId = card.itemId || (!effectId && typeof card.id === 'string' && data.lookup('items', card.id) ? card.id : null); const item = itemId ? data.lookup('items', itemId) : null; const bounty = byEffect(choices?.cards?.bounty, effectId); const tactic = byEffect(choices?.cards?.tactic, effectId); const m = data.get('assets'); const kind = card.kind === 'item' || item ? 'item' : card.kind === 'bounty' || bounty || family === 'bounty' ? 'bounty' : 'tactic'; const enemyKey = card.enemyKey || bounty?.enemyKey || eff?.params?.enemy_id || null; const team = card.team ?? tactic?.team ?? (eff?.decoIconId === 'icon_team_buff'); let icon = null; if (item) icon = itemIconUrl(m, item); else if (kind === 'bounty' && enemyKey) icon = enemyIconUrl(m, enemyKey); else if ((card.tacticKind || tactic?.kind) === 'terrain') icon = uiUrl(m, 'buffIcon/icon_stage_buff'); else if ((card.tacticKind || tactic?.kind) === 'enemyDebuff') icon = uiUrl(m, 'buffIcon/icon_enemy_debuff'); else icon = uiUrl(m, `buffIcon/${team ? 'icon_team_buff' : 'icon_player_buff'}`); return { kind, name: card.name || item?.name || eff?.name || bounty?.name || tactic?.name || '机变', desc: card.descRaw || card.desc || item?.descRaw || item?.desc || eff?.descRaw || eff?.desc || bounty?.desc || tactic?.desc || '', tier: Number.isFinite(card.tier) ? card.tier : item?.tier ?? bounty?.tier ?? null, icon, team: !!team, coin: card.coin ?? bounty?.coin ?? eff?.enemyPrice ?? null, }; } /** * @param {{ pub:any, sp:any, myId:string, solo:boolean, onPick:(idx:number)=>void, busyIdx?:number|null, total?:number|null }} props */ export function ChoiceOverlay({ pub, sp, myId, solo, onPick, busyIdx = null, total = null }) { if (!sp) return null; const fam = data.get('choices')?.families?.[sp.family] || null; const players = new Map(sortedPlayers(pub).map((p) => [p.playerId, p])); const myTurn = solo || sp.turnPid === myId; const mine = sp.pickOf.get(myId); const turnName = players.get(sp.turnPid)?.name || '队友'; const special = /_s$/.test(String(sp.family || '')); const order = solo ? [] : sp.order; return html`
倒计时结束后仍未选定将自动分配
` : html`选择一项(无时间限制)
`}