From f0966ed12124f0451e2bed69f3e66e7f6af3b95e Mon Sep 17 00:00:00 2001 From: bash Date: Fri, 8 May 2026 22:17:52 +0200 Subject: [PATCH] fix(Core/Loot): Prevent re-loot of same corpse via completed-guid set --- src/Ai/Base/Actions/LootAction.cpp | 8 ++++++-- src/Mgr/Item/LootObjectStack.cpp | 19 ++++++++++++++++++- src/Mgr/Item/LootObjectStack.h | 4 ++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/Ai/Base/Actions/LootAction.cpp b/src/Ai/Base/Actions/LootAction.cpp index f225235a2..9ffd1e526 100644 --- a/src/Ai/Base/Actions/LootAction.cpp +++ b/src/Ai/Base/Actions/LootAction.cpp @@ -79,7 +79,11 @@ bool OpenLootAction::Execute(Event /*event*/) bool result = DoLoot(lootObject); if (result) { - AI_VALUE(LootObjectStack*, "available loot")->Remove(lootObject.guid); + // MarkCompleted (not Remove) — "add all loot" reads + // "nearest corpses" without a lootable filter, so a plain + // Remove lets the same corpse re-enter the stack on the next + // tick. The completed set blocks re-add for ~5 min. + AI_VALUE(LootObjectStack*, "available loot")->MarkCompleted(lootObject.guid); context->GetValue("loot target")->Set(LootObject()); } return result; @@ -514,7 +518,7 @@ bool StoreLootAction::Execute(Event event) BroadcastHelper::BroadcastLootingItem(botAI, bot, proto); } - AI_VALUE(LootObjectStack*, "available loot")->Remove(guid); + AI_VALUE(LootObjectStack*, "available loot")->MarkCompleted(guid); // release loot WorldPacket* packet = new WorldPacket(CMSG_LOOT_RELEASE, 8); diff --git a/src/Mgr/Item/LootObjectStack.cpp b/src/Mgr/Item/LootObjectStack.cpp index 946c482b2..5c613d070 100644 --- a/src/Mgr/Item/LootObjectStack.cpp +++ b/src/Mgr/Item/LootObjectStack.cpp @@ -362,6 +362,13 @@ bool LootObject::IsLootPossible(Player* bot) bool LootObjectStack::Add(ObjectGuid guid) { + // expire old completed entries so a despawn/respawn with a reused + // guid can still be looted later + completedLoot.shrink(time(nullptr) - 300); + + if (completedLoot.find(guid) != completedLoot.end()) + return false; + if (availableLoot.size() >= MAX_LOOT_OBJECT_COUNT) { availableLoot.shrink(time(nullptr) - 30); @@ -385,7 +392,17 @@ void LootObjectStack::Remove(ObjectGuid guid) availableLoot.erase(i); } -void LootObjectStack::Clear() { availableLoot.clear(); } +void LootObjectStack::MarkCompleted(ObjectGuid guid) +{ + Remove(guid); + completedLoot.insert(guid); +} + +void LootObjectStack::Clear() +{ + availableLoot.clear(); + completedLoot.clear(); +} bool LootObjectStack::CanLoot(float maxDistance) { diff --git a/src/Mgr/Item/LootObjectStack.h b/src/Mgr/Item/LootObjectStack.h index df1b5b570..f174fce21 100644 --- a/src/Mgr/Item/LootObjectStack.h +++ b/src/Mgr/Item/LootObjectStack.h @@ -76,6 +76,7 @@ public: bool Add(ObjectGuid guid); void Remove(ObjectGuid guid); + void MarkCompleted(ObjectGuid guid); void Clear(); bool CanLoot(float maxDistance); LootObject GetLoot(float maxDistance = 0); @@ -85,6 +86,9 @@ private: Player* bot; LootTargetList availableLoot; + // Guids we already opened loot on; blocks "add all loot" from + // re-adding the same corpse before it despawns. + LootTargetList completedLoot; }; #endif