bc/server/game/logic/gameStateLogic.js

133 lines
7.8 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.

// /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
};