You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
3.7 KiB
113 lines
3.7 KiB
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;
|
|
}
|
|
}
|
|
|