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

124 lines
4.6 KiB

3 weeks ago
import type { EntityId } from 'db://assets/mx/module/ecs';
import {
AttributeComp,
BattleEventType,
MovementComp,
type BattleEvent,
} from 'db://assets/mx/module/battle';
import { BattleBuffCarryStore } from '../../manager/battleBuff/BattleBuffCarryStore';
import { resolveMarchOwnerPlayerId } from '../../manager/battleBuff/BattleBuffSideResolve';
import { resolveCarriedMoveSpeedBonusWan } from '../../manager/battleBuff/BattleBuffPassiveSkillUtil';
import type { ProjectBattleHandle } from '../runtime/BattleRuntime';
import { AI_PLAYER_ID } from '../ai/runtime/AiCampArea';
/** 被动行军速度 modifier 分组 */
const MOVE_SPEED_MOD_GROUP = 'battle_buff_move_speed';
/** 单玩家移速加成 */
type PlayerMoveBonus = {
/** playerId(出征方) */
playerId: number;
/** 万分比 */
bonusWan: number;
};
/**
* 被动 functiontype=12 云麾号角:携带方「出征兵」移速 ×(1+万分比/10000)。
* 出征兵 = 进攻对面基地的行军怪,不是己侧场上单位。
* 例外:AI 携带时加成落到本机玩家出征兵(见 docs/需求-战斗Buff阵营语义.md)。
*/
export class BattleBuffMoveSpeedHost {
private _battle: ProjectBattleHandle | null = null;
private readonly _bonuses: PlayerMoveBonus[] = [];
private _onUnitSpawnedBound = false;
/** 绑定本局并监听出怪 */
bind(battle: ProjectBattleHandle): void {
this.unbind();
this._battle = battle;
this._bonuses.length = 0;
this._pushBonus(battle.localPlayerId);
this._pushBonus(AI_PLAYER_ID);
if (this._bonuses.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._bonuses.length = 0;
}
/**
* 按携带方读被动;AI 云麾号角改落到本机玩家出征兵。
* @param carrierPlayerId 携带方
*/
private _pushBonus(carrierPlayerId: number): void {
const adjust = resolveCarriedMoveSpeedBonusWan(BattleBuffCarryStore.getPassives(carrierPlayerId));
if (!adjust.active || adjust.bonusWan <= 0) return;
const targetPlayerId = carrierPlayerId === AI_PLAYER_ID
? (this._battle?.localPlayerId ?? 0)
: carrierPlayerId;
for (let i = 0; i < this._bonuses.length; i++) {
if (this._bonuses[i].playerId !== targetPlayerId) continue;
this._bonuses[i].bonusWan += adjust.bonusWan;
return;
}
this._bonuses.push({ playerId: targetPlayerId, bonusWan: adjust.bonusWan });
}
private _onUnitSpawned = (event: BattleEvent): void => {
if (event.type !== BattleEventType.UnitSpawned) return;
this._tryApply(event.entity);
};
private _tryApply(entityId: EntityId): void {
const battle = this._battle;
if (!battle || this._bonuses.length <= 0) return;
const ownerId = resolveMarchOwnerPlayerId(battle.session, entityId);
if (ownerId < 0) return;
for (let i = 0; i < this._bonuses.length; i++) {
if (this._bonuses[i].playerId !== ownerId) continue;
this._applyMoveSpeedBonus(battle, entityId, this._bonuses[i].bonusWan);
return;
}
}
private _applyMoveSpeedBonus(battle: ProjectBattleHandle, entityId: EntityId, bonusWan: number): void {
const mul = 1 + bonusWan / 10000;
const world = battle.session.world;
if (!world.getComponent(entityId, AttributeComp)) {
world.addComponent(entityId, new AttributeComp());
}
battle.session.attributes.addModifier(entityId, {
attr: 'move_speed_mul',
op: 'Mul',
value: mul,
source: `${MOVE_SPEED_MOD_GROUP}_${bonusWan}`,
group: MOVE_SPEED_MOD_GROUP,
});
const move = world.getComponent(entityId, MovementComp);
if (move) {
move.speed = Math.max(0, (move.baseSpeed || move.speed) * mul);
}
}
}
let _host: BattleBuffMoveSpeedHost | null = null;
/** 全局出征兵移速被动 Host(单局复用) */
export function getBattleBuffMoveSpeedHost(): BattleBuffMoveSpeedHost {
if (!_host) _host = new BattleBuffMoveSpeedHost();
return _host;
}