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/mx/module/battle/combat/ReachGoalBaseDamageSystem.ts

80 lines
2.9 KiB

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);
}
}