import type { EntityId } from 'db://assets/mx/module/battle/ecs/EntityId'; import type { AbilityContext } from 'db://assets/mx/module/battle/combat/AbilityContext'; import type { Cell } from 'db://assets/mx/module/battle/battlefield/Cell'; import type { UnitDefId, EffectSpec } from 'db://assets/mx/module/battle/config/BattleConfigTypes'; import { BattlePhase } from 'db://assets/mx/module/battle/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; 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; 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;