//********************* // create by 流云 // time: Wed Mar 25 2026 // desc: //********************* import { _decorator, Component, Node, find, instantiate, RichText, Tween, Vec3 } from 'cc'; import { Auto_SkillSelect } from './Auto_SkillSelect'; import { MonsterType } from '../../manager/MonsterDataManager'; import { SkillSelectItem } from './SkillSelectItem'; import { BattleType, ChapterDifficulty } from '../../manager/ChapterDataManager'; import BeginnerGuideManager, { BeginnerGuideType } from '../BattleGame/BeginnerGuideManager'; import { GEvent } from 'db://assets/mx/module/event/GEvent'; import { ConstNumType } from '../../game/ConfigProjectData'; import { StatisticsType } from '../../game/GameData'; import { UIID } from '../../game/ConfigRes'; import { WeaponType } from '../../manager/WeaponDataManager'; import MTools from 'db://assets/mx/tools/MTools'; import { OpenParam } from '../../../mx/module/ui/UIBase'; import { BattleResLoader } from '../../game/BattleResLoader'; const { ccclass, property } = _decorator; @ccclass('UISkillSelect') export class UISkillSelect extends Auto_SkillSelect { guideBtnNode: Node = null; onLoad(): void { super.onLoad(); } onEnable(): void { super.onEnable(); if (!gg.game?.isBattleContextActive?.()) { return; } gg.game.CurentBattle.pause('SkillSelect'); } onAdded(args?: OpenParam): void { try { super.onAdded(args); } catch (e) { console.error('[UISkillSelect] onAdded/onInit error', e); try { gg.ui.reportSkillSelectInitFailed(args, e, this.getOpenFailContext()); } catch (reportErr) { console.error('[UISkillSelect] reportSkillSelectInitFailed error', reportErr); } void this.close(1); } } onDisable(): void { super.onDisable(); const battle = gg.game?.CurentBattle; if (!battle) { return; } if (battle.BattleType == BattleType.SpeedMode) { this.getAll(); } if (battle.BattleType == BattleType.OrangeWeaponMode_Ya) { battle.luosiReplicaBoxForceType = 0; battle.flushPendingJiujiuwoyaSkillUpgradeEffect(); } battle.onBlockingPanelClosed(); } onInit(): void { if (!gg.game?.isBattleContextActive?.()) { void this.close(1); return; } let isFirstSelectWeapon = this.prema || false console.log('isFirstSelectWeapon', isFirstSelectWeapon) this.showOpenCenterEff(); this.showOpenMaskEff(2); gg.game.CurentBattle.IsOpenSkillSelectTimes++; // 开启宝箱会推进“已开启次数”,需要立即刷新主界面宝箱免费/价格文案 GEvent.Ins.emit(GEvent.UpdateGameCoinNum); this.initData(false, isFirstSelectWeapon); if (this._skillSelectTreasureTrace) { console.log('[SkillSelectTrace]', JSON.stringify({ step: 'onInit_done', wave: gg.game.CurentBattle?.CurentWaveNum, openTimes: gg.game.CurentBattle?.IsOpenSkillSelectTimes, isSkillSelect: this._isSkillSelect, skillCount: this.skills?.length ?? 0, weaponCount: this.weapons?.length ?? 0, })); } } skills: ITableSkill[] = [] weapons: ITableWeapon2[] = [] tetriTypes: number[] = [] /** 救救我鸭:每个武器选项对应要替换的角色下标(优先 weaponid=1) */ private _yaCarrierIndices: number[] = []; private _isSkillSelect: boolean = true; private _itemBaseScale: Vec3 | null = null; isFirstSelectWeapon = false /** 打开失败时采集:三选一 skill/weapon id + 本局已拥有武器/技能 id(0 表示该项数据异常) */ getOpenFailContext(): Record { const battle = gg.game?.CurentBattle; const curWeaponIds = battle?.CurUseWeaponArr?.map(w => w?.weaponid).filter(id => id != null) ?? []; const curSkillIds = battle?.CurUseSkillArr?.map(s => s?.id).filter(id => id != null) ?? []; const panelType = this._resolvePanelTypeForFailContext(); const isSkillPanel = panelType === 'skill'; return { panelType, pickSkillIds: isSkillPanel ? (this.skills?.map(s => (s && s.id != null) ? s.id : 0) ?? []) : [], pickWeaponIds: !isSkillPanel ? (this.weapons?.map(w => (w && w.weaponid != null) ? w.weaponid : 0) ?? []) : [], curWeaponIds, curSkillIds, }; } /** initData 未完成时,按开箱次数推断当前应是技能箱还是武器箱 */ private _resolvePanelTypeForFailContext(): 'skill' | 'weapon' { try { if (this.isFirstSelectWeapon) { return 'weapon'; } const battle = gg.game?.CurentBattle; if (!battle) { return this._isSkillSelect ? 'skill' : 'weapon'; } let arr = gg.data?.table?.getConstArray(ConstNumType.IsOpenSkillSelect) ?? []; if (battle.BattleType == BattleType.OrangeWeaponMode_Dan) { arr = []; } const isSkill = !arr.includes(battle.IsOpenSkillSelectTimes) && battle.BattleType != BattleType.SpeedMode && !this.isFirstSelectWeapon; return isSkill ? 'skill' : 'weapon'; } catch { return this._isSkillSelect ? 'skill' : 'weapon'; } } initData(isAd: boolean = false, isFirstSelectWeapon: boolean = false) { if (!gg.game?.isBattleContextActive?.()) { return; } let arr = gg.data.table.getConstArray(ConstNumType.IsOpenSkillSelect); if(gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Dan){ arr = [] //没有武器宝箱选择 } this.isFirstSelectWeapon = isFirstSelectWeapon const yaForce = gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Ya ? gg.game.CurentBattle.luosiReplicaBoxForceType : 0; if (yaForce === 1) { //this.isFirstSelectWeapon = true; } this._isSkillSelect = !arr.includes(gg.game.CurentBattle.IsOpenSkillSelectTimes) && gg.game.CurentBattle.BattleType != BattleType.SpeedMode && !this.isFirstSelectWeapon; if (yaForce === 2) { this._isSkillSelect = true; } if (yaForce === 1) { this._isSkillSelect = false; } if (yaForce) { gg.game.CurentBattle.luosiReplicaBoxForceType = 0; } if (this._isSkillSelect && !isFirstSelectWeapon) { if (gg.data.doc.chapter == 1 && gg.game.CurentBattle.IsOpenSkillSelectTimes == 2 && gg.game.CurentBattle.curRogueSkillTimes == 0) { if (!isAd) { this.skills = gg.game.CurentBattle.SkillCore.getFirstRandomSkills() } else { this.skills = gg.game.CurentBattle.SkillCore.getSecondRandomSkills() } } else { this.skills = gg.game.CurentBattle.SkillCore.randomSkills(3, isAd).map(x => x.skill); } } else { if (gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Ya) { this.weapons = gg.game.CurentBattle.getJiujiuwoyaWeapons(isAd); this._yaCarrierIndices = gg.game.CurentBattle.getJiujiuwoyaWeaponCarrierIndices(this.weapons.length); } else { this.weapons = gg.game.CurentBattle.getWeapons(isAd); this._yaCarrierIndices = []; } this.tetriTypes = []; // console.log('this.weapons', this.weapons) if (gg.game.CurentBattle.BattleType != BattleType.SpeedMode && gg.game.CurentBattle.BattleType != BattleType.OrangeWeaponMode_Dan && gg.game.CurentBattle.BattleType != BattleType.OrangeWeaponMode_Ya) { for (let i = 0; i < this.weapons.length; i++) { this.tetriTypes.push(gg.game.CurentBattle.getTetrTypeRandom()); } } else { const n = Math.max(this.weapons.length, 3); if (gg.game.CurentBattle.BattleType != BattleType.OrangeWeaponMode_Ya) { this.tetriTypes = MTools.getRandomElements([1, 2, 3, 4, 5, 6], n); } if(gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Dan){ this.tetriTypes = gg.game.CurentBattle.ModechooseTetriType console.log('this.tetriTypes', this.tetriTypes) } } } this.updateUI() } updateUI() { const content = this.ui_content; if (!content) return; // 连续开宝箱/快速刷新时,item 可能正在做缩放 tween(scale.x=0→1) // 若此时用 children[0] 作为模板 instantiate,会把“中途缩放”的 scale 克隆过去,导致新 item 偶现变小/变大 // 仅重置 children[0] 不够:当本次只展示 2 个时,第 3 个子节点被隐藏且不会进下方循环,其 tween 仍会继续并污染下次 instantiate const kids = content.children.slice(); for (const node of kids) { if (!node?.isValid) continue; Tween.stopAllByTarget(node); const si = node.getComponent(SkillSelectItem); if (si) si.resetScale(); } const tplNode = (this.ui_singleItem?.isValid ? this.ui_singleItem : content.children[0]) ?? null; const tplItem = tplNode?.getComponent(SkillSelectItem) ?? null; if (tplItem) { if (!this._itemBaseScale) { this._itemBaseScale = tplItem.getBaseScale(); } if (this._itemBaseScale && tplNode?.isValid) { tplNode.setScale(this._itemBaseScale.x, this._itemBaseScale.y, this._itemBaseScale.z); } } for (let i = 0; i < this.ui_content.children.length; i++) { let item = this.ui_content.children[i]; item.active = false; } if (this._isSkillSelect) { for (let i = 0; i < this.skills.length; i++) { let data = this.skills[i]; let n: Node = null; if (i < this.ui_content.children.length) { n = this.ui_content.children[i]; } else { const proto = (this.ui_singleItem?.isValid ? this.ui_singleItem : this.ui_content.children[0]); n = instantiate(proto); n.parent = this.ui_content; } n.active = true; const item = n.getComponent(SkillSelectItem); if (item) { item.resetScale(); item.setSkill(data); } else if (this._itemBaseScale) { n.setScale(this._itemBaseScale.x, this._itemBaseScale.y, this._itemBaseScale.z); } } } else { for (let i = 0; i < this.weapons.length; i++) { let data = this.weapons[i]; let n: Node = null; if (i < this.ui_content.children.length) { n = this.ui_content.children[i]; } else { const proto = (this.ui_singleItem?.isValid ? this.ui_singleItem : this.ui_content.children[0]); n = instantiate(proto); n.parent = this.ui_content; } n.active = true; const item = n.getComponent(SkillSelectItem); if (item) { item.resetScale(); const ya = gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Ya; const carrierIdx = ya ? (this._yaCarrierIndices[i] ?? i) : this.tetriTypes[i]; item.setWeapon(data, carrierIdx); if (gg.data.doc.chapter == 1 && gg.game.CurentBattle.curRogueWeaponTimes == 1) { if (data.weaponid == WeaponType.FuWenTa) { this.guideBtnNode = n this.scheduleOnce(() => { this.showNewGuide() }, 0.1) } } } else if (this._itemBaseScale) { n.setScale(this._itemBaseScale.x, this._itemBaseScale.y, this._itemBaseScale.z); } } } if (this._isSkillSelect) { this.lb_tittle.string = gg.lang.get('技能升级')//'技能升级' this.lb_subTittle.string = gg.lang.get('请选择升级一个技能')//'请选择升级一个技能' } else { this.lb_tittle.string = gg.lang.get('武器升级')//'武器升级' this.lb_subTittle.string = gg.lang.get('请选择升级一个武器')//'请选择升级一个武器' if(gg.game.CurentBattle.BattleType == BattleType.SpeedMode || this.isFirstSelectWeapon) { this.lb_tittle.string = gg.lang.get('武器选择')//'武器升级' this.lb_subTittle.string = gg.lang.get('本局使用武器')//'请选择升级一个武器' } } //设置按钮状态 let rogueFreeRefreshTimes = gg.game.CurentBattle.getRogueFreeRefreshTimes() let rogueADRefreshTimes = gg.game.CurentBattle.getRogueADRefreshTimes() let rogueFreeAllGetTimes = gg.game.CurentBattle.getRogueFreeAllGetTimes() let rogueADAllGetTimes = gg.game.CurentBattle.getRogueADAllGetTimes() this.btnRefresh.active = rogueFreeRefreshTimes > 0 this.btnRefreshAD.active = !this.btnRefresh.active && rogueADRefreshTimes > 0 this.btnAll.active = rogueFreeAllGetTimes > 0 && this._isSkillSelect && !this.btnRefresh.active; this.btnADAll.active = !this.btnAll.active && rogueADAllGetTimes > 0 && this._isSkillSelect; this.btnRefresh.getChildByName('leftTimes').getComponent(RichText).string = gg.lang.get('剩余{1}次', [rogueFreeRefreshTimes]) //`${rogueFreeRefreshTimes}` this.btnRefreshAD.getChildByName('leftTimes').getComponent(RichText).string = gg.lang.get('剩余{1}次', [rogueADRefreshTimes]) //`${rogueADRefreshTimes}` this.btnAll.getChildByName('leftTimes').getComponent(RichText).string = gg.lang.get('剩余{1}次', [rogueFreeAllGetTimes]) //`${rogueFreeAllGetTimes}` this.btnADAll.getChildByName('leftTimes').getComponent(RichText).string = gg.lang.get('剩余{1}次', [rogueADAllGetTimes]) //`${rogueADAllGetTimes}` if (this._isSkillSelect && gg.game.CurentBattle.ChapterId == 1) { this.ui_dianji.active = this.btnRefresh.active } if (this._isSkillSelect && gg.game.CurentBattle.ChapterId == 1) { this.ui_dianjiAll.active = this.btnAll.active } //curRogueWeaponTimes == 0隐藏按钮 if (this._isSkillSelect) { if (gg.game.CurentBattle.curRogueSkillTimes == 0 && gg.game.CurentBattle.ChapterId == 1 && gg.game.CurentBattle.Difficulty == ChapterDifficulty.Normal) { // this.btnRefreshAD.active = false // this.btnAll.active = false // this.btnADAll.active = false //console.log('gg.game.CurentBattle.curRogueSkillTimes111', gg.game.CurentBattle.curRogueSkillTimes) } } else { if (gg.game.CurentBattle.curRogueWeaponTimes == 1 && gg.game.CurentBattle.ChapterId == 1 && gg.game.CurentBattle.Difficulty == ChapterDifficulty.Normal) { this.btnRefreshAD.active = false this.btnAll.active = false this.btnADAll.active = false this.btnRefresh.active = false this.btnSure.active = false; //console.log('gg.game.CurentBattle.curRogueWeaponTimes222', gg.game.CurentBattle.curRogueWeaponTimes) } if (gg.game.CurentBattle.BattleType == BattleType.SpeedMode || this.isFirstSelectWeapon) { this.btnRefreshAD.active = false this.btnAll.active = false this.btnADAll.active = false this.btnRefresh.active = false this.btnSure.active = true; } } } click_btnADAll(): void { gg.sdk.showVideoAd((res) => { if (res) { let curWaveNum = gg.game.CurentBattle.CurentWaveNum gg.sdk.reportDY("inLevel", `章节${gg.game.CurentBattle.getReportDYChapterId()}_${curWaveNum}-AD-技能全都要`) gg.game.CurentBattle.subRogueADAllGetTimes() this.getAll(); gg.game.CurentBattle.IsWatchAd = true gg.PRR.AdClickNum.push(2) } else { gg.ui.showToast("观看视频失败"); } }); } click_btnAll(): void { //白银宝箱 gg.game.CurentBattle.subRogueFreeAllGetTimes() this.getAll(); gg.sdk.reportDY("inLevel", `章节${gg.game.CurentBattle.getReportDYChapterId()}_${gg.game.CurentBattle.CurentWaveNum}-免费技能全都要`) } click_btnRefresh(): void { gg.game.CurentBattle.subRogueFreeRefreshTimes() gg.sdk.reportDY("inLevel", `章节${gg.game.CurentBattle.getReportDYChapterId()}_${gg.game.CurentBattle.CurentWaveNum}-免费技能刷新`) this.initData(true); } click_btnRefreshAD(): void { gg.sdk.showVideoAd((res) => { if (res) { let curWaveNum = gg.game.CurentBattle.CurentWaveNum gg.sdk.reportDY("inLevel", `章节${gg.game.CurentBattle.getReportDYChapterId()}_${curWaveNum}-AD-技能刷新`) gg.game.CurentBattle.subRogueADRefreshTimes() gg.game.CurentBattle.IsWatchAd = true gg.PRR.AdClickNum.push(1) this.initData(true); } else { gg.ui.showToast("观看视频失败"); } }); } click_btnSure(): void { if (this.isFirstSelectWeapon && gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Dan) { this.getAll(); } this.close(); } getAll() { if (this._isSkillSelect) { gg.game.CurentBattle.addCurRogueSkillTimes(); gg.game.CurentBattle.addCurHaveSkillArr(this.skills); //判断是抽卡副本 if (gg.game.CurentBattle.BattleType == BattleType.GachaMode) { GEvent.Ins.emit(GEvent.AddSkillIcon, this.skills); } } else { gg.game.CurentBattle.addCurRogueWeaponTimes(); const ya = gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Ya; for (let i = 0; i < this.weapons.length; i++) { if (ya) { const idx = this._yaCarrierIndices[i] ?? i; gg.game.CurentBattle.changeJiujiuwoyaWeapon(idx, this.weapons[i].weaponid); } else { gg.game.CurentBattle.changeTetriWeaponConfig(this.tetriTypes[i], this.weapons[i].weaponid); } } //判断是抽卡副本 if (gg.game.CurentBattle.BattleType == BattleType.GachaMode) { GEvent.Ins.emit(GEvent.AddWeaponIcon, this.weapons.map(x => x.weaponid)); } // 全选武器:预热各武器子弹 + hitEffect 爆炸 BattleResLoader.preloadWeaponCombatAssetsBatch(this.weapons); } this.close(); } showNewGuide(idx: number = 0) { if (gg.data.doc.chapter == 1 && gg.game.CurentBattle.curRogueWeaponTimes == 1) { //引导 gg.ui.openPanel(UIID.NewGuideMask, { data: [ [this.guideBtnNode], [''], () => { //gg.data.setStatistics(StatisticsType.firstChapterGuideIndex, 2) }, true, 255 ] }); } // if (gg.game.CurentBattle.Difficulty != ChapterDifficulty.Normal) { // return // } // let curRogueSkillTimes = gg.game.CurentBattle.curRogueSkillTimes // if (idx == 1 && gg.game.CurentBattle.ChapterId == 1 && this.rogueType == MonsterType.SilverBoss && curRogueSkillTimes == 0) {//&& gg.data.getLocalGuideValue('引导刷新技能') == '0' // // gg.data.setLocalGuideValue('引导刷新技能', '1') // // BeginnerGuideManager 会吞掉触摸,底层 btnRefresh 收不到点击,需在回调里补发一次刷新 // // 引导镂空/层级下,同一触摸可能先命中按钮再进回调,会触发两次 click_btnRefresh:引导期间先卸掉按钮监听 // this.btnRefresh.off(Node.EventType.TOUCH_END, this.click_btnRefresh, this) // this.ui_guideMask.active = true // let firstNode = this.btnRefresh//this.ui_guideMask.getChildByName('freeRefreshPos') // let guideActionApplied = false // let finishCallBack = () => { // if (guideActionApplied) return // guideActionApplied = true // this.ui_guideMask.active = false // this.click_btnRefresh() // //this.btnRefresh.on(Node.EventType.TOUCH_END, this.click_btnRefresh, this) // } // this.ui_guideMask.getComponent(BeginnerGuideManager).setIsGuideClick(BeginnerGuideType.DIANJI) // this.ui_guideMask.getComponent(BeginnerGuideManager).setBindNode(firstNode, finishCallBack, // gg.lang.get('刷新更高概率获得技能'), 1, 1200) // } else if (idx == 3 && gg.game.CurentBattle.ChapterId == 1 && this.rogueType == MonsterType.SilverBoss && curRogueSkillTimes == 0) {//&& gg.data.getLocalGuideValue('引导选择第一个技能') == '0' // // BeginnerGuideManager 会吞掉触摸,底层 SkillSelectItem 收不到点击,需在回调里补发 onClick // // 同一触摸若先穿透到首张卡片会触发 onClick,再进回调会双选:仅对引导绑定的那张卡卸监听 // this.ui_guideMask.active = true // let firstNode = this.ui_content.children[0] // let firstItem = firstNode?.getComponent(SkillSelectItem) // if (firstItem) { // firstNode.off(Node.EventType.TOUCH_END, firstItem.onClick, firstItem) // } // let guideActionApplied = false // let finishCallBack = () => { // if (guideActionApplied) return // guideActionApplied = true // this.ui_guideMask.active = false // let item = firstNode?.getComponent(SkillSelectItem) // if (item?.node?.isValid && item.Skill) { // item.onClick() // } // } // this.ui_guideMask.getComponent(BeginnerGuideManager).setIsGuideClick(BeginnerGuideType.DIANJI) // this.ui_guideMask.getComponent(BeginnerGuideManager).setBindNode(firstNode, finishCallBack, // gg.lang.get('品质更好更强'), 1, 1200) // } } }