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/BattleBuffEnemySlowHost.ts

133 lines
4.7 KiB

3 weeks ago
import type { EntityId } from 'db://assets/mx/module/ecs';
import {
AttributeComp,
BattleEventType,
BattleTeamId,
TeamComp,
type BattleEvent,
} from 'db://assets/mx/module/battle';
import { BattleBuffCarryStore } from '../../manager/battleBuff/BattleBuffCarryStore';
import { resolveCarriedEnemySlowWan } from '../../manager/battleBuff/BattleBuffPassiveSkillUtil';
import type { ProjectBattleHandle } from '../runtime/BattleRuntime';
import { AI_PLAYER_ID } from '../ai/runtime/AiCampArea';
/** 被动敌军减速 modifier 分组 */
const ENEMY_SLOW_MOD_GROUP = 'battle_buff_enemy_slow';
/** 单玩家减速 */
type PlayerSlow = {
/** 被进攻方 playerId(WaveSpawner ownerId) */
playerId: number;
/** 万分比 */
slowWan: number;
};
/**
* 被动 functiontype=23 弱水:进攻「携带者基地」的敌军移速 ×(1-万分比/10000)。
* Team.ownerId = 被进攻方(基地所属);减速的是往该基地冲的出征兵(敌方出征)。
*/
export class BattleBuffEnemySlowHost {
private _battle: ProjectBattleHandle | null = null;
private readonly _slows: PlayerSlow[] = [];
private _onUnitSpawnedBound = false;
/** 绑定本局并监听出怪 */
bind(battle: ProjectBattleHandle): void {
this.unbind();
this._battle = battle;
this._slows.length = 0;
this._pushSlow(battle.localPlayerId);
this._pushSlow(AI_PLAYER_ID);
if (this._slows.length <= 0) return;
battle.session.events.on(BattleEventType.UnitSpawned, this._onUnitSpawned);
this._onUnitSpawnedBound = true;
battle.session.world.forEachAlive((entityId) => {
this._tryApply(entityId);
});
}
/** 解除绑定 */
unbind(): void {
const battle = this._battle;
if (battle && this._onUnitSpawnedBound) {
battle.session.events.off(BattleEventType.UnitSpawned, this._onUnitSpawned);
}
this._onUnitSpawnedBound = false;
this._battle = null;
this._slows.length = 0;
}
private _pushSlow(playerId: number): void {
const adjust = resolveCarriedEnemySlowWan(BattleBuffCarryStore.getPassives(playerId));
if (!adjust.active || adjust.slowWan <= 0) return;
this._slows.push({ playerId, slowWan: adjust.slowWan });
}
private _onUnitSpawned = (event: BattleEvent): void => {
if (event.type !== BattleEventType.UnitSpawned) return;
this._tryApply(event.entity);
};
/** 是否已挂载弱水减速 */
isActive(): boolean {
return this._slows.length > 0;
}
/**
* 该出征怪是否受弱水减速。
* @param entityId 怪物实体
* @returns 减速万分比;不受减则 null
*/
resolveSlowWanForEntity(entityId: EntityId): number | null {
const battle = this._battle;
if (!battle || this._slows.length <= 0) return null;
const world = battle.session.world;
if (!world.isAlive(entityId)) return null;
const team = world.getComponent(entityId, TeamComp);
if (!team || !BattleTeamId.isEnemyTeam(team.team)) return null;
for (let i = 0; i < this._slows.length; i++) {
if (this._slows[i].playerId !== team.ownerId) continue;
return this._slows[i].slowWan;
}
return null;
}
private _tryApply(entityId: EntityId): void {
const battle = this._battle;
if (!battle || this._slows.length <= 0) return;
const world = battle.session.world;
if (!world.isAlive(entityId)) return;
const team = world.getComponent(entityId, TeamComp);
if (!team || !BattleTeamId.isEnemyTeam(team.team)) return;
for (let i = 0; i < this._slows.length; i++) {
if (this._slows[i].playerId !== team.ownerId) continue;
this._applySlow(battle, entityId, this._slows[i].slowWan);
return;
}
}
private _applySlow(battle: ProjectBattleHandle, entityId: EntityId, slowWan: number): void {
const world = battle.session.world;
if (!world.getComponent(entityId, AttributeComp)) {
world.addComponent(entityId, new AttributeComp());
}
const speedMul = Math.max(0, 1 - slowWan / 10000);
battle.session.attributes.addModifier(entityId, {
attr: 'move_speed_mul',
op: 'Mul',
value: speedMul,
source: `${ENEMY_SLOW_MOD_GROUP}_${slowWan}`,
group: ENEMY_SLOW_MOD_GROUP,
});
}
}
let _host: BattleBuffEnemySlowHost | null = null;
/** 全局敌军减速被动 Host(单局复用) */
export function getBattleBuffEnemySlowHost(): BattleBuffEnemySlowHost {
if (!_host) _host = new BattleBuffEnemySlowHost();
return _host;
}