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/battle/combat/TowerLevelDownHost.ts

239 lines
8.6 KiB

import type { EntityId } from 'db://assets/mx/module/ecs';
import { TeamComp, type BattleSession } from 'db://assets/mx/module/battle';
import type { ProjectBattleHandle } from '../runtime/BattleRuntime';
import { findCompositionForEntity, findGridIndexForEntity } from '../runtime/DeployEntityQuery';
import type { Player } from '../../game/Player';
import type { CocosBagBoardView } from '../view/CocosBagBoardView';
/** 降级后按新等级重绑战斗(由 BattleRuntime 注入,避免 Host 回引 CombatSetup) */
export interface ILevelDownCombatRefresh {
/**
* @param session 战斗会话
* @param entityId 塔实体
* @param level 新合成等级
* @param player 所属玩家
*/
(session: BattleSession, entityId: EntityId, level: number, player: Player): void;
}
/** 一次限时降级 */
interface LevelDownEntry {
/** 被降级实体 */
entity: EntityId;
/** 字块所属玩家 */
playerId: number;
/** 当前格 */
gridIndex: number;
/** 施加前等级 */
originLevel: number;
/** 实际降低级数 */
applied: number;
/** 剩余秒 */
remain: number;
}
let _host: TowerLevelDownHost | null = null;
/** 龟丞相 atk_buff 类型7:限时降级 */
export function getTowerLevelDownHost(): TowerLevelDownHost {
if (!_host) _host = new TowerLevelDownHost();
return _host;
}
/**
* 非组合字限时降级:最低 1 级,期间禁合成升级、可移动;到期恢复。
*/
export class TowerLevelDownHost {
private readonly _entries: LevelDownEntry[] = [];
private _bagView: CocosBagBoardView | null = null;
/** 降级后刷新战斗;未绑定时只改合成等级 */
private _refreshCombat: ILevelDownCombatRefresh | null = null;
/**
* 绑定棋盘视图(降级时抑制升级特效)。
* @param view 本机棋盘
*/
bindBagView(view: CocosBagBoardView | null): void {
this._bagView = view;
}
/**
* 绑定降级后的战斗刷新。
* @param fn 刷新函数;传 null 清除
*/
bindCombatRefresh(fn: ILevelDownCombatRefresh | null): void {
this._refreshCombat = fn;
}
/**
* 施加或刷新降级。
* @param battle 战斗句柄
* @param target 目标塔
* @param delta 降低级数
* @param durationSec 持续时间
*/
apply(battle: ProjectBattleHandle, target: EntityId, delta: number, durationSec: number): void {
const d = Math.max(1, Math.floor(Number(delta) || 1));
const dur = Number(durationSec) || 0;
if (!(dur > 0)) {
console.log('[TowerLevelDown] atk_buff 类型7缺少持续时间', target, durationSec);
this._dropOnce(battle, target, d);
return;
}
const session = battle.session;
if (!session.world.isAlive(target)) return;
const existing = this._find(target);
if (existing) {
existing.remain = dur;
this._syncGrid(battle, existing);
return;
}
const team = session.world.getComponent(target, TeamComp);
const playerId = Math.floor(Number(team?.ownerId) || 0);
const player = battle.getPlayer(playerId);
const map = battle.Map;
if (!player || !map) return;
const comp = findCompositionForEntity(target, player, session, map);
if (!comp || comp.gridIndices.length > 1) return;
const gridIndex = findGridIndexForEntity(target, player, session, map);
if (gridIndex == null) return;
const origin = Math.max(1, comp.level);
const next = Math.max(1, origin - d);
const applied = origin - next;
if (applied > 0 && !this._setLevel(battle, playerId, gridIndex, next, target)) return;
this._entries.push({ entity: target, playerId, gridIndex, originLevel: origin, applied, remain: dur });
}
/**
* 该格是否处于降级禁合成。
* @param playerId 玩家
* @param gridIndex 地图格
*/
isGridBlocked(playerId: number, gridIndex: number): boolean {
for (let i = 0; i < this._entries.length; i++) {
const e = this._entries[i];
if (e.playerId === playerId && e.gridIndex === gridIndex) return true;
}
return false;
}
/**
* 推进计时并跟随位移。
* @param battle 战斗句柄
* @param dt 逻辑秒
*/
tick(battle: ProjectBattleHandle, dt: number): void {
if (this._entries.length <= 0) return;
for (let i = this._entries.length - 1; i >= 0; i--) {
const e = this._entries[i];
this._syncGrid(battle, e);
if (!battle.session.world.isAlive(e.entity)) {
this._end(battle, i, false);
continue;
}
e.remain -= dt;
if (e.remain <= 0) this._end(battle, i, true);
}
}
/** 战斗结束:不回等级 */
clear(): void {
this._entries.length = 0;
this._bagView = null;
}
/**
* 无持续时间:只降一次级。
* @param battle 战斗句柄
* @param target 目标
* @param delta 降低级数
*/
private _dropOnce(battle: ProjectBattleHandle, target: EntityId, delta: number): void {
const session = battle.session;
if (!session.world.isAlive(target)) return;
const team = session.world.getComponent(target, TeamComp);
const playerId = Math.floor(Number(team?.ownerId) || 0);
const player = battle.getPlayer(playerId);
const map = battle.Map;
if (!player || !map) return;
const comp = findCompositionForEntity(target, player, session, map);
if (!comp || comp.gridIndices.length > 1) return;
const gridIndex = findGridIndexForEntity(target, player, session, map);
if (gridIndex == null) return;
const next = Math.max(1, comp.level - delta);
if (next === comp.level) return;
this._setLevel(battle, playerId, gridIndex, next, target);
}
/**
* 同步实体当前格。
* @param battle 战斗句柄
* @param e 运行态
*/
private _syncGrid(battle: ProjectBattleHandle, e: LevelDownEntry): void {
const player = battle.getPlayer(e.playerId);
const map = battle.Map;
if (!player || !map || !battle.session.world.isAlive(e.entity)) return;
const live = findGridIndexForEntity(e.entity, player, battle.session, map);
if (live == null || live === e.gridIndex) return;
e.gridIndex = live;
}
/**
* 结束一条:可选恢复等级。
* @param battle 战斗句柄
* @param index 下标
* @param restore 是否加回等级
*/
private _end(battle: ProjectBattleHandle, index: number, restore: boolean): void {
const e = this._entries[index];
this._entries.splice(index, 1);
if (!restore || e.applied <= 0) return;
if (!battle.session.world.isAlive(e.entity)) return;
const player = battle.getPlayer(e.playerId);
const map = battle.Map;
if (!player || !map) return;
const grid = findGridIndexForEntity(e.entity, player, battle.session, map) ?? e.gridIndex;
const comp = findCompositionForEntity(e.entity, player, battle.session, map);
const cur = comp?.level ?? 0;
if (!(cur > 0)) return;
this._setLevel(battle, e.playerId, grid, cur + e.applied, e.entity);
}
/**
* 改合成等级并刷新战斗属性。
* @param battle 战斗句柄
* @param playerId 玩家
* @param gridIndex 格
* @param newLevel 目标等级
* @param entity 实体
*/
private _setLevel(battle: ProjectBattleHandle, playerId: number, gridIndex: number, newLevel: number, entity: EntityId): boolean {
const player = battle.getPlayer(playerId);
const bag = player?.bagSession;
if (!bag) return false;
const view = this._bagView;
view?.setSuppressUpgradeFx(true);
const ok = bag.merge.setCompositionLevelAtGrid(gridIndex, newLevel);
view?.setSuppressUpgradeFx(false);
if (!ok) return false;
if (!battle.session.world.isAlive(entity)) return true;
if (!this._refreshCombat) {
console.warn('[TowerLevelDown] 战斗刷新未绑定', entity);
return true;
}
this._refreshCombat(battle.session, entity, newLevel, player);
return true;
}
/**
* 按实体查找。
* @param entity 实体
*/
private _find(entity: EntityId): LevelDownEntry | null {
for (let i = 0; i < this._entries.length; i++) {
if (this._entries[i].entity === entity) return this._entries[i];
}
return null;
}
}