Files
OnlineRpg/src/server/BattleRoom.cpp
2025-10-26 21:24:02 +08:00

257 lines
8.0 KiB
C++
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.
#include "server/BattleRoom.h"
#include "server/ClientHandler.h"
#include "common/Protocol.h"
#include "core/Skills.h"
#include <iostream>
#include <sstream>
BattleRoom::BattleRoom(int roomId,
std::shared_ptr<ClientHandler> player1,
std::shared_ptr<ClientHandler> player2,
std::shared_ptr<ICharacter> char1,
std::shared_ptr<ICharacter> 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<std::mutex> 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<std::mutex> 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();
// 获取技能简化版使用skillIndex0=普通攻击)
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<std::string> 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));
}