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.
451 lines
16 KiB
451 lines
16 KiB
|
2 days ago
|
import {
|
||
|
|
Button, Color, Label, Layout, Mask, Node, ScrollView, Sprite, UITransform, Widget,
|
||
|
|
HorizontalTextAlignment, VerticalTextAlignment, Layers, Overflow,
|
||
|
|
} from 'cc';
|
||
|
|
import { SpriteLoad } from '../../mx/components/SpriteLoad';
|
||
|
|
import type { IGmContentPanel, IGmPanelContext } from '../../mx/module/gm';
|
||
|
|
import { GmRegistry } from '../../mx/module/gm';
|
||
|
|
import { GBundle, GPath } from '../game/ConfigRes';
|
||
|
|
import { TableNames } from '../game/ConfigTableData';
|
||
|
|
import { RankDataManager } from '../manager/RankDataManager';
|
||
|
|
import { ProjectGmActions } from './ProjectGmActions';
|
||
|
|
import { GmSaveEditorPanel } from './ProjectGmSavePanel';
|
||
|
|
|
||
|
|
/** 本项目内容面板 id */
|
||
|
|
export const ProjectGmPanelId = {
|
||
|
|
itemPicker: 'itemPicker',
|
||
|
|
buffPicker: 'buffPicker',
|
||
|
|
levelPicker: 'levelPicker',
|
||
|
|
rankPicker: 'rankPicker',
|
||
|
|
saveEditor: 'saveEditor',
|
||
|
|
} as const;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* buffPicker 面板数据。
|
||
|
|
*/
|
||
|
|
export interface IGmBuffPickerData {
|
||
|
|
/** 1=主动 2=被动;0=不限 */
|
||
|
|
expectType: number;
|
||
|
|
/** 写入目标 */
|
||
|
|
mode: 'carryPassive' | 'aiActive' | 'aiPassive';
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 创建文字按钮。
|
||
|
|
*/
|
||
|
|
function makeLabelBtn(parent: Node, text: string, w: number, h: number, onClick: () => void): Node {
|
||
|
|
const n = new Node('btn');
|
||
|
|
n.layer = Layers.Enum.UI_2D;
|
||
|
|
n.addComponent(UITransform).setContentSize(w, h);
|
||
|
|
const lb = n.addComponent(Label);
|
||
|
|
lb.string = text;
|
||
|
|
lb.fontSize = 22;
|
||
|
|
lb.color = Color.WHITE;
|
||
|
|
lb.horizontalAlign = HorizontalTextAlignment.CENTER;
|
||
|
|
lb.verticalAlign = VerticalTextAlignment.CENTER;
|
||
|
|
n.addComponent(Button);
|
||
|
|
n.on(Button.EventType.CLICK, onClick, null);
|
||
|
|
parent.addChild(n);
|
||
|
|
return n;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 垂直滚动列表宿主。
|
||
|
|
*/
|
||
|
|
function makeVScroll(parent: Node, w: number, h: number): { host: Node; content: Node } {
|
||
|
|
const host = new Node('scroll');
|
||
|
|
host.layer = Layers.Enum.UI_2D;
|
||
|
|
host.addComponent(UITransform).setContentSize(w, h);
|
||
|
|
const view = new Node('view');
|
||
|
|
view.layer = Layers.Enum.UI_2D;
|
||
|
|
view.addComponent(UITransform).setContentSize(w, h);
|
||
|
|
view.addComponent(Mask);
|
||
|
|
host.addChild(view);
|
||
|
|
const content = new Node('content');
|
||
|
|
content.layer = Layers.Enum.UI_2D;
|
||
|
|
const cut = content.addComponent(UITransform);
|
||
|
|
cut.setContentSize(w, h);
|
||
|
|
cut.setAnchorPoint(0.5, 1);
|
||
|
|
content.setPosition(0, h / 2);
|
||
|
|
const layout = content.addComponent(Layout);
|
||
|
|
layout.type = Layout.Type.VERTICAL;
|
||
|
|
layout.resizeMode = Layout.ResizeMode.CONTAINER;
|
||
|
|
layout.spacingY = 4;
|
||
|
|
layout.paddingTop = 4;
|
||
|
|
view.addChild(content);
|
||
|
|
const sv = host.addComponent(ScrollView);
|
||
|
|
sv.content = content;
|
||
|
|
sv.horizontal = false;
|
||
|
|
sv.vertical = true;
|
||
|
|
parent.addChild(host);
|
||
|
|
return { host, content };
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 道具图标点选 + 数量步进。
|
||
|
|
*/
|
||
|
|
class GmItemPickerPanel implements IGmContentPanel {
|
||
|
|
private _root: Node | null = null;
|
||
|
|
private _selectedId = 0;
|
||
|
|
private _qty = 1;
|
||
|
|
private _lbSel: Label | null = null;
|
||
|
|
|
||
|
|
open(parent: Node, ctx: IGmPanelContext): void {
|
||
|
|
this.close();
|
||
|
|
const pUt = parent.getComponent(UITransform);
|
||
|
|
const W = pUt?.width || 660;
|
||
|
|
const H = pUt?.height || 900;
|
||
|
|
|
||
|
|
this._root = new Node('itemPicker');
|
||
|
|
this._root.layer = Layers.Enum.UI_2D;
|
||
|
|
this._root.addComponent(UITransform).setContentSize(W, H);
|
||
|
|
const rw = this._root.addComponent(Widget);
|
||
|
|
rw.isAlignLeft = rw.isAlignRight = rw.isAlignTop = rw.isAlignBottom = true;
|
||
|
|
rw.left = rw.right = rw.top = rw.bottom = 0;
|
||
|
|
parent.addChild(this._root);
|
||
|
|
|
||
|
|
const tip = new Node('tip');
|
||
|
|
tip.layer = Layers.Enum.UI_2D;
|
||
|
|
tip.addComponent(UITransform).setContentSize(W - 24, 40);
|
||
|
|
const tl = tip.addComponent(Label);
|
||
|
|
tl.string = '点图标立刻 +1 · 底部可一次 +10/+100';
|
||
|
|
tl.fontSize = 22;
|
||
|
|
tl.color = new Color(255, 196, 72, 255);
|
||
|
|
tl.horizontalAlign = HorizontalTextAlignment.CENTER;
|
||
|
|
tip.setPosition(0, H / 2 - 28);
|
||
|
|
this._root.addChild(tip);
|
||
|
|
|
||
|
|
const barH = 120;
|
||
|
|
const scrollH = H - 80 - barH;
|
||
|
|
const { host, content } = makeVScroll(this._root, W - 16, scrollH);
|
||
|
|
host.setPosition(0, barH / 2 - 10);
|
||
|
|
|
||
|
|
const items = gg.data.table.getTableList<ITableItem>(TableNames.Item) ?? [];
|
||
|
|
items.sort((a, b) => Number(a.id) - Number(b.id));
|
||
|
|
const cell = 80;
|
||
|
|
const cols = Math.max(4, Math.floor((W - 24) / (cell + 6)));
|
||
|
|
let rowNode: Node | null = null;
|
||
|
|
for (let i = 0; i < items.length; i++) {
|
||
|
|
if (i % cols === 0) {
|
||
|
|
rowNode = new Node(`row${i}`);
|
||
|
|
rowNode.layer = Layers.Enum.UI_2D;
|
||
|
|
rowNode.addComponent(UITransform).setContentSize(W - 24, cell);
|
||
|
|
const lay = rowNode.addComponent(Layout);
|
||
|
|
lay.type = Layout.Type.HORIZONTAL;
|
||
|
|
lay.spacingX = 6;
|
||
|
|
content.addChild(rowNode);
|
||
|
|
}
|
||
|
|
const row = items[i];
|
||
|
|
const cellN = new Node(`i${row.id}`);
|
||
|
|
cellN.layer = Layers.Enum.UI_2D;
|
||
|
|
cellN.addComponent(UITransform).setContentSize(cell - 4, cell - 4);
|
||
|
|
const sp = cellN.addComponent(Sprite);
|
||
|
|
sp.sizeMode = Sprite.SizeMode.CUSTOM;
|
||
|
|
const loader = cellN.addComponent(SpriteLoad);
|
||
|
|
if (row.icon) loader.setSprite(GPath.Item(row.icon), GBundle.Items);
|
||
|
|
cellN.addComponent(Button);
|
||
|
|
const id = Number(row.id);
|
||
|
|
const name = row.name ?? '';
|
||
|
|
cellN.on(Button.EventType.CLICK, () => {
|
||
|
|
this._selectedId = id;
|
||
|
|
ProjectGmActions.addItemNum(id, 1);
|
||
|
|
this._qty = gg.data.getItemNum(id);
|
||
|
|
this._paint();
|
||
|
|
ctx.host.toast(`${name} +1 → ${this._qty}`);
|
||
|
|
}, this);
|
||
|
|
rowNode!.addChild(cellN);
|
||
|
|
}
|
||
|
|
content.getComponent(Layout)?.updateLayout();
|
||
|
|
|
||
|
|
const bar = new Node('bar');
|
||
|
|
bar.layer = Layers.Enum.UI_2D;
|
||
|
|
bar.addComponent(UITransform).setContentSize(W - 16, barH - 16);
|
||
|
|
bar.setPosition(0, -H / 2 + barH / 2);
|
||
|
|
this._root.addChild(bar);
|
||
|
|
|
||
|
|
this._lbSel = (() => {
|
||
|
|
const sel = new Node('sel');
|
||
|
|
sel.layer = Layers.Enum.UI_2D;
|
||
|
|
sel.addComponent(UITransform).setContentSize(W - 40, 28);
|
||
|
|
const lb = sel.addComponent(Label);
|
||
|
|
lb.fontSize = 20;
|
||
|
|
lb.color = new Color(180, 220, 255, 255);
|
||
|
|
lb.horizontalAlign = HorizontalTextAlignment.CENTER;
|
||
|
|
lb.overflow = Overflow.SHRINK;
|
||
|
|
sel.setPosition(0, 28);
|
||
|
|
bar.addChild(sel);
|
||
|
|
return lb;
|
||
|
|
})();
|
||
|
|
makeLabelBtn(bar, '+10', 100, 44, () => {
|
||
|
|
if (!this._selectedId) {
|
||
|
|
ctx.host.toast('先点一个图标');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
ProjectGmActions.addItemNum(this._selectedId, 10);
|
||
|
|
this._qty = gg.data.getItemNum(this._selectedId);
|
||
|
|
this._paint();
|
||
|
|
}).setPosition(-160, -16);
|
||
|
|
|
||
|
|
makeLabelBtn(bar, '+100', 100, 44, () => {
|
||
|
|
if (!this._selectedId) {
|
||
|
|
ctx.host.toast('先点一个图标');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
ProjectGmActions.addItemNum(this._selectedId, 100);
|
||
|
|
this._qty = gg.data.getItemNum(this._selectedId);
|
||
|
|
this._paint();
|
||
|
|
}).setPosition(-40, -16);
|
||
|
|
|
||
|
|
makeLabelBtn(bar, '返回', 120, 44, () => {
|
||
|
|
ctx.refreshList();
|
||
|
|
ctx.goBack();
|
||
|
|
}).setPosition(120, -16);
|
||
|
|
|
||
|
|
this._paint();
|
||
|
|
}
|
||
|
|
|
||
|
|
close(): void {
|
||
|
|
if (this._root?.isValid) this._root.destroy();
|
||
|
|
this._root = null;
|
||
|
|
this._lbSel = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
private _paint(): void {
|
||
|
|
if (this._lbSel) {
|
||
|
|
this._lbSel.string = this._selectedId
|
||
|
|
? `最近:${this._selectedId} 持有 ${gg.data.getItemNum(this._selectedId)}`
|
||
|
|
: '点图标立刻 +1';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* BUFF 列表点选。
|
||
|
|
*/
|
||
|
|
class GmBuffPickerPanel implements IGmContentPanel {
|
||
|
|
private _root: Node | null = null;
|
||
|
|
|
||
|
|
open(parent: Node, ctx: IGmPanelContext): void {
|
||
|
|
this.close();
|
||
|
|
const data = ctx.command.panelData as IGmBuffPickerData;
|
||
|
|
if (!data?.mode) {
|
||
|
|
console.warn('[GM] buffPicker 缺少 panelData');
|
||
|
|
ctx.host.toast('面板配置错误');
|
||
|
|
ctx.goBack();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
this._root = new Node('buffPicker');
|
||
|
|
this._root.layer = Layers.Enum.UI_2D;
|
||
|
|
this._root.addComponent(UITransform).setContentSize(660, 900);
|
||
|
|
parent.addChild(this._root);
|
||
|
|
|
||
|
|
const title = new Node('t');
|
||
|
|
title.layer = Layers.Enum.UI_2D;
|
||
|
|
title.addComponent(UITransform).setContentSize(600, 36);
|
||
|
|
const tl = title.addComponent(Label);
|
||
|
|
tl.string = ctx.command.title;
|
||
|
|
tl.fontSize = 26;
|
||
|
|
tl.color = Color.WHITE;
|
||
|
|
tl.horizontalAlign = HorizontalTextAlignment.CENTER;
|
||
|
|
title.setPosition(0, 420);
|
||
|
|
this._root.addChild(title);
|
||
|
|
|
||
|
|
const { host, content } = makeVScroll(this._root, 640, 700);
|
||
|
|
host.setPosition(0, 20);
|
||
|
|
|
||
|
|
const list = gg.data.table.getTableList<ITableBattlebuff>(TableNames.Battlebuff) ?? [];
|
||
|
|
list.sort((a, b) => Number(a.id) - Number(b.id));
|
||
|
|
for (let i = 0; i < list.length; i++) {
|
||
|
|
const row = list[i];
|
||
|
|
const t = Math.floor(Number((row as { type?: number }).type) || 0);
|
||
|
|
if (data.expectType > 0 && t !== data.expectType) continue;
|
||
|
|
const id = Number(row.id);
|
||
|
|
const label = `${id} ${row.name ?? ''} (t${t})`;
|
||
|
|
makeLabelBtn(content, label, 620, 44, () => {
|
||
|
|
if (data.mode === 'carryPassive') ProjectGmActions.setPassiveCarry(id);
|
||
|
|
else if (data.mode === 'aiActive') ProjectGmActions.setAiBuffIds([id], true);
|
||
|
|
else ProjectGmActions.setAiBuffIds([id], false);
|
||
|
|
ctx.refreshList();
|
||
|
|
ctx.goBack();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
makeLabelBtn(content, '清除覆盖/空', 620, 44, () => {
|
||
|
|
if (data.mode === 'carryPassive') {
|
||
|
|
ctx.host.toast('被动携带请选具体 id');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
ProjectGmActions.setAiBuffIds(null, data.mode === 'aiActive');
|
||
|
|
ctx.refreshList();
|
||
|
|
ctx.goBack();
|
||
|
|
});
|
||
|
|
content.getComponent(Layout)?.updateLayout();
|
||
|
|
|
||
|
|
makeLabelBtn(this._root, '返回', 140, 44, () => ctx.goBack()).setPosition(0, -400);
|
||
|
|
}
|
||
|
|
|
||
|
|
close(): void {
|
||
|
|
if (this._root?.isValid) this._root.destroy();
|
||
|
|
this._root = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 关卡列表点选。
|
||
|
|
*/
|
||
|
|
class GmLevelPickerPanel implements IGmContentPanel {
|
||
|
|
private _root: Node | null = null;
|
||
|
|
|
||
|
|
open(parent: Node, ctx: IGmPanelContext): void {
|
||
|
|
this.close();
|
||
|
|
this._root = new Node('levelPicker');
|
||
|
|
this._root.layer = Layers.Enum.UI_2D;
|
||
|
|
this._root.addComponent(UITransform).setContentSize(660, 900);
|
||
|
|
parent.addChild(this._root);
|
||
|
|
|
||
|
|
const title = new Node('t');
|
||
|
|
title.layer = Layers.Enum.UI_2D;
|
||
|
|
title.addComponent(UITransform).setContentSize(600, 36);
|
||
|
|
const tl = title.addComponent(Label);
|
||
|
|
tl.string = ctx.command.title;
|
||
|
|
tl.fontSize = 26;
|
||
|
|
tl.color = Color.WHITE;
|
||
|
|
tl.horizontalAlign = HorizontalTextAlignment.CENTER;
|
||
|
|
title.setPosition(0, 420);
|
||
|
|
this._root.addChild(title);
|
||
|
|
|
||
|
|
const { host, content } = makeVScroll(this._root, 640, 700);
|
||
|
|
host.setPosition(0, 20);
|
||
|
|
|
||
|
|
makeLabelBtn(content, '0 关闭固定(随机)', 620, 44, () => {
|
||
|
|
ProjectGmActions.setFixedMap(0);
|
||
|
|
ctx.refreshList();
|
||
|
|
ctx.goBack();
|
||
|
|
});
|
||
|
|
|
||
|
|
const list = gg.data.table.getTableList<ITableLevel>(TableNames.Level) ?? [];
|
||
|
|
list.sort((a, b) => Number(a.id) - Number(b.id));
|
||
|
|
for (let i = 0; i < list.length; i++) {
|
||
|
|
const row = list[i];
|
||
|
|
const id = Number(row.id);
|
||
|
|
const name = row.name ?? '';
|
||
|
|
makeLabelBtn(content, `${id} ${name}`, 620, 44, () => {
|
||
|
|
ProjectGmActions.setFixedMap(id);
|
||
|
|
ctx.refreshList();
|
||
|
|
ctx.goBack();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
content.getComponent(Layout)?.updateLayout();
|
||
|
|
makeLabelBtn(this._root, '返回', 140, 44, () => ctx.goBack()).setPosition(0, -400);
|
||
|
|
}
|
||
|
|
|
||
|
|
close(): void {
|
||
|
|
if (this._root?.isValid) this._root.destroy();
|
||
|
|
this._root = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 段位点选 + 星级步进。
|
||
|
|
*/
|
||
|
|
class GmRankPickerPanel implements IGmContentPanel {
|
||
|
|
private _root: Node | null = null;
|
||
|
|
private _rankId = 1;
|
||
|
|
private _star = 1;
|
||
|
|
private _lb: Label | null = null;
|
||
|
|
|
||
|
|
open(parent: Node, ctx: IGmPanelContext): void {
|
||
|
|
this.close();
|
||
|
|
this._rankId = RankDataManager.getPlayerRankId() || 1;
|
||
|
|
this._star = RankDataManager.getIntraTierStars() || 1;
|
||
|
|
|
||
|
|
this._root = new Node('rankPicker');
|
||
|
|
this._root.layer = Layers.Enum.UI_2D;
|
||
|
|
this._root.addComponent(UITransform).setContentSize(660, 900);
|
||
|
|
parent.addChild(this._root);
|
||
|
|
|
||
|
|
const title = new Node('t');
|
||
|
|
title.layer = Layers.Enum.UI_2D;
|
||
|
|
title.addComponent(UITransform).setContentSize(600, 36);
|
||
|
|
const tl = title.addComponent(Label);
|
||
|
|
tl.string = ctx.command.title;
|
||
|
|
tl.fontSize = 26;
|
||
|
|
tl.color = Color.WHITE;
|
||
|
|
tl.horizontalAlign = HorizontalTextAlignment.CENTER;
|
||
|
|
title.setPosition(0, 420);
|
||
|
|
this._root.addChild(title);
|
||
|
|
|
||
|
|
const cur = new Node('cur');
|
||
|
|
cur.layer = Layers.Enum.UI_2D;
|
||
|
|
cur.addComponent(UITransform).setContentSize(600, 36);
|
||
|
|
this._lb = cur.addComponent(Label);
|
||
|
|
this._lb.fontSize = 24;
|
||
|
|
this._lb.color = Color.YELLOW;
|
||
|
|
this._lb.horizontalAlign = HorizontalTextAlignment.CENTER;
|
||
|
|
cur.setPosition(0, 360);
|
||
|
|
this._root.addChild(cur);
|
||
|
|
|
||
|
|
const { host, content } = makeVScroll(this._root, 640, 480);
|
||
|
|
host.setPosition(0, 40);
|
||
|
|
|
||
|
|
const list = gg.data.table.getTableList<ITableRank>(TableNames.Rank) ?? [];
|
||
|
|
list.sort((a, b) => Number(a.id) - Number(b.id));
|
||
|
|
for (let i = 0; i < list.length; i++) {
|
||
|
|
const row = list[i];
|
||
|
|
const id = Number(row.id);
|
||
|
|
const name = row.name ?? '';
|
||
|
|
makeLabelBtn(content, `${id} ${name}`, 620, 44, () => {
|
||
|
|
this._rankId = id;
|
||
|
|
this._paint();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
content.getComponent(Layout)?.updateLayout();
|
||
|
|
|
||
|
|
makeLabelBtn(this._root, '星-1', 100, 40, () => {
|
||
|
|
this._star = Math.max(1, this._star - 1);
|
||
|
|
this._paint();
|
||
|
|
}).setPosition(-160, -260);
|
||
|
|
makeLabelBtn(this._root, '星+1', 100, 40, () => {
|
||
|
|
this._star = Math.min(5, this._star + 1);
|
||
|
|
this._paint();
|
||
|
|
}).setPosition(-40, -260);
|
||
|
|
|
||
|
|
makeLabelBtn(this._root, '应用', 120, 44, () => {
|
||
|
|
ProjectGmActions.setRankAndStar(this._rankId, this._star);
|
||
|
|
ctx.refreshList();
|
||
|
|
ctx.goBack();
|
||
|
|
}).setPosition(100, -260);
|
||
|
|
|
||
|
|
makeLabelBtn(this._root, '返回', 120, 44, () => ctx.goBack()).setPosition(0, -320);
|
||
|
|
this._paint();
|
||
|
|
}
|
||
|
|
|
||
|
|
close(): void {
|
||
|
|
if (this._root?.isValid) this._root.destroy();
|
||
|
|
this._root = null;
|
||
|
|
this._lb = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
private _paint(): void {
|
||
|
|
if (this._lb) this._lb.string = `段位 ${this._rankId} 星 ${this._star}`;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 注册本项目内容面板。
|
||
|
|
*/
|
||
|
|
export class ProjectGmPanels {
|
||
|
|
private static _done = false;
|
||
|
|
|
||
|
|
/** 幂等注册 */
|
||
|
|
static ensureRegistered(): void {
|
||
|
|
if (this._done) return;
|
||
|
|
this._done = true;
|
||
|
|
GmRegistry.registerPanel(ProjectGmPanelId.itemPicker, () => new GmItemPickerPanel());
|
||
|
|
GmRegistry.registerPanel(ProjectGmPanelId.buffPicker, () => new GmBuffPickerPanel());
|
||
|
|
GmRegistry.registerPanel(ProjectGmPanelId.levelPicker, () => new GmLevelPickerPanel());
|
||
|
|
GmRegistry.registerPanel(ProjectGmPanelId.rankPicker, () => new GmRankPickerPanel());
|
||
|
|
GmRegistry.registerPanel(ProjectGmPanelId.saveEditor, () => new GmSaveEditorPanel());
|
||
|
|
}
|
||
|
|
}
|