Initial commit
This commit is contained in:
104
js/core/timer.js
Normal file
104
js/core/timer.js
Normal file
@@ -0,0 +1,104 @@
|
||||
// timer.js
|
||||
import * as state from './state.js';
|
||||
import { GAME_STATES } from '../config.js';
|
||||
import audioManager from '../ui/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
|
||||
let timeExpiredFlagsById = new Map(); // Track which players have had their timeout sound played
|
||||
|
||||
export function initTimer(options) {
|
||||
onTimerTickCallback = options.onTimerTick;
|
||||
onPlayerSwitchCallback = options.onPlayerSwitch;
|
||||
onGameOverCallback = options.onGameOver;
|
||||
timeExpiredFlagsById.clear(); // Reset flags on init
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// Reset the expired sound flags when starting a new timer
|
||||
timeExpiredFlagsById.clear();
|
||||
|
||||
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 - ensure we're not leaking audio resources
|
||||
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
|
||||
if(currentPlayer.remainingTime < 0) {
|
||||
state.updatePlayerTime(currentPlayerIndex, 0);
|
||||
}
|
||||
|
||||
// Play time expired sound (only once per player per game)
|
||||
if (!timeExpiredFlagsById.has(currentPlayer.id)) {
|
||||
audioManager.playTimerExpired();
|
||||
timeExpiredFlagsById.set(currentPlayer.id, true);
|
||||
}
|
||||
|
||||
// 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 and ensure we stop any sounds from current player
|
||||
audioManager.stopTimerSounds(); // Stop specific timer sounds before switching
|
||||
|
||||
if (onPlayerSwitchCallback) onPlayerSwitchCallback(nextPlayerIndex);
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
export function stopTimer() {
|
||||
clearInterval(timerInterval);
|
||||
timerInterval = null;
|
||||
// Stop all timer-related sounds to prevent them from continuing to play
|
||||
audioManager.stopTimerSounds();
|
||||
}
|
||||
|
||||
export function isTimerRunning() {
|
||||
return timerInterval !== null;
|
||||
}
|
||||
|
||||
// Clean up resources when the application is closing or component unmounts
|
||||
export function cleanup() {
|
||||
stopTimer();
|
||||
timeExpiredFlagsById.clear();
|
||||
audioManager.stopAllSounds();
|
||||
}
|
||||
Reference in New Issue
Block a user