154 lines
6.2 KiB
JavaScript
154 lines
6.2 KiB
JavaScript
// playerManager.js - Player-related operations
|
|
import * as config from '../config.js';
|
|
import * as state from './state.js';
|
|
import * as ui from '../ui/ui.js';
|
|
import * as timer from './timer.js';
|
|
import audioManager from '../ui/audio.js';
|
|
import camera from '../ui/camera.js';
|
|
|
|
export function switchToPlayer(index) {
|
|
if (index >= 0 && index < state.getPlayers().length) {
|
|
const previousIndex = state.getCurrentPlayerIndex();
|
|
if(index !== previousIndex) {
|
|
state.setCurrentPlayerIndex(index);
|
|
audioManager.play('playerSwitch');
|
|
ui.renderPlayers(); // Update UI immediately
|
|
|
|
// If the game is running, restart the timer for the new player
|
|
// The timer interval callback will handle the decrementing
|
|
if (state.getGameState() === config.GAME_STATES.RUNNING) {
|
|
timer.startTimer(); // This clears the old interval and starts anew
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export function nextPlayer() {
|
|
const currentGameState = state.getGameState();
|
|
let newIndex = -1;
|
|
|
|
if (currentGameState === config.GAME_STATES.RUNNING) {
|
|
newIndex = state.findNextPlayerWithTimeCircular(1); // Find next with time
|
|
} else {
|
|
// Allow cycling through all players if not running
|
|
const playerCount = state.getPlayers().length;
|
|
if(playerCount > 0) {
|
|
newIndex = (state.getCurrentPlayerIndex() + 1) % playerCount;
|
|
}
|
|
}
|
|
|
|
if (newIndex !== -1) {
|
|
switchToPlayer(newIndex);
|
|
} else if (currentGameState === config.GAME_STATES.RUNNING) {
|
|
console.log("NextPlayer: No other player has time remaining.");
|
|
// Optionally handle game over immediately? Timer logic should catch this too.
|
|
}
|
|
}
|
|
|
|
export function previousPlayer() {
|
|
const currentGameState = state.getGameState();
|
|
let newIndex = -1;
|
|
|
|
if (currentGameState === config.GAME_STATES.RUNNING) {
|
|
newIndex = state.findNextPlayerWithTimeCircular(-1); // Find previous with time
|
|
} else {
|
|
// Allow cycling through all players if not running
|
|
const playerCount = state.getPlayers().length;
|
|
if (playerCount > 0) {
|
|
newIndex = (state.getCurrentPlayerIndex() - 1 + playerCount) % playerCount;
|
|
}
|
|
}
|
|
|
|
if (newIndex !== -1) {
|
|
switchToPlayer(newIndex);
|
|
} else if (currentGameState === config.GAME_STATES.RUNNING) {
|
|
console.log("PreviousPlayer: No other player has time remaining.");
|
|
}
|
|
}
|
|
|
|
export function handlePlayerFormSubmit(event) {
|
|
event.preventDefault();
|
|
audioManager.play('buttonClick');
|
|
|
|
const name = ui.elements.playerNameInput.value.trim();
|
|
const timeInMinutes = parseInt(ui.elements.playerTimeInput.value, 10);
|
|
let remainingTimeSeconds = 0; // Default
|
|
const isNewPlayer = ui.elements.modalTitle.textContent === 'Add New Player';
|
|
const currentGameState = state.getGameState();
|
|
|
|
if (!name || isNaN(timeInMinutes) || timeInMinutes <= 0) {
|
|
alert('Please enter a valid name and positive time.');
|
|
return;
|
|
}
|
|
|
|
// Get remaining time ONLY if editing and game is paused/over
|
|
if (!isNewPlayer && (currentGameState === config.GAME_STATES.PAUSED || currentGameState === config.GAME_STATES.OVER)) {
|
|
const remainingTimeString = ui.elements.playerRemainingTimeInput.value;
|
|
const parsedSeconds = ui.parseTimeString(remainingTimeString);
|
|
if (parsedSeconds === null) { // Check if parsing failed
|
|
alert('Please enter remaining time in MM:SS format (e.g., 05:30).');
|
|
return;
|
|
}
|
|
remainingTimeSeconds = parsedSeconds;
|
|
// Validate remaining time against total time? Optional.
|
|
if (remainingTimeSeconds > timeInMinutes * 60) {
|
|
alert('Remaining time cannot be greater than the total time.');
|
|
return;
|
|
}
|
|
} else {
|
|
// For new players or when editing in setup, remaining time matches total time
|
|
remainingTimeSeconds = timeInMinutes * 60;
|
|
}
|
|
|
|
let imageDataUrl = ui.elements.playerImageInput.dataset.capturedImage || null;
|
|
const imageFile = ui.elements.playerImageInput.files[0];
|
|
|
|
const saveAction = (finalImageData) => {
|
|
if (isNewPlayer) {
|
|
state.addPlayer(name, timeInMinutes, finalImageData);
|
|
audioManager.play('playerAdded');
|
|
} else {
|
|
const playerIndex = state.getCurrentPlayerIndex();
|
|
// Use 'undefined' for image if no new image is provided, so state.updatePlayer keeps the old one
|
|
const imageArg = finalImageData !== null ? finalImageData : (isNewPlayer ? null : undefined);
|
|
state.updatePlayer(playerIndex, name, timeInMinutes, remainingTimeSeconds, imageArg);
|
|
audioManager.play('playerEdited');
|
|
}
|
|
ui.hidePlayerModal();
|
|
ui.renderPlayers();
|
|
ui.updateGameButton(); // Update in case player count changed for setup state
|
|
camera.stopStream(); // Ensure camera is stopped
|
|
};
|
|
|
|
if (!imageDataUrl && imageFile) {
|
|
// Handle file upload: Read file as Data URL
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => saveAction(e.target.result);
|
|
reader.onerror = (e) => {
|
|
console.error("Error reading image file:", e);
|
|
alert("Error processing image file.");
|
|
};
|
|
reader.readAsDataURL(imageFile);
|
|
} else {
|
|
// Handle captured image or no image change
|
|
const currentImage = isNewPlayer ? null : state.getCurrentPlayer()?.image;
|
|
// If imageDataUrl has content (from camera), use it.
|
|
// If not, and no file was selected, keep the current image (by passing undefined to updatePlayer later).
|
|
// If it's a new player and no image, pass null.
|
|
saveAction(imageDataUrl ?? (isNewPlayer ? null : currentImage));
|
|
}
|
|
}
|
|
|
|
export function handleDeletePlayer() {
|
|
audioManager.play('buttonClick');
|
|
const success = state.deletePlayer(state.getCurrentPlayerIndex());
|
|
if (success) {
|
|
audioManager.play('playerDeleted');
|
|
ui.hidePlayerModal();
|
|
ui.renderPlayers();
|
|
ui.updateGameButton(); // Update in case player count dropped below 2
|
|
} else {
|
|
alert('Cannot delete player. Minimum of 2 players required.');
|
|
}
|
|
camera.stopStream();
|
|
}
|