mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
Fix quest item loot parsing and quest item progress tracking
- add SMSG_QUESTUPDATE_ADD_ITEM logical opcode mapping (0x197) - handle quest item progress updates in GameHandler - parse quest-item section in SMSG_LOOT_RESPONSE (regular + quest items) - add quest item progress storage in quest log entries - show tracked kill/item progress in Quest Log UI
This commit is contained in:
parent
e5cacbc330
commit
56c309b27d
7 changed files with 79 additions and 1 deletions
|
|
@ -702,6 +702,8 @@ public:
|
||||||
bool complete = false;
|
bool complete = false;
|
||||||
// Objective kill counts: objectiveIndex -> (current, required)
|
// Objective kill counts: objectiveIndex -> (current, required)
|
||||||
std::unordered_map<uint32_t, std::pair<uint32_t, uint32_t>> killCounts;
|
std::unordered_map<uint32_t, std::pair<uint32_t, uint32_t>> killCounts;
|
||||||
|
// Quest item progress: itemId -> current count
|
||||||
|
std::unordered_map<uint32_t, uint32_t> itemCounts;
|
||||||
};
|
};
|
||||||
const std::vector<QuestLogEntry>& getQuestLog() const { return questLog_; }
|
const std::vector<QuestLogEntry>& getQuestLog() const { return questLog_; }
|
||||||
void abandonQuest(uint32_t questId);
|
void abandonQuest(uint32_t questId);
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,7 @@ enum class LogicalOpcode : uint16_t {
|
||||||
SMSG_QUESTGIVER_QUEST_COMPLETE,
|
SMSG_QUESTGIVER_QUEST_COMPLETE,
|
||||||
CMSG_QUESTLOG_REMOVE_QUEST,
|
CMSG_QUESTLOG_REMOVE_QUEST,
|
||||||
SMSG_QUESTUPDATE_ADD_KILL,
|
SMSG_QUESTUPDATE_ADD_KILL,
|
||||||
|
SMSG_QUESTUPDATE_ADD_ITEM,
|
||||||
SMSG_QUESTUPDATE_COMPLETE,
|
SMSG_QUESTUPDATE_COMPLETE,
|
||||||
CMSG_QUEST_QUERY,
|
CMSG_QUEST_QUERY,
|
||||||
SMSG_QUEST_QUERY_RESPONSE,
|
SMSG_QUEST_QUERY_RESPONSE,
|
||||||
|
|
|
||||||
|
|
@ -1762,6 +1762,7 @@ struct LootItem {
|
||||||
uint32_t randomSuffix = 0;
|
uint32_t randomSuffix = 0;
|
||||||
uint32_t randomPropertyId = 0;
|
uint32_t randomPropertyId = 0;
|
||||||
uint8_t lootSlotType = 0;
|
uint8_t lootSlotType = 0;
|
||||||
|
bool isQuestItem = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** SMSG_LOOT_RESPONSE data */
|
/** SMSG_LOOT_RESPONSE data */
|
||||||
|
|
|
||||||
|
|
@ -1456,6 +1456,30 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Opcode::SMSG_QUESTUPDATE_ADD_ITEM: {
|
||||||
|
// Quest item count update: itemId + count
|
||||||
|
if (packet.getSize() - packet.getReadPos() >= 8) {
|
||||||
|
uint32_t itemId = packet.readUInt32();
|
||||||
|
uint32_t count = packet.readUInt32();
|
||||||
|
queryItemInfo(itemId, 0);
|
||||||
|
|
||||||
|
std::string itemLabel = "item #" + std::to_string(itemId);
|
||||||
|
if (const ItemQueryResponseData* info = getItemInfo(itemId)) {
|
||||||
|
if (!info->name.empty()) itemLabel = info->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool updatedAny = false;
|
||||||
|
for (auto& quest : questLog_) {
|
||||||
|
if (quest.complete) continue;
|
||||||
|
quest.itemCounts[itemId] = count;
|
||||||
|
updatedAny = true;
|
||||||
|
}
|
||||||
|
addSystemChatMessage("Quest item: " + itemLabel + " (" + std::to_string(count) + ")");
|
||||||
|
LOG_INFO("Quest item update: itemId=", itemId, " count=", count,
|
||||||
|
" trackedQuestsUpdated=", updatedAny);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Opcode::SMSG_QUESTUPDATE_COMPLETE: {
|
case Opcode::SMSG_QUESTUPDATE_COMPLETE: {
|
||||||
// Quest objectives completed - mark as ready to turn in
|
// Quest objectives completed - mark as ready to turn in
|
||||||
uint32_t questId = packet.readUInt32();
|
uint32_t questId = packet.readUInt32();
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,7 @@ static const OpcodeNameEntry kOpcodeNames[] = {
|
||||||
{"SMSG_QUESTGIVER_QUEST_COMPLETE", LogicalOpcode::SMSG_QUESTGIVER_QUEST_COMPLETE},
|
{"SMSG_QUESTGIVER_QUEST_COMPLETE", LogicalOpcode::SMSG_QUESTGIVER_QUEST_COMPLETE},
|
||||||
{"CMSG_QUESTLOG_REMOVE_QUEST", LogicalOpcode::CMSG_QUESTLOG_REMOVE_QUEST},
|
{"CMSG_QUESTLOG_REMOVE_QUEST", LogicalOpcode::CMSG_QUESTLOG_REMOVE_QUEST},
|
||||||
{"SMSG_QUESTUPDATE_ADD_KILL", LogicalOpcode::SMSG_QUESTUPDATE_ADD_KILL},
|
{"SMSG_QUESTUPDATE_ADD_KILL", LogicalOpcode::SMSG_QUESTUPDATE_ADD_KILL},
|
||||||
|
{"SMSG_QUESTUPDATE_ADD_ITEM", LogicalOpcode::SMSG_QUESTUPDATE_ADD_ITEM},
|
||||||
{"SMSG_QUESTUPDATE_COMPLETE", LogicalOpcode::SMSG_QUESTUPDATE_COMPLETE},
|
{"SMSG_QUESTUPDATE_COMPLETE", LogicalOpcode::SMSG_QUESTUPDATE_COMPLETE},
|
||||||
{"CMSG_QUEST_QUERY", LogicalOpcode::CMSG_QUEST_QUERY},
|
{"CMSG_QUEST_QUERY", LogicalOpcode::CMSG_QUEST_QUERY},
|
||||||
{"SMSG_QUEST_QUERY_RESPONSE", LogicalOpcode::SMSG_QUEST_QUERY_RESPONSE},
|
{"SMSG_QUEST_QUERY_RESPONSE", LogicalOpcode::SMSG_QUEST_QUERY_RESPONSE},
|
||||||
|
|
@ -549,6 +550,7 @@ void OpcodeTable::loadWotlkDefaults() {
|
||||||
{LogicalOpcode::SMSG_QUESTGIVER_QUEST_COMPLETE, 0x191},
|
{LogicalOpcode::SMSG_QUESTGIVER_QUEST_COMPLETE, 0x191},
|
||||||
{LogicalOpcode::CMSG_QUESTLOG_REMOVE_QUEST, 0x194},
|
{LogicalOpcode::CMSG_QUESTLOG_REMOVE_QUEST, 0x194},
|
||||||
{LogicalOpcode::SMSG_QUESTUPDATE_ADD_KILL, 0x196},
|
{LogicalOpcode::SMSG_QUESTUPDATE_ADD_KILL, 0x196},
|
||||||
|
{LogicalOpcode::SMSG_QUESTUPDATE_ADD_ITEM, 0x197},
|
||||||
{LogicalOpcode::SMSG_QUESTUPDATE_COMPLETE, 0x195},
|
{LogicalOpcode::SMSG_QUESTUPDATE_COMPLETE, 0x195},
|
||||||
{LogicalOpcode::CMSG_QUEST_QUERY, 0x05C},
|
{LogicalOpcode::CMSG_QUEST_QUERY, 0x05C},
|
||||||
{LogicalOpcode::SMSG_QUEST_QUERY_RESPONSE, 0x05D},
|
{LogicalOpcode::SMSG_QUEST_QUERY_RESPONSE, 0x05D},
|
||||||
|
|
|
||||||
|
|
@ -2861,6 +2861,12 @@ network::Packet LootReleasePacket::build(uint64_t lootGuid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LootResponseParser::parse(network::Packet& packet, LootResponseData& data) {
|
bool LootResponseParser::parse(network::Packet& packet, LootResponseData& data) {
|
||||||
|
data = LootResponseData{};
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 14) {
|
||||||
|
LOG_WARNING("LootResponseParser: packet too short");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
data.lootGuid = packet.readUInt64();
|
data.lootGuid = packet.readUInt64();
|
||||||
data.lootType = packet.readUInt8();
|
data.lootType = packet.readUInt8();
|
||||||
data.gold = packet.readUInt32();
|
data.gold = packet.readUInt32();
|
||||||
|
|
@ -2868,6 +2874,10 @@ bool LootResponseParser::parse(network::Packet& packet, LootResponseData& data)
|
||||||
|
|
||||||
data.items.reserve(itemCount);
|
data.items.reserve(itemCount);
|
||||||
for (uint8_t i = 0; i < itemCount; ++i) {
|
for (uint8_t i = 0; i < itemCount; ++i) {
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 22) {
|
||||||
|
LOG_WARNING("LootResponseParser: truncated regular item list");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
LootItem item;
|
LootItem item;
|
||||||
item.slotIndex = packet.readUInt8();
|
item.slotIndex = packet.readUInt8();
|
||||||
item.itemId = packet.readUInt32();
|
item.itemId = packet.readUInt32();
|
||||||
|
|
@ -2879,7 +2889,30 @@ bool LootResponseParser::parse(network::Packet& packet, LootResponseData& data)
|
||||||
data.items.push_back(item);
|
data.items.push_back(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("Loot response: ", (int)itemCount, " items, ", data.gold, " copper");
|
uint8_t questItemCount = 0;
|
||||||
|
if (packet.getSize() - packet.getReadPos() >= 1) {
|
||||||
|
questItemCount = packet.readUInt8();
|
||||||
|
data.items.reserve(data.items.size() + questItemCount);
|
||||||
|
for (uint8_t i = 0; i < questItemCount; ++i) {
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 22) {
|
||||||
|
LOG_WARNING("LootResponseParser: truncated quest item list");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LootItem item;
|
||||||
|
item.slotIndex = packet.readUInt8();
|
||||||
|
item.itemId = packet.readUInt32();
|
||||||
|
item.count = packet.readUInt32();
|
||||||
|
item.displayInfoId = packet.readUInt32();
|
||||||
|
item.randomSuffix = packet.readUInt32();
|
||||||
|
item.randomPropertyId = packet.readUInt32();
|
||||||
|
item.lootSlotType = packet.readUInt8();
|
||||||
|
item.isQuestItem = true;
|
||||||
|
data.items.push_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Loot response: ", (int)itemCount, " regular + ", (int)questItemCount,
|
||||||
|
" quest items, ", data.gold, " copper");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,21 @@ void QuestLogScreen::render(game::GameHandler& gameHandler) {
|
||||||
ImGui::TextWrapped("%s", processedObjectives.c_str());
|
ImGui::TextWrapped("%s", processedObjectives.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sel.killCounts.empty() || !sel.itemCounts.empty()) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f), "Tracked Progress");
|
||||||
|
for (const auto& [entry, progress] : sel.killCounts) {
|
||||||
|
ImGui::BulletText("Kill %u: %u/%u", entry, progress.first, progress.second);
|
||||||
|
}
|
||||||
|
for (const auto& [itemId, count] : sel.itemCounts) {
|
||||||
|
std::string itemLabel = "Item " + std::to_string(itemId);
|
||||||
|
if (const auto* info = gameHandler.getItemInfo(itemId)) {
|
||||||
|
if (!info->name.empty()) itemLabel = info->name;
|
||||||
|
}
|
||||||
|
ImGui::BulletText("%s: %u", itemLabel.c_str(), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Abandon button
|
// Abandon button
|
||||||
if (!sel.complete) {
|
if (!sel.complete) {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue