mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add Tier 3 commands: guild management, PvP, ready check, and duel forfeit
- Guild commands: /ginfo, /groster, /gmotd, /gpromote, /gdemote, /gquit, /ginvite - PvP toggle: /pvp to toggle PvP flag - Ready check system: /readycheck, /ready, /notready for group coordination - Duel forfeit: /yield, /forfeit, /surrender to cancel active duels
This commit is contained in:
parent
acef7ccbec
commit
85a7d66c4e
6 changed files with 492 additions and 0 deletions
|
|
@ -235,6 +235,25 @@ public:
|
|||
void followTarget();
|
||||
void assistTarget();
|
||||
|
||||
// PvP
|
||||
void togglePvp();
|
||||
|
||||
// Guild commands
|
||||
void requestGuildInfo();
|
||||
void requestGuildRoster();
|
||||
void setGuildMotd(const std::string& motd);
|
||||
void promoteGuildMember(const std::string& playerName);
|
||||
void demoteGuildMember(const std::string& playerName);
|
||||
void leaveGuild();
|
||||
void inviteToGuild(const std::string& playerName);
|
||||
|
||||
// Ready check
|
||||
void initiateReadyCheck();
|
||||
void respondToReadyCheck(bool ready);
|
||||
|
||||
// Duel
|
||||
void forfeitDuel();
|
||||
|
||||
// ---- Phase 1: Name queries ----
|
||||
void queryPlayerName(uint64_t guid);
|
||||
void queryCreatureInfo(uint32_t entry, uint64_t guid);
|
||||
|
|
|
|||
|
|
@ -85,6 +85,31 @@ enum class Opcode : uint16_t {
|
|||
CMSG_SHOWING_HELM = 0x2B9,
|
||||
CMSG_SHOWING_CLOAK = 0x2BA,
|
||||
|
||||
// ---- PvP ----
|
||||
CMSG_TOGGLE_PVP = 0x253,
|
||||
|
||||
// ---- Guild ----
|
||||
CMSG_GUILD_INVITE = 0x082,
|
||||
CMSG_GUILD_ACCEPT = 0x084,
|
||||
CMSG_GUILD_DECLINE_INVITATION = 0x085,
|
||||
CMSG_GUILD_INFO = 0x087,
|
||||
CMSG_GUILD_GET_ROSTER = 0x089,
|
||||
CMSG_GUILD_PROMOTE_MEMBER = 0x08B,
|
||||
CMSG_GUILD_DEMOTE_MEMBER = 0x08C,
|
||||
CMSG_GUILD_LEAVE = 0x08D,
|
||||
CMSG_GUILD_MOTD = 0x091,
|
||||
SMSG_GUILD_INFO = 0x088,
|
||||
SMSG_GUILD_ROSTER = 0x08A,
|
||||
|
||||
// ---- Ready Check ----
|
||||
MSG_RAID_READY_CHECK = 0x322,
|
||||
MSG_RAID_READY_CHECK_CONFIRM = 0x3AE,
|
||||
|
||||
// ---- Duel ----
|
||||
CMSG_DUEL_ACCEPTED = 0x16C,
|
||||
CMSG_DUEL_CANCELLED = 0x16D,
|
||||
SMSG_DUEL_REQUESTED = 0x167,
|
||||
|
||||
// ---- Random Roll ----
|
||||
MSG_RANDOM_ROLL = 0x1FB,
|
||||
|
||||
|
|
|
|||
|
|
@ -802,6 +802,88 @@ public:
|
|||
static network::Packet build(bool show);
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// PvP
|
||||
// ============================================================
|
||||
|
||||
/** CMSG_TOGGLE_PVP packet builder */
|
||||
class TogglePvpPacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Guild Commands
|
||||
// ============================================================
|
||||
|
||||
/** CMSG_GUILD_INFO packet builder */
|
||||
class GuildInfoPacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_GET_ROSTER packet builder */
|
||||
class GuildRosterPacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_MOTD packet builder */
|
||||
class GuildMotdPacket {
|
||||
public:
|
||||
static network::Packet build(const std::string& motd);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_PROMOTE_MEMBER packet builder */
|
||||
class GuildPromotePacket {
|
||||
public:
|
||||
static network::Packet build(const std::string& playerName);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_DEMOTE_MEMBER packet builder */
|
||||
class GuildDemotePacket {
|
||||
public:
|
||||
static network::Packet build(const std::string& playerName);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_LEAVE packet builder */
|
||||
class GuildLeavePacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_INVITE packet builder */
|
||||
class GuildInvitePacket {
|
||||
public:
|
||||
static network::Packet build(const std::string& playerName);
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Ready Check
|
||||
// ============================================================
|
||||
|
||||
/** MSG_RAID_READY_CHECK packet builder */
|
||||
class ReadyCheckPacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
/** MSG_RAID_READY_CHECK_CONFIRM packet builder */
|
||||
class ReadyCheckConfirmPacket {
|
||||
public:
|
||||
static network::Packet build(bool ready);
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Duel
|
||||
// ============================================================
|
||||
|
||||
/** CMSG_DUEL_CANCELLED packet builder */
|
||||
class DuelCancelPacket {
|
||||
public:
|
||||
static network::Packet build();
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Random Roll
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -1893,6 +1893,157 @@ void GameHandler::assistTarget() {
|
|||
LOG_INFO("Assisting ", targetName, ", now targeting GUID: 0x", std::hex, assistTargetGuid, std::dec);
|
||||
}
|
||||
|
||||
void GameHandler::togglePvp() {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot toggle PvP: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = TogglePvpPacket::build();
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("PvP flag toggled.");
|
||||
LOG_INFO("Toggled PvP flag");
|
||||
}
|
||||
|
||||
void GameHandler::requestGuildInfo() {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot request guild info: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = GuildInfoPacket::build();
|
||||
socket->send(packet);
|
||||
LOG_INFO("Requested guild info");
|
||||
}
|
||||
|
||||
void GameHandler::requestGuildRoster() {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot request guild roster: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = GuildRosterPacket::build();
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("Requesting guild roster...");
|
||||
LOG_INFO("Requested guild roster");
|
||||
}
|
||||
|
||||
void GameHandler::setGuildMotd(const std::string& motd) {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot set guild MOTD: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = GuildMotdPacket::build(motd);
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("Guild MOTD updated.");
|
||||
LOG_INFO("Set guild MOTD: ", motd);
|
||||
}
|
||||
|
||||
void GameHandler::promoteGuildMember(const std::string& playerName) {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot promote guild member: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerName.empty()) {
|
||||
addSystemChatMessage("You must specify a player name.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = GuildPromotePacket::build(playerName);
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("Promoting " + playerName + "...");
|
||||
LOG_INFO("Promoting guild member: ", playerName);
|
||||
}
|
||||
|
||||
void GameHandler::demoteGuildMember(const std::string& playerName) {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot demote guild member: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerName.empty()) {
|
||||
addSystemChatMessage("You must specify a player name.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = GuildDemotePacket::build(playerName);
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("Demoting " + playerName + "...");
|
||||
LOG_INFO("Demoting guild member: ", playerName);
|
||||
}
|
||||
|
||||
void GameHandler::leaveGuild() {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot leave guild: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = GuildLeavePacket::build();
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("Leaving guild...");
|
||||
LOG_INFO("Leaving guild");
|
||||
}
|
||||
|
||||
void GameHandler::inviteToGuild(const std::string& playerName) {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot invite to guild: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerName.empty()) {
|
||||
addSystemChatMessage("You must specify a player name.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = GuildInvitePacket::build(playerName);
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("Inviting " + playerName + " to guild...");
|
||||
LOG_INFO("Inviting to guild: ", playerName);
|
||||
}
|
||||
|
||||
void GameHandler::initiateReadyCheck() {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot initiate ready check: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isInGroup()) {
|
||||
addSystemChatMessage("You must be in a group to initiate a ready check.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = ReadyCheckPacket::build();
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("Ready check initiated.");
|
||||
LOG_INFO("Initiated ready check");
|
||||
}
|
||||
|
||||
void GameHandler::respondToReadyCheck(bool ready) {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot respond to ready check: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = ReadyCheckConfirmPacket::build(ready);
|
||||
socket->send(packet);
|
||||
addSystemChatMessage(ready ? "You are ready." : "You are not ready.");
|
||||
LOG_INFO("Responded to ready check: ", ready ? "ready" : "not ready");
|
||||
}
|
||||
|
||||
void GameHandler::forfeitDuel() {
|
||||
if (state != WorldState::IN_WORLD || !socket) {
|
||||
LOG_WARNING("Cannot forfeit duel: not in world or not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
auto packet = DuelCancelPacket::build();
|
||||
socket->send(packet);
|
||||
addSystemChatMessage("You have forfeited the duel.");
|
||||
LOG_INFO("Forfeited duel");
|
||||
}
|
||||
|
||||
void GameHandler::releaseSpirit() {
|
||||
if (!playerDead_) return;
|
||||
if (socket && state == WorldState::IN_WORLD) {
|
||||
|
|
|
|||
|
|
@ -1334,6 +1334,93 @@ network::Packet ShowingCloakPacket::build(bool show) {
|
|||
return packet;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PvP
|
||||
// ============================================================
|
||||
|
||||
network::Packet TogglePvpPacket::build() {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_TOGGLE_PVP));
|
||||
LOG_DEBUG("Built CMSG_TOGGLE_PVP");
|
||||
return packet;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Guild Commands
|
||||
// ============================================================
|
||||
|
||||
network::Packet GuildInfoPacket::build() {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_GUILD_INFO));
|
||||
LOG_DEBUG("Built CMSG_GUILD_INFO");
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet GuildRosterPacket::build() {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_GUILD_GET_ROSTER));
|
||||
LOG_DEBUG("Built CMSG_GUILD_GET_ROSTER");
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet GuildMotdPacket::build(const std::string& motd) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_GUILD_MOTD));
|
||||
packet.writeString(motd);
|
||||
LOG_DEBUG("Built CMSG_GUILD_MOTD: ", motd);
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet GuildPromotePacket::build(const std::string& playerName) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_GUILD_PROMOTE_MEMBER));
|
||||
packet.writeString(playerName);
|
||||
LOG_DEBUG("Built CMSG_GUILD_PROMOTE_MEMBER: ", playerName);
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet GuildDemotePacket::build(const std::string& playerName) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_GUILD_DEMOTE_MEMBER));
|
||||
packet.writeString(playerName);
|
||||
LOG_DEBUG("Built CMSG_GUILD_DEMOTE_MEMBER: ", playerName);
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet GuildLeavePacket::build() {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_GUILD_LEAVE));
|
||||
LOG_DEBUG("Built CMSG_GUILD_LEAVE");
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet GuildInvitePacket::build(const std::string& playerName) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_GUILD_INVITE));
|
||||
packet.writeString(playerName);
|
||||
LOG_DEBUG("Built CMSG_GUILD_INVITE: ", playerName);
|
||||
return packet;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Ready Check
|
||||
// ============================================================
|
||||
|
||||
network::Packet ReadyCheckPacket::build() {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::MSG_RAID_READY_CHECK));
|
||||
LOG_DEBUG("Built MSG_RAID_READY_CHECK");
|
||||
return packet;
|
||||
}
|
||||
|
||||
network::Packet ReadyCheckConfirmPacket::build(bool ready) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::MSG_RAID_READY_CHECK_CONFIRM));
|
||||
packet.writeUInt8(ready ? 1 : 0);
|
||||
LOG_DEBUG("Built MSG_RAID_READY_CHECK_CONFIRM: ready=", ready);
|
||||
return packet;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Duel
|
||||
// ============================================================
|
||||
|
||||
network::Packet DuelCancelPacket::build() {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_DUEL_CANCELLED));
|
||||
LOG_DEBUG("Built CMSG_DUEL_CANCELLED");
|
||||
return packet;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Random Roll
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -1178,6 +1178,134 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) {
|
|||
return;
|
||||
}
|
||||
|
||||
// /pvp command
|
||||
if (cmdLower == "pvp") {
|
||||
gameHandler.togglePvp();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /ginfo command
|
||||
if (cmdLower == "ginfo" || cmdLower == "guildinfo") {
|
||||
gameHandler.requestGuildInfo();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /groster command
|
||||
if (cmdLower == "groster" || cmdLower == "guildroster") {
|
||||
gameHandler.requestGuildRoster();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /gmotd command
|
||||
if (cmdLower == "gmotd" || cmdLower == "guildmotd") {
|
||||
if (spacePos != std::string::npos) {
|
||||
std::string motd = command.substr(spacePos + 1);
|
||||
gameHandler.setGuildMotd(motd);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
game::MessageChatData msg;
|
||||
msg.type = game::ChatType::SYSTEM;
|
||||
msg.language = game::ChatLanguage::UNIVERSAL;
|
||||
msg.message = "Usage: /gmotd <message>";
|
||||
gameHandler.addLocalChatMessage(msg);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /gpromote command
|
||||
if (cmdLower == "gpromote" || cmdLower == "guildpromote") {
|
||||
if (spacePos != std::string::npos) {
|
||||
std::string playerName = command.substr(spacePos + 1);
|
||||
gameHandler.promoteGuildMember(playerName);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
game::MessageChatData msg;
|
||||
msg.type = game::ChatType::SYSTEM;
|
||||
msg.language = game::ChatLanguage::UNIVERSAL;
|
||||
msg.message = "Usage: /gpromote <player>";
|
||||
gameHandler.addLocalChatMessage(msg);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /gdemote command
|
||||
if (cmdLower == "gdemote" || cmdLower == "guilddemote") {
|
||||
if (spacePos != std::string::npos) {
|
||||
std::string playerName = command.substr(spacePos + 1);
|
||||
gameHandler.demoteGuildMember(playerName);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
game::MessageChatData msg;
|
||||
msg.type = game::ChatType::SYSTEM;
|
||||
msg.language = game::ChatLanguage::UNIVERSAL;
|
||||
msg.message = "Usage: /gdemote <player>";
|
||||
gameHandler.addLocalChatMessage(msg);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /gquit command
|
||||
if (cmdLower == "gquit" || cmdLower == "guildquit" || cmdLower == "leaveguild") {
|
||||
gameHandler.leaveGuild();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /ginvite command
|
||||
if (cmdLower == "ginvite" || cmdLower == "guildinvite") {
|
||||
if (spacePos != std::string::npos) {
|
||||
std::string playerName = command.substr(spacePos + 1);
|
||||
gameHandler.inviteToGuild(playerName);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
game::MessageChatData msg;
|
||||
msg.type = game::ChatType::SYSTEM;
|
||||
msg.language = game::ChatLanguage::UNIVERSAL;
|
||||
msg.message = "Usage: /ginvite <player>";
|
||||
gameHandler.addLocalChatMessage(msg);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /readycheck command
|
||||
if (cmdLower == "readycheck" || cmdLower == "rc") {
|
||||
gameHandler.initiateReadyCheck();
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /ready command (respond yes to ready check)
|
||||
if (cmdLower == "ready") {
|
||||
gameHandler.respondToReadyCheck(true);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /notready command (respond no to ready check)
|
||||
if (cmdLower == "notready" || cmdLower == "nr") {
|
||||
gameHandler.respondToReadyCheck(false);
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /yield or /forfeit command
|
||||
if (cmdLower == "yield" || cmdLower == "forfeit" || cmdLower == "surrender") {
|
||||
gameHandler.forfeitDuel();
|
||||
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