import { Board } from "./board.ts";
import { GameEvent } from "./game-event.ts";
import { Game } from "./game.ts";
import { Player } from "./player.ts";
const FRAME_MS = 80; // ~12.5 fps, matching Java's 80 ms period
/**
* AnimationManager — drives all visual effects at ~12.5 fps using rAF.
*
* Each tick:
* 1. Calls player.onFrame(cell) so damage/heal flashes fade
* 2. Calls onFrame() on every animated piece via the board's AnimationProxy
* list (terrain, agents, items, effects including InFlightItem projectiles)
*
* The board and player references are set by the Game controller just before
* the game loop starts via setContext().
*/
export class AnimationManager {
#board!: Board;
#player!: Player;
#game!: Game;
#running: boolean = false;
#rafId: number | null = null;
lastTime: number = 0;
constructor() {
this.loop = this.loop.bind(this);
}
loop(now: number) {
if (!this.#running) {
return;
}
this.#rafId = requestAnimationFrame(this.loop);
if (now - this.lastTime < FRAME_MS) {
return;
}
this.lastTime = now;
this.tick();
}
/**
* Inject game context. Called by the Game controller before start().
*/
setContext(board: Board, player: Player, game: Game) {
this.#board = board;
this.#player = player;
this.#game = game;
}
start() {
if (this.#running) {
return;
}
this.#running = true;
this.lastTime = performance.now();
this.#rafId = requestAnimationFrame(this.loop);
}
stop() {
this.#running = false;
if (this.#rafId !== null) {
cancelAnimationFrame(this.#rafId);
this.#rafId = null;
}
}
isRunning(): boolean {
return this.#rafId != null;
}
tick() {
const board = this.#board;
const player = this.#player;
const event = new GameEvent(player, board, this.#game);
// Advance player flash counters
const playerCell = board.getCurrentCell();
player.onFrame(playerCell);
// Dispatch onFrame to all animated pieces (terrain, agents, items, effects).
// Walking backwards mirrors Java: animations can remove themselves mid-tick
// without corrupting the forward iteration.
const animated = board.animated;
for (let i = animated.length - 1; i >= 0; i--) {
animated[i].tick(event, board);
}
}
}
export const animationManager = new AnimationManager();