feedback1 integrate: WK bond popup and card chips include 变形同构体 wearers

# Conflicts:
#	docs/SIM.md
#	public/js/ui/bondStrip.js
#	public/js/ui/detailPanel.js
#	server/sim/snapshot.js
This commit is contained in:
sganggs committed 2026-10-03 06:56:27 +08:00
commit ff0f8d0211
15 files changed
+526 -45

No files matched your search

+16 -10
View File
@@ -1,8 +1,10 @@
// Bond strip (active-bond discs under the top bar) and the bond detail popup: the key facts first (user playtest #2
// item 9: name, members in play / next threshold, layers, reached tier and its threshold row, the current effect with
// layer-resolved numbers), then the full description and the member list with owned / on-board state (a bond the
// mode never activates says 本局禁用 — gameLogic modeOffBonds). Opened from
// the detail panel's bond chips it docks beside that panel (`beside`: the panel's side).
// layer-resolved numbers), then the full description and the member list with owned / on-board state — operators that
// are members through 变形同构体 included (tagged 同构, gameLogic bondMembers; such a row opens the wearer's card with its
// items: the pair and the granted chip), so the list's count agrees with 在场 (a bond the mode never activates says
// 本局禁用 — gameLogic modeOffBonds). Opened from the detail panel's bond chips it docks beside that panel (`beside`: the
// panel's side).
// Research 06 §11.1: round mint discs, stack count over the disc, name below, sorted by stacks; grey =
// present but inactive; in 联防 / boss rounds the strip is dimmed ("层数叠加已禁用").
// Watching a teammate (DESIGN §20.15, ui/watchBonds.js) the strip and the popup show THAT player's bonds and layers:
@@ -59,12 +61,14 @@ export function BondStrip({ bonds, layersDisabled = false, onOpen, openId = null
/**
* Bond detail popup.
* @param {{ bondId: string, entry?: any, priv?: any, banned?: string[], onClose: Function, onMember?: (chessId:string)=>void,
* @param {{ bondId: string, entry?: any, priv?: any, banned?: string[], onClose: Function,
* onMember?: (chessId:string, items?:string[]|null)=>void,
* place?: 'left'|'beside'|'besideR'|'right'|null, over?: boolean, beside?: 'left'|'right'|null, owner?: string|null, off?: boolean }} props —
* `place`: where it opens (gameLogic bondPopupPlace; `beside: 'left'` = the older spelling of 'beside'); `over`: above the
* detail card; `owner`: the watched teammate's name (`entry` / `priv` are then theirs: ui/watchBonds.js); `off`: the mode
* never activates this bond (gameLogic modeOffBonds — 标准's 10 inactive bonds): 本局禁用 instead of 未激活, with a note, no
* 在场 count and no 当前效果 block (its numbers would promise an effect the mode never gives; the bond text stays)
* detail card; `owner`: the watched teammate's name (`entry` / `priv` are then theirs: ui/watchBonds.js); `onMember`
* gets a 变形同构体 row's item ids too (its card shows the pair and the granted chip), null for a plain member; `off`: the
* mode never activates this bond (gameLogic modeOffBonds — 标准's 10 inactive bonds): 本局禁用 instead of 未激活, with a
* note, no 在场 count and no 当前效果 block (its numbers would promise an effect the mode never gives; the bond text stays)
*/
export function BondPopup({ bondId, entry, priv, banned = [], onClose, onMember, place = null, over = false, beside = null, owner = null, off = false }) {
const b = data.lookup('bonds', bondId);
@@ -74,7 +78,7 @@ export function BondPopup({ bondId, entry, priv, banned = [], onClose, onMember,
const th = Array.isArray(entry?.thresholds) && entry.thresholds.length ? entry.thresholds : b.thresholds || [];
const tier = off ? 0 : entry?.tier ?? bondTier(count, th, b.maxCount);
const active = !off && (entry ? !!entry.active : tier > 0);
const members = bondMembers(b, priv, banned, (id) => data.lookup('chess', id));
const members = bondMembers(b, priv, banned, (id) => data.lookup('chess', id), (id) => data.lookup('items', id));
const countsHand = entry?.countsHand ?? b.countsHand;
const next = nextThreshold(count, th);
const hasNow = !off && !!(b.effectDescRaw || b.effectDesc);
@@ -110,11 +114,13 @@ export function BondPopup({ bondId, entry, priv, banned = [], onClose, onMember,
<section class="bpop__sec">
<h4>成员 <small>${members.filter((x) => x.onBoard).length}/${members.length}</small></h4>
<div class="bpop__members">
${members.map((mb) => html`<button key=${mb.id} type="button" class=${cx('bpop__member', mb.onBoard && 'is-on', mb.owned && !mb.onBoard && 'is-owned', mb.banned && 'is-banned')}
onClick=${() => onMember?.(mb.id)} title=${`${mb.name}${mb.banned ? '(本局禁用)' : mb.onBoard ? '(在场)' : mb.owned ? '(整备区)' : ''}`}>
${members.map((mb) => html`<button key=${mb.id} type="button" class=${cx('bpop__member', mb.onBoard && 'is-on', mb.owned && !mb.onBoard && 'is-owned', mb.banned && 'is-banned', mb.granted && 'is-granted')}
onClick=${() => onMember?.(mb.id, mb.granted && Array.isArray(mb.items) ? mb.items : null)} data-granted=${mb.granted ? '1' : null}
title=${`${mb.name}${mb.granted ? '(变形同构体:视为本盟约成员)' : ''}${mb.banned ? '(本局禁用)' : mb.onBoard ? '(在场)' : mb.owned ? '(整备区)' : ''}`}>
<${UnitThumb} kind="chess" id=${mb.id} size="sm" dim=${!mb.owned || mb.banned} />
<span class="bpop__mname">${mb.name}</span>
${mb.banned ? html`<span class="bpop__ban"><${Icon} name="close" /></span>` : null}
${mb.granted ? html`<span class="bpop__iso" aria-hidden="true">同构</span>` : null}
</button>`)}
</div>
</section>