mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add Tier 7 commands: combat and trade
Combat Commands: - /duel - Challenge target to a duel (CMSG_DUEL_PROPOSED 0x166) - /trade - Open trade window with target (CMSG_INITIATE_TRADE 0x116) - /startattack - Begin auto-attacking target - /stopattack - Stop auto-attacking - /stopcasting - Cancel current spell cast New opcodes: - CMSG_DUEL_PROPOSED (0x166) for initiating duels - CMSG_INITIATE_TRADE (0x116) for starting trades Packet builders: - DuelProposedPacket - sends duel challenge to target GUID - InitiateTradePacket - sends trade request to target GUID - AttackSwingPacket, AttackStopPacket, CancelCastPacket reused from existing Game handler methods: - proposeDuel(targetGuid) - challenge target to duel - initiateTrade(targetGuid) - open trade with target - stopCasting() - cancel current spell cast (uses existing casting state) All commands include validation for target selection and world state. Removed duplicate packet class definitions from previous phases.
This commit is contained in:
parent
d5b734a591
commit
bca3f64af6
6 changed files with 201 additions and 38 deletions
|
|
@ -270,6 +270,11 @@ public:
|
|||
void clearMainAssist();
|
||||
void requestRaidInfo();
|
||||
|
||||
// Combat and Trade
|
||||
void proposeDuel(uint64_t targetGuid);
|
||||
void initiateTrade(uint64_t targetGuid);
|
||||
void stopCasting();
|
||||
|
||||
// ---- Phase 1: Name queries ----
|
||||
void queryPlayerName(uint64_t guid);
|
||||
void queryCreatureInfo(uint32_t entry, uint64_t guid);
|
||||
|
|
|
|||
|
|
@ -106,10 +106,14 @@ enum class Opcode : uint16_t {
|
|||
MSG_RAID_READY_CHECK_CONFIRM = 0x3AE,
|
||||
|
||||
// ---- Duel ----
|
||||
CMSG_DUEL_PROPOSED = 0x166,
|
||||
CMSG_DUEL_ACCEPTED = 0x16C,
|
||||
CMSG_DUEL_CANCELLED = 0x16D,
|
||||
SMSG_DUEL_REQUESTED = 0x167,
|
||||
|
||||
// ---- Trade ----
|
||||
CMSG_INITIATE_TRADE = 0x116,
|
||||
|
||||
// ---- Random Roll ----
|
||||
MSG_RANDOM_ROLL = 0x1FB,
|
||||
|
||||
|
|
|
|||
|
|
@ -917,6 +917,40 @@ public:
|
|||
static network::Packet build();
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Combat and Trade
|
||||
// ============================================================
|
||||
|
||||
/** CMSG_DUEL_PROPOSED packet builder */
|
||||
class DuelProposedPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t targetGuid);
|
||||
};
|
||||
|
||||
/** CMSG_INITIATE_TRADE packet builder */
|
||||
class InitiateTradePacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t targetGuid);
|
||||
};
|
||||
|
||||
/** CMSG_ATTACKSWING packet builder */
|
||||
class AttackSwingPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t targetGuid);
|
||||
};
|
||||
|
||||
/** CMSG_ATTACKSTOP packet builder */
|
||||
class AttackStopPacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
/** CMSG_CANCEL_CAST packet builder */
|
||||
class CancelCastPacket {
|
||||
public:
|
||||
static network::Packet build(uint32_t spellId);
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Random Roll
|
||||
// ============================================================
|
||||
|
|
@ -1074,18 +1108,6 @@ public:
|
|||
static bool parse(network::Packet& packet, MonsterMoveData& data);
|
||||
};
|
||||
|
||||
/** CMSG_ATTACKSWING packet builder */
|
||||
class AttackSwingPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t targetGuid);
|
||||
};
|
||||
|
||||
/** CMSG_ATTACKSTOP packet builder */
|
||||
class AttackStopPacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
/** SMSG_ATTACKSTART data */
|
||||
struct AttackStartData {
|
||||
uint64_t attackerGuid = 0;
|
||||
|
|
@ -1223,12 +1245,6 @@ public:
|
|||
static network::Packet build(uint32_t spellId, uint64_t targetGuid, uint8_t castCount);
|
||||
};
|
||||
|
||||
/** CMSG_CANCEL_CAST packet builder */
|
||||
class CancelCastPacket {
|
||||
public:
|
||||
static network::Packet build(uint32_t spellId);
|
||||
};
|
||||
|
||||
/** CMSG_CANCEL_AURA packet builder */
|
||||
class CancelAuraPacket {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -2219,6 +2219,63 @@ void GameHandler::requestRaidInfo() {
|
|||
LOG_INFO("Requested raid info");
|
||||
}
|
||||
|
||||
void GameHandler::proposeDuel(uint64_t targetGuid) {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot propose duel: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetGuid == 0) {
|
||||
addSystemChatMessage("You must target a player to challenge to a duel.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = DuelProposedPacket::build(targetGuid);
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("You have challenged your target to a duel.");
|
||||
LOG_INFO("Proposed duel to target: 0x", std::hex, targetGuid, std::dec);
|
||||
}
|
||||
|
||||
void GameHandler::initiateTrade(uint64_t targetGuid) {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot initiate trade: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetGuid == 0) {
|
||||
addSystemChatMessage("You must target a player to trade with.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = InitiateTradePacket::build(targetGuid);
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("Requesting trade with target.");
|
||||
LOG_INFO("Initiated trade with target: 0x", std::hex, targetGuid, std::dec);
|
||||
}
|
||||
|
||||
void GameHandler::stopCasting() {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot stop casting: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!casting) {
|
||||
return; // Not casting anything
|
||||
}
|
||||
|
||||
// Send cancel cast packet with current spell ID
|
||||
auto packet = CancelCastPacket::build(currentCastSpellId);
|
||||
socket->send(packet);
|
||||
|
||||
// Reset casting state
|
||||
casting = false;
|
||||
currentCastSpellId = 0;
|
||||
castTimeRemaining = 0.0f;
|
||||
castTimeTotal = 0.0f;
|
||||
|
||||
LOG_INFO("Cancelled spell cast");
|
||||
}
|
||||
|
||||
void GameHandler::releaseSpirit() {
|
||||
if (!playerDead_) return;
|
||||
if (socket && state == WorldState::IN_WORLD) {
|
||||
|
|
|
|||
|
|
@ -1452,6 +1452,45 @@ network::Packet RequestRaidInfoPacket::build() {
|
|||
return packet;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Combat and Trade
|
||||
// ============================================================
|
||||
|
||||
network::Packet DuelProposedPacket::build(uint64_t targetGuid) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_DUEL_PROPOSED));
|
||||
packet.writeUInt64(targetGuid);
|
||||
LOG_DEBUG("Built CMSG_DUEL_PROPOSED for target: 0x", std::hex, targetGuid, std::dec);
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet InitiateTradePacket::build(uint64_t targetGuid) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_INITIATE_TRADE));
|
||||
packet.writeUInt64(targetGuid);
|
||||
LOG_DEBUG("Built CMSG_INITIATE_TRADE for target: 0x", std::hex, targetGuid, std::dec);
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet AttackSwingPacket::build(uint64_t targetGuid) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_ATTACKSWING));
|
||||
packet.writeUInt64(targetGuid);
|
||||
LOG_DEBUG("Built CMSG_ATTACKSWING for target: 0x", std::hex, targetGuid, std::dec);
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet AttackStopPacket::build() {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_ATTACKSTOP));
|
||||
LOG_DEBUG("Built CMSG_ATTACKSTOP");
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet CancelCastPacket::build(uint32_t spellId) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_CANCEL_CAST));
|
||||
packet.writeUInt32(0); // cast count/sequence
|
||||
packet.writeUInt32(spellId);
|
||||
LOG_DEBUG("Built CMSG_CANCEL_CAST for spell: ", spellId);
|
||||
return packet;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Random Roll
|
||||
// ============================================================
|
||||
|
|
@ -1777,19 +1816,6 @@ bool MonsterMoveParser::parse(network::Packet& packet, MonsterMoveData& data) {
|
|||
// Phase 2: Combat Core
|
||||
// ============================================================
|
||||
|
||||
network::Packet AttackSwingPacket::build(uint64_t targetGuid) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_ATTACKSWING));
|
||||
packet.writeUInt64(targetGuid);
|
||||
LOG_DEBUG("Built CMSG_ATTACKSWING: target=0x", std::hex, targetGuid, std::dec);
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet AttackStopPacket::build() {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_ATTACKSTOP));
|
||||
LOG_DEBUG("Built CMSG_ATTACKSTOP");
|
||||
return packet;
|
||||
}
|
||||
|
||||
bool AttackStartParser::parse(network::Packet& packet, AttackStartData& data) {
|
||||
if (packet.getSize() < 16) return false;
|
||||
data.attackerGuid = packet.readUInt64();
|
||||
|
|
@ -1971,13 +1997,6 @@ network::Packet CastSpellPacket::build(uint32_t spellId, uint64_t targetGuid, ui
|
|||
return packet;
|
||||
}
|
||||
|
||||
network::Packet CancelCastPacket::build(uint32_t spellId) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_CANCEL_CAST));
|
||||
packet.writeUInt32(0); // sequence
|
||||
packet.writeUInt32(spellId);
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet CancelAuraPacket::build(uint32_t spellId) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_CANCEL_AURA));
|
||||
packet.writeUInt32(spellId);
|
||||
|
|
|
|||
|
|
@ -1398,6 +1398,68 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Combat and Trade commands
|
||||
if (cmdLower == "duel") {
|
||||
if (gameHandler.hasTarget()) {
|
||||
gameHandler.proposeDuel(gameHandler.getTargetGuid());
|
||||
} else if (spacePos != std::string::npos) {
|
||||
// Target player by name (would need name-to-GUID lookup)
|
||||
game::MessageChatData msg;
|
||||
msg.type = game::ChatType::SYSTEM;
|
||||
msg.language = game::ChatLanguage::UNIVERSAL;
|
||||
msg.message = "You must target a player to challenge to a duel.";
|
||||
gameHandler.addLocalChatMessage(msg);
|
||||
} else {
|
||||
game::MessageChatData msg;
|
||||
msg.type = game::ChatType::SYSTEM;
|
||||
msg.language = game::ChatLanguage::UNIVERSAL;
|
||||
msg.message = "You must target a player to challenge to a duel.";
|
||||
gameHandler.addLocalChatMessage(msg);
|
||||
}
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "trade") {
|
||||
if (gameHandler.hasTarget()) {
|
||||
gameHandler.initiateTrade(gameHandler.getTargetGuid());
|
||||
} else {
|
||||
game::MessageChatData msg;
|
||||
msg.type = game::ChatType::SYSTEM;
|
||||
msg.language = game::ChatLanguage::UNIVERSAL;
|
||||
msg.message = "You must target a player to trade with.";
|
||||
gameHandler.addLocalChatMessage(msg);
|
||||
}
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "startattack") {
|
||||
if (gameHandler.hasTarget()) {
|
||||
gameHandler.startAutoAttack(gameHandler.getTargetGuid());
|
||||
} else {
|
||||
game::MessageChatData msg;
|
||||
msg.type = game::ChatType::SYSTEM;
|
||||
msg.language = game::ChatLanguage::UNIVERSAL;
|
||||
msg.message = "You have no target.";
|
||||
gameHandler.addLocalChatMessage(msg);
|
||||
}
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "stopattack") {
|
||||
gameHandler.stopAutoAttack();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdLower == "stopcasting") {
|
||||
gameHandler.stopCasting();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// Chat channel slash commands
|
||||
bool isChannelCommand = false;
|
||||
if (cmdLower == "s" || cmdLower == "say") {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue