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:
Kelsi 2026-02-18 04:06:14 -08:00
parent d3b04640f3
commit 98212a3f91
7 changed files with 79 additions and 1 deletions

View file

@ -1456,6 +1456,30 @@ void GameHandler::handlePacket(network::Packet& packet) {
}
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: {
// Quest objectives completed - mark as ready to turn in
uint32_t questId = packet.readUInt32();

View file

@ -208,6 +208,7 @@ static const OpcodeNameEntry kOpcodeNames[] = {
{"SMSG_QUESTGIVER_QUEST_COMPLETE", LogicalOpcode::SMSG_QUESTGIVER_QUEST_COMPLETE},
{"CMSG_QUESTLOG_REMOVE_QUEST", LogicalOpcode::CMSG_QUESTLOG_REMOVE_QUEST},
{"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},
{"CMSG_QUEST_QUERY", LogicalOpcode::CMSG_QUEST_QUERY},
{"SMSG_QUEST_QUERY_RESPONSE", LogicalOpcode::SMSG_QUEST_QUERY_RESPONSE},
@ -549,6 +550,7 @@ void OpcodeTable::loadWotlkDefaults() {
{LogicalOpcode::SMSG_QUESTGIVER_QUEST_COMPLETE, 0x191},
{LogicalOpcode::CMSG_QUESTLOG_REMOVE_QUEST, 0x194},
{LogicalOpcode::SMSG_QUESTUPDATE_ADD_KILL, 0x196},
{LogicalOpcode::SMSG_QUESTUPDATE_ADD_ITEM, 0x197},
{LogicalOpcode::SMSG_QUESTUPDATE_COMPLETE, 0x195},
{LogicalOpcode::CMSG_QUEST_QUERY, 0x05C},
{LogicalOpcode::SMSG_QUEST_QUERY_RESPONSE, 0x05D},

View file

@ -2861,6 +2861,12 @@ network::Packet LootReleasePacket::build(uint64_t lootGuid) {
}
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.lootType = packet.readUInt8();
data.gold = packet.readUInt32();
@ -2868,6 +2874,10 @@ bool LootResponseParser::parse(network::Packet& packet, LootResponseData& data)
data.items.reserve(itemCount);
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;
item.slotIndex = packet.readUInt8();
item.itemId = packet.readUInt32();
@ -2879,7 +2889,30 @@ bool LootResponseParser::parse(network::Packet& packet, LootResponseData& data)
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;
}