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
+29 -3
View File
@@ -1139,22 +1139,48 @@ void Creature::SetLootRecipient(Unit* unit, bool withGroup)
m_lootRecipient.Clear(); m_lootRecipient.Clear();
m_lootRecipientGroup = 0; m_lootRecipientGroup = 0;
RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE | UNIT_DYNFLAG_TAPPED); RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE | UNIT_DYNFLAG_TAPPED);
ResetAllowedLooters();
return; return;
} }
//if (unit->GetTypeId() != TYPEID_PLAYER && !unit->IsVehicle())
// return;
Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself(); Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!player) // normal creature, no player involved if (!player) // normal creature, no player involved
return; return;
m_lootRecipient = player->GetGUID(); m_lootRecipient = player->GetGUID();
Map* map = GetMap();
if (map && map->IsDungeon() && (isWorldBoss() || IsDungeonBoss()))
{
AddAllowedLooter(m_lootRecipient);
}
if (withGroup) if (withGroup)
{ {
if (Group* group = player->GetGroup()) if (Group* group = player->GetGroup())
{
m_lootRecipientGroup = group->GetGUID().GetCounter(); m_lootRecipientGroup = group->GetGUID().GetCounter();
if (map && map->IsDungeon() && (isWorldBoss() || IsDungeonBoss()))
{
Map::PlayerList const& PlayerList = map->GetPlayers();
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
if (Player* groupMember = i->GetSource())
{
if (groupMember->IsGameMaster() || groupMember->IsSpectator())
{
continue;
}
if (groupMember->GetGroup() == group)
{
AddAllowedLooter(groupMember->GetGUID());
}
}
}
}
}
} }
else else
m_lootRecipientGroup = 0; m_lootRecipientGroup = 0;
+2 -1
View File
@@ -198,6 +198,7 @@ public:
Loot loot; Loot loot;
[[nodiscard]] ObjectGuid GetLootRecipientGUID() const { return m_lootRecipient; } [[nodiscard]] ObjectGuid GetLootRecipientGUID() const { return m_lootRecipient; }
[[nodiscard]] Player* GetLootRecipient() const; [[nodiscard]] Player* GetLootRecipient() const;
[[nodiscard]] ObjectGuid::LowType GetLootRecipientGroupGUID() const { return m_lootRecipientGroup; }
[[nodiscard]] Group* GetLootRecipientGroup() const; [[nodiscard]] Group* GetLootRecipientGroup() const;
[[nodiscard]] bool hasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; } [[nodiscard]] bool hasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; }
bool isTappedBy(Player const* player) const; // return true if the creature is tapped by the player or a member of his party. bool isTappedBy(Player const* player) const; // return true if the creature is tapped by the player or a member of his party.
@@ -374,7 +375,7 @@ protected:
static float _GetHealthMod(int32 Rank); static float _GetHealthMod(int32 Rank);
ObjectGuid m_lootRecipient; ObjectGuid m_lootRecipient;
uint32 m_lootRecipientGroup; ObjectGuid::LowType m_lootRecipientGroup;
/// Timers /// Timers
time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance
@@ -2305,29 +2305,60 @@ Group* GameObject::GetLootRecipientGroup() const
return sGroupMgr->GetGroupByGUID(m_lootRecipientGroup); return sGroupMgr->GetGroupByGUID(m_lootRecipientGroup);
} }
void GameObject::SetLootRecipient(Unit* unit) void GameObject::SetLootRecipient(Creature* creature)
{ {
// set the player whose group should receive the right // set the player whose group should receive the right
// to loot the creature after it dies // to loot the creature after it dies
// should be set to nullptr after the loot disappears // should be set to nullptr after the loot disappears
if (!creature)
if (!unit)
{ {
m_lootRecipient.Clear(); m_lootRecipient.Clear();
m_lootRecipientGroup = 0; m_lootRecipientGroup = 0;
ResetAllowedLooters();
return; return;
} }
if (unit->GetTypeId() != TYPEID_PLAYER && !unit->IsVehicle()) m_lootRecipient = creature->GetLootRecipientGUID();
return; m_lootRecipientGroup = creature->GetLootRecipientGroupGUID();
SetAllowedLooters(creature->GetAllowedLooters());
}
Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself(); void GameObject::SetLootRecipient(Map* map)
if (!player) // normal creature, no player involved {
return; Group* group = nullptr;
Map::PlayerList const& PlayerList = map->GetPlayers();
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
if (Player* groupMember = i->GetSource())
{
if (groupMember->IsGameMaster() || groupMember->IsSpectator())
{
continue;
}
m_lootRecipient = player->GetGUID(); if (!m_lootRecipient)
if (Group* group = player->GetGroup()) {
m_lootRecipientGroup = group->GetGUID().GetCounter(); m_lootRecipient = groupMember->GetGUID();
}
Group* memberGroup = groupMember->GetGroup();
if (memberGroup && !group)
{
group = memberGroup;
m_lootRecipientGroup = group->GetGUID().GetCounter();
}
if (memberGroup == group)
{
AddAllowedLooter(groupMember->GetGUID());
}
}
}
if (!group)
{
AddAllowedLooter(m_lootRecipient);
}
} }
bool GameObject::IsLootAllowedFor(Player const* player) const bool GameObject::IsLootAllowedFor(Player const* player) const
@@ -863,7 +863,8 @@ public:
[[nodiscard]] Player* GetLootRecipient() const; [[nodiscard]] Player* GetLootRecipient() const;
[[nodiscard]] Group* GetLootRecipientGroup() const; [[nodiscard]] Group* GetLootRecipientGroup() const;
void SetLootRecipient(Unit* unit); void SetLootRecipient(Creature* creature);
void SetLootRecipient(Map* map);
bool IsLootAllowedFor(Player const* player) const; bool IsLootAllowedFor(Player const* player) const;
[[nodiscard]] bool HasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; } [[nodiscard]] bool HasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; }
uint32 m_groupLootTimer; // (msecs)timer used for group loot uint32 m_groupLootTimer; // (msecs)timer used for group loot
@@ -982,7 +983,7 @@ protected:
Position m_stationaryPosition; Position m_stationaryPosition;
ObjectGuid m_lootRecipient; ObjectGuid m_lootRecipient;
uint32 m_lootRecipientGroup; ObjectGuid::LowType m_lootRecipientGroup;
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
uint32 m_lootGenerationTime; uint32 m_lootGenerationTime;
private: private:
@@ -3036,3 +3036,33 @@ float WorldObject::GetFloorZ() const
return std::max<float>(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ() + std::max(GetCollisionHeight(), Z_OFFSET_FIND_HEIGHT))); return std::max<float>(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ() + std::max(GetCollisionHeight(), Z_OFFSET_FIND_HEIGHT)));
} }
void WorldObject::AddAllowedLooter(ObjectGuid guid)
{
_allowedLooters.insert(guid);
}
void WorldObject::SetAllowedLooters(GuidUnorderedSet const looters)
{
_allowedLooters = looters;
}
void WorldObject::ResetAllowedLooters()
{
_allowedLooters.clear();
}
bool WorldObject::HasAllowedLooter(ObjectGuid guid) const
{
if (_allowedLooters.empty())
{
return true;
}
return _allowedLooters.find(guid) != _allowedLooters.end();
}
GuidUnorderedSet const& WorldObject::GetAllowedLooters() const
{
return _allowedLooters;
}
+8
View File
@@ -1047,6 +1047,12 @@ public:
[[nodiscard]] virtual float GetCollisionWidth() const { return GetObjectSize(); } [[nodiscard]] virtual float GetCollisionWidth() const { return GetObjectSize(); }
[[nodiscard]] virtual float GetCollisionRadius() const { return GetObjectSize() / 2; } [[nodiscard]] virtual float GetCollisionRadius() const { return GetObjectSize() / 2; }
void AddAllowedLooter(ObjectGuid guid);
void ResetAllowedLooters();
void SetAllowedLooters(GuidUnorderedSet const looters);
[[nodiscard]] bool HasAllowedLooter(ObjectGuid guid) const;
[[nodiscard]] GuidUnorderedSet const& GetAllowedLooters() const;
protected: protected:
std::string m_name; std::string m_name;
bool m_isActive; bool m_isActive;
@@ -1091,6 +1097,8 @@ private:
bool CanDetectInvisibilityOf(WorldObject const* obj) const; bool CanDetectInvisibilityOf(WorldObject const* obj) const;
//bool CanDetectStealthOf(WorldObject const* obj) const; //bool CanDetectStealthOf(WorldObject const* obj) const;
bool CanDetectStealthOf(WorldObject const* obj, bool checkAlert = false) const; bool CanDetectStealthOf(WorldObject const* obj, bool checkAlert = false) const;
GuidUnorderedSet _allowedLooters;
}; };
namespace Acore namespace Acore
+26 -4
View File
@@ -7560,7 +7560,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
if (groupRules) if (groupRules)
group->UpdateLooterGuid(go, true); group->UpdateLooterGuid(go, true);
loot->FillLoot(lootid, LootTemplates_Gameobject, this, !groupRules, false, go->GetLootMode()); loot->FillLoot(lootid, LootTemplates_Gameobject, this, !groupRules, false, go->GetLootMode(), go);
go->SetLootGenerationTime(); go->SetLootGenerationTime();
// get next RR player (for next loot) // get next RR player (for next loot)
@@ -11846,18 +11846,40 @@ void Player::RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewar
bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
{ {
if (!pRewardSource || !IsInMap(pRewardSource)) WorldObject const* player = GetCorpse();
return false;
const WorldObject* player = GetCorpse();
if (!player || IsAlive()) if (!player || IsAlive())
{
player = this; player = this;
}
if (!pRewardSource || !player->IsInMap(pRewardSource))
{
return false;
}
if (pRewardSource->GetMap()->IsDungeon()) if (pRewardSource->GetMap()->IsDungeon())
{
return true; return true;
}
return pRewardSource->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE); return pRewardSource->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE);
} }
bool Player::IsAtLootRewardDistance(WorldObject const* pRewardSource) const
{
if (!IsAtGroupRewardDistance(pRewardSource))
{
return false;
}
if (HasPendingBind())
{
return false;
}
return pRewardSource->HasAllowedLooter(GetGUID());
}
bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const
{ {
if (!pOther) if (!pOther)
+1
View File
@@ -1996,6 +1996,7 @@ public:
void InitDisplayIds(); void InitDisplayIds();
bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const; bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const;
bool IsAtLootRewardDistance(WorldObject const* pRewardSource) const;
bool IsAtRecruitAFriendDistance(WorldObject const* pOther) const; bool IsAtRecruitAFriendDistance(WorldObject const* pOther) const;
void RewardPlayerAndGroupAtKill(Unit* victim, bool isBattleGround); void RewardPlayerAndGroupAtKill(Unit* victim, bool isBattleGround);
void RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewardSource); void RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewardSource);
+2 -2
View File
@@ -16935,7 +16935,7 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
else if (Group* lrg = creature->GetLootRecipientGroup()) else if (Group* lrg = creature->GetLootRecipientGroup())
for (GroupReference* itr = lrg->GetFirstMember(); itr != nullptr; itr = itr->next()) for (GroupReference* itr = lrg->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource()) if (Player* member = itr->GetSource())
if (member->IsAtGroupRewardDistance(creature)) if (member->IsAtLootRewardDistance(creature))
{ {
player = member; player = member;
break; break;
@@ -16997,7 +16997,7 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
loot->clear(); loot->clear();
if (uint32 lootid = creature->GetCreatureTemplate()->lootid) if (uint32 lootid = creature->GetCreatureTemplate()->lootid)
loot->FillLoot(lootid, LootTemplates_Creature, looter, false, false, creature->GetLootMode()); loot->FillLoot(lootid, LootTemplates_Creature, looter, false, false, creature->GetLootMode(), creature);
if (creature->GetLootMode()) if (creature->GetLootMode())
loot->generateMoneyLoot(creature->GetCreatureTemplate()->mingold, creature->GetCreatureTemplate()->maxgold); loot->generateMoneyLoot(creature->GetCreatureTemplate()->mingold, creature->GetCreatureTemplate()->maxgold);
+23 -22
View File
@@ -964,7 +964,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member) if (!member)
continue; continue;
if (member->IsAtGroupRewardDistance(pLootedObject)) if (member->IsAtLootRewardDistance(pLootedObject))
{ {
if (i->AllowedForPlayer(member)) if (i->AllowedForPlayer(member))
{ {
@@ -1048,7 +1048,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject)
if (!member) if (!member)
continue; continue;
if (member->IsAtGroupRewardDistance(pLootedObject)) if (member->IsAtLootRewardDistance(pLootedObject))
{ {
if (i->AllowedForPlayer(member)) if (i->AllowedForPlayer(member))
{ {
@@ -1108,7 +1108,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject)
if (!playerToRoll) if (!playerToRoll)
continue; continue;
if (i->AllowedForPlayer(playerToRoll) && playerToRoll->IsAtGroupRewardDistance(lootedObject)) if (i->AllowedForPlayer(playerToRoll) && playerToRoll->IsAtLootRewardDistance(lootedObject))
{ {
r->totalPlayersRolling++; r->totalPlayersRolling++;
if (playerToRoll->GetPassOnGroupLoot()) if (playerToRoll->GetPassOnGroupLoot())
@@ -1182,7 +1182,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject)
if (!playerToRoll) if (!playerToRoll)
continue; continue;
if (i->AllowedForPlayer(playerToRoll) && playerToRoll->IsAtGroupRewardDistance(lootedObject)) if (i->AllowedForPlayer(playerToRoll) && playerToRoll->IsAtLootRewardDistance(lootedObject))
{ {
r->totalPlayersRolling++; r->totalPlayersRolling++;
r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
@@ -1247,31 +1247,32 @@ void Group::MasterLoot(Loot* loot, WorldObject* pLootedObject)
i->is_blocked = !i->is_underthreshold; i->is_blocked = !i->is_underthreshold;
} }
uint32 real_count = 0; std::vector<Player*> looters;
WorldPacket data(SMSG_LOOT_MASTER_LIST, 330);
data << (uint8)GetMembersCount();
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next())
{ {
Player* looter = itr->GetSource(); Player* looter = itr->GetSource();
if (!looter->IsInWorld()) if (!looter->IsInWorld())
continue;
if (looter->IsAtGroupRewardDistance(pLootedObject))
{ {
data << looter->GetGUID(); continue;
++real_count; }
if (looter->IsAtLootRewardDistance(pLootedObject))
{
looters.push_back(looter);
} }
} }
data.put<uint8>(0, real_count); WorldPacket data(SMSG_LOOT_MASTER_LIST, 1 + looters.size() * (1 + 8));
data << uint8(looters.size());
for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) for (Player* looter : looters)
{ {
Player* looter = itr->GetSource(); data << looter->GetGUID();
if (looter->IsAtGroupRewardDistance(pLootedObject)) }
looter->GetSession()->SendPacket(&data);
for (Player* looter : looters)
{
looter->GetSession()->SendPacket(&data);
} }
} }
@@ -1775,7 +1776,7 @@ void Group::UpdateLooterGuid(WorldObject* pLootedObject, bool ifneed)
{ {
// not update if only update if need and ok // not update if only update if need and ok
Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid); Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid);
if (looter && looter->IsAtGroupRewardDistance(pLootedObject)) if (looter && looter->IsAtLootRewardDistance(pLootedObject))
return; return;
} }
++guid_itr; ++guid_itr;
@@ -1786,7 +1787,7 @@ void Group::UpdateLooterGuid(WorldObject* pLootedObject, bool ifneed)
for (member_citerator itr = guid_itr; itr != m_memberSlots.end(); ++itr) for (member_citerator itr = guid_itr; itr != m_memberSlots.end(); ++itr)
{ {
if (Player* player = ObjectAccessor::FindPlayer(itr->guid)) if (Player* player = ObjectAccessor::FindPlayer(itr->guid))
if (player->IsAtGroupRewardDistance(pLootedObject)) if (player->IsAtLootRewardDistance(pLootedObject))
{ {
pNewLooter = player; pNewLooter = player;
break; break;
@@ -1799,7 +1800,7 @@ void Group::UpdateLooterGuid(WorldObject* pLootedObject, bool ifneed)
for (member_citerator itr = m_memberSlots.begin(); itr != guid_itr; ++itr) for (member_citerator itr = m_memberSlots.begin(); itr != guid_itr; ++itr)
{ {
if (Player* player = ObjectAccessor::FindPlayer(itr->guid)) if (Player* player = ObjectAccessor::FindPlayer(itr->guid))
if (player->IsAtGroupRewardDistance(pLootedObject)) if (player->IsAtLootRewardDistance(pLootedObject))
{ {
pNewLooter = player; pNewLooter = player;
break; break;
+1 -1
View File
@@ -170,7 +170,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
if (!member) if (!member)
continue; continue;
if (player->IsAtGroupRewardDistance(member)) if (player->IsAtLootRewardDistance(member))
playersNear.push_back(member); playersNear.push_back(member);
} }
+1 -1
View File
@@ -209,7 +209,7 @@ bool LootItemStorage::LoadStoredLoot(Item* item, Player* player)
if (loot->unlootedCount) 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 // 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) // 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 // Must be provided
if (!lootOwner) if (!lootOwner)
@@ -541,9 +541,15 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
roundRobinPlayer = lootOwner->GetGUID(); roundRobinPlayer = lootOwner->GetGUID();
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) 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 if (Player* player = itr->GetSource()) // should actually be looted object instead of lootOwner but looter has to be really close so doesnt really matter
FillNotNormalLootFor(player, player->IsAtGroupRewardDistance(lootOwner)); {
if (player->IsAtLootRewardDistance(lootSource ? lootSource : lootOwner))
{
FillNotNormalLootFor(player);
}
}
}
for (uint8 i = 0; i < items.size(); ++i) 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 // ... for personal loot
else else
FillNotNormalLootFor(lootOwner, true); FillNotNormalLootFor(lootOwner);
return true; return true;
} }
void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting) void Loot::FillNotNormalLootFor(Player* player)
{ {
ObjectGuid playerGuid = player->GetGUID(); ObjectGuid playerGuid = player->GetGUID();
@@ -573,11 +579,7 @@ void Loot::FillNotNormalLootFor(Player* player, bool presentAtLooting)
qmapitr = PlayerNonQuestNonFFAConditionalItems.find(playerGuid); qmapitr = PlayerNonQuestNonFFAConditionalItems.find(playerGuid);
if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end()) if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end())
FillNonQuestNonFFAConditionalLoot(player, presentAtLooting); FillNonQuestNonFFAConditionalLoot(player);
// if not auto-processed player will have to come and pick it up manually
if (!presentAtLooting)
return;
// Process currency items // Process currency items
uint32 max_slot = GetMaxSlotInLootFor(player); uint32 max_slot = GetMaxSlotInLootFor(player);
@@ -658,7 +660,7 @@ QuestItemList* Loot::FillQuestLoot(Player* player)
return ql; return ql;
} }
QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting) QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
{ {
QuestItemList* ql = new QuestItemList(); QuestItemList* ql = new QuestItemList();
@@ -667,8 +669,8 @@ QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool pres
LootItem& item = items[i]; 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 (!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()) if (!item.conditions.empty())
{ {
ql->push_back(QuestItem(i)); ql->push_back(QuestItem(i));
+3 -3
View File
@@ -362,7 +362,7 @@ struct Loot
void RemoveLooter(ObjectGuid GUID) { PlayersLooting.erase(GUID); } void RemoveLooter(ObjectGuid GUID) { PlayersLooting.erase(GUID); }
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount); 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) // Inserts the item into the loot (called by LootTemplate processors)
void AddItem(LootStoreItem const& item); void AddItem(LootStoreItem const& item);
@@ -372,12 +372,12 @@ struct Loot
bool hasItemForAll() const; bool hasItemForAll() const;
bool hasItemFor(Player* player) const; bool hasItemFor(Player* player) const;
[[nodiscard]] bool hasOverThresholdItem() const; [[nodiscard]] bool hasOverThresholdItem() const;
void FillNotNormalLootFor(Player* player, bool presentAtLooting); void FillNotNormalLootFor(Player* player);
private: private:
QuestItemList* FillFFALoot(Player* player); QuestItemList* FillFFALoot(Player* player);
QuestItemList* FillQuestLoot(Player* player); QuestItemList* FillQuestLoot(Player* player);
QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting); QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player);
typedef GuidSet PlayersLootingSet; typedef GuidSet PlayersLootingSet;
PlayersLootingSet PlayersLooting; PlayersLootingSet PlayersLooting;
@@ -127,7 +127,7 @@ public:
else if (HelpersKilled == MAX_ACTIVE_HELPERS) else if (HelpersKilled == MAX_ACTIVE_HELPERS)
{ {
me->loot.clear(); me->loot.clear();
me->loot.FillLoot(me->GetCreatureTemplate()->lootid, LootTemplates_Creature, me->GetLootRecipient(), false, false, 1); me->loot.FillLoot(me->GetCreatureTemplate()->lootid, LootTemplates_Creature, me->GetLootRecipient(), false, false, 1, me);
instance->SetData(DATA_DELRISSA_EVENT, DONE); instance->SetData(DATA_DELRISSA_EVENT, DONE);
me->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); me->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
} }
@@ -425,17 +425,10 @@ public:
cacheEntry = GO_CRUSADERS_CACHE_25_H; cacheEntry = GO_CRUSADERS_CACHE_25_H;
break; break;
} }
if (GameObject* go = c->SummonGameObject(cacheEntry, Locs[LOC_CENTER].GetPositionX(), Locs[LOC_CENTER].GetPositionY(), Locs[LOC_CENTER].GetPositionZ(), Locs[LOC_CENTER].GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 630000000)) if (GameObject* go = c->SummonGameObject(cacheEntry, Locs[LOC_CENTER].GetPositionX(), Locs[LOC_CENTER].GetPositionY(), Locs[LOC_CENTER].GetPositionZ(), Locs[LOC_CENTER].GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 630000000))
{ {
Map::PlayerList const& pl = instance->GetPlayers(); go->SetLootRecipient(instance);
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
if (Player* plr = itr->GetSource())
if (Group* g = plr->GetGroup())
if (!plr->IsGameMaster() && g->GetLeaderGUID() == plr->GetGUID())
{
go->SetLootRecipient(plr);
break;
}
} }
} }
@@ -1375,16 +1368,7 @@ public:
if (GameObject* chest = c->SummonGameObject(tributeChest, 665.12f, 143.78f, 142.12f, 0.0f, 0, 0, 0, 0, 90000000)) if (GameObject* chest = c->SummonGameObject(tributeChest, 665.12f, 143.78f, 142.12f, 0.0f, 0, 0, 0, 0, 90000000))
{ {
chest->SetRespawnTime(chest->GetRespawnDelay()); chest->SetRespawnTime(chest->GetRespawnDelay());
chest->SetLootRecipient(instance);
Map::PlayerList const& pl = instance->GetPlayers();
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
if (Player* plr = itr->GetSource())
if (Group* g = plr->GetGroup())
if (!plr->IsGameMaster() && g->GetLeaderGUID() == plr->GetGUID())
{
chest->SetLootRecipient(plr);
break;
}
} }
} }
} }
@@ -760,7 +760,7 @@ public:
case GO_CACHE_OF_THE_DREAMWALKER_10H: case GO_CACHE_OF_THE_DREAMWALKER_10H:
case GO_CACHE_OF_THE_DREAMWALKER_25H: case GO_CACHE_OF_THE_DREAMWALKER_25H:
if (Creature* valithria = instance->GetCreature(ValithriaDreamwalkerGUID)) if (Creature* valithria = instance->GetCreature(ValithriaDreamwalkerGUID))
go->SetLootRecipient(valithria->GetLootRecipient()); go->SetLootRecipient(valithria);
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN); go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN);
break; break;
case GO_SCOURGE_TRANSPORTER_LK: case GO_SCOURGE_TRANSPORTER_LK:
@@ -1029,14 +1029,7 @@ public:
{ {
if (GameObject* loot = instance->GetGameObject(GunshipArmoryGUID)) if (GameObject* loot = instance->GetGameObject(GunshipArmoryGUID))
{ {
Map::PlayerList const& pl = instance->GetPlayers(); loot->SetLootRecipient(instance);
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
if (Player* p = itr->GetSource())
if (!p->IsGameMaster() && p->GetGroup() && p->GetGroup()->isRaidGroup())
{
loot->SetLootRecipient(p);
break;
}
loot->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN); loot->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN);
} }
} }
@@ -1050,7 +1043,7 @@ public:
if (GameObject* loot = instance->GetGameObject(DeathbringersCacheGUID)) if (GameObject* loot = instance->GetGameObject(DeathbringersCacheGUID))
{ {
if (Creature* deathbringer = instance->GetCreature(DeathbringerSaurfangGUID)) if (Creature* deathbringer = instance->GetCreature(DeathbringerSaurfangGUID))
loot->SetLootRecipient(deathbringer->GetLootRecipient()); loot->SetLootRecipient(deathbringer);
loot->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN); loot->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE | GO_FLAG_NODESPAWN);
} }
[[fallthrough]]; [[fallthrough]];
@@ -211,7 +211,7 @@ public:
c->SetLootMode(1); c->SetLootMode(1);
c->loot.clear(); c->loot.clear();
if (uint32 lootid = c->GetCreatureTemplate()->lootid) if (uint32 lootid = c->GetCreatureTemplate()->lootid)
c->loot.FillLoot(lootid, LootTemplates_Creature, c->GetLootRecipient(), false, false, c->GetLootMode()); c->loot.FillLoot(lootid, LootTemplates_Creature, c->GetLootRecipient(), false, false, c->GetLootMode(), c);
if (c->GetLootMode()) if (c->GetLootMode())
c->loot.generateMoneyLoot(c->GetCreatureTemplate()->mingold, c->GetCreatureTemplate()->maxgold); c->loot.generateMoneyLoot(c->GetCreatureTemplate()->mingold, c->GetCreatureTemplate()->maxgold);
c->DestroyForNearbyPlayers(); c->DestroyForNearbyPlayers();
@@ -226,7 +226,7 @@ public:
c->SetLootMode(1); c->SetLootMode(1);
c->loot.clear(); c->loot.clear();
if (uint32 lootid = c->GetCreatureTemplate()->lootid) if (uint32 lootid = c->GetCreatureTemplate()->lootid)
c->loot.FillLoot(lootid, LootTemplates_Creature, c->GetLootRecipient(), false, false, c->GetLootMode()); c->loot.FillLoot(lootid, LootTemplates_Creature, c->GetLootRecipient(), false, false, c->GetLootMode(), c);
if (c->GetLootMode()) if (c->GetLootMode())
c->loot.generateMoneyLoot(c->GetCreatureTemplate()->mingold, c->GetCreatureTemplate()->maxgold); c->loot.generateMoneyLoot(c->GetCreatureTemplate()->mingold, c->GetCreatureTemplate()->maxgold);
c->DestroyForNearbyPlayers(); c->DestroyForNearbyPlayers();
@@ -104,7 +104,7 @@ public:
else if (actionId == MAX_ADD_NUMBER) else if (actionId == MAX_ADD_NUMBER)
{ {
me->loot.clear(); me->loot.clear();
me->loot.FillLoot(me->GetCreatureTemplate()->lootid, LootTemplates_Creature, me->GetLootRecipient(), false, false, 1); me->loot.FillLoot(me->GetCreatureTemplate()->lootid, LootTemplates_Creature, me->GetLootRecipient(), false, false, 1, me);
me->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); me->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
_JustDied(); _JustDied();
} }