diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index b1d732ef..fc592b4e 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -746,6 +746,8 @@ public: } // Send CMSG_PET_ACTION to issue a pet command void sendPetAction(uint32_t action, uint64_t targetGuid = 0); + // Toggle autocast for a pet spell via CMSG_PET_SPELL_AUTOCAST + void togglePetSpellAutocast(uint32_t spellId); const std::unordered_set& getKnownSpells() const { return knownSpells; } // ---- Pet Stable ---- diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index f0456c5e..915de132 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -18291,6 +18291,24 @@ void GameHandler::dismissPet() { socket->send(packet); } +void GameHandler::togglePetSpellAutocast(uint32_t spellId) { + if (petGuid_ == 0 || spellId == 0 || state != WorldState::IN_WORLD || !socket) return; + bool currentlyOn = petAutocastSpells_.count(spellId) != 0; + uint8_t newState = currentlyOn ? 0 : 1; + // CMSG_PET_SPELL_AUTOCAST: petGuid(8) + spellId(4) + state(1) + network::Packet pkt(wireOpcode(Opcode::CMSG_PET_SPELL_AUTOCAST)); + pkt.writeUInt64(petGuid_); + pkt.writeUInt32(spellId); + pkt.writeUInt8(newState); + socket->send(pkt); + // Optimistically update local state; server will confirm via SMSG_PET_SPELLS + if (newState) + petAutocastSpells_.insert(spellId); + else + petAutocastSpells_.erase(spellId); + LOG_DEBUG("togglePetSpellAutocast: spellId=", spellId, " autocast=", (int)newState); +} + void GameHandler::renamePet(const std::string& newName) { if (petGuid_ == 0 || state != WorldState::IN_WORLD || !socket) return; if (newName.empty() || newName.size() > 12) return; // Server enforces max 12 chars diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index b81405cc..0e1dcf1e 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -3899,6 +3899,10 @@ void GameScreen::renderPetFrame(game::GameHandler& gameHandler) { uint64_t targetGuid = (actionId > 5) ? gameHandler.getTargetGuid() : 0u; gameHandler.sendPetAction(slotVal, targetGuid); } + // Right-click toggles autocast for castable pet spells (actionId > 6) + if (actionId > 6 && ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + gameHandler.togglePetSpellAutocast(actionId); + } // Tooltip: rich spell info for pet spells, simple label for built-in commands if (ImGui::IsItemHovered()) { @@ -3920,8 +3924,10 @@ void GameScreen::renderPetFrame(game::GameHandler& gameHandler) { if (nm.empty()) nm = "Spell #" + std::to_string(actionId); ImGui::Text("%s", nm.c_str()); } - if (autocastOn) - ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "Autocast: On"); + ImGui::TextColored(autocastOn + ? ImVec4(0.4f, 1.0f, 0.4f, 1.0f) + : ImVec4(0.6f, 0.6f, 0.6f, 1.0f), + "Autocast: %s (right-click to toggle)", autocastOn ? "On" : "Off"); if (petOnCd) { if (petCd >= 60.0f) ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),