mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-08-02 19:10:49 -04:00
fix: derive quest collect-item progress from bag contents
3.3.5a servers do not push collect-item objective counts (unlike kill credit, which arrives in the quest-log update fields), so the tracker relying solely on SMSG_QUESTUPDATE_ADD_ITEM never advanced when quest items were looted. Reconcile item objectives against actual bag contents on every inventory rebuild instead.
This commit is contained in:
@@ -1610,6 +1610,9 @@ public:
|
||||
// Quest log
|
||||
using QuestLogEntry = QuestHandler::QuestLogEntry;
|
||||
const std::vector<QuestLogEntry>& getQuestLog() const;
|
||||
// Reconcile collect-item quest objectives against current bag contents.
|
||||
// Forwards to QuestHandler; called by InventoryHandler after each rebuild.
|
||||
void reconcileQuestItemObjectives(const std::unordered_map<uint32_t, uint32_t>& carriedCounts);
|
||||
int getMaxQuestLogSlots() const;
|
||||
// QuestSort.dbc name for negative ZoneOrSort values (class/profession/seasonal)
|
||||
const std::string& getQuestSortName(uint32_t sortId) const;
|
||||
|
||||
@@ -137,6 +137,14 @@ public:
|
||||
bool resyncQuestLogFromServerSlots(bool forceQueryMetadata);
|
||||
void applyQuestStateFromFields(const FlatFieldMap& fields);
|
||||
void applyPackedKillCountsFromFields(QuestLogEntry& quest);
|
||||
// Reconcile collect-item objective progress against the player's actual
|
||||
// bag contents. In 3.3.5a the server does not push item objective counts
|
||||
// (unlike kill credit, which arrives packed in the quest-log update
|
||||
// fields) — the authentic client derives them by counting matching item
|
||||
// IDs in the bags. Called after every inventory rebuild. `carriedCounts`
|
||||
// maps itemId -> total quantity currently held across backpack + bags.
|
||||
void reconcileItemObjectivesFromInventory(
|
||||
const std::unordered_map<uint32_t, uint32_t>& carriedCounts);
|
||||
void clearPendingQuestAccept(uint32_t questId);
|
||||
void triggerQuestAcceptResync(uint32_t questId, uint64_t npcGuid, const char* reason);
|
||||
|
||||
|
||||
@@ -2736,6 +2736,11 @@ const std::vector<GameHandler::QuestLogEntry>& GameHandler::getQuestLog() const
|
||||
static const std::vector<QuestLogEntry> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
void GameHandler::reconcileQuestItemObjectives(
|
||||
const std::unordered_map<uint32_t, uint32_t>& carriedCounts) {
|
||||
if (questHandler_) questHandler_->reconcileItemObjectivesFromInventory(carriedCounts);
|
||||
}
|
||||
int GameHandler::getMaxQuestLogSlots() const {
|
||||
return questHandler_ ? questHandler_->maxQuestLogSlots() : 25;
|
||||
}
|
||||
|
||||
@@ -3484,6 +3484,29 @@ void InventoryHandler::rebuildOnlineInventory() {
|
||||
}(), " keyring=", [&](){
|
||||
int c = 0; for (auto g : owner_.keyringSlotGuidsRef()) if (g) c++; return c;
|
||||
}());
|
||||
|
||||
// Reconcile collect-item quest objectives against what the player is
|
||||
// actually carrying. In 3.3.5a the server never pushes item objective
|
||||
// counts, so this bag-count pass is the only thing that advances "collect
|
||||
// N of item" progress when quest items are looted (or removed). Count
|
||||
// backpack + the four equipped bags — the same set the server checks at
|
||||
// turn-in — summing stacks per item id.
|
||||
std::unordered_map<uint32_t, uint32_t> carriedCounts;
|
||||
const auto& inv = owner_.inventoryRef();
|
||||
for (int i = 0; i < inv.getBackpackSize(); i++) {
|
||||
const auto& slot = inv.getBackpackSlot(i);
|
||||
if (!slot.empty())
|
||||
carriedCounts[slot.item.itemId] += std::max<uint32_t>(1, slot.item.stackCount);
|
||||
}
|
||||
for (int bagIdx = 0; bagIdx < 4; bagIdx++) {
|
||||
int numSlots = inv.getBagSize(bagIdx);
|
||||
for (int s = 0; s < numSlots; s++) {
|
||||
const auto& slot = inv.getBagSlot(bagIdx, s);
|
||||
if (!slot.empty())
|
||||
carriedCounts[slot.item.itemId] += std::max<uint32_t>(1, slot.item.stackCount);
|
||||
}
|
||||
}
|
||||
owner_.reconcileQuestItemObjectives(carriedCounts);
|
||||
}
|
||||
|
||||
void InventoryHandler::maybeDetectVisibleItemLayout() {
|
||||
|
||||
@@ -27,6 +27,54 @@ QuestGiverStatus QuestHandler::getQuestGiverStatus(uint64_t guid) const {
|
||||
return (it != npcQuestStatus_.end()) ? it->second : QuestGiverStatus::NONE;
|
||||
}
|
||||
|
||||
void QuestHandler::reconcileItemObjectivesFromInventory(
|
||||
const std::unordered_map<uint32_t, uint32_t>& carriedCounts) {
|
||||
bool changedAny = false;
|
||||
bool maybeCompletedObjective = false;
|
||||
for (auto& quest : questLog_) {
|
||||
if (quest.complete) continue;
|
||||
for (const auto& obj : quest.itemObjectives) {
|
||||
if (obj.itemId == 0 || obj.required == 0) continue;
|
||||
// Keep the derived required-count map in sync so the
|
||||
// SMSG_QUESTUPDATE_ADD_ITEM path and this one agree.
|
||||
quest.requiredItemCounts[obj.itemId] = obj.required;
|
||||
|
||||
auto cit = carriedCounts.find(obj.itemId);
|
||||
const uint32_t held = (cit != carriedCounts.end()) ? cit->second : 0;
|
||||
const uint32_t newCount = std::min(held, obj.required);
|
||||
uint32_t& tracked = quest.itemCounts[obj.itemId];
|
||||
if (tracked == newCount) continue;
|
||||
|
||||
const bool wasComplete = tracked >= obj.required;
|
||||
tracked = newCount;
|
||||
changedAny = true;
|
||||
if (!wasComplete && newCount >= obj.required)
|
||||
maybeCompletedObjective = true;
|
||||
|
||||
// Push the per-objective progress to the on-screen tracker.
|
||||
std::string itemLabel = "item #" + std::to_string(obj.itemId);
|
||||
if (const ItemQueryResponseData* info = owner_.getItemInfo(obj.itemId)) {
|
||||
if (!info->name.empty()) itemLabel = info->name;
|
||||
} else {
|
||||
// Name not cached yet — request it so the next refresh labels
|
||||
// the objective properly.
|
||||
owner_.queryItemInfo(obj.itemId, 0);
|
||||
}
|
||||
if (owner_.questProgressCallbackRef())
|
||||
owner_.questProgressCallbackRef()(quest.title, itemLabel, newCount, obj.required);
|
||||
}
|
||||
}
|
||||
|
||||
if (changedAny && owner_.addonEventCallbackRef()) {
|
||||
owner_.addonEventCallbackRef()("QUEST_WATCH_UPDATE", {});
|
||||
owner_.addonEventCallbackRef()("QUEST_LOG_UPDATE", {});
|
||||
owner_.addonEventCallbackRef()("UNIT_QUEST_LOG_CHANGED", {"player"});
|
||||
}
|
||||
// Collecting the last item may have made a quest turn-in-able (! → ?),
|
||||
// so refresh nearby giver markers immediately.
|
||||
if (maybeCompletedObjective) requeryNearbyQuestGiverStatus();
|
||||
}
|
||||
|
||||
void QuestHandler::requeryNearbyQuestGiverStatus() {
|
||||
if (questGiverRequeryCooldown_ > 0.0f) {
|
||||
questGiverRequeryPending_ = true;
|
||||
|
||||
Reference in New Issue
Block a user