diff --git a/include/game/world_packets.hpp b/include/game/world_packets.hpp index 786cab8b..5d75e887 100644 --- a/include/game/world_packets.hpp +++ b/include/game/world_packets.hpp @@ -2086,6 +2086,14 @@ public: static network::Packet build(uint64_t npcGuid, uint32_t questId); }; +/** Reward item entry (shared by quest detail/offer windows) */ +struct QuestRewardItem { + uint32_t itemId = 0; + uint32_t count = 0; + uint32_t displayInfoId = 0; + uint32_t choiceSlot = 0; // Original reward slot index from server payload +}; + /** SMSG_QUESTGIVER_QUEST_DETAILS data (simplified) */ struct QuestDetailsData { uint64_t npcGuid = 0; @@ -2096,6 +2104,8 @@ struct QuestDetailsData { uint32_t suggestedPlayers = 0; uint32_t rewardMoney = 0; uint32_t rewardXp = 0; + std::vector rewardChoiceItems; // Player picks one of these + std::vector rewardItems; // These are always given }; /** SMSG_QUESTGIVER_QUEST_DETAILS parser */ @@ -2104,14 +2114,6 @@ public: static bool parse(network::Packet& packet, QuestDetailsData& data); }; -/** Reward item entry (shared by quest detail/offer windows) */ -struct QuestRewardItem { - uint32_t itemId = 0; - uint32_t count = 0; - uint32_t displayInfoId = 0; - uint32_t choiceSlot = 0; // Original reward slot index from server payload -}; - /** SMSG_QUESTGIVER_REQUEST_ITEMS data (turn-in progress check) */ struct QuestRequestItemsData { uint64_t npcGuid = 0; diff --git a/src/game/packet_parsers_tbc.cpp b/src/game/packet_parsers_tbc.cpp index ebe467ea..c523df13 100644 --- a/src/game/packet_parsers_tbc.cpp +++ b/src/game/packet_parsers_tbc.cpp @@ -739,9 +739,15 @@ bool TbcPacketParsers::parseQuestDetails(network::Packet& packet, QuestDetailsDa if (packet.getReadPos() + 4 <= packet.getSize()) { uint32_t choiceCount = packet.readUInt32(); for (uint32_t i = 0; i < choiceCount && packet.getReadPos() + 12 <= packet.getSize(); ++i) { - packet.readUInt32(); // itemId - packet.readUInt32(); // count - packet.readUInt32(); // displayInfo + uint32_t itemId = packet.readUInt32(); + uint32_t count = packet.readUInt32(); + uint32_t dispId = packet.readUInt32(); + if (itemId != 0) { + QuestRewardItem ri; + ri.itemId = itemId; ri.count = count; ri.displayInfoId = dispId; + ri.choiceSlot = i; + data.rewardChoiceItems.push_back(ri); + } } } @@ -749,9 +755,14 @@ bool TbcPacketParsers::parseQuestDetails(network::Packet& packet, QuestDetailsDa if (packet.getReadPos() + 4 <= packet.getSize()) { uint32_t rewardCount = packet.readUInt32(); for (uint32_t i = 0; i < rewardCount && packet.getReadPos() + 12 <= packet.getSize(); ++i) { - packet.readUInt32(); // itemId - packet.readUInt32(); // count - packet.readUInt32(); // displayInfo + uint32_t itemId = packet.readUInt32(); + uint32_t count = packet.readUInt32(); + uint32_t dispId = packet.readUInt32(); + if (itemId != 0) { + QuestRewardItem ri; + ri.itemId = itemId; ri.count = count; ri.displayInfoId = dispId; + data.rewardItems.push_back(ri); + } } } diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index 710ad501..c3adbcb0 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -3446,9 +3446,15 @@ bool QuestDetailsParser::parse(network::Packet& packet, QuestDetailsData& data) /*choiceCount*/ packet.readUInt32(); for (int i = 0; i < 6; i++) { if (packet.getReadPos() + 12 > packet.getSize()) break; - packet.readUInt32(); // itemId - packet.readUInt32(); // count - packet.readUInt32(); // displayInfo + uint32_t itemId = packet.readUInt32(); + uint32_t count = packet.readUInt32(); + uint32_t dispId = packet.readUInt32(); + if (itemId != 0) { + QuestRewardItem ri; + ri.itemId = itemId; ri.count = count; ri.displayInfoId = dispId; + ri.choiceSlot = static_cast(i); + data.rewardChoiceItems.push_back(ri); + } } } @@ -3457,9 +3463,14 @@ bool QuestDetailsParser::parse(network::Packet& packet, QuestDetailsData& data) /*rewardCount*/ packet.readUInt32(); for (int i = 0; i < 4; i++) { if (packet.getReadPos() + 12 > packet.getSize()) break; - packet.readUInt32(); // itemId - packet.readUInt32(); // count - packet.readUInt32(); // displayInfo + uint32_t itemId = packet.readUInt32(); + uint32_t count = packet.readUInt32(); + uint32_t dispId = packet.readUInt32(); + if (itemId != 0) { + QuestRewardItem ri; + ri.itemId = itemId; ri.count = count; ri.displayInfoId = dispId; + data.rewardItems.push_back(ri); + } } } diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index f66e6749..80afafb2 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -6714,7 +6714,63 @@ void GameScreen::renderQuestDetailsWindow(game::GameHandler& gameHandler) { ImGui::TextWrapped("%s", processedObjectives.c_str()); } - // Rewards + // Choice reward items (player picks one) + if (!quest.rewardChoiceItems.empty()) { + ImGui::Spacing(); + ImGui::Separator(); + ImGui::TextColored(ImVec4(1.0f, 0.82f, 0.0f, 1.0f), "Choose one reward:"); + for (const auto& ri : quest.rewardChoiceItems) { + gameHandler.ensureItemInfo(ri.itemId); + auto* info = gameHandler.getItemInfo(ri.itemId); + VkDescriptorSet iconTex = VK_NULL_HANDLE; + uint32_t dispId = ri.displayInfoId; + if (info && info->valid && info->displayInfoId != 0) dispId = info->displayInfoId; + if (dispId != 0) iconTex = inventoryScreen.getItemIcon(dispId); + + std::string label; + if (info && info->valid && !info->name.empty()) + label = info->name; + else + label = "Item " + std::to_string(ri.itemId); + if (ri.count > 1) label += " x" + std::to_string(ri.count); + + if (iconTex) { + ImGui::Image((void*)(intptr_t)iconTex, ImVec2(18, 18)); + ImGui::SameLine(); + } + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), " %s", label.c_str()); + } + } + + // Fixed reward items (always given) + if (!quest.rewardItems.empty()) { + ImGui::Spacing(); + ImGui::Separator(); + ImGui::TextColored(ImVec4(1.0f, 0.82f, 0.0f, 1.0f), "You will receive:"); + for (const auto& ri : quest.rewardItems) { + gameHandler.ensureItemInfo(ri.itemId); + auto* info = gameHandler.getItemInfo(ri.itemId); + VkDescriptorSet iconTex = VK_NULL_HANDLE; + uint32_t dispId = ri.displayInfoId; + if (info && info->valid && info->displayInfoId != 0) dispId = info->displayInfoId; + if (dispId != 0) iconTex = inventoryScreen.getItemIcon(dispId); + + std::string label; + if (info && info->valid && !info->name.empty()) + label = info->name; + else + label = "Item " + std::to_string(ri.itemId); + if (ri.count > 1) label += " x" + std::to_string(ri.count); + + if (iconTex) { + ImGui::Image((void*)(intptr_t)iconTex, ImVec2(18, 18)); + ImGui::SameLine(); + } + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), " %s", label.c_str()); + } + } + + // XP and money rewards if (quest.rewardXp > 0 || quest.rewardMoney > 0) { ImGui::Spacing(); ImGui::Separator();