//********************* // create by 流云 // time: Thu Sep 25 2025 // desc: //********************* import { _decorator, Label, Node, sp, Sprite } from 'cc'; import { Auto_BattleRevive } from './Auto_BattleRevive'; import { BattleReviveNodes, playBattleReviveOpen, prepareBattleReviveOpen, stopBattleReviveOpen, syncBtnLayout, } from './BattleReviveOpenAnim'; import { UIID } from '../../game/ConfigRes'; import { GEvent } from 'db://assets/mx/module/event/GEvent'; import { readRevivePeachRewardAmount } from '../../battle/runtime/BattleRuntime'; import { IPopAnimConfig } from 'db://assets/mx/module/ui/popAnim'; const { ccclass } = _decorator; @ccclass('UIBattleRevive') export class UIBattleRevive extends Auto_BattleRevive { private _reviveNodes: BattleReviveNodes = null; onLoad(): void { super.onLoad(); this._bindReviveNodes(); } /** preparePopOpenPose 可能在 onLoad 之前调用,需惰性绑定节点 */ private _bindReviveNodes(): void { if (this._reviveNodes || !this.ui_center) return; const progressNode = this.lb_progress?.node ?? this.ui_center.getChildByName('lb_progress'); this._reviveNodes = { bg: this.ui_center.getChildByName('复活背景'), title: this._resolveReviveTitle(), spine: this._resolveReviveSpine(), progressBg: this.ui_center.getChildByName('圆角矩形 1160'), progressPrefix: this.ui_center.getChildByName('Label'), progressLabel: progressNode, progressSuffix: this.ui_center.getChildByName('Label-001'), rewardLabel: this.ui_center.getChildByName('复活奖励'), rewardPanel: this.ui_center.getChildByName('组 2562'), tipText: this.ui_center.getChildByName('Label2'), btnLayout: this.ui_center.getChildByName('btnLayout'), }; } /** 预制体里有两个「复活继续」:取带 Spine 的角色动画,跳过标题 Sprite */ private _resolveReviveSpine(): Node { for (const c of this.ui_center.children) { if (c.name === '复活继续' && c.getComponent(sp.Skeleton)) return c; } console.log('[UIBattleRevive] revive spine node not found'); return null; } /** 预制体里有两个「复活继续」:取带 Sprite 的标题图,跳过废弃 Spine */ private _resolveReviveTitle(): Node { for (const c of this.ui_center.children) { if (c.name === '复活继续' && c.getComponent(Sprite)) return c; } return this.ui_center.getChildByName('复活继续'); } onDisable(): void { if (this._reviveNodes) { stopBattleReviveOpen(this._reviveNodes); } super.onDisable(); } preparePopOpenPose(): void { const cfg = this.uiInfo?.uiconf?.popAnim as IPopAnimConfig | undefined; if (!cfg) return; // UIManager 会在 onLoad 前调用;此处仅遮罩,节点隐藏与序列在 onInit 执行 gg.ui.popAnim.prepareOpen(this.node, cfg.mask ?? 'dim', 'none'); } playPopFromConfig(): void { const cfg = this.uiInfo?.uiconf?.popAnim as IPopAnimConfig | undefined; if (!cfg) return; if (cfg.mask !== 'none') { this.popMask(cfg.mask ?? 'dim'); } } onInit(): void { this.refreshFailReviveLeftNum(); syncBtnLayout(this._reviveNodes?.btnLayout); this.refreshGameProgress(); if (this._reviveNodes) { prepareBattleReviveOpen(this._reviveNodes); } this._playReviveMotivation(); } private _playReviveMotivation(): void { if (!this._reviveNodes) return; const progressPercent = this._readProgressPercent(); const reviveBtn = this.btnFreeRevive.active ? this.btnFreeRevive : this.btnAdRevive; playBattleReviveOpen({ nodes: this._reviveNodes, progressPercent, reviveBtn, onComplete: () => { this.notifyOpenAnimEnd(); }, }); } private _readProgressPercent(): number { const raw = parseInt(this.lb_progress.string, 10); return Number.isFinite(raw) ? raw : 0; } refreshGameProgress() { let curDeadMonsterNum = gg.game.CurentBattle.MonsterDeadNum; let totalMonsterNum = gg.game.CurentBattle.TotalMonsterNum; this.lb_progress.string = `${Math.floor((totalMonsterNum - curDeadMonsterNum) / totalMonsterNum * 100)}%` } refreshFailReviveLeftNum() { if (!this.btnAdRevive?.isValid || !this.btnFreeRevive?.isValid) return; let curFailReviveLeftNum = gg.game.CurentBattle.curFailReviveLeftNum; this.btnAdRevive.getChildByName('leftTimes').getComponent(Label).string = gg.lang.get('剩余次数x{1}', [curFailReviveLeftNum]) this.btnFreeRevive.getChildByName('leftTimes').getComponent(Label).string = gg.lang.get('剩余次数x{1}', [curFailReviveLeftNum]) this.btnFreeRevive.active = gg.game.CurentSelectChapterId == 1 && curFailReviveLeftNum >= 2 this.btnAdRevive.active = !this.btnFreeRevive.active } click_btnBack(): void { let curWaveNum = gg.game.CurentBattle.CurentWaveNum; gg.sdk.reportDY("inLevel", `${gg.game.getReportDYBattleLabel(curWaveNum)}-放弃复活`) this.close(2).then(() => { gg.game.CurentBattle.gameOver(false); gg.ui.openPanel(UIID.BattleFail); }); } click_btnAdRevive() { gg.sdk.showVideoAd((res) => { if (res) { let curWaveNum = gg.game.CurentBattle.CurentWaveNum; gg.sdk.reportDY("inLevel", `${gg.game.getReportDYBattleLabel(curWaveNum)}-AD-广告复活`) gg.game.CurentBattle.curFailReviveLeftNum--; this.refreshFailReviveLeftNum() this.close(2).then(() => { this.gameReborn(); GEvent.Ins.emit(GEvent.GameReborn) }); } else { gg.ui.showToast('观看视频失败'); } }) } click_btnFreeRevive(): void { let curWaveNum = gg.game.CurentBattle.CurentWaveNum; gg.sdk.reportDY("inLevel", `${gg.game.getReportDYBattleLabel(curWaveNum)}-复活`) gg.game.CurentBattle.curFailReviveLeftNum--; this.refreshFailReviveLeftNum() this.close(2).then(() => { this.gameReborn(); GEvent.Ins.emit(GEvent.GameReborn) }); } gameReborn(): void { const battle = gg.game.CurentBattle; gg.ui.removeQueuedPopPanels(UIID.BattleRevive); battle.setCurentWallHp(battle.WallMaxHp); battle.resetAliveMonstersToBornPosAfterRevive(); const peach = readRevivePeachRewardAmount(); if (peach > 0) { battle.addCoinNum(peach); battle.lastRevivePeachGrant = peach; GEvent.Ins.emit(GEvent.UpdateGameCoinNum); GEvent.Ins.emit(GEvent.RevivePeachGrant, peach); } else { console.error( '[UIBattleRevive] revive peach amount is 0, reward=', peach, ); } GEvent.Ins.emit(GEvent.playerHit); battle.session.leaveWaitReviveToCombat(); } }