// /public/js/main.js import { initAuth } from './auth.js'; import { initGameSetup } from './gameSetup.js'; import { initGameplay } from './gameplay.js'; // Предполагаем, что ui.js загружен перед этим скриптом (в HTML) // и создал глобальный объект window.gameUI // Также ui.js будет читать window.gameState, window.gameData, window.myPlayerId, window.GAME_CONFIG document.addEventListener('DOMContentLoaded', () => { const socket = io({ // Опции Socket.IO, если нужны }); // --- DOM Элементы для общего UI-управления --- // (Эти элементы управляют общим потоком приложения, а не деталями боя) const authSection = document.getElementById('auth-section'); const loginForm = document.getElementById('login-form'); const registerForm = document.getElementById('register-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'); // Для auth.js 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'); 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"]'); // для gameSetup.js const gameWrapper = document.querySelector('.game-wrapper'); // Элементы, связанные с gameOver, управляются через window.gameUI.showGameOver, // но кнопка "Вернуться в меню" может быть здесь для общего сброса. const returnToMenuButton = document.getElementById('return-to-menu-button'); const turnTimerContainer = document.getElementById('turn-timer-container'); const turnTimerSpan = document.getElementById('turn-timer'); // --- Состояние клиента (глобальное для main и передаваемое в модули) --- // Это состояние будет модифицироваться из разных модулей let clientState = { isLoggedIn: false, loggedInUsername: '', myUserId: null, isInGame: false, // Игровые переменные, которые ранее были глобальными в client.js // и от которых зависит ui.js currentGameId: null, currentGameState: null, myPlayerId: null, myCharacterKey: null, opponentCharacterKey: null, playerBaseStatsServer: null, opponentBaseStatsServer: null, playerAbilitiesServer: null, opponentAbilitiesServer: null, }; // Обновляем глобальные переменные window, на которые рассчитывает ui.js // Это временная мера. В идеале, ui.js должен получать эти данные как аргументы функций. function updateGlobalWindowVariablesForUI() { window.gameState = clientState.currentGameState; window.gameData = { playerBaseStats: clientState.playerBaseStatsServer, opponentBaseStats: clientState.opponentBaseStatsServer, playerAbilities: clientState.playerAbilitiesServer, opponentAbilities: clientState.opponentAbilitiesServer }; window.myPlayerId = clientState.myPlayerId; // window.GAME_CONFIG остается как есть, если он глобальный и не меняется часто // Если GAME_CONFIG приходит от сервера, его тоже нужно обновлять здесь // if (clientState.serverConfig) window.GAME_CONFIG = { ...clientState.serverConfig }; } // --- Функции управления UI (для переключения основных экранов и общих сообщений) --- function showAuthScreen() { authSection.style.display = 'block'; userInfoDiv.style.display = 'none'; gameSetupDiv.style.display = 'none'; gameWrapper.style.display = 'none'; if (window.gameUI?.showGameOver) { // Скрываем модалку GameOver, если была window.gameUI.showGameOver(false, "", null, { finalGameState: { isGameOver: false } }); } setAuthMessage("Ожидание подключения к серверу..."); statusContainer.style.display = 'block'; clientState.isInGame = false; // disableGameControls(); // Вызов будет из gameplay.js resetGameVariables(); // Важно для сброса состояния updateGlobalWindowVariablesForUI(); // Обновляем глоб. переменные для ui.js 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'; if (window.gameUI?.showGameOver) { // Скрываем модалку GameOver window.gameUI.showGameOver(false, "", null, { finalGameState: { isGameOver: false } }); } setGameStatusMessage("Выберите режим игры или присоединитесь к существующей."); statusContainer.style.display = 'block'; socket.emit('requestPvPGameList'); // Запрашиваем список игр if (availableGamesDiv) availableGamesDiv.innerHTML = '

Доступные PvP игры:

Загрузка...

