diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 2fe0dcec..e8c22327 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -609,6 +609,7 @@ public: void cancelCast(); void cancelAura(uint32_t spellId); void dismissPet(); + void renamePet(const std::string& newName); bool hasPet() const { return petGuid_ != 0; } uint64_t getPetGuid() const { return petGuid_; } diff --git a/include/game/world_packets.hpp b/include/game/world_packets.hpp index 2bb89907..71be1501 100644 --- a/include/game/world_packets.hpp +++ b/include/game/world_packets.hpp @@ -2718,5 +2718,14 @@ public: static network::Packet build(uint64_t stableMasterGuid, uint32_t petNumber); }; +class PetRenamePacket { +public: + /** CMSG_PET_RENAME: rename the player's active pet. + * petGuid: the pet's object GUID (from GameHandler::getPetGuid()) + * name: new name (max 12 chars; server validates and may reject) + * isDeclined: 0 for non-Cyrillic locales (no declined name forms) */ + static network::Packet build(uint64_t petGuid, const std::string& name, uint8_t isDeclined = 0); +}; + } // namespace game } // namespace wowee diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index 69e0ff44..56e133cd 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -434,6 +434,10 @@ private: char gmTicketBuf_[2048] = {}; void renderGmTicketWindow(game::GameHandler& gameHandler); + // Pet rename modal (triggered from pet frame context menu) + bool petRenameOpen_ = false; + char petRenameBuf_[16] = {}; + // Inspect window bool showInspectWindow_ = false; void renderInspectWindow(game::GameHandler& gameHandler); diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 903c5799..28414f65 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -14655,6 +14655,14 @@ void GameHandler::dismissPet() { socket->send(packet); } +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 + auto packet = PetRenamePacket::build(petGuid_, newName, 0); + socket->send(packet); + LOG_INFO("Sent CMSG_PET_RENAME: petGuid=0x", std::hex, petGuid_, std::dec, " name='", newName, "'"); +} + void GameHandler::requestStabledPetList() { if (state != WorldState::IN_WORLD || !socket || stableMasterGuid_ == 0) return; auto pkt = ListStabledPetsPacket::build(stableMasterGuid_); diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index f5bb0e44..98ddd9d3 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -5421,5 +5421,13 @@ network::Packet UnstablePetPacket::build(uint64_t stableMasterGuid, uint32_t pet return p; } +network::Packet PetRenamePacket::build(uint64_t petGuid, const std::string& name, uint8_t isDeclined) { + network::Packet p(wireOpcode(Opcode::CMSG_PET_RENAME)); + p.writeUInt64(petGuid); + p.writeString(name); // null-terminated + p.writeUInt8(isDeclined); + return p; +} + } // namespace game } // namespace wowee diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 7093120d..6a3cc61d 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -3030,11 +3030,41 @@ void GameScreen::renderPetFrame(game::GameHandler& gameHandler) { if (ImGui::MenuItem("Target Pet")) { gameHandler.setTarget(petGuid); } + if (ImGui::MenuItem("Rename Pet")) { + ImGui::CloseCurrentPopup(); + petRenameOpen_ = true; + petRenameBuf_[0] = '\0'; + } if (ImGui::MenuItem("Dismiss Pet")) { gameHandler.dismissPet(); } ImGui::EndPopup(); } + // Pet rename modal (opened via context menu) + if (petRenameOpen_) { + ImGui::OpenPopup("Rename Pet###PetRename"); + petRenameOpen_ = false; + } + if (ImGui::BeginPopupModal("Rename Pet###PetRename", nullptr, + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse)) { + ImGui::Text("Enter new pet name (max 12 characters):"); + ImGui::SetNextItemWidth(180.0f); + bool submitted = ImGui::InputText("##PetRenameInput", petRenameBuf_, sizeof(petRenameBuf_), + ImGuiInputTextFlags_EnterReturnsTrue); + ImGui::SameLine(); + if (ImGui::Button("OK") || submitted) { + std::string newName(petRenameBuf_); + if (!newName.empty() && newName.size() <= 12) { + gameHandler.renamePet(newName); + } + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } ImGui::PopStyleColor(); if (petLevel > 0) { ImGui::SameLine();