core/game-event.ts

import { Agent } from "./agent.ts";
import { Board } from "./board.ts";
import { Cell } from "./cell.ts";
import { events } from "./event-bus.ts";
import { Game } from "./game.ts";
import { Player } from "./player.ts";

/**
 * A cancellable game event passed to piece callbacks.
 * Carries a reference to the current player and board so callbacks can
 * read game state and fire messages without needing to import Game.
 */
export class GameEvent {
  player: Player;
  board: Board;
  game: Game;
  #cancelled: boolean;
  originCell: Cell | null;
  #kills: Array<{ cell: Cell, agent: Agent }> | null;
  constructor(player: Player, board: Board, game: Game) {
    this.player = player;
    this.board = board;
    this.game = game;
    this.#cancelled = false;
    this.originCell = null;
    this.#kills = null;
  }

  /**
   * Record that an agent has been killed (changeHealth returned 0).
   * Callers are responsible for removing the agent from the board after
   * processing all callbacks.
   */
  kill(cell: Cell, agent: Agent) {
    if (!this.#kills) {
      this.#kills = [];
    }
    this.#kills.push({ cell, agent });
  }

  get kills(): Array<{ cell: Cell, agent: Agent }> | null {
    return this.#kills;
  }

  /**
   * Cancel with an optional message. If a message is provided, it will be centered on
   * the player’s cell, unless a cell argument is passed to the method.
   * @param message
   * @param cell 
   */
  cancel(message?: string, cell?: Cell) {
    this.#cancelled = true;
    if (message) {
      events.fireMessage(message, cell ?? this.board.getCurrentCell());
    }
  }

  /** True if the event has been cancelled. */
  get isCancelled(): boolean {
    return this.#cancelled;
  }

  /** Allow a cancelled event to proceed (used by Game controller). */
  suppressCancel() {
    this.#cancelled = false;
  }
}