bc/server/game/logic/tauntLogic.js
2025-05-25 17:47:38 +03:00

151 lines
10 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.

// /server/game/logic/tauntLogic.js
const GAME_CONFIG = require('../../core/config');
// Предполагаем, что gameData.tauntSystem импортируется или доступен.
// Если tauntSystem экспортируется напрямую из data/taunts.js:
// const { tauntSystem } = require('../../data/taunts');
// Если он часть общего gameData, который собирается в data/index.js:
const gameData = require('../../data'); // Тогда используем gameData.tauntSystem
/**
* Получает случайную насмешку из системы насмешек.
* @param {string} speakerCharacterKey - Ключ персонажа, который говорит.
* @param {string} trigger - Тип триггера насмешки (например, 'selfCastAbility', 'onBattleState', 'onOpponentAction').
* @param {string|number|object} [subTriggerOrContext={}] - Может быть ID способности, специфичный ключ состояния ('start', 'dominating') или объект контекста.
* @param {object} configToUse - Конфигурационный объект игры (GAME_CONFIG).
* @param {object} opponentFullData - Полные данные персонажа, к которому обращена насмешка (цель).
* @param {object} currentGameState - Текущее полное состояние игры.
* @returns {string} Текст насмешки или "(Молчание)".
*/
function getRandomTaunt(speakerCharacterKey, trigger, subTriggerOrContext = {}, configToUse, opponentFullData, currentGameState) {
// console.log(`[TauntLogic DEBUG] Called with: speaker=${speakerCharacterKey}, trigger=${trigger}, subTriggerOrContext=`, subTriggerOrContext, `opponentKey=${opponentFullData?.baseStats?.characterKey}`);
const tauntSystemToUse = gameData.tauntSystem || (gameData.default && gameData.default.tauntSystem); // Совместимость, если gameData имеет default экспорт
if (!tauntSystemToUse) {
console.error("[TauntLogic ERROR] tauntSystem is not available from gameData import!");
return "(Молчание)";
}
const speakerTauntBranch = tauntSystemToUse[speakerCharacterKey];
if (!speakerTauntBranch) {
// console.log(`[TauntLogic] No taunt branch for speaker: ${speakerCharacterKey}`);
return "(Молчание)";
}
const opponentKeyForTaunts = opponentFullData?.baseStats?.characterKey;
if (!opponentKeyForTaunts) {
// console.log(`[TauntLogic] Opponent key for taunts not available for speaker ${speakerCharacterKey}, trigger ${trigger}. OpponentData:`, opponentFullData);
// Особый случай для старта AI игры, где оппонент (AI Балард) может быть известен, даже если opponentFullData не полон
if (trigger === 'onBattleState' && subTriggerOrContext === 'start' && speakerCharacterKey === 'elena' && currentGameState.gameMode === 'ai') {
// Елена против Баларда (AI) в начале боя
const elenaVsBalardStartTaunts = speakerTauntBranch.balard?.onBattleState?.start;
if (Array.isArray(elenaVsBalardStartTaunts) && elenaVsBalardStartTaunts.length > 0) {
return elenaVsBalardStartTaunts[Math.floor(Math.random() * elenaVsBalardStartTaunts.length)] || "(Молчание)";
}
}
return "(Молчание)";
}
const specificTauntBranch = speakerTauntBranch[opponentKeyForTaunts];
if (!specificTauntBranch || !specificTauntBranch[trigger]) {
// console.log(`[TauntLogic] No specific taunt branch or trigger branch for ${speakerCharacterKey} vs ${opponentKeyForTaunts}, trigger: ${trigger}`);
return "(Молчание)";
}
let tauntSet = specificTauntBranch[trigger];
let context = {};
let subTriggerKey = null; // Это будет ключ для прямого доступа к массиву насмешек, например, ID способности или 'start'
if (typeof subTriggerOrContext === 'string' || typeof subTriggerOrContext === 'number') {
subTriggerKey = subTriggerOrContext;
// Если subTriggerOrContext - это ID способности, помещаем его в контекст для onOpponentAction
if (trigger === 'onOpponentAction' || trigger === 'selfCastAbility') {
context.abilityId = subTriggerOrContext;
}
} else if (typeof subTriggerOrContext === 'object' && subTriggerOrContext !== null) {
context = { ...subTriggerOrContext };
// Если ID способности передан в контексте, используем его как subTriggerKey для прямого доступа
if (context.abilityId && (trigger === 'selfCastAbility' || trigger === 'onOpponentAction')) {
subTriggerKey = context.abilityId;
} else if (trigger === 'onBattleState' && typeof context === 'string') { // на случай если GameInstance передает строку для onBattleState
subTriggerKey = context;
}
}
// Для basicAttack subTriggerKey может быть 'merciful', 'dominating' или null (тогда general)
if (trigger === 'basicAttack' && typeof subTriggerOrContext === 'string') {
subTriggerKey = subTriggerOrContext;
}
// console.log(`[TauntLogic DEBUG] Parsed: trigger=${trigger}, subTriggerKey=${subTriggerKey}, context=`, context);
let potentialTaunts = [];
if (subTriggerKey !== null && typeof tauntSet === 'object' && !Array.isArray(tauntSet) && tauntSet[subTriggerKey]) {
// Если есть subTriggerKey и tauntSet - это объект (а не массив), то получаем вложенный набор
tauntSet = tauntSet[subTriggerKey];
} else if (Array.isArray(tauntSet)) {
// Если tauntSet уже массив (например, для onOpponentAttackBlocked), используем его как есть
potentialTaunts = tauntSet; // Присваиваем сразу
} else if (typeof tauntSet === 'object' && tauntSet.general) { // Фоллбэк на general, если subTriggerKey не найден в объекте
tauntSet = tauntSet.general;
}
// Специальная обработка для onOpponentAction с исходом (success/fail)
if (trigger === 'onOpponentAction' && typeof tauntSet === 'object' && !Array.isArray(tauntSet) && context.outcome) {
if (tauntSet[context.outcome]) {
potentialTaunts = tauntSet[context.outcome];
} else {
// console.log(`[TauntLogic] No outcome '${context.outcome}' for onOpponentAction, abilityId ${context.abilityId}`);
potentialTaunts = []; // Явно пустой, чтобы не упасть ниже
}
} else if (Array.isArray(tauntSet)) {
potentialTaunts = tauntSet;
}
// Обработка basicAttack (merciful/dominating/general)
if (trigger === 'basicAttack' && specificTauntBranch.basicAttack) { // Убедимся что ветка basicAttack существует
const basicAttackBranch = specificTauntBranch.basicAttack;
if (speakerCharacterKey === 'elena' && opponentKeyForTaunts === 'balard' && currentGameState && currentGameState[GAME_CONFIG.OPPONENT_ID]) {
const opponentState = currentGameState[GAME_CONFIG.OPPONENT_ID]; // Балард всегда оппонент для Елены в этом контексте
if (opponentState && opponentState.maxHp > 0) {
const opponentHpPerc = (opponentState.currentHp / opponentState.maxHp) * 100;
if (opponentHpPerc <= configToUse.PLAYER_MERCY_TAUNT_THRESHOLD_PERCENT && basicAttackBranch.dominating) {
potentialTaunts = basicAttackBranch.dominating;
} else if (basicAttackBranch.merciful) {
potentialTaunts = basicAttackBranch.merciful;
} else if (basicAttackBranch.general) { // Фоллбэк на general если нет merciful
potentialTaunts = basicAttackBranch.general;
}
} else if (basicAttackBranch.general) { // Если нет HP данных, используем general
potentialTaunts = basicAttackBranch.general;
}
} else if (basicAttackBranch.general) { // Общий случай для basicAttack
potentialTaunts = basicAttackBranch.general;
}
// Если subTriggerKey был ('merciful'/'dominating') и он найден в basicAttackBranch, то tauntSet уже установлен выше
// Этот блок if (trigger === 'basicAttack') должен быть более специфичным или объединен с логикой subTriggerKey выше.
// Пока оставим как есть, предполагая, что subTriggerKey для basicAttack обрабатывается отдельно.
// Если subTriggerKey был 'merciful' или 'dominating', и такой ключ есть в basicAttackBranch, то tauntSet уже должен быть им.
if (subTriggerKey && basicAttackBranch[subTriggerKey]) {
potentialTaunts = basicAttackBranch[subTriggerKey];
} else if (potentialTaunts.length === 0 && basicAttackBranch.general) { // Если не нашли по subTriggerKey, берем general
potentialTaunts = basicAttackBranch.general;
}
}
if (!Array.isArray(potentialTaunts) || potentialTaunts.length === 0) {
// console.log(`[TauntLogic] No potential taunts found or empty array for ${speakerCharacterKey} vs ${opponentKeyForTaunts}, trigger: ${trigger}, subTriggerKey: ${subTriggerKey}`);
return "(Молчание)";
}
const selectedTaunt = potentialTaunts[Math.floor(Math.random() * potentialTaunts.length)];
// console.log(`[TauntLogic] Selected for ${speakerCharacterKey} vs ${opponentKeyForTaunts} (Trigger: ${trigger}, SubTriggerKey: ${subTriggerKey}): "${selectedTaunt}"`);
return selectedTaunt || "(Молчание)";
}
module.exports = {
getRandomTaunt
};