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.
233 lines
8.2 KiB
233 lines
8.2 KiB
import { game, Node } from 'cc';
|
|
import { BattlePhase } from 'db://assets/mx/module/battle';
|
|
import { GEvent } from '../../../mx/module/event/GEvent';
|
|
import { getShieldAdTriggerDist } from '../../battle/bag/BagPrepConfig';
|
|
import { BattleUiPauseGate } from '../../battle/BattleUiPauseGate';
|
|
import type { ProjectBattleHandle } from '../../battle/runtime/BattleRuntime';
|
|
import type { BattleGameMenShenTrapController } from './BattleGameMenShenTrapController';
|
|
import { BattleGameItemAdBtnPulse } from './BattleGameItemAdBtnPulse';
|
|
|
|
/** 广告类型 */
|
|
enum ItemAdKind {
|
|
/** 无 */
|
|
None = 0,
|
|
/** 门神盾牌 */
|
|
MenShen = 1,
|
|
}
|
|
|
|
/** 观看广告期间暂停 */
|
|
const AD_PAUSE_TOKEN = 'ad:battleItem';
|
|
|
|
/**
|
|
* BattleGame btnItem:门神盾牌广告入口。
|
|
* - 盾牌:怪首次离终点 Const23 格内触发,每局 1 次;放置陷阱后隐藏
|
|
*/
|
|
export class BattleGameItemAdPresenter {
|
|
private _btnItem: Node | null = null;
|
|
private _menIcon: Node | null = null;
|
|
private _videoIcon: Node | null = null;
|
|
|
|
private _battle: ProjectBattleHandle | null = null;
|
|
private _menShenTrap: BattleGameMenShenTrapController | null = null;
|
|
|
|
private _adPending = false;
|
|
private _activeKind = ItemAdKind.None;
|
|
private _shieldScanDone = false;
|
|
/** 盾牌广告已点击并放置陷阱 */
|
|
private _shieldBtnDismissed = false;
|
|
private _onBoardChanged: (() => void) | null = null;
|
|
private readonly _btnPulse = new BattleGameItemAdBtnPulse();
|
|
private _btnPulseActive = false;
|
|
/** 威胁扫描降频 */
|
|
private _threatScanAcc = 0;
|
|
/** 缓存:Const23 内是否有进攻怪 */
|
|
private _threatInZone = false;
|
|
|
|
/**
|
|
* @param btnItem ui_ready/btnItem 根节点
|
|
* @param menShenTrap 门神陷阱控制器
|
|
*/
|
|
bind(battle: ProjectBattleHandle | null, btnItem: Node | null, menShenTrap: BattleGameMenShenTrapController | null): void {
|
|
this.unbind();
|
|
this._battle = battle;
|
|
this._menShenTrap = menShenTrap;
|
|
this._btnItem = btnItem;
|
|
|
|
if (!btnItem?.isValid) {
|
|
console.log('[BattleItemAd] btnItem 缺失');
|
|
return;
|
|
}
|
|
|
|
const shovelIcon = btnItem.getChildByName('shovelIcon');
|
|
const goldShovelIcon = btnItem.getChildByName('goldShovelIcon');
|
|
const numNode = btnItem.getChildByName('num');
|
|
this._setNodeActive(shovelIcon, false);
|
|
this._setNodeActive(goldShovelIcon, false);
|
|
this._setNodeActive(numNode, false);
|
|
|
|
this._menIcon = btnItem.getChildByName('menIcon');
|
|
this._videoIcon = btnItem.getChildByName('video');
|
|
|
|
btnItem.on(Node.EventType.TOUCH_END, this._onBtnClick, this);
|
|
this._onBoardChanged = () => this._refreshVisibility();
|
|
GEvent.Ins.on(GEvent.UpdateBestPlace, this._onBoardChanged, this);
|
|
this._refreshVisibility();
|
|
}
|
|
|
|
/** 解除绑定 */
|
|
unbind(): void {
|
|
if (this._btnItem?.isValid) {
|
|
this._btnItem.off(Node.EventType.TOUCH_END, this._onBtnClick, this);
|
|
}
|
|
if (this._onBoardChanged) {
|
|
GEvent.Ins.off(GEvent.UpdateBestPlace, this._onBoardChanged, this);
|
|
}
|
|
this._onBoardChanged = null;
|
|
if (this._adPending) {
|
|
this._adPending = false;
|
|
BattleUiPauseGate.release(AD_PAUSE_TOKEN);
|
|
}
|
|
this._btnItem = null;
|
|
this._menIcon = null;
|
|
this._videoIcon = null;
|
|
this._battle = null;
|
|
this._menShenTrap = null;
|
|
this._activeKind = ItemAdKind.None;
|
|
this._shieldScanDone = false;
|
|
this._shieldBtnDismissed = false;
|
|
this._btnPulseActive = false;
|
|
this._threatScanAcc = 0;
|
|
this._threatInZone = false;
|
|
this._syncBtnPulse(false);
|
|
}
|
|
|
|
/** 帧更新:扫描盾牌触发条件并刷新显隐 */
|
|
tick(_dt: number): void {
|
|
this._threatScanAcc++;
|
|
if (this._threatScanAcc % 12 === 1) {
|
|
this._threatInZone = this._scanThreatInZone();
|
|
}
|
|
this._tickShieldOffer();
|
|
this._refreshVisibility();
|
|
}
|
|
|
|
/** 首次满足距离时触发盾牌广告 */
|
|
private _tickShieldOffer(): void {
|
|
const battle = this._battle;
|
|
const trap = this._menShenTrap;
|
|
if (!battle || !trap || battle.menShenAdConsumed) return;
|
|
if (battle.canShowMenShenAd()) {
|
|
this._shieldScanDone = true;
|
|
return;
|
|
}
|
|
if (this._shieldScanDone) return;
|
|
if (battle.session.phase !== BattlePhase.COMBAT || battle.session.ended) return;
|
|
|
|
const triggerDist = getShieldAdTriggerDist();
|
|
if (!(triggerDist > 0)) return;
|
|
if (!this._threatInZone) return;
|
|
|
|
battle.triggerMenShenAdOffer();
|
|
this._shieldScanDone = true;
|
|
}
|
|
|
|
/** 刷新 btnItem 显隐与图标 */
|
|
private _refreshVisibility(): void {
|
|
const kind = this._resolveActiveKind();
|
|
this._activeKind = kind;
|
|
|
|
const btn = this._btnItem;
|
|
if (!btn?.isValid) return;
|
|
const show = kind !== ItemAdKind.None;
|
|
if (btn.active !== show) btn.active = show;
|
|
this._syncBtnPulse(show);
|
|
if (!show) return;
|
|
|
|
const showMen = kind === ItemAdKind.MenShen;
|
|
this._setNodeActive(this._menIcon, showMen);
|
|
this._setNodeActive(this._videoIcon, true);
|
|
}
|
|
|
|
/** 解析当前应展示的广告类型(仅门神盾牌) */
|
|
private _resolveActiveKind(): ItemAdKind {
|
|
const battle = this._battle;
|
|
if (!battle || battle.session.ended) return ItemAdKind.None;
|
|
|
|
const canMenShen = !this._shieldBtnDismissed && battle.canShowMenShenAd();
|
|
const hasThreatInConst23 = this._hasMonsterInShieldTriggerZone();
|
|
|
|
if (canMenShen && hasThreatInConst23) return ItemAdKind.MenShen;
|
|
if (canMenShen) return ItemAdKind.MenShen;
|
|
return ItemAdKind.None;
|
|
}
|
|
|
|
/** Const23 触发距离内是否存在进攻怪(用降频缓存) */
|
|
private _hasMonsterInShieldTriggerZone(): boolean {
|
|
return this._threatInZone;
|
|
}
|
|
|
|
/** 扫描 Const23 内进攻怪 */
|
|
private _scanThreatInZone(): boolean {
|
|
const trap = this._menShenTrap;
|
|
if (!trap || !this._battle) return false;
|
|
const triggerDist = getShieldAdTriggerDist();
|
|
if (!(triggerDist > 0)) return false;
|
|
return trap.shouldOfferShieldAd(triggerDist);
|
|
}
|
|
|
|
private readonly _onBtnClick = (): void => {
|
|
if (this._adPending) return;
|
|
const kind = this._activeKind;
|
|
if (kind === ItemAdKind.MenShen) {
|
|
this._playMenShenAd();
|
|
}
|
|
};
|
|
|
|
/** 观看门神广告并布置陷阱 */
|
|
private _playMenShenAd(): void {
|
|
const battle = this._battle;
|
|
const trap = this._menShenTrap;
|
|
if (!battle?.canShowMenShenAd() || !trap) return;
|
|
|
|
this._adPending = true;
|
|
BattleUiPauseGate.acquire(AD_PAUSE_TOKEN);
|
|
gg.sdk.showVideoAd((res) => {
|
|
if (!this._adPending) return;
|
|
this._adPending = false;
|
|
BattleUiPauseGate.release(AD_PAUSE_TOKEN);
|
|
if (game.isPaused()) game.resume();
|
|
if (!res) {
|
|
gg.ui.showToast('观看视频失败');
|
|
return;
|
|
}
|
|
const b = this._battle;
|
|
const t = this._menShenTrap;
|
|
if (!b?.canShowMenShenAd() || !t) return;
|
|
|
|
b.IsWatchAd = true;
|
|
b.consumeMenShenAd();
|
|
if (!t.tryPlaceTraps()) {
|
|
console.log('[BattleItemAd] 门神陷阱放置失败');
|
|
}
|
|
const curWaveNum = gg.game.CurentBattle.CurentWaveNum;
|
|
gg.sdk.reportDY('inLevel', `${gg.game.getReportDYBattleCountLabel(curWaveNum)}-AD-广告门神盾牌`);
|
|
this._shieldBtnDismissed = true;
|
|
this._refreshVisibility();
|
|
});
|
|
}
|
|
|
|
private _setNodeActive(node: Node | null, active: boolean): void {
|
|
if (node?.isValid && node.active !== active) node.active = active;
|
|
}
|
|
|
|
/** btnItem 显示时循环跳动,隐藏时停止 */
|
|
private _syncBtnPulse(active: boolean): void {
|
|
if (active === this._btnPulseActive) return;
|
|
this._btnPulseActive = active;
|
|
if (active) {
|
|
this._btnPulse.bind(this._btnItem);
|
|
} else {
|
|
this._btnPulse.unbind();
|
|
}
|
|
}
|
|
}
|
|
|