// /server/game/logic/gameStateLogic.js // GAME_CONFIG будет передаваться в функции как параметр configToUse. // dataUtils также может передаваться, если нужен для какой-то логики здесь. /** * Внутренняя проверка условий конца игры (основано на HP). * @param {object} currentGameState - Текущее состояние игры. * // configToUse и dataUtils здесь не используются, но могут понадобиться для более сложных условий * @param {object} configToUse - Конфигурация игры. * @param {object} dataUtils - Утилиты для доступа к данным. * @returns {boolean} true, если игра окончена по HP, иначе false. */ function checkGameOverInternal(currentGameState, configToUse, dataUtils) { if (!currentGameState || currentGameState.isGameOver) { // Если игра уже помечена как оконченная, или нет состояния, возвращаем текущий статус return currentGameState ? currentGameState.isGameOver : true; } // Убеждаемся, что оба бойца определены в gameState и не являются плейсхолдерами if (!currentGameState.player || !currentGameState.opponent || !currentGameState.player.characterKey || !currentGameState.opponent.characterKey || // Проверяем, что персонажи назначены currentGameState.opponent.name === 'Ожидание игрока...' || // Дополнительная проверка на плейсхолдер !currentGameState.opponent.maxHp || currentGameState.opponent.maxHp <= 0) { return false; // Игра не может закончиться по HP, если один из бойцов не готов/не определен } const playerDead = currentGameState.player.currentHp <= 0; const opponentDead = currentGameState.opponent.currentHp <= 0; return playerDead || opponentDead; // Игра окончена, если хотя бы один мертв } /** * Определяет результат завершения игры (победитель, проигравший, причина). * Вызывается, когда checkGameOverInternal вернул true или игра завершается по другой причине (дисконнект, таймаут). * @param {object} currentGameState - Текущее состояние игры. * @param {object} configToUse - Конфигурация игры (GAME_CONFIG). * @param {string} gameMode - Режим игры ('ai' или 'pvp'). * @param {string} [explicitReason=null] - Явная причина завершения (например, 'turn_timeout', 'opponent_disconnected'). * Если null, причина определяется по HP. * @param {string} [explicitWinnerRole=null] - Явный победитель (если известен, например, при дисконнекте). * @param {string} [explicitLoserRole=null] - Явный проигравший (если известен). * @returns {{isOver: boolean, winnerRole: string|null, loserRole: string|null, reason: string, logMessage: string}} */ function getGameOverResult( currentGameState, configToUse, gameMode, explicitReason = null, explicitWinnerRole = null, explicitLoserRole = null ) { if (!currentGameState) { return { isOver: true, winnerRole: null, loserRole: null, reason: 'error_no_gamestate', logMessage: 'Ошибка: нет состояния игры.' }; } // Если причина уже задана (например, дисконнект или таймаут), используем ее if (explicitReason) { let winnerName = explicitWinnerRole ? (currentGameState[explicitWinnerRole]?.name || explicitWinnerRole) : 'Никто'; let loserName = explicitLoserRole ? (currentGameState[explicitLoserRole]?.name || explicitLoserRole) : 'Никто'; let logMsg = ""; if (explicitReason === 'turn_timeout') { logMsg = `⏱️ Время хода для ${loserName} истекло! Победа присуждается ${winnerName}!`; } else if (explicitReason === 'opponent_disconnected') { logMsg = `🔌 Игрок ${loserName} отключился. Победа присуждается ${winnerName}!`; if (gameMode === 'ai' && explicitLoserRole === configToUse.PLAYER_ID) { // Игрок отключился в AI игре winnerName = currentGameState.opponent?.name || 'AI'; // AI "выиграл" по факту, но не формально logMsg = `🔌 Игрок ${loserName} отключился. Игра завершена.`; explicitWinnerRole = null; // В AI режиме нет формального победителя при дисконнекте игрока } } else { logMsg = `Игра завершена. Причина: ${explicitReason}. Победитель: ${winnerName}.`; } return { isOver: true, winnerRole: explicitWinnerRole, loserRole: explicitLoserRole, reason: explicitReason, logMessage: logMsg }; } // Если явной причины нет, проверяем по HP const playerDead = currentGameState.player?.currentHp <= 0; const opponentDead = currentGameState.opponent?.currentHp <= 0; if (!playerDead && !opponentDead) { return { isOver: false, winnerRole: null, loserRole: null, reason: 'not_over_hp', logMessage: "" }; // Игра еще не окончена по HP } let winnerRole = null; let loserRole = null; let reason = 'hp_zero'; let logMessage = ""; if (gameMode === 'ai') { if (playerDead) { // Игрок проиграл AI winnerRole = configToUse.OPPONENT_ID; // AI победил loserRole = configToUse.PLAYER_ID; logMessage = `😭 ПОРАЖЕНИЕ! ${currentGameState.opponent.name} оказался сильнее! 😭`; } else { // Игрок победил AI (opponentDead) winnerRole = configToUse.PLAYER_ID; loserRole = configToUse.OPPONENT_ID; logMessage = `🏁 ПОБЕДА! Вы одолели ${currentGameState.opponent.name}! 🏁`; } } else { // PvP режим if (playerDead && opponentDead) { // Ничья - победа присуждается игроку в слоте 'player' (или по другим правилам) winnerRole = configToUse.PLAYER_ID; loserRole = configToUse.OPPONENT_ID; logMessage = `⚔️ Ничья! Оба бойца пали! Победа присуждается ${currentGameState.player.name} по правилам арены!`; reason = 'draw_player_wins'; } else if (playerDead) { winnerRole = configToUse.OPPONENT_ID; loserRole = configToUse.PLAYER_ID; logMessage = `🏁 ПОБЕДА! ${currentGameState.opponent.name} одолел(а) ${currentGameState.player.name}! 🏁`; } else { // opponentDead winnerRole = configToUse.PLAYER_ID; loserRole = configToUse.OPPONENT_ID; logMessage = `🏁 ПОБЕДА! ${currentGameState.player.name} одолел(а) ${currentGameState.opponent.name}! 🏁`; } } return { isOver: true, winnerRole, loserRole, reason, logMessage }; } module.exports = { checkGameOverInternal, getGameOverResult };