// 干员持有 (operator ownership, 0.2.0 补位 — the approved plan, owner's decision 2026-10-05): the second tab of the
// 干员调配 overlay (screens/loadout.js). The 53 NORMAL chess of this season's shop, grouped by tier — each card shows the
// operator and its official stand-in (avatar, name, the skill it fields) and switches between 持有 and 未持有 with a
// tap. A chess marked 未持有 is shown as its stand-in in the match — shop and reward cards, hand, board, detail card,
// result (portrait, name, model, skills, talents, range; a small 「替补」 mark — the owner's recall of the official mode,
// 2026-10-06) — while its bonds, 特质, tier, price and merge stay the chess's. PRESET chess always field their own
// operator and are not listed.
// Default: everything owned; 全部持有 resets. Out of match: the next match takes the list (in co-op it only affects the
// player's own pieces). The list lives in ui/loadoutSync.js (localStorage + room.ownership); the model is
// ui/ownershipModel.js. Styles: css/screens/loadout.css (own-*).
import { useMemo, useState } from '../../vendor/hooks.module.js';
import { html, TierChip, Icon } from '../ui/components.js';
import { Img } from '../ui/gameComponents.js';
import { chessAvatarUrl } from '../ui/assetUrls.js';
import { data } from '../data.js';
import { PROF_NAME } from '../ui/loadoutModel.js';
import { ownershipRoster, rosterByTier, isOwned, standInSummary } from '../ui/ownershipModel.js';
import { t, tParts } from '../../../shared/i18n.js';
const cx = (...p) => p.flat().filter(Boolean).join(' ');
const ROMAN = ['', 'I', 'II', 'III', 'IV', 'V', 'VI'];
/** The roster of the tab (data.list('chess'), memoised on the data being ready). */
export function useOwnershipRoster(ready) {
return useMemo(() => ownershipRoster(data.list('chess')), [ready, data.locale()]);
}
/** One chess: the operator → its stand-in, and the 持有 switch (the whole card is the switch). */
export function OwnCard({ m, chess, backups, owned, onToggle }) {
const si = standInSummary(chess, backups);
const skill = si?.skill;
const slot = skill && Number.isInteger(skill.index) ? `S${skill.index + 1}` : '';
const label = owned ? t('{name}:持有', { name: chess.name }) : t('{name}:未持有,由 {standIn} 上场', { name: chess.name, standIn: si?.name || t('替补干员') });
return html``;
}
/**
* The tab's body.
* @param {{ m: any, roster: any[], notOwned: string[], onToggle: (chessId: string, owned: boolean) => void }} props
*/
export function OwnershipPanel({ m, roster, notOwned, onToggle }) {
const [offOnly, setOffOnly] = useState(false);
const backups = data.get('backups');
const list = offOnly ? roster.filter((c) => !isOwned(notOwned, c.chessId)) : roster;
const groups = rosterByTier(list);
return html`