bc/public/js/main.js

296 lines
16 KiB
JavaScript
Raw 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/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 = '<h3>Доступные PvP игры:</h3><p>Загрузка...</p>'; // Очистка перед запросом
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(); // Показываем начальный экран аутентификации
});