import { instantiate, Layout, Node } from 'cc'; import { isElementGlyphType, type MapTileBoard, type MapTileRecord } from 'db://assets/mx/module/merge'; import type { MapManager } from '../map/legacy/MapManager'; import { WeaponComposeConfigProvider } from '../bag/WeaponComposeConfigProvider'; import { TextGrid } from './TextGrid'; import { buildTextGridEntityData } from '../combat/TowerQueryService'; interface PlacedTextEntry { gridIndex: number; tile: MapTileRecord; } /** * 战斗阶段左侧「已放置文字」列表(ui_haveTextList) * 以 ui_haveTextList 的第一个子节点为模版克隆展示。 */ export class CombatHaveTextListView { private _root: Node | null = null; private _template: Node | null = null; private _items: Node[] = []; bind(root: Node): void { this.unbind(); this._root = root; this._template = root.children[0] ?? null; if (this._template) { this._template.active = false; } this._ensureLayout(); } unbind(): void { this._clearItems(); this._root = null; this._template = null; } /** 根据当前地图字块刷新列表 */ refresh(map: MapManager, board: MapTileBoard | null): void { this._clearItems(); if (!this._root?.isValid || !this._template?.isValid || !board) return; WeaponComposeConfigProvider.instance.load(); const entries = this._collectTextTiles(map, board); for (const entry of entries) { const item = instantiate(this._template); item.parent = this._root; item.active = true; this._applyTile(item, entry); this._items.push(item); } this._root.getComponent(Layout)?.updateLayout(); } setVisible(visible: boolean): void { if (this._root?.isValid) { this._root.active = visible; } } private _collectTextTiles(map: MapManager, board: MapTileBoard): PlacedTextEntry[] { const entries: PlacedTextEntry[] = []; board.forEachTile((gridIndex, tile) => { const type = WeaponComposeConfigProvider.instance.getWeapon2Type(tile.weapon2Id); if (!isElementGlyphType(type)) return; entries.push({ gridIndex, tile }); }); entries.sort((a, b) => { const ga = map.getMapGridByIndex(a.gridIndex); const gb = map.getMapGridByIndex(b.gridIndex); if (!ga || !gb) return a.gridIndex - b.gridIndex; if (ga.Row !== gb.Row) return ga.Row - gb.Row; return ga.Col - gb.Col; }); return entries; } private _applyTile(item: Node, entry: PlacedTextEntry): void { const textNode = item.getChildByName('textGrid') ?? item.children[0]; if (!textNode?.isValid) return; const comp = textNode.getComponent(TextGrid) ?? textNode.addComponent(TextGrid); const { tile, gridIndex } = entry; const entity = buildTextGridEntityData( { kind: 'map', gridIndex }, tile, { player: gg.game.localPlayer }, ); if (!entity) return; comp.setData(entity); comp.enableDrag(false); } private _ensureLayout(): void { if (!this._root?.isValid) return; let layout = this._root.getComponent(Layout); if (!layout) { layout = this._root.addComponent(Layout); layout.type = Layout.Type.HORIZONTAL; layout.resizeMode = Layout.ResizeMode.CONTAINER; layout.spacingX = 8; } } private _clearItems(): void { for (const item of this._items) { if (item?.isValid) item.destroy(); } this._items.length = 0; } }