import type { World, EntityId } from 'db://assets/mx/module/ecs'; import type { ISystem } from 'db://assets/mx/module/ecs'; import { BattlePhase } from '../core/BattlePhase'; import { BattleTeamId } from '../ecs/BattleTeamId'; import { MovementComp, TeamComp } from '../ecs/Components'; import type { PlayerSlot } from '../player/PlayerSlot'; import type { BattleEventBus } from '../events/BattleEventBus'; import type { LifecycleSystem } from './LifecycleSystem'; /** 怪物到达攻击点:对手营地 -1 血并移除该怪 */ export class ReachGoalBaseDamageSystem implements ISystem { /** 调度优先级(Movement 50 之后) */ readonly priority = 55; /** 是否启用 */ enabled = true; /** 本帧待结算漏怪 */ private readonly _leakIds: EntityId[] = []; /** * @param _world ECS 世界 * @param _players 玩家槽 * @param _events 事件总线 * @param _lifecycle 实体生命周期 * @param _getPhase 当前战斗阶段 */ constructor( private readonly _world: World, private readonly _players: PlayerSlot[], private readonly _events: BattleEventBus, private readonly _lifecycle: LifecycleSystem, private readonly _getPhase: () => BattlePhase, ) {} /** 每帧收集已到达攻击点的敌怪并结算漏怪 */ tick(_dt: number): void { if (this._getPhase() !== BattlePhase.COMBAT) return; this._leakIds.length = 0; this._world.view2(MovementComp, TeamComp).forEach(this._collectLeak); for (let i = 0; i < this._leakIds.length; i++) { this._applyLeak(this._leakIds[i]); } } /** * 收集本帧到达攻击点的敌怪。 * @param id 实体 * @param move 移动组件 * @param team 阵营 */ private readonly _collectLeak = (id: EntityId, move: MovementComp, team: TeamComp): void => { if (!BattleTeamId.isEnemyTeam(team.team)) return; if (!move.reachedGoal || !move.hasAttackGoal) return; if (move.spawnProtected || move.presentLocked || move.imprisoned) return; if (move.bajiaoBlowRetreating || move.forcePathSpeed > 0) return; this._leakIds.push(id); }; /** * @param id 到达营地的敌怪 */ private _applyLeak(id: EntityId): void { if (!this._world.isAlive(id)) return; const team = this._world.getComponent(id, TeamComp); if (!team) { console.log('[ReachGoal] 漏怪无 TeamComp', id); this._lifecycle.despawn(id); return; } const slot = this._players[team.ownerId]; if (!slot) { console.log('[ReachGoal] 无对应玩家槽', team.ownerId, id); this._lifecycle.despawn(id); return; } if (slot.wallHp > 0) { slot.damageWall(1, this._events); } this._lifecycle.despawn(id); } }