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/events/BattleEvents.ts

167 lines
8.0 KiB

import type { EntityId } from '../ecs/EntityId';
import type { AbilityContext } from '../combat/AbilityContext';
import type { Cell } from '../battlefield/Cell';
import type { UnitDefId, EffectSpec } from '../config/BattleConfigTypes';
import { BattlePhase } from '../core/BattlePhase';
import { BattleEventType } from './BattleEventType';
/** 战斗事件联合类型(type 字段必须使用 BattleEventType 枚举) */
export type BattleEvent =
| { type: BattleEventType.PhaseChanged; phase: BattlePhase; prev: BattlePhase }
| { type: BattleEventType.UnitPlaced; entity: EntityId; playerId: number; cell: Cell }
| { type: BattleEventType.UnitSold; entity: EntityId; playerId: number }
| { type: BattleEventType.AbilityCast; ctx: AbilityContext }
| {
type: BattleEventType.PresentationCue;
caster: EntityId;
abilityId: string;
cueId: string;
params: Record<string, unknown>;
atMs: number;
castInstanceId: number;
targetEntityIds: EntityId[];
}
| {
type: BattleEventType.AbilityCastEnd;
caster: EntityId;
abilityId: string;
castInstanceId: number;
durationSec: number;
}
| { type: BattleEventType.DamageDealt; caster: EntityId; target: EntityId; amount: number; damageType?: string; fromPassiveResult?: boolean }
| { type: BattleEventType.AttackBefore; caster: EntityId; targets: EntityId[]; abilityId?: string }
| { type: BattleEventType.HitAfter; caster: EntityId; target: EntityId; amount: number; isCrit: boolean; abilityId?: string; damageType?: string }
| { type: BattleEventType.BuffApplied; target: EntityId; buffId: string; duration: number; caster: EntityId }
| { type: BattleEventType.BuffRemoved; target: EntityId; buffId: string }
| { type: BattleEventType.ProjectileSpawned; projectile: EntityId; caster: EntityId; prefab?: string }
| { type: BattleEventType.ProjectileHit; projectile: EntityId; caster: EntityId; target: EntityId; hitEffects: EffectSpec[] }
| { type: BattleEventType.EntityKilled; killer: EntityId; victim: EntityId; damageType?: string; fromPassiveResult?: boolean }
| { type: BattleEventType.UnitDespawned; entity: EntityId }
| { type: BattleEventType.WallDamaged; playerId: number; amount: number; remain: number }
| { type: BattleEventType.WaveStart; waveIndex: number; playerId?: number }
| { type: BattleEventType.WaveEnd; waveIndex: number; playerId?: number }
| { type: BattleEventType.UnitSpawned; entity: EntityId; unitDefId: UnitDefId; spawnPort: number; hp: number }
| { type: BattleEventType.BattleEnd; win: boolean; reason?: string }
| { type: BattleEventType.Custom; name: string; payload?: unknown };
/** 战斗事件监听器 */
export type BattleEventListener = (event: BattleEvent) => void;
/**
* 战斗事件工厂
* 所有 logic → view 的事件须通过此处构造,避免散落字符串字面量。
*/
export const BattleEventFactory = {
/** @returns 阶段切换事件 */
phaseChanged(phase: BattlePhase, prev: BattlePhase): BattleEvent {
return { type: BattleEventType.PhaseChanged, phase, prev };
},
/** @returns 单位部署事件 */
unitPlaced(entity: EntityId, playerId: number, cell: Cell): BattleEvent {
return { type: BattleEventType.UnitPlaced, entity, playerId, cell };
},
/** @returns 单位出售事件 */
unitSold(entity: EntityId, playerId: number): BattleEvent {
return { type: BattleEventType.UnitSold, entity, playerId };
},
/** @returns 技能施放事件 */
abilityCast(ctx: AbilityContext): BattleEvent {
return { type: BattleEventType.AbilityCast, ctx };
},
/** @returns 表现 cue 事件(逻辑 → 表现层语义阶段) */
presentationCue(args: {
caster: EntityId;
abilityId: string;
cueId: string;
params?: Record<string, unknown>;
atMs?: number;
castInstanceId: number;
targetEntityIds?: EntityId[];
}): BattleEvent {
return {
type: BattleEventType.PresentationCue,
caster: args.caster,
abilityId: args.abilityId,
cueId: args.cueId,
params: args.params ?? {},
atMs: args.atMs ?? 0,
castInstanceId: args.castInstanceId,
targetEntityIds: args.targetEntityIds ?? [],
};
},
/** @returns 技能施法结束事件 */
abilityCastEnd(
caster: EntityId,
abilityId: string,
castInstanceId: number,
durationSec: number,
): BattleEvent {
return {
type: BattleEventType.AbilityCastEnd,
caster,
abilityId,
castInstanceId,
durationSec,
};
},
/** @returns 造成伤害事件 */
damageDealt(caster: EntityId, target: EntityId, amount: number, damageType?: string, fromPassiveResult?: boolean): BattleEvent {
return { type: BattleEventType.DamageDealt, caster, target, amount, damageType, fromPassiveResult };
},
/** @returns 攻击前事件(伤害结算前) */
attackBefore(caster: EntityId, targets: EntityId[], abilityId?: string): BattleEvent {
return { type: BattleEventType.AttackBefore, caster, targets, abilityId };
},
/** @returns 命中后事件(伤害结算后) */
hitAfter(caster: EntityId, target: EntityId, amount: number, isCrit: boolean, abilityId?: string, damageType?: string): BattleEvent {
return { type: BattleEventType.HitAfter, caster, target, amount, isCrit, abilityId, damageType };
},
/** @returns Buff 施加事件 */
buffApplied(target: EntityId, buffId: string, duration: number, caster: EntityId): BattleEvent {
return { type: BattleEventType.BuffApplied, target, buffId, duration, caster };
},
/** @returns Buff 移除事件 */
buffRemoved(target: EntityId, buffId: string): BattleEvent {
return { type: BattleEventType.BuffRemoved, target, buffId };
},
/** @returns 投射物生成事件 */
projectileSpawned(projectile: EntityId, caster: EntityId, prefab?: string): BattleEvent {
return { type: BattleEventType.ProjectileSpawned, projectile, caster, prefab };
},
/** @returns 投射物命中事件 */
projectileHit(projectile: EntityId, caster: EntityId, target: EntityId, hitEffects: EffectSpec[]): BattleEvent {
return { type: BattleEventType.ProjectileHit, projectile, caster, target, hitEffects };
},
/** @returns 实体击杀事件 */
entityKilled(killer: EntityId, victim: EntityId, damageType?: string, fromPassiveResult?: boolean): BattleEvent {
return { type: BattleEventType.EntityKilled, killer, victim, damageType, fromPassiveResult };
},
/** @returns 实体无击杀结算移除事件 */
unitDespawned(entity: EntityId): BattleEvent {
return { type: BattleEventType.UnitDespawned, entity };
},
/** @returns 城墙受伤事件 */
wallDamaged(playerId: number, amount: number, remain: number): BattleEvent {
return { type: BattleEventType.WallDamaged, playerId, amount, remain };
},
/** @returns 波次开始事件 */
waveStart(waveIndex: number, playerId?: number): BattleEvent {
return { type: BattleEventType.WaveStart, waveIndex, playerId };
},
/** @returns 波次结束事件 */
waveEnd(waveIndex: number, playerId?: number): BattleEvent {
return { type: BattleEventType.WaveEnd, waveIndex, playerId };
},
/** @returns 怪物生成事件 */
unitSpawned(entity: EntityId, unitDefId: UnitDefId, spawnPort: number, hp: number): BattleEvent {
return { type: BattleEventType.UnitSpawned, entity, unitDefId, spawnPort, hp };
},
/** @returns 战斗结束事件 */
battleEnd(win: boolean, reason?: string): BattleEvent {
return { type: BattleEventType.BattleEnd, win, reason };
},
/** @returns 自定义事件 */
custom(name: string, payload?: unknown): BattleEvent {
return { type: BattleEventType.Custom, name, payload };
},
} as const;