mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-06 04:23:47 +00:00
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:
@@ -1139,22 +1139,48 @@ void Creature::SetLootRecipient(Unit* unit, bool withGroup)
|
||||
m_lootRecipient.Clear();
|
||||
m_lootRecipientGroup = 0;
|
||||
RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE | UNIT_DYNFLAG_TAPPED);
|
||||
ResetAllowedLooters();
|
||||
return;
|
||||
}
|
||||
|
||||
//if (unit->GetTypeId() != TYPEID_PLAYER && !unit->IsVehicle())
|
||||
// return;
|
||||
|
||||
Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if (!player) // normal creature, no player involved
|
||||
return;
|
||||
|
||||
m_lootRecipient = player->GetGUID();
|
||||
|
||||
Map* map = GetMap();
|
||||
if (map && map->IsDungeon() && (isWorldBoss() || IsDungeonBoss()))
|
||||
{
|
||||
AddAllowedLooter(m_lootRecipient);
|
||||
}
|
||||
|
||||
if (withGroup)
|
||||
{
|
||||
if (Group* group = player->GetGroup())
|
||||
{
|
||||
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
|
||||
m_lootRecipientGroup = 0;
|
||||
|
||||
@@ -198,6 +198,7 @@ public:
|
||||
Loot loot;
|
||||
[[nodiscard]] ObjectGuid GetLootRecipientGUID() const { return m_lootRecipient; }
|
||||
[[nodiscard]] Player* GetLootRecipient() const;
|
||||
[[nodiscard]] ObjectGuid::LowType GetLootRecipientGroupGUID() const { return m_lootRecipientGroup; }
|
||||
[[nodiscard]] Group* GetLootRecipientGroup() const;
|
||||
[[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.
|
||||
@@ -374,7 +375,7 @@ protected:
|
||||
static float _GetHealthMod(int32 Rank);
|
||||
|
||||
ObjectGuid m_lootRecipient;
|
||||
uint32 m_lootRecipientGroup;
|
||||
ObjectGuid::LowType m_lootRecipientGroup;
|
||||
|
||||
/// Timers
|
||||
time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance
|
||||
|
||||
@@ -2305,29 +2305,60 @@ Group* GameObject::GetLootRecipientGroup() const
|
||||
return sGroupMgr->GetGroupByGUID(m_lootRecipientGroup);
|
||||
}
|
||||
|
||||
void GameObject::SetLootRecipient(Unit* unit)
|
||||
void GameObject::SetLootRecipient(Creature* creature)
|
||||
{
|
||||
// set the player whose group should receive the right
|
||||
// to loot the creature after it dies
|
||||
// should be set to nullptr after the loot disappears
|
||||
|
||||
if (!unit)
|
||||
if (!creature)
|
||||
{
|
||||
m_lootRecipient.Clear();
|
||||
m_lootRecipientGroup = 0;
|
||||
ResetAllowedLooters();
|
||||
return;
|
||||
}
|
||||
|
||||
if (unit->GetTypeId() != TYPEID_PLAYER && !unit->IsVehicle())
|
||||
return;
|
||||
m_lootRecipient = creature->GetLootRecipientGUID();
|
||||
m_lootRecipientGroup = creature->GetLootRecipientGroupGUID();
|
||||
SetAllowedLooters(creature->GetAllowedLooters());
|
||||
}
|
||||
|
||||
Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if (!player) // normal creature, no player involved
|
||||
return;
|
||||
void GameObject::SetLootRecipient(Map* map)
|
||||
{
|
||||
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 (Group* group = player->GetGroup())
|
||||
m_lootRecipientGroup = group->GetGUID().GetCounter();
|
||||
if (!m_lootRecipient)
|
||||
{
|
||||
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
|
||||
|
||||
@@ -863,7 +863,8 @@ public:
|
||||
|
||||
[[nodiscard]] Player* GetLootRecipient() const;
|
||||
[[nodiscard]] Group* GetLootRecipientGroup() const;
|
||||
void SetLootRecipient(Unit* unit);
|
||||
void SetLootRecipient(Creature* creature);
|
||||
void SetLootRecipient(Map* map);
|
||||
bool IsLootAllowedFor(Player const* player) const;
|
||||
[[nodiscard]] bool HasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; }
|
||||
uint32 m_groupLootTimer; // (msecs)timer used for group loot
|
||||
@@ -982,7 +983,7 @@ protected:
|
||||
Position m_stationaryPosition;
|
||||
|
||||
ObjectGuid m_lootRecipient;
|
||||
uint32 m_lootRecipientGroup;
|
||||
ObjectGuid::LowType m_lootRecipientGroup;
|
||||
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
|
||||
uint32 m_lootGenerationTime;
|
||||
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)));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1047,6 +1047,12 @@ public:
|
||||
[[nodiscard]] virtual float GetCollisionWidth() const { return GetObjectSize(); }
|
||||
[[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:
|
||||
std::string m_name;
|
||||
bool m_isActive;
|
||||
@@ -1091,6 +1097,8 @@ private:
|
||||
bool CanDetectInvisibilityOf(WorldObject const* obj) const;
|
||||
//bool CanDetectStealthOf(WorldObject const* obj) const;
|
||||
bool CanDetectStealthOf(WorldObject const* obj, bool checkAlert = false) const;
|
||||
|
||||
GuidUnorderedSet _allowedLooters;
|
||||
};
|
||||
|
||||
namespace Acore
|
||||
|
||||
@@ -7560,7 +7560,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
||||
if (groupRules)
|
||||
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();
|
||||
|
||||
// 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
|
||||
{
|
||||
if (!pRewardSource || !IsInMap(pRewardSource))
|
||||
return false;
|
||||
const WorldObject* player = GetCorpse();
|
||||
WorldObject const* player = GetCorpse();
|
||||
if (!player || IsAlive())
|
||||
{
|
||||
player = this;
|
||||
}
|
||||
|
||||
if (!pRewardSource || !player->IsInMap(pRewardSource))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pRewardSource->GetMap()->IsDungeon())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (!pOther)
|
||||
|
||||
@@ -1996,6 +1996,7 @@ public:
|
||||
void InitDisplayIds();
|
||||
|
||||
bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const;
|
||||
bool IsAtLootRewardDistance(WorldObject const* pRewardSource) const;
|
||||
bool IsAtRecruitAFriendDistance(WorldObject const* pOther) const;
|
||||
void RewardPlayerAndGroupAtKill(Unit* victim, bool isBattleGround);
|
||||
void RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewardSource);
|
||||
|
||||
@@ -16935,7 +16935,7 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
|
||||
else if (Group* lrg = creature->GetLootRecipientGroup())
|
||||
for (GroupReference* itr = lrg->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
if (Player* member = itr->GetSource())
|
||||
if (member->IsAtGroupRewardDistance(creature))
|
||||
if (member->IsAtLootRewardDistance(creature))
|
||||
{
|
||||
player = member;
|
||||
break;
|
||||
@@ -16997,7 +16997,7 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp
|
||||
loot->clear();
|
||||
|
||||
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())
|
||||
loot->generateMoneyLoot(creature->GetCreatureTemplate()->mingold, creature->GetCreatureTemplate()->maxgold);
|
||||
|
||||
Reference in New Issue
Block a user