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.
167 lines
8.1 KiB
167 lines
8.1 KiB
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<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;
|
|
|