diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index b2ff31a8..94e5cb44 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -707,6 +707,12 @@ public: bool hasPendingGroupInvite() const { return pendingGroupInvite; } const std::string& getPendingInviterName() const { return pendingInviterName; } + // ---- Item text (books / readable items) ---- + bool isItemTextOpen() const { return itemTextOpen_; } + const std::string& getItemText() const { return itemText_; } + void closeItemText() { itemTextOpen_ = false; } + void queryItemText(uint64_t itemGuid); + // ---- Shared Quest ---- bool hasPendingSharedQuest() const { return pendingSharedQuest_; } uint32_t getSharedQuestId() const { return sharedQuestId_; } @@ -1303,6 +1309,7 @@ private: // ---- Instance lockout handler ---- void handleRaidInstanceInfo(network::Packet& packet); + void handleItemTextQueryResponse(network::Packet& packet); void handleQuestConfirmAccept(network::Packet& packet); void handleSummonRequest(network::Packet& packet); void handleTradeStatus(network::Packet& packet); @@ -1663,6 +1670,10 @@ private: bool pendingGroupInvite = false; std::string pendingInviterName; + // Item text state + bool itemTextOpen_ = false; + std::string itemText_; + // Shared quest state bool pendingSharedQuest_ = false; uint32_t sharedQuestId_ = 0; diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index b4d5a735..cb5f6ddb 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -209,6 +209,7 @@ private: void renderTradeRequestPopup(game::GameHandler& gameHandler); void renderSummonRequestPopup(game::GameHandler& gameHandler); void renderSharedQuestPopup(game::GameHandler& gameHandler); + void renderItemTextWindow(game::GameHandler& gameHandler); void renderBuffBar(game::GameHandler& gameHandler); void renderLootWindow(game::GameHandler& gameHandler); void renderGossipWindow(game::GameHandler& gameHandler); diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 5734cb93..dd5e6da5 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -1997,6 +1997,9 @@ void GameHandler::handlePacket(network::Packet& packet) { case Opcode::SMSG_QUEST_CONFIRM_ACCEPT: handleQuestConfirmAccept(packet); break; + case Opcode::SMSG_ITEM_TEXT_QUERY_RESPONSE: + handleItemTextQueryResponse(packet); + break; case Opcode::SMSG_SUMMON_REQUEST: handleSummonRequest(packet); break; @@ -15046,6 +15049,33 @@ void GameHandler::handleAuctionCommandResult(network::Packet& packet) { " error=", result.errorCode); } +// --------------------------------------------------------------------------- +// Item text (SMSG_ITEM_TEXT_QUERY_RESPONSE) +// uint64 itemGuid + uint8 isEmpty + string text (when !isEmpty) +// --------------------------------------------------------------------------- + +void GameHandler::handleItemTextQueryResponse(network::Packet& packet) { + size_t rem = packet.getSize() - packet.getReadPos(); + if (rem < 9) return; // guid(8) + isEmpty(1) + + /*uint64_t guid =*/ packet.readUInt64(); + uint8_t isEmpty = packet.readUInt8(); + if (!isEmpty) { + itemText_ = packet.readString(); + itemTextOpen_= !itemText_.empty(); + } + LOG_DEBUG("SMSG_ITEM_TEXT_QUERY_RESPONSE: isEmpty=", (int)isEmpty, + " len=", itemText_.size()); +} + +void GameHandler::queryItemText(uint64_t itemGuid) { + if (state != WorldState::IN_WORLD || !socket) return; + network::Packet pkt(wireOpcode(Opcode::CMSG_ITEM_TEXT_QUERY)); + pkt.writeUInt64(itemGuid); + socket->send(pkt); + LOG_DEBUG("CMSG_ITEM_TEXT_QUERY: guid=0x", std::hex, itemGuid, std::dec); +} + // --------------------------------------------------------------------------- // SMSG_QUEST_CONFIRM_ACCEPT (shared quest from group member) // uint32 questId + string questTitle + uint64 sharerGuid diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 6ba93447..e99130f1 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -401,6 +401,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { renderTradeRequestPopup(gameHandler); renderSummonRequestPopup(gameHandler); renderSharedQuestPopup(gameHandler); + renderItemTextWindow(gameHandler); renderGuildInvitePopup(gameHandler); renderGuildRoster(gameHandler); renderBuffBar(gameHandler); @@ -4405,6 +4406,42 @@ void GameScreen::renderDuelRequestPopup(game::GameHandler& gameHandler) { ImGui::End(); } +void GameScreen::renderItemTextWindow(game::GameHandler& gameHandler) { + if (!gameHandler.isItemTextOpen()) return; + + auto* window = core::Application::getInstance().getWindow(); + float screenW = window ? static_cast(window->getWidth()) : 1280.0f; + float screenH = window ? static_cast(window->getHeight()) : 720.0f; + + ImGui::SetNextWindowPos(ImVec2(screenW * 0.5f - 200, screenH * 0.15f), + ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiCond_FirstUseEver); + + bool open = true; + if (!ImGui::Begin("Book", &open, ImGuiWindowFlags_NoCollapse)) { + ImGui::End(); + if (!open) gameHandler.closeItemText(); + return; + } + if (!open) { + ImGui::End(); + gameHandler.closeItemText(); + return; + } + + // Parchment-toned background text + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.2f, 0.1f, 0.0f, 1.0f)); + ImGui::TextWrapped("%s", gameHandler.getItemText().c_str()); + ImGui::PopStyleColor(); + + ImGui::Spacing(); + if (ImGui::Button("Close", ImVec2(80, 0))) { + gameHandler.closeItemText(); + } + + ImGui::End(); +} + void GameScreen::renderSharedQuestPopup(game::GameHandler& gameHandler) { if (!gameHandler.hasPendingSharedQuest()) return;