fix(Core/Loot): (#7452)

- Players that did not participate in killing dungeon boss are not eligible to get loot.
- Players that are too far away from the looted object are not eligible to get loot.
- Players that released spirit and were outside the dungeon when the loot has been released are eligible to get loot.
- Players that have pending bind are not eligible to get loot.
- Properly get loot recipient for some chests in dungeons.
- All above fixes should work in any loot mode (group loot, master loot, etc.)
- Closes #2104.
This commit is contained in:
UltraNix
2021-08-24 23:48:22 +02:00
committed by GitHub
parent a594bf5b29
commit 1b7d3708a6
19 changed files with 197 additions and 97 deletions
+1 -1
View File
@@ -209,7 +209,7 @@ bool LootItemStorage::LoadStoredLoot(Item* item, Player* player)
if (loot->unlootedCount)
{
loot->FillNotNormalLootFor(player, true);
loot->FillNotNormalLootFor(player);
}
// Mark the item if it has loot so it won't be generated again on open
+16 -14
View File
@@ -510,7 +510,7 @@ void Loot::AddItem(LootStoreItem const& item)
}
// Calls processor of corresponding LootTemplate (which handles everything including references)
bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError, uint16 lootMode /*= LOOT_MODE_DEFAULT*/)
bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError, uint16 lootMode /*= LOOT_MODE_DEFAULT*/, WorldObject* lootSource /*= nullptr*/)
{
// Must be provided
if (!lootOwner)
@@ -541,9 +541,15 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
roundRobinPlayer = lootOwner->GetGUID();
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
if (player->IsInMap(lootOwner)) // pussywizard: multithreading crashfix
FillNotNormalLootFor(player, player->IsAtGroupRewardDistance(lootOwner));
{
if (Player* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
{
if (player->IsAtLootRewardDistance(lootSource ? lootSource : lootOwner))
{
FillNotNormalLootFor(player);
}
}
}
for (uint8 i = 0; i < items.size(); ++i)
{
@@ -554,12 +560,12 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
}
// ... for personal loot
else
FillNotNormalLootFor(lootOwner, true);
FillNotNormalLootFor(lootOwner);
return true;
}
void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting)
void Loot::FillNotNormalLootFor(Player* player)
{
ObjectGuid playerGuid = player->GetGUID();
@@ -573,11 +579,7 @@ void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting)
qmapitr = PlayerNonQuestNonFFAConditionalItems.find(playerGuid);
if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
FillNonQuestNonFFAConditionalLoot(player, presentAtLooting);
// if not auto-processed player will have to come and pick it up manually
if (!presentAtLooting)
return;
FillNonQuestNonFFAConditionalLoot(player);
// Process currency items
uint32 max_slot = GetMaxSlotInLootFor(player);
@@ -658,7 +660,7 @@ QuestItemList* Loot::FillQuestLoot(Player* player)
return ql;
}
QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting)
QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
{
QuestItemList* ql = new QuestItemList();
@@ -667,8 +669,8 @@ QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool pres
LootItem& item = items[i];
if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player) || (item.follow_loot_rules && player->GetGroup() && ((player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetMasterLooterGuid() == player->GetGUID()) || player->GetGroup()->GetLootMethod() != MASTER_LOOT ))))
{
if (presentAtLooting)
item.AddAllowedLooter(player);
item.AddAllowedLooter(player);
if (!item.conditions.empty())
{
ql->push_back(QuestItem(i));
+3 -3
View File
@@ -362,7 +362,7 @@ struct Loot
void RemoveLooter(ObjectGuid GUID) { PlayersLooting.erase(GUID); }
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount);
bool FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError = false, uint16 lootMode = LOOT_MODE_DEFAULT);
bool FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError = false, uint16 lootMode = LOOT_MODE_DEFAULT, WorldObject* lootSource = nullptr);
// Inserts the item into the loot (called by LootTemplate processors)
void AddItem(LootStoreItem const& item);
@@ -372,12 +372,12 @@ struct Loot
bool hasItemForAll() const;
bool hasItemFor(Player* player) const;
[[nodiscard]] bool hasOverThresholdItem() const;
void FillNotNormalLootFor(Player* player, bool presentAtLooting);
void FillNotNormalLootFor(Player* player);
private:
QuestItemList* FillFFALoot(Player* player);
QuestItemList* FillQuestLoot(Player* player);
QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting);
QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player);
typedef GuidSet PlayersLootingSet;
PlayersLootingSet PlayersLooting;