mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add Tier 2 utility commands: helm/cloak toggles, follow, and assist
Display Toggle Commands: - Add /helm, /helmet, /showhelm to toggle helm visibility - Add /cloak, /showcloak to toggle cloak visibility - Track visibility state with helmVisible_ and cloakVisible_ flags - Show confirmation messages: "Helm/Cloak is now visible/hidden" - Use CMSG_SHOWING_HELM (0x2B9) and CMSG_SHOWING_CLOAK (0x2BA) Follow Command: - Add /follow and /f to follow current target - Works with both players and NPCs - Show "Now following [Name]" confirmation message - Track follow target with followTargetGuid_ for future movement logic Assist Command: - Add /assist to target what your current target is targeting - Read target's target from UNIT_FIELD_TARGET update fields (offset 6-7) - Reconstruct 64-bit target GUID from two 32-bit field values - Automatically switch your target to assist target - Show helpful messages: "[Name] has no target" when appropriate - Essential for combat coordination in groups Implementation: - Add ShowingHelmPacket and ShowingCloakPacket builders - Add toggleHelm() and toggleCloak() methods with state management - Add followTarget() for setting follow target - Add assistTarget() with smart target field reading - Use Entity::getFields() to access protected update fields - Handle missing targets and invalid states gracefully - All commands provide chat feedback - Support multiple aliases for user convenience
This commit is contained in:
parent
ec32286b0d
commit
acef7ccbec
6 changed files with 198 additions and 0 deletions
|
|
@ -227,6 +227,14 @@ public:
|
||||||
// Stand state
|
// Stand state
|
||||||
void setStandState(uint8_t state); // 0=stand, 1=sit, 2=sit_chair, 3=sleep, 4=sit_low_chair, 5=sit_medium_chair, 6=sit_high_chair, 7=dead, 8=kneel, 9=submerged
|
void setStandState(uint8_t state); // 0=stand, 1=sit, 2=sit_chair, 3=sleep, 4=sit_low_chair, 5=sit_medium_chair, 6=sit_high_chair, 7=dead, 8=kneel, 9=submerged
|
||||||
|
|
||||||
|
// Display toggles
|
||||||
|
void toggleHelm();
|
||||||
|
void toggleCloak();
|
||||||
|
|
||||||
|
// Follow/Assist
|
||||||
|
void followTarget();
|
||||||
|
void assistTarget();
|
||||||
|
|
||||||
// ---- Phase 1: Name queries ----
|
// ---- Phase 1: Name queries ----
|
||||||
void queryPlayerName(uint64_t guid);
|
void queryPlayerName(uint64_t guid);
|
||||||
void queryCreatureInfo(uint32_t entry, uint64_t guid);
|
void queryCreatureInfo(uint32_t entry, uint64_t guid);
|
||||||
|
|
@ -626,6 +634,13 @@ private:
|
||||||
// ---- Logout state ----
|
// ---- Logout state ----
|
||||||
bool loggingOut_ = false;
|
bool loggingOut_ = false;
|
||||||
|
|
||||||
|
// ---- Display state ----
|
||||||
|
bool helmVisible_ = true;
|
||||||
|
bool cloakVisible_ = true;
|
||||||
|
|
||||||
|
// ---- Follow state ----
|
||||||
|
uint64_t followTargetGuid_ = 0;
|
||||||
|
|
||||||
// ---- Online item tracking ----
|
// ---- Online item tracking ----
|
||||||
struct OnlineItemInfo {
|
struct OnlineItemInfo {
|
||||||
uint32_t entry = 0;
|
uint32_t entry = 0;
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,10 @@ enum class Opcode : uint16_t {
|
||||||
// ---- Stand State ----
|
// ---- Stand State ----
|
||||||
CMSG_STAND_STATE_CHANGE = 0x101,
|
CMSG_STAND_STATE_CHANGE = 0x101,
|
||||||
|
|
||||||
|
// ---- Display Toggles ----
|
||||||
|
CMSG_SHOWING_HELM = 0x2B9,
|
||||||
|
CMSG_SHOWING_CLOAK = 0x2BA,
|
||||||
|
|
||||||
// ---- Random Roll ----
|
// ---- Random Roll ----
|
||||||
MSG_RANDOM_ROLL = 0x1FB,
|
MSG_RANDOM_ROLL = 0x1FB,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -786,6 +786,22 @@ public:
|
||||||
static network::Packet build(uint8_t state);
|
static network::Packet build(uint8_t state);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Display Toggles
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
/** CMSG_SHOWING_HELM packet builder */
|
||||||
|
class ShowingHelmPacket {
|
||||||
|
public:
|
||||||
|
static network::Packet build(bool show);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** CMSG_SHOWING_CLOAK packet builder */
|
||||||
|
class ShowingCloakPacket {
|
||||||
|
public:
|
||||||
|
static network::Packet build(bool show);
|
||||||
|
};
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Random Roll
|
// Random Roll
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -1776,6 +1776,123 @@ void GameHandler::setStandState(uint8_t standState) {
|
||||||
LOG_INFO("Changed stand state to: ", (int)standState);
|
LOG_INFO("Changed stand state to: ", (int)standState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameHandler::toggleHelm() {
|
||||||
|
if (state != WorldState::IN_WORLD || !socket) {
|
||||||
|
LOG_WARNING("Cannot toggle helm: not in world or not connected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
helmVisible_ = !helmVisible_;
|
||||||
|
auto packet = ShowingHelmPacket::build(helmVisible_);
|
||||||
|
socket->send(packet);
|
||||||
|
addSystemChatMessage(helmVisible_ ? "Helm is now visible." : "Helm is now hidden.");
|
||||||
|
LOG_INFO("Helm visibility toggled: ", helmVisible_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameHandler::toggleCloak() {
|
||||||
|
if (state != WorldState::IN_WORLD || !socket) {
|
||||||
|
LOG_WARNING("Cannot toggle cloak: not in world or not connected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cloakVisible_ = !cloakVisible_;
|
||||||
|
auto packet = ShowingCloakPacket::build(cloakVisible_);
|
||||||
|
socket->send(packet);
|
||||||
|
addSystemChatMessage(cloakVisible_ ? "Cloak is now visible." : "Cloak is now hidden.");
|
||||||
|
LOG_INFO("Cloak visibility toggled: ", cloakVisible_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameHandler::followTarget() {
|
||||||
|
if (state != WorldState::IN_WORLD) {
|
||||||
|
LOG_WARNING("Cannot follow: not in world");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetGuid == 0) {
|
||||||
|
addSystemChatMessage("You must target someone to follow.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto target = getTarget();
|
||||||
|
if (!target) {
|
||||||
|
addSystemChatMessage("Invalid target.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set follow target
|
||||||
|
followTargetGuid_ = targetGuid;
|
||||||
|
|
||||||
|
// Get target name
|
||||||
|
std::string targetName = "Target";
|
||||||
|
if (target->getType() == ObjectType::PLAYER) {
|
||||||
|
auto player = std::static_pointer_cast<Player>(target);
|
||||||
|
if (!player->getName().empty()) {
|
||||||
|
targetName = player->getName();
|
||||||
|
}
|
||||||
|
} else if (target->getType() == ObjectType::UNIT) {
|
||||||
|
auto unit = std::static_pointer_cast<Unit>(target);
|
||||||
|
targetName = unit->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
addSystemChatMessage("Now following " + targetName + ".");
|
||||||
|
LOG_INFO("Following target: ", targetName, " (GUID: 0x", std::hex, targetGuid, std::dec, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameHandler::assistTarget() {
|
||||||
|
if (state != WorldState::IN_WORLD) {
|
||||||
|
LOG_WARNING("Cannot assist: not in world");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetGuid == 0) {
|
||||||
|
addSystemChatMessage("You must target someone to assist.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto target = getTarget();
|
||||||
|
if (!target) {
|
||||||
|
addSystemChatMessage("Invalid target.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get target name
|
||||||
|
std::string targetName = "Target";
|
||||||
|
if (target->getType() == ObjectType::PLAYER) {
|
||||||
|
auto player = std::static_pointer_cast<Player>(target);
|
||||||
|
if (!player->getName().empty()) {
|
||||||
|
targetName = player->getName();
|
||||||
|
}
|
||||||
|
} else if (target->getType() == ObjectType::UNIT) {
|
||||||
|
auto unit = std::static_pointer_cast<Unit>(target);
|
||||||
|
targetName = unit->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read target GUID from update fields (UNIT_FIELD_TARGET)
|
||||||
|
// Field offset 6 is typically UNIT_FIELD_TARGET in 3.3.5a
|
||||||
|
uint64_t assistTargetGuid = 0;
|
||||||
|
const auto& fields = target->getFields();
|
||||||
|
auto it = fields.find(6);
|
||||||
|
if (it != fields.end()) {
|
||||||
|
// Low 32 bits
|
||||||
|
assistTargetGuid = it->second;
|
||||||
|
// Try to get high 32 bits from next field
|
||||||
|
auto it2 = fields.find(7);
|
||||||
|
if (it2 != fields.end()) {
|
||||||
|
assistTargetGuid |= (static_cast<uint64_t>(it2->second) << 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assistTargetGuid == 0) {
|
||||||
|
addSystemChatMessage(targetName + " has no target.");
|
||||||
|
LOG_INFO("Assist: ", targetName, " has no target");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set our target to their target
|
||||||
|
setTarget(assistTargetGuid);
|
||||||
|
LOG_INFO("Assisting ", targetName, ", now targeting GUID: 0x", std::hex, assistTargetGuid, std::dec);
|
||||||
|
}
|
||||||
|
|
||||||
void GameHandler::releaseSpirit() {
|
void GameHandler::releaseSpirit() {
|
||||||
if (!playerDead_) return;
|
if (!playerDead_) return;
|
||||||
if (socket && state == WorldState::IN_WORLD) {
|
if (socket && state == WorldState::IN_WORLD) {
|
||||||
|
|
|
||||||
|
|
@ -1316,6 +1316,24 @@ network::Packet StandStateChangePacket::build(uint8_t state) {
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Display Toggles
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
network::Packet ShowingHelmPacket::build(bool show) {
|
||||||
|
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_SHOWING_HELM));
|
||||||
|
packet.writeUInt8(show ? 1 : 0);
|
||||||
|
LOG_DEBUG("Built CMSG_SHOWING_HELM: show=", show);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
network::Packet ShowingCloakPacket::build(bool show) {
|
||||||
|
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_SHOWING_CLOAK));
|
||||||
|
packet.writeUInt8(show ? 1 : 0);
|
||||||
|
LOG_DEBUG("Built CMSG_SHOWING_CLOAK: show=", show);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Random Roll
|
// Random Roll
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -1150,6 +1150,34 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /helm command
|
||||||
|
if (cmdLower == "helm" || cmdLower == "helmet" || cmdLower == "showhelm") {
|
||||||
|
gameHandler.toggleHelm();
|
||||||
|
chatInputBuffer[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /cloak command
|
||||||
|
if (cmdLower == "cloak" || cmdLower == "showcloak") {
|
||||||
|
gameHandler.toggleCloak();
|
||||||
|
chatInputBuffer[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /follow command
|
||||||
|
if (cmdLower == "follow" || cmdLower == "f") {
|
||||||
|
gameHandler.followTarget();
|
||||||
|
chatInputBuffer[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /assist command
|
||||||
|
if (cmdLower == "assist") {
|
||||||
|
gameHandler.assistTarget();
|
||||||
|
chatInputBuffer[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Chat channel slash commands
|
// Chat channel slash commands
|
||||||
bool isChannelCommand = false;
|
bool isChannelCommand = false;
|
||||||
if (cmdLower == "s" || cmdLower == "say") {
|
if (cmdLower == "s" || cmdLower == "say") {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue