/** * Enum for game-wide event types. */ export enum Events { DAMAGE_DEALT = 'combat:damage_dealt', ENTITY_DIED = 'combat:entity_died', EVOLVED = 'evolution:evolved', MUTATION_GAINED = 'evolution:mutation_gained', EXP_GAINED = 'stats:exp_gained', LEVEL_UP = 'stats:level_up', SKILL_LEARNED = 'skills:learned', ATTACK_PERFORMED = 'combat:attack_performed', SKILL_COOLDOWN_STARTED = 'skills:cooldown_started', } /** * Event data types */ export interface DamageDealtEvent { x: number; y: number; value: number; color: string; } export interface MutationGainedEvent { name: string; description?: string; } export interface SkillLearnedEvent { id: string; } export interface EntityDiedEvent { entity: unknown; } export interface AttackPerformedEvent { entity: unknown; angle: number; } type EventCallback = (data?: unknown) => void; /** * Lightweight EventBus for pub/sub communication between systems. */ export class EventBus { private listeners: Map; constructor() { this.listeners = new Map(); } /** * Subscribe to an event with a callback. * @param event - The event name from the Events enum * @param callback - The function to call when the event is emitted * @returns An unsubscribe function */ on(event: string, callback: EventCallback): () => void { if (!this.listeners.has(event)) { this.listeners.set(event, []); } const callbacks = this.listeners.get(event); if (callbacks) { callbacks.push(callback); } return () => this.off(event, callback); } /** * Unsubscribe a specific callback from an event. * @param event - The event name * @param callback - The original callback function to remove */ off(event: string, callback: EventCallback): void { if (!this.listeners.has(event)) return; const callbacks = this.listeners.get(event); if (callbacks) { const index = callbacks.indexOf(callback); if (index > -1) { callbacks.splice(index, 1); } } } /** * Emit an event to all subscribers. * @param event - The event name * @param data - Data to pass to the callbacks */ emit(event: string, data?: unknown): void { if (!this.listeners.has(event)) return; const callbacks = this.listeners.get(event); if (callbacks) { callbacks.forEach((callback) => callback(data)); } } }