bc/public/js/client_del.js

583 lines
32 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// /public/js/client.js
document.addEventListener('DOMContentLoaded', () => {
const socket = io({
// Опции Socket.IO, если нужны
// transports: ['websocket'], // Можно попробовать для отладки, если есть проблемы с polling
});
// --- Состояние клиента ---
let currentGameState = null;
let myPlayerId = null; // Технический ID слота в игре ('player' или 'opponent')
let myUserId = null; // ID залогиненного пользователя (из БД)
let myCharacterKey = null;
let opponentCharacterKey = null;
let currentGameId = null;
let playerBaseStatsServer = null;
let opponentBaseStatsServer = null;
let playerAbilitiesServer = null;
let opponentAbilitiesServer = null;
let isLoggedIn = false;
let loggedInUsername = '';
let isInGame = false;
// --- DOM Элементы ---
const authSection = document.getElementById('auth-section');
const registerForm = document.getElementById('register-form');
const loginForm = document.getElementById('login-form');
const authMessage = document.getElementById('auth-message');
const statusContainer = document.getElementById('status-container');
const userInfoDiv = document.getElementById('user-info');
const loggedInUsernameSpan = document.getElementById('logged-in-username');
const logoutButton = document.getElementById('logout-button');
const gameSetupDiv = document.getElementById('game-setup');
const createAIGameButton = document.getElementById('create-ai-game');
const createPvPGameButton = document.getElementById('create-pvp-game');
const joinPvPGameButton = document.getElementById('join-pvp-game'); // Убедитесь, что ID в HTML 'join-pvp-game'
const findRandomPvPGameButton = document.getElementById('find-random-pvp-game');
const gameIdInput = document.getElementById('game-id-input');
const availableGamesDiv = document.getElementById('available-games-list');
const gameStatusMessage = document.getElementById('game-status-message');
const pvpCharacterRadios = document.querySelectorAll('input[name="pvp-character"]');
const gameWrapper = document.querySelector('.game-wrapper');
const attackButton = document.getElementById('button-attack');
const returnToMenuButton = document.getElementById('return-to-menu-button');
const gameOverScreen = document.getElementById('game-over-screen');
const abilitiesGrid = document.getElementById('abilities-grid');
const turnTimerSpan = document.getElementById('turn-timer');
const turnTimerContainer = document.getElementById('turn-timer-container');
// --- Функции управления UI ---
function showAuthScreen() {
authSection.style.display = 'block';
userInfoDiv.style.display = 'none';
gameSetupDiv.style.display = 'none';
gameWrapper.style.display = 'none';
hideGameOverModal();
setAuthMessage("Ожидание подключения к серверу...");
statusContainer.style.display = 'block';
isInGame = false;
disableGameControls();
resetGameVariables();
if (turnTimerContainer) turnTimerContainer.style.display = 'none';
if (turnTimerSpan) turnTimerSpan.textContent = '--';
}
function showGameSelectionScreen(username) {
authSection.style.display = 'none';
userInfoDiv.style.display = 'block';
loggedInUsernameSpan.textContent = username;
gameSetupDiv.style.display = 'block';
gameWrapper.style.display = 'none';
hideGameOverModal();
setGameStatusMessage("Выберите режим игры или присоединитесь к существующей.");
statusContainer.style.display = 'block';
socket.emit('requestPvPGameList');
updateAvailableGamesList([]); // Очищаем перед запросом
if (gameIdInput) gameIdInput.value = '';
const elenaRadio = document.getElementById('char-elena');
if (elenaRadio) elenaRadio.checked = true;
isInGame = false;
disableGameControls();
resetGameVariables(); // Сбрасываем игровые переменные при выходе в меню
if (turnTimerContainer) turnTimerContainer.style.display = 'none';
if (turnTimerSpan) turnTimerSpan.textContent = '--';
enableSetupButtons(); // Включаем кнопки на экране выбора игры
}
function showGameScreen() {
hideGameOverModal();
authSection.style.display = 'none';
userInfoDiv.style.display = 'block'; // Оставляем инфо о пользователе
gameSetupDiv.style.display = 'none';
gameWrapper.style.display = 'flex';
setGameStatusMessage(""); // Очищаем статус, т.к. есть индикатор хода
statusContainer.style.display = 'none'; // Скрываем общий статус контейнер
isInGame = true;
disableGameControls(); // Кнопки включатся, когда будет ход игрока
if (turnTimerContainer) turnTimerContainer.style.display = 'block'; // Показываем таймер
if (turnTimerSpan) turnTimerSpan.textContent = '--'; // Начальное значение
}
function resetGameVariables() {
currentGameId = null; currentGameState = null; myPlayerId = null;
myCharacterKey = null; opponentCharacterKey = null;
playerBaseStatsServer = null; opponentBaseStatsServer = null;
playerAbilitiesServer = null; opponentAbilitiesServer = null;
window.gameState = null; window.gameData = null; window.myPlayerId = null;
}
function hideGameOverModal() {
const hiddenClass = window.GAME_CONFIG?.CSS_CLASS_HIDDEN || 'hidden';
if (gameOverScreen && !gameOverScreen.classList.contains(hiddenClass)) {
gameOverScreen.classList.add(hiddenClass);
if (window.gameUI?.uiElements?.gameOver?.modalContent) {
window.gameUI.uiElements.gameOver.modalContent.style.transform = 'scale(0.8) translateY(30px)';
window.gameUI.uiElements.gameOver.modalContent.style.opacity = '0';
}
const opponentPanel = window.gameUI?.uiElements?.opponent?.panel;
if (opponentPanel?.classList.contains('dissolving')) {
opponentPanel.classList.remove('dissolving');
opponentPanel.style.opacity = '1'; opponentPanel.style.transform = 'scale(1) translateY(0)';
}
}
}
function setAuthMessage(message, isError = false) {
if (authMessage) {
authMessage.textContent = message;
authMessage.className = isError ? 'error' : 'success';
authMessage.style.display = message ? 'block' : 'none';
}
if (message && gameStatusMessage) gameStatusMessage.style.display = 'none';
}
function setGameStatusMessage(message, isError = false) {
if (gameStatusMessage) {
gameStatusMessage.textContent = message;
gameStatusMessage.style.display = message ? 'block' : 'none';
gameStatusMessage.style.color = isError ? 'var(--damage-color, red)' : 'var(--turn-color, yellow)';
if (statusContainer) statusContainer.style.display = message ? 'block' : 'none';
}
if (message && authMessage) authMessage.style.display = 'none';
}
function getSelectedCharacterKey() {
let selectedKey = 'elena';
if (pvpCharacterRadios) {
pvpCharacterRadios.forEach(radio => { if (radio.checked) selectedKey = radio.value; });
}
return selectedKey;
}
function enableGameControls(enableAttack = true, enableAbilities = true) {
if (attackButton) attackButton.disabled = !enableAttack;
if (abilitiesGrid) {
const cls = window.GAME_CONFIG?.CSS_CLASS_ABILITY_BUTTON || 'ability-button';
abilitiesGrid.querySelectorAll(`.${cls}`).forEach(b => { b.disabled = !enableAbilities; });
}
if (window.gameUI?.uiElements?.controls?.buttonBlock) window.gameUI.uiElements.controls.buttonBlock.disabled = true;
}
function disableGameControls() { enableGameControls(false, false); }
function disableSetupButtons() {
if(createAIGameButton) createAIGameButton.disabled = true;
if(createPvPGameButton) createPvPGameButton.disabled = true;
if(joinPvPGameButton) joinPvPGameButton.disabled = true;
if(findRandomPvPGameButton) findRandomPvPGameButton.disabled = true;
if(availableGamesDiv) availableGamesDiv.querySelectorAll('button').forEach(btn => btn.disabled = true);
}
function enableSetupButtons() {
if(createAIGameButton) createAIGameButton.disabled = false;
if(createPvPGameButton) createPvPGameButton.disabled = false;
if(joinPvPGameButton) joinPvPGameButton.disabled = false;
if(findRandomPvPGameButton) findRandomPvPGameButton.disabled = false;
// Кнопки в списке игр включаются в updateAvailableGamesList
}
// --- Инициализация обработчиков событий ---
if (registerForm) registerForm.addEventListener('submit', (e) => {
e.preventDefault();
const u = document.getElementById('register-username').value;
const p = document.getElementById('register-password').value;
registerForm.querySelector('button').disabled = true;
if(loginForm) loginForm.querySelector('button').disabled = true;
socket.emit('register', { username: u, password: p });
});
if (loginForm) loginForm.addEventListener('submit', (e) => {
e.preventDefault();
const u = document.getElementById('login-username').value;
const p = document.getElementById('login-password').value;
if(registerForm) registerForm.querySelector('button').disabled = true;
loginForm.querySelector('button').disabled = true;
socket.emit('login', { username: u, password: p });
});
if (logoutButton) logoutButton.addEventListener('click', () => {
logoutButton.disabled = true; socket.emit('logout');
isLoggedIn = false; loggedInUsername = ''; myUserId = null;
resetGameVariables(); isInGame = false; disableGameControls();
showAuthScreen(); setGameStatusMessage("Вы вышли из системы.");
logoutButton.disabled = false;
});
if (createAIGameButton) createAIGameButton.addEventListener('click', () => {
if (!isLoggedIn) { setGameStatusMessage("Пожалуйста, войдите.", true); return; }
disableSetupButtons();
socket.emit('createGame', { mode: 'ai', characterKey: 'elena' }); // AI всегда за Елену
setGameStatusMessage("Создание игры против AI...");
});
if (createPvPGameButton) createPvPGameButton.addEventListener('click', () => {
if (!isLoggedIn) { setGameStatusMessage("Пожалуйста, войдите.", true); return; }
disableSetupButtons();
socket.emit('createGame', { mode: 'pvp', characterKey: getSelectedCharacterKey() });
setGameStatusMessage("Создание PvP игры...");
});
if (joinPvPGameButton) joinPvPGameButton.addEventListener('click', () => { // Убедитесь, что ID кнопки 'join-pvp-game'
if (!isLoggedIn) { setGameStatusMessage("Пожалуйста, войдите.", true); return; }
const gameId = gameIdInput.value.trim();
if (gameId) {
disableSetupButtons();
socket.emit('joinGame', { gameId: gameId });
setGameStatusMessage(`Присоединение к игре ${gameId}...`);
} else setGameStatusMessage("Введите ID игры.", true);
});
if (findRandomPvPGameButton) findRandomPvPGameButton.addEventListener('click', () => {
if (!isLoggedIn) { setGameStatusMessage("Пожалуйста, войдите.", true); return; }
disableSetupButtons();
socket.emit('findRandomGame', { characterKey: getSelectedCharacterKey() });
setGameStatusMessage("Поиск случайной PvP игры...");
});
if (attackButton) attackButton.addEventListener('click', () => {
if (isLoggedIn && isInGame && currentGameId && currentGameState && !currentGameState.isGameOver) {
socket.emit('playerAction', { actionType: 'attack' });
} else { /* обработка ошибки/некорректного состояния */ }
});
function handleAbilityButtonClick(event) {
const abilityId = event.currentTarget.dataset.abilityId;
if (isLoggedIn && isInGame && currentGameId && abilityId && currentGameState && !currentGameState.isGameOver) {
socket.emit('playerAction', { actionType: 'ability', abilityId: abilityId });
} else { /* обработка ошибки/некорректного состояния */ }
}
if (returnToMenuButton) returnToMenuButton.addEventListener('click', () => {
if (!isLoggedIn) { showAuthScreen(); return; }
returnToMenuButton.disabled = true;
resetGameVariables(); isInGame = false; disableGameControls(); hideGameOverModal();
showGameSelectionScreen(loggedInUsername); // Возвращаемся на экран выбора
// Кнопка включится при следующем показе модалки
});
function initializeAbilityButtons() {
// ... (код без изменений, как был)
if (!abilitiesGrid || !window.gameUI || !window.GAME_CONFIG) {
if (abilitiesGrid) abilitiesGrid.innerHTML = '<p class="placeholder-text">Ошибка загрузки способностей.</p>';
return;
}
abilitiesGrid.innerHTML = '';
const config = window.GAME_CONFIG;
const abilitiesToDisplay = playerAbilitiesServer;
const baseStatsForResource = playerBaseStatsServer;
if (!abilitiesToDisplay || abilitiesToDisplay.length === 0 || !baseStatsForResource) {
abilitiesGrid.innerHTML = '<p class="placeholder-text">Нет доступных способностей.</p>';
return;
}
const resourceName = baseStatsForResource.resourceName || "Ресурс";
const abilityButtonClass = config.CSS_CLASS_ABILITY_BUTTON || 'ability-button';
abilitiesToDisplay.forEach(ability => {
const button = document.createElement('button');
button.id = `ability-btn-${ability.id}`;
button.classList.add(abilityButtonClass);
button.dataset.abilityId = ability.id;
let cooldown = ability.cooldown;
let cooldownText = (typeof cooldown === 'number' && cooldown > 0) ? ` (КД: ${cooldown} х.)` : "";
let title = `${ability.name} (${ability.cost} ${resourceName})${cooldownText} - ${ability.description || 'Нет описания'}`;
button.setAttribute('title', title);
const nameSpan = document.createElement('span'); nameSpan.classList.add('ability-name'); nameSpan.textContent = ability.name; button.appendChild(nameSpan);
const descSpan = document.createElement('span'); descSpan.classList.add('ability-desc'); descSpan.textContent = `(${ability.cost} ${resourceName})`; button.appendChild(descSpan);
const cdDisplay = document.createElement('span'); cdDisplay.classList.add('ability-cooldown-display'); cdDisplay.style.display = 'none'; button.appendChild(cdDisplay);
button.addEventListener('click', handleAbilityButtonClick);
abilitiesGrid.appendChild(button);
});
const placeholder = abilitiesGrid.querySelector('.placeholder-text');
if (placeholder) placeholder.remove();
}
function updateAvailableGamesList(games) {
if (!availableGamesDiv) return;
availableGamesDiv.innerHTML = '<h3>Доступные PvP игры:</h3>';
if (games && games.length > 0) {
const ul = document.createElement('ul');
games.forEach(game => {
if (game && game.id) {
const li = document.createElement('li');
li.textContent = `ID: ${game.id.substring(0, 8)}... - ${game.status || 'Ожидает игрока'}`;
const joinBtn = document.createElement('button');
joinBtn.textContent = 'Присоединиться';
joinBtn.dataset.gameId = game.id;
// === ИЗМЕНЕНИЕ: Деактивация кнопки "Присоединиться" для своих игр ===
if (isLoggedIn && myUserId && game.ownerIdentifier === myUserId) {
joinBtn.disabled = true;
joinBtn.title = "Вы не можете присоединиться к своей же ожидающей игре.";
} else {
joinBtn.disabled = false;
}
// === КОНЕЦ ИЗМЕНЕНИЯ ===
joinBtn.addEventListener('click', (e) => {
if (!isLoggedIn) { setGameStatusMessage("Пожалуйста, войдите.", true); return; }
if (e.target.disabled) return; // Не обрабатывать клик по отключенной кнопке
disableSetupButtons();
socket.emit('joinGame', { gameId: e.target.dataset.gameId });
});
li.appendChild(joinBtn);
ul.appendChild(li);
}
});
availableGamesDiv.appendChild(ul);
} else {
availableGamesDiv.innerHTML += '<p>Нет доступных игр. Создайте свою!</p>';
}
enableSetupButtons(); // Включаем основные кнопки создания/поиска
}
// --- Обработчики событий Socket.IO ---
socket.on('connect', () => {
console.log('[Client] Socket connected:', socket.id);
if (isLoggedIn && myUserId) { // Проверяем и isLoggedIn и myUserId
socket.emit('requestGameState'); // Запрашиваем состояние, если были залогинены
} else {
showAuthScreen(); // Иначе показываем экран логина
}
});
socket.on('registerResponse', (data) => {
setAuthMessage(data.message, !data.success);
if (data.success && registerForm) registerForm.reset();
if(registerForm) registerForm.querySelector('button').disabled = false;
if(loginForm) loginForm.querySelector('button').disabled = false;
});
socket.on('loginResponse', (data) => {
setAuthMessage(data.message, !data.success);
if (data.success) {
isLoggedIn = true;
loggedInUsername = data.username;
myUserId = data.userId; // === ИЗМЕНЕНИЕ: Сохраняем ID пользователя ===
setAuthMessage("");
showGameSelectionScreen(data.username);
} else {
isLoggedIn = false; loggedInUsername = ''; myUserId = null;
if(registerForm) registerForm.querySelector('button').disabled = false;
if(loginForm) loginForm.querySelector('button').disabled = false;
}
});
socket.on('gameNotFound', (data) => {
console.log('[Client] Game not found/ended:', data?.message);
resetGameVariables(); isInGame = false; disableGameControls(); hideGameOverModal();
if (turnTimerContainer) turnTimerContainer.style.display = 'none';
if (turnTimerSpan) turnTimerSpan.textContent = '--';
if (isLoggedIn) {
showGameSelectionScreen(loggedInUsername);
setGameStatusMessage(data?.message || "Активная игровая сессия не найдена.");
} else {
showAuthScreen();
setAuthMessage(data?.message || "Пожалуйста, войдите.");
}
});
socket.on('disconnect', (reason) => {
console.log('[Client] Disconnected:', reason);
setGameStatusMessage(`Отключено: ${reason}. Обновите страницу.`, true);
disableGameControls();
if (turnTimerSpan) turnTimerSpan.textContent = 'Откл.';
// Не сбрасываем isLoggedIn, чтобы при переподключении можно было восстановить сессию
});
socket.on('gameCreated', (data) => { // Сервер присылает это после успешного createGame
console.log('[Client] Game created by this client:', data);
currentGameId = data.gameId;
myPlayerId = data.yourPlayerId; // Сервер должен прислать роль создателя
// Остальные данные (gameState, baseStats) придут с gameStarted или gameState (если это PvP ожидание)
// Если это PvP и игра ожидает, сервер может прислать waitingForOpponent
});
socket.on('gameStarted', (data) => {
if (!isLoggedIn) return;
console.log('[Client] Game started:', data);
// ... (остальной код gameStarted без изменений, как был)
if (window.gameUI?.uiElements?.opponent?.panel) {
const opponentPanel = window.gameUI.uiElements.opponent.panel;
if (opponentPanel.classList.contains('dissolving')) {
opponentPanel.classList.remove('dissolving');
opponentPanel.style.opacity = '1'; opponentPanel.style.transform = 'scale(1) translateY(0)';
}
}
currentGameId = data.gameId; myPlayerId = data.yourPlayerId; currentGameState = data.initialGameState;
playerBaseStatsServer = data.playerBaseStats; opponentBaseStatsServer = data.opponentBaseStats;
playerAbilitiesServer = data.playerAbilities; opponentAbilitiesServer = data.opponentAbilities;
myCharacterKey = playerBaseStatsServer?.characterKey; opponentCharacterKey = opponentBaseStatsServer?.characterKey;
if (data.clientConfig) window.GAME_CONFIG = { ...data.clientConfig };
else if (!window.GAME_CONFIG) {
window.GAME_CONFIG = { PLAYER_ID: 'player', OPPONENT_ID: 'opponent', CSS_CLASS_HIDDEN: 'hidden' };
}
window.gameState = currentGameState;
window.gameData = { playerBaseStats: playerBaseStatsServer, opponentBaseStats: opponentBaseStatsServer, playerAbilities: playerAbilitiesServer, opponentAbilities: opponentAbilitiesServer };
window.myPlayerId = myPlayerId;
showGameScreen(); initializeAbilityButtons();
if (window.gameUI?.uiElements?.log?.list) window.gameUI.uiElements.log.list.innerHTML = '';
if (window.gameUI && typeof window.gameUI.addToLog === 'function' && data.log) {
data.log.forEach(logEntry => window.gameUI.addToLog(logEntry.message, logEntry.type));
}
requestAnimationFrame(() => {
if (window.gameUI && typeof window.gameUI.updateUI === 'function') {
window.gameUI.updateUI();
}
});
hideGameOverModal(); setGameStatusMessage("");
});
// Используется для восстановления состояния уже идущей игры
socket.on('gameState', (data) => {
if (!isLoggedIn) return;
console.log('[Client] Received full gameState (e.g. on reconnect):', data);
// Это событие теперь может дублировать 'gameStarted' для переподключения.
// Убедимся, что логика похожа на gameStarted.
currentGameId = data.gameId;
myPlayerId = data.yourPlayerId;
currentGameState = data.gameState; // Используем gameState вместо initialGameState
playerBaseStatsServer = data.playerBaseStats;
opponentBaseStatsServer = data.opponentBaseStats;
playerAbilitiesServer = data.playerAbilities;
opponentAbilitiesServer = data.opponentAbilities;
myCharacterKey = playerBaseStatsServer?.characterKey;
opponentCharacterKey = opponentBaseStatsServer?.characterKey;
if (data.clientConfig) window.GAME_CONFIG = { ...data.clientConfig };
else if (!window.GAME_CONFIG) {
window.GAME_CONFIG = { PLAYER_ID: 'player', OPPONENT_ID: 'opponent', CSS_CLASS_HIDDEN: 'hidden' };
}
window.gameState = currentGameState;
window.gameData = { playerBaseStats: playerBaseStatsServer, opponentBaseStats: opponentBaseStatsServer, playerAbilities: playerAbilitiesServer, opponentAbilities: opponentAbilitiesServer };
window.myPlayerId = myPlayerId;
if (!isInGame) showGameScreen(); // Показываем экран игры, если еще не там
initializeAbilityButtons(); // Переинициализируем кнопки
// Лог при 'gameState' может быть уже накопленным, добавляем его
if (window.gameUI?.uiElements?.log?.list && data.log) { // Очищаем лог перед добавлением нового при полном обновлении
window.gameUI.uiElements.log.list.innerHTML = '';
}
if (window.gameUI && typeof window.gameUI.addToLog === 'function' && data.log) {
data.log.forEach(logEntry => window.gameUI.addToLog(logEntry.message, logEntry.type));
}
requestAnimationFrame(() => {
if (window.gameUI && typeof window.gameUI.updateUI === 'function') {
window.gameUI.updateUI();
}
});
hideGameOverModal();
// Таймер будет обновлен следующим событием 'turnTimerUpdate'
});
socket.on('gameStateUpdate', (data) => {
if (!isLoggedIn || !isInGame || !currentGameId || !window.GAME_CONFIG) return;
currentGameState = data.gameState; window.gameState = currentGameState;
if (window.gameUI?.updateUI) window.gameUI.updateUI();
if (window.gameUI?.addToLog && data.log) {
data.log.forEach(log => window.gameUI.addToLog(log.message, log.type));
}
});
socket.on('logUpdate', (data) => {
if (!isLoggedIn || !isInGame || !currentGameId || !window.GAME_CONFIG) return;
if (window.gameUI?.addToLog && data.log) {
data.log.forEach(log => window.gameUI.addToLog(log.message, log.type));
}
});
socket.on('gameOver', (data) => {
// ... (код без изменений, как был)
if (!isLoggedIn || !currentGameId || !window.GAME_CONFIG) {
if (!currentGameId && isLoggedIn) socket.emit('requestGameState');
else if (!isLoggedIn) showAuthScreen();
return;
}
const playerWon = data.winnerId === myPlayerId;
currentGameState = data.finalGameState; window.gameState = currentGameState;
if (window.gameUI?.updateUI) window.gameUI.updateUI();
if (window.gameUI?.addToLog && data.log) {
data.log.forEach(log => window.gameUI.addToLog(log.message, log.type));
}
if (window.gameUI?.showGameOver) {
const oppKey = window.gameData?.opponentBaseStats?.characterKey;
window.gameUI.showGameOver(playerWon, data.reason, oppKey, data);
}
if (returnToMenuButton) returnToMenuButton.disabled = false;
setGameStatusMessage("Игра окончена. " + (playerWon ? "Вы победили!" : "Вы проиграли."));
if (window.gameUI?.updateTurnTimerDisplay) { // Обновляем UI таймера
window.gameUI.updateTurnTimerDisplay(null, false, currentGameState?.gameMode); // Передаем null, чтобы показать "Конец" или скрыть
}
});
socket.on('waitingForOpponent', () => {
if (!isLoggedIn) return;
setGameStatusMessage("Ожидание присоединения оппонента...");
disableGameControls(); // Боевые кнопки неактивны
disableSetupButtons(); // Кнопки создания/присоединения тоже, пока ждем
if (createPvPGameButton) createPvPGameButton.disabled = false; // Оставляем активной "Создать PvP" для отмены
if (window.gameUI?.updateTurnTimerDisplay) {
window.gameUI.updateTurnTimerDisplay(null, false, 'pvp'); // Таймер неактивен
}
});
socket.on('opponentDisconnected', (data) => {
if (!isLoggedIn || !isInGame || !currentGameId || !window.GAME_CONFIG) return;
const name = data.disconnectedCharacterName || 'Противник';
if (window.gameUI?.addToLog) window.gameUI.addToLog(`🔌 Противник (${name}) отключился.`, 'system');
if (currentGameState && !currentGameState.isGameOver) {
setGameStatusMessage(`Противник (${name}) отключился. Ожидание...`, true);
disableGameControls();
}
});
socket.on('gameError', (data) => {
console.error('[Client] Server error:', data.message);
if (isLoggedIn && isInGame && currentGameState && !currentGameState.isGameOver && window.gameUI?.addToLog) {
window.gameUI.addToLog(`❌ Ошибка игры: ${data.message}`, 'system');
disableGameControls(); setGameStatusMessage(`Ошибка: ${data.message}.`, true);
} else {
setGameStatusMessage(`❌ Ошибка: ${data.message}`, true);
if (isLoggedIn) enableSetupButtons(); // Если на экране выбора игры, включаем кнопки
else { // Если на экране логина
if(registerForm) registerForm.querySelector('button').disabled = false;
if(loginForm) loginForm.querySelector('button').disabled = false;
}
}
});
socket.on('availablePvPGamesList', (games) => {
if (!isLoggedIn) return;
updateAvailableGamesList(games);
});
socket.on('noPendingGamesFound', (data) => { // Вызывается, когда создается новая игра после поиска
if (!isLoggedIn) return;
setGameStatusMessage(data.message || "Свободных игр не найдено. Создана новая для вас.");
updateAvailableGamesList([]); // Очищаем список
// currentGameId и myPlayerId должны были прийти с gameCreated
isInGame = false; // Еще не в активной фазе боя
disableGameControls();
disableSetupButtons(); // Мы в ожидающей игре
if (window.gameUI?.updateTurnTimerDisplay) {
window.gameUI.updateTurnTimerDisplay(null, false, 'pvp');
}
});
socket.on('turnTimerUpdate', (data) => {
if (!isInGame || !currentGameState || currentGameState.isGameOver) {
if (window.gameUI?.updateTurnTimerDisplay && !currentGameState?.isGameOver) { // Только если не game over
window.gameUI.updateTurnTimerDisplay(null, false, currentGameState?.gameMode);
}
return;
}
if (window.gameUI && typeof window.gameUI.updateTurnTimerDisplay === 'function') {
// Определяем, является ли текущий ход ходом этого клиента
const isMyActualTurn = myPlayerId && currentGameState.isPlayerTurn === (myPlayerId === GAME_CONFIG.PLAYER_ID);
window.gameUI.updateTurnTimerDisplay(data.remainingTime, isMyActualTurn, currentGameState.gameMode);
}
});
showAuthScreen(); // Начальный экран
});