import { Button, color } from 'cc'; import { Label } from 'cc'; import { EventTouch } from 'cc'; import { instantiate } from 'cc'; import { EditBox } from 'cc'; import { _decorator, Component, Node } from 'cc'; import { isValid } from 'cc'; import { GBundle, GPath, UIID } from './ConfigRes'; import { UILayer } from '../../mx/module/ui/UIManager'; import { ItemNumType, OtherDataType, StatisticsType } from './GameData'; import { GEvent } from '../../mx/module/event/GEvent'; import { TableNames } from './ConfigTableData'; import MTools from '../../mx/tools/MTools'; import { sdkConfig } from '../sdk/sdkConfig'; import { parseGmBagWeapon2Filter } from '../battle/bag/BagWeaponPool'; import { parseGmAiBattleBuffIds } from '../battle/debug/GmBattlePreset'; import { preloadGmHeroActorPrefabs } from '../battle/heros/HeroActorRes'; import { BattleRuntime } from '../battle/runtime/BattleRuntime'; import { DailyShopDataManager } from '../manager/DailyShopDataManager'; import { HeadIconManager } from '../manager/HeadIconManager'; import { DailyShopKind } from '../manager/DailyShopTypes'; import { EmolumentDataManager } from '../manager/EmolumentDataManager'; import { RankBoardManager } from '../manager/RankBoardManager'; import { RankDataManager } from '../manager/RankDataManager'; const { ccclass, property } = _decorator; /** GM「设置排行星级&胜场」:PopEmolument 待领星级 */ const GM_EMOLUMENT_SNAP_STARS = 50; /** GM「设置排行星级&胜场」:PopEmolument 待领胜场 */ const GM_EMOLUMENT_SNAP_WINS = 50; @ccclass('GM') export class GM extends Component { static Instance: GM; static ShowGM = false; static show() { this.ShowGM = !this.ShowGM; if (GM.Instance && isValid(GM.Instance.node)) { GM.Instance.node.active = this.ShowGM; return; } if (this.ShowGM) { let res = gg.res.getNode(GPath.UIPrefab, "gm", GBundle.First); gg.ui.showNode(res, UILayer.DeBug); GM.Instance = res.getComponent(GM); } } @property(EditBox) eb_prama: EditBox; @property(Node) ui_quickBtns: Node; @property(Node) ui_paramBtns: Node; @property(Node) ui_help: Node; @property(Label) lb_help: Label; content: Node; btnGM: Node; btnClear: Button; btnClose: Button; btnHelp: Button; protected onLoad(): void { this.content = this.node.find("content"); this.btnGM = this.node.find("btnGM"); this.btnClear = this.content.find("ui_content/ui_head/btnClear").getComponent(Button); this.btnClose = this.content.find("ui_content/ui_head/btnClose").getComponent(Button); this.btnHelp = this.content.find("ui_content/ui_head/btnHelp").getComponent(Button); } protected onEnable(): void { this.btnGM.on(Button.EventType.CLICK, this.onOpenGM, this); this.btnClear.node.on(Button.EventType.CLICK, this.onClear, this); this.btnClose.node.on(Button.EventType.CLICK, this.onClose, this); this.btnHelp.node.on(Button.EventType.CLICK, this.onHelp, this); this.ui_help.on(Button.EventType.CLICK, this.onHelpUI, this); this.btnGM.active = false; this.onOpenGM(); this.initBtnEvents(); this.lb_help.string = this._helpStr; this.ui_help.active = false; } protected onDisable(): void { this.btnGM.off(Button.EventType.CLICK, this.onOpenGM, this); this.btnClear.node.off(Button.EventType.CLICK, this.onClear, this); this.btnClose.node.off(Button.EventType.CLICK, this.onClose, this); this.btnHelp.node.off(Button.EventType.CLICK, this.onHelp, this); this.ui_help.off(Button.EventType.CLICK, this.onHelpUI, this); this.ui_quickBtns.children.map(x => x.off(Node.EventType.TOUCH_END, this.onQuickBtnClick, this)); this.ui_paramBtns.children.map(x => x.off(Node.EventType.TOUCH_END, this.onParamBtnClick, this)); } initBtnEvents() { for (let i = 0; i < this.quickBtns.length; i++) { let btn: Node = null; if (i < this.ui_quickBtns.children.length) btn = this.ui_quickBtns.children[i]; else btn = instantiate(this.ui_quickBtns.children[0]); btn.active = true; btn.name = this.quickBtns[i]; btn.setParent(this.ui_quickBtns); btn.getComponentInChildren(Label).string = this.quickBtns[i]; btn.getComponentInChildren(Label).outlineColor = color().fromHEX(this.colors[i % this.colors.length]); btn.on(Node.EventType.TOUCH_END, this.onQuickBtnClick, this); } for (let i = 0; i < this.paramBtns.length; i++) { let btn = null; if (i < this.ui_paramBtns.children.length) btn = this.ui_paramBtns.children[i]; else btn = instantiate(this.ui_paramBtns.children[0]); btn.active = true; let [name, desc] = this.paramBtns[i].split("|"); btn.name = name; btn.setParent(this.ui_paramBtns); btn.getChildByName("lb1").getComponent(Label).string = name; btn.getChildByName("lb1").getComponent(Label).outlineColor = color().fromHEX(this.colors[i % this.colors.length]); btn.getChildByName("lb2").getComponent(Label).string = "参数:" + desc; btn.on(Node.EventType.TOUCH_END, this.onParamBtnClick, this); } this.scheduleOnce(() => { this.refreshparamBtns() }, 1) } refreshparamBtns() { for (let i = 0; i < this.ui_paramBtns.children.length; i++) { const btn = this.ui_paramBtns.children[i]; const lb2 = btn.getChildByName('lb2')?.getComponent(Label); if (!lb2) continue; switch (btn.name) { case '设置金钱': lb2.string = `参数:${gg.data.getItemNum(ItemNumType.money)}`; break; case '设置体力': lb2.string = `参数:${gg.data.getItemNum(ItemNumType.vigour)}`; break; case '设置钻石': lb2.string = `参数:${gg.data.getItemNum(ItemNumType.diamond)}`; break; case '设置关卡解锁': lb2.string = `参数:${gg.data.doc.rankId}`; break; case '设置星数': lb2.string = `参数:${RankDataManager.getPlayerRankStars()}`; break; case '设置玩家局内血量': { const runtime = gg.battle.match; const inBattleHp = runtime instanceof BattleRuntime ? runtime.WallMaxHp : 0; const preset = gg.game.playerHp; lb2.string = preset > 0 ? `参数:${preset}(下局)${inBattleHp > 0 ? ` 当前${inBattleHp}` : ''}` : `参数:0(默认)${inBattleHp > 0 ? ` 当前${inBattleHp}` : ''}`; break; } case '设置玩家等级': lb2.string = `参数:${gg.data.getPlayerLevel()}`; break; case '设置通关怪物数量': { const n = sdkConfig.isDebugFastWinMonsterNum; lb2.string = n > 0 ? `参数:${n}` : '参数:0(关闭)'; break; } case '指定背包文字': { const cur = gg.game.gmBagWeapon2Ids; lb2.string = cur?.length ? `参数:${cur.join(',')}` : '参数:未指定(正常随机)'; break; } case '设置AI主动BUFF': { const cur = gg.game.gmAiActiveBuffIds; lb2.string = cur?.length ? `参数:${cur.join(',')}(常驻)` : '参数:未指定(每局随机)'; break; } case '设置AI被动BUFF': { const cur = gg.game.gmAiPassiveBuffIds; lb2.string = cur?.length ? `参数:${cur.join(',')}(常驻)` : '参数:未指定(每局随机)'; break; } case '固定地图': { const id = Math.floor(Number(gg.game.gmMapId) || 0); lb2.string = this._formatFixedLevelParam(id); break; } case '设置主动BUFF': { const slotId = DailyShopDataManager.getActiveSlotIds()[0] ?? 0; const parsed = slotId > 0 ? DailyShopDataManager.getParsed(slotId) : null; lb2.string = parsed ? `参数:${parsed.id}(${parsed.name})` : (slotId > 0 ? `参数:${slotId}` : '参数:空'); break; } case '设置被动BUFF': { const slotId = DailyShopDataManager.getPassiveSlotIds()[0] ?? 0; const parsed = slotId > 0 ? DailyShopDataManager.getParsed(slotId) : null; lb2.string = parsed ? `参数:${parsed.id}(${parsed.name})` : (slotId > 0 ? `参数:${slotId}` : '参数:空'); break; } } } } onClear() { gg.ui.closeAllPanel(); GEvent.Ins.emit(GEvent.GameRestart); gg.game.reset('GM重置'); } onOpenGM() { this.content.active = true; this.btnGM.active = false; } onHelp() { this.ui_help.active = !this.ui_help.active; } onHelpUI() { this.ui_help.active = false; } onClose() { GM.show(); // this.content.active = false; // this.btnGM.active = true; } colors = ["#21F018", "#05DBF8", "#EF9EFF", "#FFFF00", "#FFE09E", "#E8FF9E", "#47CA14", "#3CDCF1", "#E0FF00", "#20FA80"]; quickBtns = [ '清除副本次数难度全开', '今日首次登录(每日重置)', '复制存档', '一键获取所有武器', '设置武器等级', '设置武器和技能', '清除指定背包文字', '快速胜利1怪', '关闭快速胜利', '关闭广告', '显示广告', '重置每日商店or抽奖', '重置每日商店BUFF', '打开每日商店无限次数', '关闭每日商店无限次数', '清除AI主动BUFF', '清除AI被动BUFF', '清除固定地图', '测试七十二变→妙手神偷', '关闭七十二变固定', '设置排行星级&胜场', '打开内购', '关闭内购', '开启己方营地不掉血', '关闭己方营地不掉血', '开启敌方营地不掉血', '关闭敌方营地不掉血', ]; paramBtns = [ '设置道具数量|道具ID 数量(空格分隔)', '设置武器数量|武器ID 数量(空格分隔)', '设置主动BUFF|主动buffID(只设置第一个)', '设置被动BUFF|被动buffID(只设置第一个)', '设置金钱|金币数量', '设置体力|体力数量', '设置钻石|钻石数量', '设置关卡解锁|段位id', '设置星数|总星数(最低1)', '设置玩家局内血量|城墙血量(下局生效,局内同步)', '设置玩家等级|主角等级', '设置玩家存档|JSON存档字符串', '设置通关怪物数量|击杀N怪后通关,0关闭', '指定背包文字|weapon2Id或名称,逗号分隔', '设置AI主动BUFF|Battlebuff.id,逗号分隔(下局生效)', '设置AI被动BUFF|Battlebuff.id,逗号分隔(下局生效)', '固定地图|Level.id(关卡表),0关闭', ]; onQuickBtnClick(event: EventTouch) { switch (event.target.name) { case '关闭广告': gg.sdk.showAd = false; gg.ui.showToast('已关闭广告'); GM.show(); break; case '显示广告': gg.sdk.showAd = true; gg.ui.showToast('已开启广告'); GM.show(); break; case '打开内购': sdkConfig.isIAPVersion = true; gg.ui.showToast('已打开内购版本'); GM.show(); break; case '关闭内购': sdkConfig.isIAPVersion = false; gg.ui.showToast('已关闭内购版本'); GM.show(); break; case '清除副本次数难度全开': gg.data.setStatistics(StatisticsType.BoxChallengeCount, 0); gg.data.setStatistics(StatisticsType.gachaChallengeModeCount, 0); gg.data.setStatistics(StatisticsType.InfiniteChallengeCount, 0); gg.data.setStatistics(StatisticsType.PropChallengeCount, 0); gg.data.setStatistics(StatisticsType.WeaponChallengeCount, 0); gg.data.setStatistics(StatisticsType.BoxModelLevel, 5); gg.data.setStatistics(StatisticsType.InfiniteModelLevel, 5); gg.data.setStatistics(StatisticsType.PropModelLevel, 5); gg.data.setStatistics(StatisticsType.WeaponModelLevel, 5); gg.data.setStatistics(StatisticsType.GachaChallengeModeLevel, 5); gg.data.setStatistics(StatisticsType.BossChallengeCount, 0); gg.data.resetReplicaEnterAndSweepCountsToday(); gg.data.saveToServer(); gg.ui.showToast('副本次数已清零,难度已全开'); GM.show(); break; case '今日首次登录(每日重置)': gg.data.onFirstLoginToday(); gg.ui.showToast('今日首次登录(每日重置)成功'); GM.show(); break; case '复制存档': MTools.CopyTextEvent(JSON.stringify(gg.data.doc)); gg.ui.showToast('复制存档成功'); GM.show(); break; case '一键获取所有武器': { void (async () => { const added = await gg.equip.gmGrantAllBagEquips(); gg.data.saveToServer(); GEvent.Ins.emit(GEvent.UpdateCombatPower); gg.ui.showToast(added > 0 ? `已发放成品武器 ${added} 种(含新武器)` : 'Weapon 表成品已齐'); GM.show(); })(); break; } case '设置武器和技能': gg.ui.openPanel(UIID.PopGM, { data: 2 }); GM.show(); break; case '设置武器等级': gg.ui.openPanel(UIID.PopGM, { data: 1 }); GM.show(); break; case '清除指定背包文字': gg.game.gmBagWeapon2Ids = null; gg.ui.showToast('已恢复背包正常刷新'); this._refreshBagIfPrep(); GM.show(); break; case '快速胜利1怪': sdkConfig.isDebugFastWinMonsterNum = 1; gg.ui.showToast('快速胜利:击杀1怪后通关'); GM.show(); break; case '关闭快速胜利': sdkConfig.isDebugFastWinMonsterNum = 0; gg.ui.showToast('已关闭快速胜利'); GM.show(); break; case '重置每日商店or抽奖': DailyShopDataManager.gmResetShopAndLotteryKeepCarry(); gg.ui.showToast('已重置每日商店/抽奖(保留携带道具)'); GM.show(); break; case '重置每日商店BUFF': DailyShopDataManager.gmClearCarriedBuffs(); gg.ui.showToast('已清空携带的每日商店BUFF'); GM.show(); break; case '打开每日商店无限次数': DailyShopDataManager.GM_UNLIMITED_DAILY_SHOP = true; gg.ui.showToast('已打开每日商店无限次数'); GM.show(); break; case '关闭每日商店无限次数': DailyShopDataManager.GM_UNLIMITED_DAILY_SHOP = false; DailyShopDataManager.gmResetShopAndLotteryKeepCarry(); gg.ui.showToast('已关闭每日商店无限次数并重置货架'); GM.show(); break; case '清除AI主动BUFF': gg.game.gmAiActiveBuffIds = null; gg.ui.showToast('已恢复 AI 主动匹配随机'); GM.show(); break; case '清除AI被动BUFF': gg.game.gmAiPassiveBuffIds = null; gg.ui.showToast('已恢复 AI 被动匹配随机'); GM.show(); break; case '清除固定地图': gg.game.gmMapId = 0; gg.ui.showToast('已恢复地图随机'); GM.show(); break; case '测试七十二变→妙手神偷': { gg.game.gmRandomActiveFixBuffId = 16; const result = DailyShopDataManager.gmSetFirstCarrySlot(DailyShopKind.Active, '20'); if (result.wrongKind) { gg.ui.showToast('七十二变(id=20) 非主动 buff,请检查配表'); break; } if (!result.ok) { gg.ui.showToast('写入七十二变失败,请检查 Battlebuff 表'); break; } gg.data.saveToServer(); gg.ui.showToast('已开启:七十二变 CD 结束固定→妙手神偷(id=16)'); GM.show(); break; } case '关闭七十二变固定': gg.game.gmRandomActiveFixBuffId = null; gg.ui.showToast('已关闭七十二变固定 roll,恢复随机'); GM.show(); break; case '设置排行星级&胜场': this._gmSetRankStarsAndDailyWins(); GM.show(); break; case '开启己方营地不掉血': this._setCampImmune(true, true); break; case '关闭己方营地不掉血': this._setCampImmune(true, false); break; case '开启敌方营地不掉血': this._setCampImmune(false, true); break; case '关闭敌方营地不掉血': this._setCampImmune(false, false); break; } this.refreshparamBtns(); } onParamBtnClick(event: EventTouch) { let needSaveServer = false; switch (event.target.name) { case '设置道具数量': { const parts = this.eb_prama.string.trim().split(/\s+/); const itemId = Number(parts[0]); const num = Number(parts[1]); if (!Number.isFinite(itemId) || !Number.isFinite(num)) { gg.ui.showToast('格式:道具ID 数量'); break; } gg.data.setItemNum(itemId, num); needSaveServer = true; gg.ui.showToast(`道具 ${itemId} 已设为 ${num}`); break; } case '设置武器数量': { const parts = this.eb_prama.string.trim().split(/\s+/); const equipId = Number(parts[0]); const num = Number(parts[1]); if (!Number.isFinite(equipId) || !Number.isFinite(num)) { gg.ui.showToast('格式:武器ID 数量'); break; } const conf = gg.equip.getEquip(equipId); if (!conf) { gg.ui.showToast(`武器ID ${equipId} 无效`); break; } gg.equip.setHaveEquipCount(equipId, num); needSaveServer = true; gg.ui.showToast(`武器 ${equipId} 已设为 ${gg.equip.getHaveEquipCount(equipId)}`); break; } case '设置主动BUFF': { const result = DailyShopDataManager.gmSetFirstCarrySlot(DailyShopKind.Active, this.eb_prama.string); if (result.wrongKind) { gg.ui.showToast('该 id 为被动 buff,不能写入主动第1槽'); break; } if (!result.ok) { gg.ui.showToast('请填主动 Battlebuff.id(type=1) 或名称'); break; } needSaveServer = true; if (result.parsed) { gg.ui.showToast(`主动第1槽 → ${result.parsed.id}(${result.parsed.name})`); } else { gg.ui.showToast('已清空主动第1槽'); } break; } case '设置被动BUFF': { const result = DailyShopDataManager.gmSetFirstCarrySlot(DailyShopKind.Passive, this.eb_prama.string); if (result.wrongKind) { gg.ui.showToast('该 id 为主动 buff,不能写入被动第1槽'); break; } if (!result.ok) { gg.ui.showToast('请填被动 Battlebuff.id(type=2) 或名称'); break; } needSaveServer = true; if (result.parsed) { gg.ui.showToast(`被动第1槽 → ${result.parsed.id}(${result.parsed.name})`); } else { gg.ui.showToast('已清空被动第1槽'); } break; } case '设置金钱': { const num = this._readParamInt(); if (num === null) break; gg.data.setItemNum(ItemNumType.money, num); needSaveServer = true; break; } case '设置体力': { const num = this._readParamInt(); if (num === null) break; gg.data.setItemNum(ItemNumType.vigour, num); needSaveServer = true; break; } case '设置钻石': { const num = this._readParamInt(); if (num === null) break; gg.data.setItemNum(ItemNumType.diamond, num); needSaveServer = true; break; } case '设置关卡解锁': { const rankId = this._readParamInt(); if (rankId === null || rankId < 1) { gg.ui.showToast('请输入有效段位 id'); break; } gg.data.doc.rankId = rankId; needSaveServer = true; gg.ui.showToast(`段位已设为 ${gg.data.doc.rankId}`); break; } case '设置星数': { const stars = this._readParamInt(); if (stars === null || stars < 1) { gg.ui.showToast('请输入有效星数(>=1)'); break; } gg.data.doc.rankStars = stars; HeadIconManager.onRankStarsChanged(); needSaveServer = true; void RankBoardManager.syncSelfScore(); GEvent.Ins.emit(GEvent.UpdateRankStars); gg.ui.showToast(`星数已设为 ${gg.data.doc.rankStars}`); break; } case '设置玩家局内血量': { const hp = this._readParamInt(); if (hp === null || hp <= 0) { gg.ui.showToast('请输入正整数血量'); break; } this._applyPlayerWallHp(hp); gg.ui.showToast(`城墙血量 ${hp}${gg.battle.match ? '(局内已同步)' : '(下局生效)'}`); break; } case '设置玩家等级': { const level = this._readParamInt(); if (level === null || level < 0) { gg.ui.showToast('请输入有效等级'); break; } this._applyUserLevel(level); needSaveServer = true; GEvent.Ins.emit(GEvent.UpdateCombatPower); gg.ui.showToast(`主角等级已设为 ${gg.data.getPlayerLevel()}`); break; } case '设置玩家存档': try { const doc = JSON.parse(this.eb_prama.string); if (!doc || typeof doc !== 'object') { gg.ui.showToast('存档格式错误'); break; } gg.data.doc = doc; gg.data['_IsFirstLogin'] = false; gg.game.init(); GEvent.Ins.emit(GEvent.UpdateItemNum); gg.data.saveLocal(); gg.ui.showToast('设置成功'); GM.show(); } catch { gg.ui.showToast('存档格式错误'); } break; case '设置通关怪物数量': { const n = Math.floor(Number(this.eb_prama.string)); if (Number.isNaN(n) || n < 0) { gg.ui.showToast('请输入非负整数,0=关闭'); break; } sdkConfig.isDebugFastWinMonsterNum = n; gg.ui.showToast(n > 0 ? `快速胜利:击杀${n}怪后通关` : '已关闭快速胜利'); break; } case '指定背包文字': gg.game.gmBagWeapon2Ids = parseGmBagWeapon2Filter(this.eb_prama.string); preloadGmHeroActorPrefabs(); if (gg.game.gmBagWeapon2Ids?.length) { gg.ui.showToast(`背包仅刷: ${gg.game.gmBagWeapon2Ids.join(',')}`); } else if (this.eb_prama.string.trim() === '' || this.eb_prama.string.trim() === '0') { gg.ui.showToast('已关闭指定刷新'); } else { gg.ui.showToast('未识别文字,请填 weapon2Id 或名称'); } this._refreshBagIfPrep(); break; case '设置AI主动BUFF': { const ids = parseGmAiBattleBuffIds(this.eb_prama.string, 1); gg.game.gmAiActiveBuffIds = ids; if (ids?.length) { gg.ui.showToast(`AI主动常驻: ${ids.join(',')}`); } else if (this.eb_prama.string.trim() === '' || this.eb_prama.string.trim() === '0') { gg.ui.showToast('已关闭 AI 主动覆盖(恢复每局随机)'); } else { gg.ui.showToast('未识别主动 id,请填 Battlebuff.id(type=1)'); } break; } case '设置AI被动BUFF': { const ids = parseGmAiBattleBuffIds(this.eb_prama.string, 2); gg.game.gmAiPassiveBuffIds = ids; if (ids?.length) { gg.ui.showToast(`AI被动常驻: ${ids.join(',')}`); } else if (this.eb_prama.string.trim() === '' || this.eb_prama.string.trim() === '0') { gg.ui.showToast('已关闭 AI 被动覆盖(恢复每局随机)'); } else { gg.ui.showToast('未识别被动 id,请填 Battlebuff.id(type=2)'); } break; } case '固定地图': { const n = this._readParamInt(); if (n === null) break; if (n <= 0) { gg.game.gmMapId = 0; gg.ui.showToast('已关闭固定地图(恢复随机)'); break; } const clamped = gg.data.project.clampBattleLevelId(n); if (clamped !== n) { console.log('[GM] 固定地图 id 不在 Level 表,已钳到', n, clamped); } gg.game.gmMapId = clamped; gg.ui.showToast(this._formatFixedLevelToast(clamped)); break; } } if (needSaveServer) { gg.data.saveToServer(); } else { gg.data.saveLocal(); } this.refreshparamBtns(); } /** * GM:己方/敌方营地不掉血(仅本次登录内存)。 * @param local true=己方营地 false=敌方营地 * @param immune 是否免伤 */ private _setCampImmune(local: boolean, immune: boolean): void { if (local) { gg.game.gmLocalCampImmune = immune; } else { gg.game.gmEnemyCampImmune = immune; } const runtime = gg.battle.match; if (runtime instanceof BattleRuntime) { runtime.syncGmCampImmune(); } const side = local ? '己方' : '敌方'; gg.ui.showToast(immune ? `已开启${side}营地不掉血(本次登录)` : `已关闭${side}营地不掉血`); GM.show(); } /** GM:写入 PopEmolument 待领快照并标今日首次登录,重新进 Home 弹窗 */ private _gmSetRankStarsAndDailyWins(): void { const ok = EmolumentDataManager.gmPrepareFirstLoginPopTest( GM_EMOLUMENT_SNAP_STARS, GM_EMOLUMENT_SNAP_WINS, ); if (!ok) { gg.ui.showToast('俸禄待领星级须 > 0'); return; } gg.data.saveToServer(); gg.ui.showToast( `俸禄待领 星${GM_EMOLUMENT_SNAP_STARS} 胜${GM_EMOLUMENT_SNAP_WINS},请重新进 Home`, ); } private _readParamInt(): number | null { const n = Math.floor(Number(this.eb_prama.string.trim())); if (!Number.isFinite(n)) { gg.ui.showToast('请输入有效数字'); return null; } return n; } private _refreshBagIfPrep(): void { const runtime = gg.battle.match; if (!(runtime instanceof BattleRuntime)) return; const session = runtime.bagSession; if (session?.merge.prepActive) { session.refreshBag(runtime.LevelConfigId, false); } } /** 预设下局城墙血量;局内则同步当前 slot */ private _applyPlayerWallHp(hp: number): void { gg.game.playerHp = hp; const runtime = gg.battle.match; if (!(runtime instanceof BattleRuntime)) return; const slot = runtime.localSlot; if (!slot) return; slot.wallMaxHp = hp; slot.wallHp = hp; } /** 设置主角等级(Role 表已移除) */ private _applyUserLevel(_targetLevel: number): void { } private _helpStr = `GM 工具帮助 【快速按钮】 · 清除副本次数难度全开:重置各副本挑战次数,难度解锁到 5 · 今日首次登录:触发每日重置逻辑 · 复制存档:复制当前 doc JSON 到剪贴板 · 一键获取所有武器:Weapon 全表成品各发 1 把(含 isshow=1 与新增;新武器保留弹窗/角标) · 设置武器等级 / 设置武器和技能:打开 PopGM 面板 · 清除指定背包文字:恢复随机 · 快速胜利 / 关闭快速胜利:调试通关 · 重置每日商店or抽奖:重抽货架/抽奖池并清零购买次数,保留携带道具 · 重置每日商店BUFF:清空当前携带的主动/被动道具 · 打开/关闭每日商店无限次数:不限制货架购买和抽奖次数(关闭时自动重置货架) · 清除AI主动/被动BUFF:恢复匹配随机抽取 · 清除固定地图:恢复关卡随机 · 测试七十二变→妙手神偷:主动第1槽=七十二变(id=20),CD 结束固定 roll 妙手神偷(id=16) · 关闭七十二变固定:恢复七十二变正常随机 · 设置排行星级&胜场:俸禄待领星50胜50 + 标今日首次登录,重新进 Home 弹 PopEmolument · 关闭/显示广告、打开/关闭内购:切换调试开关 · 开启/关闭己方或敌方营地不掉血:本次登录有效,不写档 【参数按钮】(先在输入框填参数再点按钮) · 设置道具数量:道具ID 数量(空格分隔) · 设置武器数量:武器ID 数量(空格分隔,写入成品库存) · 设置主动BUFF:Battlebuff.id(type=1),只写携带第1槽(有则替换;0/空=清空) · 设置被动BUFF:Battlebuff.id(type=2),只写携带第1槽(有则替换;0/空=清空) · 设置金钱 / 体力 / 钻石:单个数字 · 设置关卡解锁:章节 id · 设置星数:总星数(>=1) · 设置玩家局内血量:城墙最大血量 · 设置玩家等级:主角总等级 · 设置玩家存档:粘贴 JSON 存档 · 设置通关怪物数量:N 或 0 关闭 · 指定背包文字:id 或名称,逗号分隔 · 设置AI主动BUFF:Battlebuff.id,逗号分隔(type=1,下局生效;空/0 关闭) · 设置AI被动BUFF:Battlebuff.id,逗号分隔(type=2,下局生效;空/0 关闭) · 固定地图:填 Level.id(关卡表 name 对应关卡);0 关闭随机 `; /** GM 固定关卡:参数行展示 */ private _formatFixedLevelParam(levelId: number): string { if (levelId <= 0) return '参数:0(随机)'; const row = gg.data.table.getTableData(TableNames.Level, levelId); const name = typeof row?.name === 'string' ? row.name.trim() : ''; return name ? `参数:${levelId}(${name})` : `参数:${levelId}`; } /** GM 固定关卡:设置成功 toast */ private _formatFixedLevelToast(levelId: number): string { const row = gg.data.table.getTableData(TableNames.Level, levelId); const name = typeof row?.name === 'string' ? row.name.trim() : ''; return name ? `下局固定关卡${levelId}(${name})` : `下局固定关卡${levelId}`; } }