mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 17:43:52 +00:00
feat: display quest reward items in quest details acceptance window
Parse and store reward items (choice and fixed) from SMSG_QUESTGIVER_QUEST_DETAILS in both WotLK (QuestDetailsParser) and TBC/Classic (TbcPacketParsers) parsers. Show item icons, names, and counts in the quest acceptance dialog alongside XP/money. Move QuestRewardItem before QuestDetailsData in header to fix forward-reference.
This commit is contained in:
parent
9f8a0907c4
commit
1ff48259cc
4 changed files with 101 additions and 21 deletions
|
|
@ -2086,6 +2086,14 @@ public:
|
||||||
static network::Packet build(uint64_t npcGuid, uint32_t questId);
|
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) */
|
/** SMSG_QUESTGIVER_QUEST_DETAILS data (simplified) */
|
||||||
struct QuestDetailsData {
|
struct QuestDetailsData {
|
||||||
uint64_t npcGuid = 0;
|
uint64_t npcGuid = 0;
|
||||||
|
|
@ -2096,6 +2104,8 @@ struct QuestDetailsData {
|
||||||
uint32_t suggestedPlayers = 0;
|
uint32_t suggestedPlayers = 0;
|
||||||
uint32_t rewardMoney = 0;
|
uint32_t rewardMoney = 0;
|
||||||
uint32_t rewardXp = 0;
|
uint32_t rewardXp = 0;
|
||||||
|
std::vector<QuestRewardItem> rewardChoiceItems; // Player picks one of these
|
||||||
|
std::vector<QuestRewardItem> rewardItems; // These are always given
|
||||||
};
|
};
|
||||||
|
|
||||||
/** SMSG_QUESTGIVER_QUEST_DETAILS parser */
|
/** SMSG_QUESTGIVER_QUEST_DETAILS parser */
|
||||||
|
|
@ -2104,14 +2114,6 @@ public:
|
||||||
static bool parse(network::Packet& packet, QuestDetailsData& data);
|
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) */
|
/** SMSG_QUESTGIVER_REQUEST_ITEMS data (turn-in progress check) */
|
||||||
struct QuestRequestItemsData {
|
struct QuestRequestItemsData {
|
||||||
uint64_t npcGuid = 0;
|
uint64_t npcGuid = 0;
|
||||||
|
|
|
||||||
|
|
@ -739,9 +739,15 @@ bool TbcPacketParsers::parseQuestDetails(network::Packet& packet, QuestDetailsDa
|
||||||
if (packet.getReadPos() + 4 <= packet.getSize()) {
|
if (packet.getReadPos() + 4 <= packet.getSize()) {
|
||||||
uint32_t choiceCount = packet.readUInt32();
|
uint32_t choiceCount = packet.readUInt32();
|
||||||
for (uint32_t i = 0; i < choiceCount && packet.getReadPos() + 12 <= packet.getSize(); ++i) {
|
for (uint32_t i = 0; i < choiceCount && packet.getReadPos() + 12 <= packet.getSize(); ++i) {
|
||||||
packet.readUInt32(); // itemId
|
uint32_t itemId = packet.readUInt32();
|
||||||
packet.readUInt32(); // count
|
uint32_t count = packet.readUInt32();
|
||||||
packet.readUInt32(); // displayInfo
|
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()) {
|
if (packet.getReadPos() + 4 <= packet.getSize()) {
|
||||||
uint32_t rewardCount = packet.readUInt32();
|
uint32_t rewardCount = packet.readUInt32();
|
||||||
for (uint32_t i = 0; i < rewardCount && packet.getReadPos() + 12 <= packet.getSize(); ++i) {
|
for (uint32_t i = 0; i < rewardCount && packet.getReadPos() + 12 <= packet.getSize(); ++i) {
|
||||||
packet.readUInt32(); // itemId
|
uint32_t itemId = packet.readUInt32();
|
||||||
packet.readUInt32(); // count
|
uint32_t count = packet.readUInt32();
|
||||||
packet.readUInt32(); // displayInfo
|
uint32_t dispId = packet.readUInt32();
|
||||||
|
if (itemId != 0) {
|
||||||
|
QuestRewardItem ri;
|
||||||
|
ri.itemId = itemId; ri.count = count; ri.displayInfoId = dispId;
|
||||||
|
data.rewardItems.push_back(ri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3446,9 +3446,15 @@ bool QuestDetailsParser::parse(network::Packet& packet, QuestDetailsData& data)
|
||||||
/*choiceCount*/ packet.readUInt32();
|
/*choiceCount*/ packet.readUInt32();
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
if (packet.getReadPos() + 12 > packet.getSize()) break;
|
if (packet.getReadPos() + 12 > packet.getSize()) break;
|
||||||
packet.readUInt32(); // itemId
|
uint32_t itemId = packet.readUInt32();
|
||||||
packet.readUInt32(); // count
|
uint32_t count = packet.readUInt32();
|
||||||
packet.readUInt32(); // displayInfo
|
uint32_t dispId = packet.readUInt32();
|
||||||
|
if (itemId != 0) {
|
||||||
|
QuestRewardItem ri;
|
||||||
|
ri.itemId = itemId; ri.count = count; ri.displayInfoId = dispId;
|
||||||
|
ri.choiceSlot = static_cast<uint32_t>(i);
|
||||||
|
data.rewardChoiceItems.push_back(ri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3457,9 +3463,14 @@ bool QuestDetailsParser::parse(network::Packet& packet, QuestDetailsData& data)
|
||||||
/*rewardCount*/ packet.readUInt32();
|
/*rewardCount*/ packet.readUInt32();
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (packet.getReadPos() + 12 > packet.getSize()) break;
|
if (packet.getReadPos() + 12 > packet.getSize()) break;
|
||||||
packet.readUInt32(); // itemId
|
uint32_t itemId = packet.readUInt32();
|
||||||
packet.readUInt32(); // count
|
uint32_t count = packet.readUInt32();
|
||||||
packet.readUInt32(); // displayInfo
|
uint32_t dispId = packet.readUInt32();
|
||||||
|
if (itemId != 0) {
|
||||||
|
QuestRewardItem ri;
|
||||||
|
ri.itemId = itemId; ri.count = count; ri.displayInfoId = dispId;
|
||||||
|
data.rewardItems.push_back(ri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6714,7 +6714,63 @@ void GameScreen::renderQuestDetailsWindow(game::GameHandler& gameHandler) {
|
||||||
ImGui::TextWrapped("%s", processedObjectives.c_str());
|
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) {
|
if (quest.rewardXp > 0 || quest.rewardMoney > 0) {
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue