#include "server/BattleRoom.h" #include "server/ClientHandler.h" #include "common/Protocol.h" #include "core/Skills.h" #include #include BattleRoom::BattleRoom(int roomId, std::shared_ptr player1, std::shared_ptr player2, std::shared_ptr char1, std::shared_ptr char2) : m_roomId(roomId), m_player1(player1), m_player2(player2), m_char1(char1), m_char2(char2), m_isRunning(false), m_currentTurn(0), m_turnCount(0) { } BattleRoom::~BattleRoom() { if (m_isRunning) { endBattle(); } } void BattleRoom::start() { std::lock_guard lock(m_mutex); if (m_isRunning) { return; } m_isRunning = true; m_turnCount = 0; // 根据速度决定谁先手 m_currentTurn = (m_char1->getSpeed() >= m_char2->getSpeed()) ? 0 : 1; // 发送战斗开始消息 std::string startLog = "战斗开始:" + m_char1->getName() + " vs " + m_char2->getName(); addLog(startLog); // 通知双方战斗开始 std::string msg1 = Protocol::buildMessage(Protocol::S2C_BATTLE_START, {m_char2->getName(), "Mage"}); // 简化:对手信息 std::string msg2 = Protocol::buildMessage(Protocol::S2C_BATTLE_START, {m_char1->getName(), "Warrior"}); sendToPlayer1(msg1); sendToPlayer2(msg2); // 发送初始回合通知 notifyTurn(); sendBattleStatus(); std::cout << "战斗 " << m_roomId << " 已开始:" << startLog << std::endl; } bool BattleRoom::handleAction(const std::string& username, int skillIndex, const std::string& targetName) { std::lock_guard lock(m_mutex); std::cout << "[DEBUG] handleAction called: user=" << username << " skillIndex=" << skillIndex << " target=" << targetName << std::endl; if (!m_isRunning) { std::cout << "[DEBUG] Battle not running!" << std::endl; return false; } // 检查是否轮到该玩家 if (!isPlayerTurn(username)) { std::cout << "[DEBUG] Not player's turn! Current turn: " << m_currentTurn << std::endl; return false; } std::cout << "[DEBUG] Executing action..." << std::endl; // 确定攻击者和防守者 ICharacter* attacker = (m_currentTurn == 0) ? m_char1.get() : m_char2.get(); ICharacter* defender = (m_currentTurn == 0) ? m_char2.get() : m_char1.get(); // 获取技能(简化版:使用skillIndex,0=普通攻击) ISkill* skill = nullptr; if (skillIndex == 0) { skill = attacker->getSkill("NormalAttack"); } else if (skillIndex == 1) { // 获取第二个技能 skill = (m_currentTurn == 0) ? (m_char1->getSkill("HeavyStrike") ? m_char1->getSkill("HeavyStrike") : m_char1->getSkill("Fireball")) : (m_char2->getSkill("HeavyStrike") ? m_char2->getSkill("HeavyStrike") : m_char2->getSkill("Fireball")); } if (!skill) { std::cerr << "[ERROR] Skill not found for skillIndex " << skillIndex << " for character " << attacker->getName() << ". Falling back to NormalAttack." << std::endl; skill = attacker->getSkill("NormalAttack"); } // 最终检查,如果连普通攻击都没有,就无法继续 if (!skill) { std::cerr << "[FATAL] Critical error: NormalAttack skill is missing for character " << attacker->getName() << ". Cannot proceed with action." << std::endl; // 在这种严重错误下,也许应该结束战斗或通知玩家 broadcastToBoth(Protocol::buildBattleLog("错误:攻击失败,找不到技能!")); return false; // 提前退出,防止崩溃 } // 执行技能 int defenderHpBefore = defender->getHp(); skill->execute(*attacker, *defender); int defenderHpAfter = defender->getHp(); int damage = defenderHpBefore - defenderHpAfter; // 记录战斗日志 std::ostringstream logStream; logStream << attacker->getName() << " 使用 " << skill->getName() << " 攻击 " << defender->getName() << ",造成 " << damage << " 点伤害!"; std::string actionLog = logStream.str(); addLog(actionLog); // 广播战斗日志 broadcastToBoth(Protocol::buildBattleLog(actionLog)); // 发送状态更新 sendBattleStatus(); // 检查战斗是否结束 if (isFinished()) { endBattle(); return true; } // 切换回合 m_currentTurn = (m_currentTurn == 0) ? 1 : 0; m_turnCount++; // 通知下一回合 notifyTurn(); return true; } bool BattleRoom::isFinished() const { return !m_char1->isAlive() || !m_char2->isAlive() || m_turnCount >= 50; } std::string BattleRoom::getWinner() const { if (m_char1->isAlive() && !m_char2->isAlive()) { return m_char1->getName(); } else if (m_char2->isAlive() && !m_char1->isAlive()) { return m_char2->getName(); } return ""; // 平局或未结束 } std::vector BattleRoom::getBattleLog() const { return m_historyLog.getAllEntries(); } bool BattleRoom::isPlayerTurn(const std::string& username) const { if (m_currentTurn == 0) { return username == m_player1->getUsername(); } else { return username == m_player2->getUsername(); } } void BattleRoom::executeTurn() { // 这个方法在简化版本中不使用,由handleAction处理 } void BattleRoom::broadcastToBoth(const std::string& message) { sendToPlayer1(message); sendToPlayer2(message); } void BattleRoom::sendToPlayer1(const std::string& message) { if (m_player1) { m_player1->sendMessage(message); } } void BattleRoom::sendToPlayer2(const std::string& message) { if (m_player2) { m_player2->sendMessage(message); } } void BattleRoom::addLog(const std::string& log) { m_historyLog.add(log); } void BattleRoom::endBattle() { if (!m_isRunning) { return; } m_isRunning = false; std::string winner = getWinner(); std::string endLog; if (!winner.empty()) { endLog = winner + " 获胜!"; // 通知胜负 if (winner == m_player1->getUsername()) { sendToPlayer1(Protocol::buildMessage(Protocol::S2C_BATTLE_END, {"WIN"})); sendToPlayer2(Protocol::buildMessage(Protocol::S2C_BATTLE_END, {"LOSE"})); } else { sendToPlayer1(Protocol::buildMessage(Protocol::S2C_BATTLE_END, {"LOSE"})); sendToPlayer2(Protocol::buildMessage(Protocol::S2C_BATTLE_END, {"WIN"})); } } else { endLog = "战斗以平局结束!"; broadcastToBoth(Protocol::buildMessage(Protocol::S2C_BATTLE_END, {"DRAW"})); } addLog(endLog); broadcastToBoth(Protocol::buildBattleLog(endLog)); // 重置玩家状态 m_player1->setState(ClientState::Lobby); m_player1->setBattleRoomId(-1); m_player2->setState(ClientState::Lobby); m_player2->setBattleRoomId(-1); std::cout << "战斗 " << m_roomId << " 已结束:" << endLog << std::endl; } void BattleRoom::notifyTurn() { if (m_currentTurn == 0) { sendToPlayer1(Protocol::buildMessage(Protocol::S2C_BATTLE_TURN, {"YOUR_TURN"})); sendToPlayer2(Protocol::buildMessage(Protocol::S2C_BATTLE_TURN, {"OPP_TURN"})); } else { sendToPlayer1(Protocol::buildMessage(Protocol::S2C_BATTLE_TURN, {"OPP_TURN"})); sendToPlayer2(Protocol::buildMessage(Protocol::S2C_BATTLE_TURN, {"YOUR_TURN"})); } } void BattleRoom::sendBattleStatus() { std::ostringstream status; status << m_char1->getName() << " HP:" << m_char1->getHp() << " | " << m_char2->getName() << " HP:" << m_char2->getHp(); std::string statusMsg = status.str(); addLog(statusMsg); broadcastToBoth(Protocol::buildBattleLog(statusMsg)); }