// timer.js import * as state from './state.js'; import { GAME_STATES } from './config.js'; import audioManager from './audio.js'; let timerInterval = null; let onTimerTickCallback = null; // Callback for UI updates let onPlayerSwitchCallback = null; // Callback for when player switches due to time running out let onGameOverCallback = null; // Callback for when all players run out of time export function initTimer(options) { onTimerTickCallback = options.onTimerTick; onPlayerSwitchCallback = options.onPlayerSwitch; onGameOverCallback = options.onGameOver; } export function startTimer() { if (timerInterval) clearInterval(timerInterval); // Clear existing interval if any // Stop any previous sounds (like low time warning) before starting fresh audioManager.stopAllSounds(); // Consider if this is too aggressive timerInterval = setInterval(() => { const currentPlayerIndex = state.getCurrentPlayerIndex(); const currentPlayer = state.getCurrentPlayer(); // Get player data after index if (!currentPlayer) { console.warn("Timer running but no current player found."); stopTimer(); return; } // Only decrease time if the current player has time left if (currentPlayer.remainingTime > 0) { const newTime = currentPlayer.remainingTime - 1; state.updatePlayerTime(currentPlayerIndex, newTime); // Update state // Play timer sounds audioManager.playTimerSound(newTime); // Notify UI to update if (onTimerTickCallback) onTimerTickCallback(); } else { // Current player's time just hit 0 or was already 0 // Ensure time is exactly 0 if it somehow went negative (unlikely with check above) if(currentPlayer.remainingTime < 0) { state.updatePlayerTime(currentPlayerIndex, 0); } // Stop this player's timer tick sound if it was playing // audioManager.stop('timerTick'); // Or specific low time sound // Play time expired sound (only once) // Check if we just hit zero to avoid playing repeatedly // This logic might be complex, audioManager could handle idempotency if (currentPlayer.remainingTime === 0 && !currentPlayer.timeExpiredSoundPlayed) { audioManager.playTimerExpired(); // We need a way to mark that the sound played for this player this turn. // This might require adding a temporary flag to the player state, // or handling it within the audioManager. Let's assume audioManager handles it for now. } // Check if the game should end or switch player if (state.areAllTimersFinished()) { stopTimer(); if (onGameOverCallback) onGameOverCallback(); } else { // Find the *next* player who still has time const nextPlayerIndex = state.findNextPlayerWithTime(); // This finds ANY player with time if (nextPlayerIndex !== -1 && nextPlayerIndex !== currentPlayerIndex) { // Switch player if (onPlayerSwitchCallback) onPlayerSwitchCallback(nextPlayerIndex); // Play switch sound (might be handled in app.js based on state change) // audioManager.play('playerSwitch'); // Or let app.js handle sounds based on actions // Immediately update UI after switch if (onTimerTickCallback) onTimerTickCallback(); } else if (nextPlayerIndex === -1) { // This case shouldn't be reached if areAllTimersFinished is checked first, but as a safeguard: console.warn("Timer tick: Current player out of time, but no next player found, yet not all timers finished?"); stopTimer(); // Stop timer if state is inconsistent if (onGameOverCallback) onGameOverCallback(); // Treat as game over } // If nextPlayerIndex is the same as currentPlayerIndex, means others are out of time, let this timer continue (or rather, stop ticking down as remainingTime is 0) } } }, 1000); } export function stopTimer() { clearInterval(timerInterval); timerInterval = null; // Optionally stop timer sounds here if needed // audioManager.stop('timerTick'); } export function isTimerRunning() { return timerInterval !== null; }