133 lines
7.8 KiB
JavaScript
133 lines
7.8 KiB
JavaScript
// /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
|
||
}; |