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.
AdLike2048/assets/script/ui/BattleGame/BattleGameDailyShopSkillDra...

760 lines
35 KiB

3 weeks ago
import {
EventTouch, instantiate, Node, UIOpacity, UITransform, Vec2, Vec3,
} from 'cc';
import type { CocosBagBoardView, BattleBuffSkillDropTarget } from '../../battle/view/CocosBagBoardView';
import {
BattleGameSkillDragKind,
readBattleBuffAttackSpeedConfig,
readBattleBuffBindNetDuration,
readBattleBuffConfuseHeroDuration,
readBattleBuffFireTrapConfig,
readBattleBuffRandomLevelConfig,
readBattleBuffRecyclePeachCount,
readBattleBuffUnitLevelDelta,
resolveBattleGameSkillDragKind,
} from '../../manager/battleBuff/BattleBuffActiveSkillUtil';
import type { BattleBuffAttackSpeedConfig, BattleBuffFireTrapConfig, BattleBuffRandomLevelConfig } from '../../manager/battleBuff/BattleBuffParamParse';
import { DragPlaceLinePresenter } from '../../battle/view/DragPlaceLinePresenter';
import type { BattleGameBindNetTrapController } from './BattleGameBindNetTrapController';
import type { BattleGameFireTrapController } from './BattleGameFireTrapController';
import type { BattleGameRecycleToPeachPresenter } from './BattleGameRecycleToPeachPresenter';
import type { BattleGameRewriteGlyphPresenter } from './BattleGameRewriteGlyphPresenter';
import type { BattleGameAttackSpeedFxPresenter } from './BattleGameAttackSpeedFxPresenter';
import type { BattleGameRandomLevelFxPresenter } from './BattleGameRandomLevelFxPresenter';
import type { BattleGameUnitLevelUpFxPresenter } from './BattleGameUnitLevelUpFxPresenter';
import type { BattleGameAttackRangeFxPresenter } from './BattleGameAttackRangeFxPresenter';
import type { BattleGameExtraBossFxPresenter } from './BattleGameExtraBossFxPresenter';
import type { BattleGameConfuseHeroFxPresenter } from './BattleGameConfuseHeroFxPresenter';
import type { BattleGameStealGlyphFxPresenter } from './BattleGameStealGlyphFxPresenter';
import type { BattleGameDailyShopSkillView } from './BattleGameDailyShopSkillView';
import type { ProjectBattleHandle } from '../../battle/runtime/BattleRuntime';
import { BattlePhase } from 'db://assets/mx/module/battle';
import { BattleAudio } from '../../battle/audio/BattleAudio';
import { DailyShopKind } from '../../manager/DailyShopTypes';
import type { DailyShopOwnedDesc } from '../PopDailyShopLottery/DailyShopLotteryIcon';
/** 拖拽触发阈值(像素) */
const DRAG_SENSITIVITY_PX = 10;
/** 拖拽 icon 影子透明度 */
const DRAG_ICON_GHOST_OPACITY = 200;
/** skill1 / skill2 拖到地图:升级 / 缚仙网 / 乾坤袋等主动 buff */
export class BattleGameDailyShopSkillDrag {
private _skillView: BattleGameDailyShopSkillView | null = null;
private _bagView: CocosBagBoardView | null = null;
private _trapController: BattleGameBindNetTrapController | null = null;
private _fireTrapController: BattleGameFireTrapController | null = null;
private _recyclePresenter: BattleGameRecycleToPeachPresenter | null = null;
private _rewriteGlyphPresenter: BattleGameRewriteGlyphPresenter | null = null;
private _attackSpeedFxPresenter: BattleGameAttackSpeedFxPresenter | null = null;
private _randomLevelFxPresenter: BattleGameRandomLevelFxPresenter | null = null;
private _unitLevelUpFxPresenter: BattleGameUnitLevelUpFxPresenter | null = null;
private _attackRangeFxPresenter: BattleGameAttackRangeFxPresenter | null = null;
private _extraBossFxPresenter: BattleGameExtraBossFxPresenter | null = null;
private _confuseHeroFxPresenter: BattleGameConfuseHeroFxPresenter | null = null;
private _stealGlyphFxPresenter: BattleGameStealGlyphFxPresenter | null = null;
private _battle: ProjectBattleHandle | null = null;
private _ownedDesc: DailyShopOwnedDesc | null = null;
private _dragLayer: Node | null = null;
private readonly _linePresenter = new DragPlaceLinePresenter();
private _slotNodes: Node[] = [];
private _activeSlotIndex = -1;
private _activeDragKind: BattleGameSkillDragKind | null = null;
private _dragging = false;
private _dragTesting = false;
private _dragStart = new Vec2();
/** 拉线起点:skill 槽 icon 世界坐标(拖动期间固定,与字块拉线一致) */
private _lineAnchorWorld = new Vec3();
/** 拉线终点 fallback:跟随手指的 icon 影子 */
private _cursorWorld = new Vec3();
/** 跟随手指的 icon 影子(instantiate 副本,原 icon 留槽位) */
private _dragIconGhost: Node | null = null;
private _paramValue = 0;
private _randomLevelConfig: BattleBuffRandomLevelConfig | null = null;
private _attackSpeedConfig: BattleBuffAttackSpeedConfig | null = null;
private _fireTrapConfig: BattleBuffFireTrapConfig | null = null;
/** 攻速符 buffId(用于区分不同 buff 的叠加) */
private _attackSpeedBuffId = 0;
/** 千里眼 buffId(用于区分不同 buff 的叠加) */
private _rangeBuffId = 0;
/** 绑定 skill 拖拽(需在 bagView / trapController bind 之后调用) */
bind(
skillView: BattleGameDailyShopSkillView | null,
bagView: CocosBagBoardView | null,
trapController: BattleGameBindNetTrapController | null,
fireTrapController: BattleGameFireTrapController | null,
recyclePresenter: BattleGameRecycleToPeachPresenter | null,
rewriteGlyphPresenter: BattleGameRewriteGlyphPresenter | null,
attackSpeedFxPresenter: BattleGameAttackSpeedFxPresenter | null,
randomLevelFxPresenter: BattleGameRandomLevelFxPresenter | null,
unitLevelUpFxPresenter: BattleGameUnitLevelUpFxPresenter | null,
attackRangeFxPresenter: BattleGameAttackRangeFxPresenter | null,
extraBossFxPresenter: BattleGameExtraBossFxPresenter | null,
confuseHeroFxPresenter: BattleGameConfuseHeroFxPresenter | null,
stealGlyphFxPresenter: BattleGameStealGlyphFxPresenter | null,
battle: ProjectBattleHandle | null,
dragLayer: Node | null | undefined,
lineNode: Node | null | undefined,
ownedDesc?: DailyShopOwnedDesc | null,
): void {
this.unbind();
this._skillView = skillView;
this._bagView = bagView;
this._ownedDesc = ownedDesc ?? null;
this._trapController = trapController;
this._fireTrapController = fireTrapController;
this._recyclePresenter = recyclePresenter;
this._rewriteGlyphPresenter = rewriteGlyphPresenter;
this._attackSpeedFxPresenter = attackSpeedFxPresenter;
this._randomLevelFxPresenter = randomLevelFxPresenter;
this._unitLevelUpFxPresenter = unitLevelUpFxPresenter;
this._attackRangeFxPresenter = attackRangeFxPresenter;
this._extraBossFxPresenter = extraBossFxPresenter;
this._confuseHeroFxPresenter = confuseHeroFxPresenter;
this._stealGlyphFxPresenter = stealGlyphFxPresenter;
this._battle = battle;
this._dragLayer = dragLayer?.isValid ? dragLayer : null;
this._linePresenter.bind(lineNode ?? null);
this._bindSlotNodes();
}
/** roll 后刷新 skill 触摸绑定(不重建 Drag / Presenter) */
refreshSlotBindings(): void {
for (const node of this._slotNodes) {
if (!node?.isValid) continue;
node.off(Node.EventType.TOUCH_START, this._onTouchStart, this);
node.off(Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
node.off(Node.EventType.TOUCH_END, this._onTouchEnd, this);
node.off(Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
}
this._slotNodes.length = 0;
this._bindSlotNodes();
}
/** 注销触摸 */
unbind(): void {
this._cancelDrag();
for (const node of this._slotNodes) {
if (!node?.isValid) continue;
node.off(Node.EventType.TOUCH_START, this._onTouchStart, this);
node.off(Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
node.off(Node.EventType.TOUCH_END, this._onTouchEnd, this);
node.off(Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
}
this._slotNodes.length = 0;
this._linePresenter.unbind();
this._skillView = null;
this._bagView = null;
this._trapController = null;
this._fireTrapController = null;
this._recyclePresenter = null;
this._rewriteGlyphPresenter = null;
this._attackSpeedFxPresenter = null;
this._randomLevelFxPresenter = null;
this._unitLevelUpFxPresenter = null;
this._attackRangeFxPresenter = null;
this._extraBossFxPresenter = null;
this._confuseHeroFxPresenter = null;
this._stealGlyphFxPresenter = null;
this._battle = null;
this._ownedDesc = null;
this._dragLayer = null;
}
/** 为 skill1 / skill2 注册触摸(携带即注册;七十二变 roll 后在拖拽时动态解析 cast 类型) */
private _bindSlotNodes(): void {
const view = this._skillView;
if (!view) return;
for (let slotIndex = 0; slotIndex < 2; slotIndex++) {
const slot = view.getSlot(slotIndex);
const root = slot?.root;
if (!root?.isValid || !root.active || !slot.hasCarriedBuff()) continue;
root.on(Node.EventType.TOUCH_START, this._onTouchStart, this);
root.on(Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
root.on(Node.EventType.TOUCH_END, this._onTouchEnd, this);
root.on(Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
root['battleShopSkillSlotIndex'] = slotIndex;
this._slotNodes.push(root);
}
}
/** 触摸开始 */
private _onTouchStart(event: EventTouch): void {
if (this._dragging) return;
const slotIndex = this._resolveSlotIndex(event);
if (slotIndex < 0) return;
const slot = this._skillView?.getSlot(slotIndex);
if (!slot?.root.active || !slot.hasCarriedBuff()) return;
const pos = event.getUILocation();
this._dragStart.set(pos.x, pos.y);
this._activeSlotIndex = slotIndex;
this._dragTesting = true;
if (!this._canBeginDrag(slotIndex)) return;
}
/** 触摸移动 */
private _onTouchMove(event: EventTouch): void {
if (!this._dragTesting && !this._dragging) return;
const pos = event.getUILocation();
if (!this._dragging && this._dragTesting) {
if (
Math.abs(this._dragStart.x - pos.x) < DRAG_SENSITIVITY_PX
&& Math.abs(this._dragStart.y - pos.y) < DRAG_SENSITIVITY_PX
) {
return;
}
if (!this._canBeginDrag(this._activeSlotIndex)) {
this._resetDragState();
return;
}
this._beginDragVisual(this._activeSlotIndex, event);
}
if (!this._dragging) return;
this._updateDragVisual(event);
}
/** 触摸结束 */
private _onTouchEnd(event: EventTouch): void {
this._finishDrag(event);
}
/** 触摸取消 */
private _onTouchCancel(event: EventTouch): void {
this._finishDrag(event);
}
/** 是否可开始拖拽 */
private _canBeginDrag(slotIndex: number): boolean {
const bagView = this._bagView;
const skillView = this._skillView;
if (!bagView || !skillView) return false;
const slot = skillView.getSlot(slotIndex);
const row = slot?.getBuffRow();
const kind = slot?.getCastDragKind() ?? resolveBattleGameSkillDragKind(row);
if (!slot?.isReady() || kind == null) return false;
if (!slot.getIconNode()?.isValid) return false;
if (kind === BattleGameSkillDragKind.UnitLevelUp) {
if (!bagView.isBattleBuffSkillEnabled()) return false;
const levelDelta = readBattleBuffUnitLevelDelta(row);
if (levelDelta <= 0) return false;
this._paramValue = levelDelta;
this._randomLevelConfig = null;
} else if (kind === BattleGameSkillDragKind.RandomLevel) {
if (!bagView.isBattleBuffSkillEnabled()) return false;
const cfg = readBattleBuffRandomLevelConfig(row);
if (!cfg) return false;
this._randomLevelConfig = cfg;
this._paramValue = 0;
} else if (kind === BattleGameSkillDragKind.RewriteGlyph) {
if (!bagView.isBattleBuffSkillEnabled() || !this._rewriteGlyphPresenter || this._rewriteGlyphPresenter.isPlaying) {
return false;
}
this._randomLevelConfig = null;
this._attackSpeedConfig = null;
this._paramValue = 0;
} else if (kind === BattleGameSkillDragKind.AttackSpeedGlobal) {
if (!bagView.isBattleBuffSkillEnabled()) return false;
const cfg = readBattleBuffAttackSpeedConfig(row);
if (!cfg) return false;
this._attackSpeedConfig = cfg;
this._attackSpeedBuffId = Number(row?.id) || 0;
if (this._attackSpeedBuffId <= 0) return false;
this._randomLevelConfig = null;
this._paramValue = 0;
} else if (kind === BattleGameSkillDragKind.AttackRangeGlobal) {
if (!bagView.isBattleBuffSkillEnabled()) return false;
this._rangeBuffId = Number(row?.id) || 0;
if (this._rangeBuffId <= 0) return false;
this._attackSpeedConfig = null;
this._randomLevelConfig = null;
this._paramValue = 0;
} else if (kind === BattleGameSkillDragKind.BindNet) {
if (!bagView.isBattleBuffSkillEnabled() || !this._trapController) return false;
const bindSec = readBattleBuffBindNetDuration(row);
if (bindSec <= 0) return false;
this._paramValue = bindSec;
this._randomLevelConfig = null;
this._fireTrapConfig = null;
} else if (kind === BattleGameSkillDragKind.FireTrap) {
if (!bagView.isBattleBuffSkillEnabled() || !this._fireTrapController) return false;
const cfg = readBattleBuffFireTrapConfig(row);
if (!cfg) return false;
this._fireTrapConfig = cfg;
this._randomLevelConfig = null;
this._attackSpeedConfig = null;
this._paramValue = 0;
} else if (kind === BattleGameSkillDragKind.RecycleToPeach) {
if (!bagView.isBattleBuffSkillEnabled() || !this._recyclePresenter) {
return false;
}
const peachCount = readBattleBuffRecyclePeachCount(row);
if (peachCount <= 0) return false;
this._paramValue = peachCount;
this._randomLevelConfig = null;
this._attackSpeedConfig = null;
this._fireTrapConfig = null;
} else if (kind === BattleGameSkillDragKind.ExtraBoss) {
if (!bagView.isBattleBuffSkillEnabled() || !this._extraBossFxPresenter || this._extraBossFxPresenter.isPlaying) {
return false;
}
const battle = this._battle;
if (!battle || battle.session.phase !== BattlePhase.COMBAT) return false;
this._randomLevelConfig = null;
this._attackSpeedConfig = null;
this._fireTrapConfig = null;
this._paramValue = 0;
} else if (kind === BattleGameSkillDragKind.ConfuseHero) {
if (!bagView.isBattleBuffSkillEnabled() || !this._confuseHeroFxPresenter || this._confuseHeroFxPresenter.isPlaying) {
return false;
}
const battle = this._battle;
if (!battle || battle.session.phase !== BattlePhase.COMBAT) return false;
const durationSec = readBattleBuffConfuseHeroDuration(row);
if (durationSec <= 0) return false;
this._paramValue = durationSec;
this._randomLevelConfig = null;
this._attackSpeedConfig = null;
this._fireTrapConfig = null;
} else if (kind === BattleGameSkillDragKind.StealGlyph) {
if (!bagView.isBattleBuffSkillEnabled() || !this._stealGlyphFxPresenter || this._stealGlyphFxPresenter.isPlaying) {
return false;
}
const battle = this._battle;
if (!battle || battle.session.phase !== BattlePhase.COMBAT) return false;
this._randomLevelConfig = null;
this._attackSpeedConfig = null;
this._fireTrapConfig = null;
this._paramValue = 0;
} else {
return false;
}
this._activeDragKind = kind;
return true;
}
/** 克隆 skill icon 到拖拽层作为跟随手指的影子 */
private _beginDragVisual(slotIndex: number, event: EventTouch): void {
const icon = this._skillView?.getSlot(slotIndex)?.getIconNode();
const dragLayer = this._dragLayer;
if (!icon?.isValid || !dragLayer?.isValid) {
this._resetDragState();
return;
}
// prefab 中 ui_fly 默认 inactive;挂到未激活层会导致影子全程不可见
if (!dragLayer.active) {
dragLayer.active = true;
}
this._ownedDesc?.hide();
this._clearDragIconGhost();
const ghost = instantiate(icon);
ghost.name = 'skillDragIconGhost';
ghost.parent = dragLayer;
ghost.setWorldPosition(icon.worldPosition);
ghost.setWorldScale(icon.worldScale);
ghost.setSiblingIndex(dragLayer.children.length - 1);
const ghostOpacity = ghost.getComponent(UIOpacity) ?? ghost.addComponent(UIOpacity);
ghostOpacity.opacity = DRAG_ICON_GHOST_OPACITY;
this._dragging = true;
this._dragTesting = false;
this._dragIconGhost = ghost;
icon.getWorldPosition(this._lineAnchorWorld);
this._setIconAtUiPos(event);
BattleAudio.vibratePickup();
}
/** 更新 icon 影子 / 拉线 / 落点预览 */
private _updateDragVisual(event: EventTouch): void {
const bagView = this._bagView;
const ghost = this._dragIconGhost;
if (!bagView || !ghost?.isValid || this._activeDragKind == null) return;
this._setIconAtUiPos(event);
ghost.getWorldPosition(this._cursorWorld);
const uiPos = event.getUILocation();
this._updateSkillDragDropPreview(bagView, uiPos);
const lineTo = this._resolveSkillDragLineTargetWorld(bagView, uiPos) ?? this._cursorWorld;
this._linePresenter.show(this._lineAnchorWorld, lineTo);
}
/** 主动道具拖放:刷新绿/红格预览 */
private _updateSkillDragDropPreview(bagView: CocosBagBoardView, uiPos: { x: number; y: number }): void {
const kind = this._activeDragKind;
if (kind == null) return;
if (kind === BattleGameSkillDragKind.UnitLevelUp) {
bagView.setBattleBuffLevelUpDropPreview(
bagView.resolveBattleBuffSkillDropTargetAtUiPos(uiPos),
this._paramValue,
);
return;
}
if (kind === BattleGameSkillDragKind.RandomLevel) {
bagView.setBattleBuffRandomLevelDropPreview(
bagView.resolveBattleBuffSkillDropTargetAtUiPos(uiPos),
);
return;
}
if (kind === BattleGameSkillDragKind.RewriteGlyph) {
bagView.setBattleBuffRewriteGlyphDropPreview(
bagView.resolveBattleBuffSkillDropTargetAtUiPos(uiPos),
);
return;
}
if (kind === BattleGameSkillDragKind.AttackSpeedGlobal) {
bagView.setBattleBuffAttackSpeedDropPreview(
bagView.resolveBattleBuffSkillDropTargetAtUiPos(uiPos),
this._attackSpeedBuffId,
);
return;
}
if (kind === BattleGameSkillDragKind.AttackRangeGlobal) {
bagView.setBattleBuffAttackRangeDropPreview(
bagView.resolveBattleBuffSkillDropTargetAtUiPos(uiPos),
this._rangeBuffId,
);
return;
}
if (kind === BattleGameSkillDragKind.BindNet || kind === BattleGameSkillDragKind.FireTrap) {
const gridIndex = bagView.resolveWalkableTrapGridAtUiPos(uiPos, this._hasTrapAt.bind(this));
bagView.setBindNetTrapDropPreview(gridIndex, this._hasTrapAt.bind(this));
return;
}
if (kind === BattleGameSkillDragKind.RecycleToPeach) {
bagView.setBattleBuffRecycleDropPreview(
bagView.resolveBattleBuffSkillDropTargetAtUiPos(uiPos),
);
return;
}
if (kind === BattleGameSkillDragKind.ConfuseHero) {
bagView.setConfuseHeroDropPreviewAtUiPos(uiPos);
return;
}
if (kind === BattleGameSkillDragKind.StealGlyph) {
bagView.setStealGlyphDropPreviewAtUiPos(uiPos);
}
}
/** 主动道具拉线终点:有悬停落点则指向落点,否则跟手指(与字块拉线一致) */
private _resolveSkillDragLineTargetWorld(
bagView: CocosBagBoardView,
uiPos: { x: number; y: number },
): Vec3 | null {
const kind = this._activeDragKind;
if (kind == null) return null;
if (
kind === BattleGameSkillDragKind.UnitLevelUp
|| kind === BattleGameSkillDragKind.RandomLevel
|| kind === BattleGameSkillDragKind.RewriteGlyph
|| kind === BattleGameSkillDragKind.AttackSpeedGlobal
|| kind === BattleGameSkillDragKind.AttackRangeGlobal
|| kind === BattleGameSkillDragKind.RecycleToPeach
) {
const dropTarget = bagView.resolveBattleBuffSkillDropTargetAtUiPos(uiPos);
return dropTarget ? this._dropTargetWorld(bagView, dropTarget) : null;
}
if (kind === BattleGameSkillDragKind.BindNet || kind === BattleGameSkillDragKind.FireTrap) {
const gridIndex = bagView.resolveWalkableTrapGridAtUiPos(uiPos, this._hasTrapAt.bind(this));
return gridIndex != null ? bagView.getMapGridWorldPosition(gridIndex) : null;
}
if (kind === BattleGameSkillDragKind.ExtraBoss) {
const spawnPort = bagView.resolveOwnSpawnPortAtUiPos(uiPos);
return spawnPort != null ? bagView.getSpawnPointWorldPosition(spawnPort) : null;
}
if (kind === BattleGameSkillDragKind.ConfuseHero) {
const target = bagView.resolveConfuseHeroTargetAtUiPos(uiPos);
if (target != null) return bagView.getConfuseHeroTargetWorldCenter(target);
const enemyGridIndex = bagView.resolveStealGlyphEnemyGridAtUiPos(uiPos);
return enemyGridIndex != null ? bagView.getMapGridWorldPosition(enemyGridIndex) : null;
}
if (kind === BattleGameSkillDragKind.StealGlyph) {
const enemyGridIndex = bagView.resolveStealGlyphEnemyGridAtUiPos(uiPos);
return enemyGridIndex != null ? bagView.getMapGridWorldPosition(enemyGridIndex) : null;
}
return null;
}
/** 字块类主动 buff 落点世界坐标 */
private _dropTargetWorld(bagView: CocosBagBoardView, target: BattleBuffSkillDropTarget): Vec3 | null {
return target.kind === 'bag'
? bagView.getBagSlotWorldPosition(target.slotIndex)
: bagView.getMapGridWorldPosition(target.gridIndex);
}
/** 松手:尝试施放 */
private _finishDrag(event: EventTouch): void {
if (this._dragging && this._activeDragKind != null) {
const bagView = this._bagView;
const skillView = this._skillView;
const slotIndex = this._activeSlotIndex;
const uiPos = event.getUILocation();
let success = false;
if (this._activeDragKind === BattleGameSkillDragKind.UnitLevelUp) {
const dropTarget = bagView?.resolveBattleBuffSkillDropTargetAtUiPos(uiPos) ?? null;
const presenter = this._unitLevelUpFxPresenter;
success = !!(
bagView
&& dropTarget
&& presenter
&& bagView.canApplyBattleBuffLevelUpTarget(dropTarget, this._paramValue)
&& presenter.tryPlay(
dropTarget,
this._paramValue,
() => skillView?.startCooldown(slotIndex),
)
);
} else if (this._activeDragKind === BattleGameSkillDragKind.RandomLevel) {
const cfg = this._randomLevelConfig;
const dropTarget = bagView?.resolveBattleBuffSkillDropTargetAtUiPos(uiPos) ?? null;
const presenter = this._randomLevelFxPresenter;
success = !!(
bagView
&& cfg
&& dropTarget
&& presenter
&& bagView.canApplyBattleBuffRandomLevelTarget(dropTarget)
&& presenter.tryPlay(
dropTarget,
cfg.levelUpProbsWan,
() => skillView?.startCooldown(slotIndex),
)
);
} else if (this._activeDragKind === BattleGameSkillDragKind.RewriteGlyph) {
const dropTarget = bagView?.resolveBattleBuffSkillDropTargetAtUiPos(uiPos) ?? null;
const presenter = this._rewriteGlyphPresenter;
success = !!(
bagView
&& dropTarget
&& presenter
&& bagView.canApplyBattleBuffRewriteGlyphTarget(dropTarget)
&& presenter.tryPlay(
dropTarget,
() => skillView?.startCooldown(slotIndex),
)
);
} else if (this._activeDragKind === BattleGameSkillDragKind.AttackSpeedGlobal) {
const cfg = this._attackSpeedConfig;
const dropTarget = bagView?.resolveBattleBuffSkillDropTargetAtUiPos(uiPos) ?? null;
const applied = !!(
bagView
&& cfg
&& dropTarget
&& bagView.canApplyBattleBuffAttackSpeedTarget(dropTarget, this._attackSpeedBuffId)
&& bagView.applyBattleBuffAttackSpeedTarget(dropTarget, slotIndex, this._attackSpeedBuffId, cfg.bonusWan)
);
if (applied) {
this._attackSpeedFxPresenter?.tryPlay(dropTarget!);
} else if (dropTarget && bagView?.isAttackSpeedTargetAlreadyUsed(dropTarget, this._attackSpeedBuffId)) {
gg.ui.showToast('此道具无法重复使用');
}
success = applied;
} else if (this._activeDragKind === BattleGameSkillDragKind.AttackRangeGlobal) {
const dropTarget = bagView?.resolveBattleBuffSkillDropTargetAtUiPos(uiPos) ?? null;
const rangeFxPreview = dropTarget && bagView?.canApplyBattleBuffAttackRangeTarget(dropTarget, this._rangeBuffId)
? bagView.resolveAttackRangeBuffFxPreview(dropTarget)
: null;
const applied = !!(
bagView
&& dropTarget
&& bagView.canApplyBattleBuffAttackRangeTarget(dropTarget, this._rangeBuffId)
&& bagView.applyBattleBuffAttackRangeTarget(dropTarget, slotIndex, this._rangeBuffId)
);
if (applied) {
this._attackRangeFxPresenter?.tryPlay(dropTarget!, rangeFxPreview);
} else if (dropTarget && bagView?.isAttackRangeTargetMeleeUnit(dropTarget)) {
gg.ui.showToast('此道具无法作用于近战单位');
} else if (dropTarget && bagView?.isAttackRangeTargetAlreadyUsed(dropTarget, this._rangeBuffId)) {
gg.ui.showToast('此道具无法重复使用');
}
success = applied;
} else if (this._activeDragKind === BattleGameSkillDragKind.BindNet) {
const gridIndex = bagView?.resolveWalkableTrapGridAtUiPos(uiPos, this._hasTrapAt.bind(this)) ?? null;
success = !!(
this._trapController
&& bagView
&& gridIndex != null
&& bagView.canPlaceBindNetTrapAt(gridIndex, this._hasTrapAt.bind(this))
&& this._trapController.tryPlace(gridIndex, this._paramValue)
);
} else if (this._activeDragKind === BattleGameSkillDragKind.FireTrap) {
const cfg = this._fireTrapConfig;
const gridIndex = bagView?.resolveWalkableTrapGridAtUiPos(uiPos, this._hasTrapAt.bind(this)) ?? null;
success = !!(
cfg
&& this._fireTrapController
&& bagView
&& gridIndex != null
&& bagView.canPlaceBindNetTrapAt(gridIndex, this._hasTrapAt.bind(this))
&& this._fireTrapController.tryPlace(gridIndex, cfg.maxDamage, cfg.durationSec)
);
} else if (this._activeDragKind === BattleGameSkillDragKind.RecycleToPeach) {
const dropTarget = bagView?.resolveBattleBuffSkillDropTargetAtUiPos(uiPos) ?? null;
const presenter = this._recyclePresenter;
success = !!(
bagView
&& dropTarget
&& presenter
&& bagView.canApplyBattleBuffRecycleTarget(dropTarget)
&& presenter.tryPlay(
dropTarget,
this._paramValue,
() => skillView?.startCooldown(slotIndex),
)
);
} else if (this._activeDragKind === BattleGameSkillDragKind.ExtraBoss) {
const spawnPort = bagView?.resolveOwnSpawnPortAtUiPos(uiPos) ?? null;
const presenter = this._extraBossFxPresenter;
success = !!(
bagView
&& spawnPort != null
&& presenter
&& presenter.tryPlay(
spawnPort,
() => skillView?.startCooldown(slotIndex),
)
);
} else if (this._activeDragKind === BattleGameSkillDragKind.ConfuseHero) {
const enemyGridIndex = bagView?.resolveStealGlyphEnemyGridAtUiPos(uiPos) ?? null;
const target = bagView?.resolveConfuseHeroTargetAtUiPos(uiPos) ?? null;
const presenter = this._confuseHeroFxPresenter;
if (enemyGridIndex != null && bagView) {
const reason = bagView.getConfuseHeroRejectReason(enemyGridIndex);
if (reason === 'single_glyph') {
gg.ui.showToast('只能对合成神将施放');
} else if (reason === 'already_charmed') {
gg.ui.showToast('目标已被迷惑');
}
}
success = !!(
bagView
&& target
&& presenter
&& presenter.tryPlay(
target,
this._paramValue,
() => skillView?.startCooldown(slotIndex),
)
);
} else if (this._activeDragKind === BattleGameSkillDragKind.StealGlyph) {
const rawGridIndex = bagView?.resolveStealGlyphEnemyGridAtUiPos(uiPos) ?? null;
const presenter = this._stealGlyphFxPresenter;
if (rawGridIndex != null && bagView) {
const reason = bagView.getStealGlyphRejectReason(rawGridIndex);
if (reason === 'composed') {
gg.ui.showToast('合成武将不能偷取');
} else if (reason === 'no_space') {
gg.ui.showToast('没空位放置不能偷取');
} else if (reason === 'invalid') {
gg.ui.showToast('只能偷武将散字或普通字');
}
}
const enemyGridIndex = bagView?.resolveStealGlyphTargetAtUiPos(uiPos) ?? null;
success = !!(
bagView
&& enemyGridIndex != null
&& presenter
&& presenter.tryPlay(
enemyGridIndex,
() => skillView?.startCooldown(slotIndex),
)
);
}
if (success && skillView && this._activeDragKind !== BattleGameSkillDragKind.RecycleToPeach
&& this._activeDragKind !== BattleGameSkillDragKind.RewriteGlyph
&& this._activeDragKind !== BattleGameSkillDragKind.UnitLevelUp
&& this._activeDragKind !== BattleGameSkillDragKind.RandomLevel
&& this._activeDragKind !== BattleGameSkillDragKind.ExtraBoss
&& this._activeDragKind !== BattleGameSkillDragKind.ConfuseHero
&& this._activeDragKind !== BattleGameSkillDragKind.StealGlyph) {
skillView.startCooldown(slotIndex);
}
} else {
this._tryShowSkillDescOnTap();
}
this._cancelDrag();
}
/** 拖拽 skill 轻触:显示描述(与 PopDailyShopBuy 一致) */
private _tryShowSkillDescOnTap(): void {
if (!this._dragTesting || this._dragging || this._activeSlotIndex < 0) return;
const slot = this._skillView?.getSlot(this._activeSlotIndex);
const parsed = slot?.getParsed();
const root = slot?.root;
const desc = this._ownedDesc;
if (!parsed || !root?.isValid || !desc) return;
desc.show(root, parsed, DailyShopKind.Active);
}
/** 行走格陷阱是否存在(缚仙网 / 三昧真火) */
private _hasTrapAt(idx: number): boolean {
return (this._trapController?.hasTrapAt(idx) ?? false)
|| (this._fireTrapController?.hasTrapAt(idx) ?? false);
}
/** icon 影子跟随触摸点 */
private _setIconAtUiPos(event: EventTouch): void {
const ghost = this._dragIconGhost;
const dragLayer = this._dragLayer;
if (!ghost?.isValid || !dragLayer?.isValid) return;
const uiPos = event.getUILocation();
const layerUt = dragLayer.getComponent(UITransform);
if (!layerUt) return;
const local = layerUt.convertToNodeSpaceAR(new Vec3(uiPos.x, uiPos.y, 0));
ghost.setPosition(local);
}
/** 清理拖拽态并销毁 icon 影子 */
private _cancelDrag(): void {
this._bagView?.clearBattleBuffDropPreview();
this._linePresenter.hide();
this._clearDragIconGhost();
this._resetDragState();
}
/** 销毁 icon 拖拽影子 */
private _clearDragIconGhost(): void {
const ghost = this._dragIconGhost;
if (ghost?.isValid) {
ghost.destroy();
}
this._dragIconGhost = null;
}
/** 重置内部状态 */
private _resetDragState(): void {
this._dragging = false;
this._dragTesting = false;
this._activeSlotIndex = -1;
this._activeDragKind = null;
this._paramValue = 0;
this._randomLevelConfig = null;
this._attackSpeedConfig = null;
this._fireTrapConfig = null;
this._attackSpeedBuffId = 0;
this._rangeBuffId = 0;
}
/** 从节点反查槽位下标 */
private _resolveSlotIndex(event: EventTouch): number {
let cur = event.target as Node | null;
while (cur?.isValid) {
const idx = cur['battleShopSkillSlotIndex'];
if (typeof idx === 'number') return idx;
cur = cur.parent;
}
return -1;
}
}