'; // Очистка перед запросом if (gameIdInput) gameIdInput.value = ''; const elenaRadio = document.getElementById('char-elena'); // Для сброса выбора персонажа if (elenaRadio) elenaRadio.checked = true; clientState.isInGame = false; // disableGameControls(); // Вызов будет из gameplay.js resetGameVariables(); updateGlobalWindowVariablesForUI(); if (turnTimerContainer) turnTimerContainer.style.display = 'none'; if (turnTimerSpan) turnTimerSpan.textContent = '--'; enableSetupButtons(); } function showGameScreen() { if (window.gameUI?.showGameOver) { // Скрываем модалку GameOver window.gameUI.showGameOver(false, "", null, { finalGameState: { isGameOver: false } }); } authSection.style.display = 'none'; userInfoDiv.style.display = 'block'; // Оставляем инфо о пользователе gameSetupDiv.style.display = 'none'; gameWrapper.style.display = 'flex'; setGameStatusMessage(""); // Очищаем статус statusContainer.style.display = 'none'; // Скрываем общий статус контейнер clientState.isInGame = true; // disableGameControls(); // Начальная деактивация, gameplay.js включит при ходе updateGlobalWindowVariablesForUI(); // Убедимся, что ui.js имеет свежие данные if (turnTimerContainer) turnTimerContainer.style.display = 'block'; if (turnTimerSpan) turnTimerSpan.textContent = '--'; } function resetGameVariables() { clientState.currentGameId = null; clientState.currentGameState = null; clientState.myPlayerId = null; clientState.myCharacterKey = null; clientState.opponentCharacterKey = null; clientState.playerBaseStatsServer = null; clientState.opponentBaseStatsServer = null; clientState.playerAbilitiesServer = null; clientState.opponentAbilitiesServer = null; // Также обновляем глобальные переменные для ui.js updateGlobalWindowVariablesForUI(); } 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'; // Скрываем другой статус } // Функции для управления кнопками на экране выбора игры (могут быть вызваны из gameSetup) 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 (в gameSetup.js) } // --- Сборка зависимостей для передачи в модули --- const dependencies = { socket, clientState, // Объект состояния, который модули могут читать и изменять ui: { // Функции и элементы для управления общим UI и состоянием showAuthScreen, showGameSelectionScreen, showGameScreen, setAuthMessage, setGameStatusMessage, resetGameVariables, updateGlobalWindowVariablesForUI, // Важно для ui.js disableSetupButtons, enableSetupButtons, elements: { // Передаем элементы, нужные для специфической логики модулей // Для auth.js loginForm, registerForm, logoutButton, // Для gameSetup.js createAIGameButton, createPvPGameButton, joinPvPGameButton, findRandomPvPGameButton, gameIdInput, availableGamesDiv, pvpCharacterRadios, // Для gameplay.js (или для обработки gameover здесь) returnToMenuButton, } }, // gameUI: window.gameUI // Можно передать, если модули должны напрямую вызывать gameUI. // Но пока gameplay.js будет использовать глобальный window.gameUI }; // Инициализация модулей initAuth(dependencies); initGameSetup(dependencies); initGameplay(dependencies); // --- Обработчики событий Socket.IO (глобальные для приложения) --- socket.on('connect', () => { console.log('[Client] Socket connected:', socket.id); setAuthMessage("Успешно подключено к серверу. Вход..."); if (clientState.isLoggedIn && clientState.myUserId) { // Пытаемся восстановить состояние игры, если были залогинены socket.emit('requestGameState'); } else { // Показываем экран логина, если не залогинены showAuthScreen(); } }); socket.on('disconnect', (reason) => { console.warn('[Client] Disconnected:', reason); setGameStatusMessage(`Отключено от сервера: ${reason}. Попытка переподключения...`, true); // Здесь можно добавить логику для UI, показывающую состояние "отключено" // disableGameControls(); // будет в gameplay if (turnTimerSpan) turnTimerSpan.textContent = 'Откл.'; // Не сбрасываем isLoggedIn, чтобы при переподключении можно было восстановить сессию }); // Общая обработка ошибок от сервера, если они не перехвачены в модулях socket.on('gameError', (data) => { console.error('[Client] Received gameError:', data.message); // Показываем ошибку пользователю if (clientState.isInGame && window.gameUI?.addToLog) { window.gameUI.addToLog(`❌ Ошибка сервера: ${data.message}`, 'system'); // Здесь можно решить, нужно ли возвращать в меню или просто показать сообщение } else if (clientState.isLoggedIn) { setGameStatusMessage(`❌ Ошибка: ${data.message}`, true); enableSetupButtons(); // Возвращаем активность кнопкам на экране выбора игры } else { setAuthMessage(`❌ Ошибка: ${data.message}`, true); if(registerForm) registerForm.querySelector('button').disabled = false; if(loginForm) loginForm.querySelector('button').disabled = false; } }); // Обработчик для gameNotFound, который может прийти при реконнекте, если игры нет socket.on('gameNotFound', (data) => { console.log('[Client] Main: Game not found/ended:', data?.message); dependencies.ui.resetGameVariables(); // Сбрасываем игровые переменные clientState.isInGame = false; // disableGameControls(); // в gameplay if (window.gameUI?.showGameOver) window.gameUI.showGameOver(false, "", null, { finalGameState: { isGameOver: false } }); // Скрыть модалку if (turnTimerContainer) turnTimerContainer.style.display = 'none'; if (turnTimerSpan) turnTimerSpan.textContent = '--'; if (clientState.isLoggedIn) { showGameSelectionScreen(clientState.loggedInUsername); setGameStatusMessage(data?.message || "Активная игровая сессия не найдена."); } else { showAuthScreen(); setAuthMessage(data?.message || "Пожалуйста, войдите."); } }); // --- Инициализация UI --- showAuthScreen(); // Показываем начальный экран аутентификации });