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_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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-19
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user