aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2022-09-01 20:07:58 +0200
committerShauren <shauren.trinity@gmail.com>2022-09-01 20:07:58 +0200
commit7957e2d380e08fa831765f610c0e29d2f3e11a04 (patch)
tree55632f7f94edb3096360c983abbdd448d8dc79d7
parent62e5b52d2b91832889f02edc7bbd83ad474923e3 (diff)
Core/Loot: Allocate Loot separately from objects
-rw-r--r--src/server/game/Entities/Corpse/Corpse.cpp1
-rw-r--r--src/server/game/Entities/Corpse/Corpse.h7
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp22
-rw-r--r--src/server/game/Entities/Creature/Creature.h6
-rw-r--r--src/server/game/Entities/Creature/Trainer.cpp1
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp10
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h5
-rw-r--r--src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp1
-rw-r--r--src/server/game/Entities/Item/Item.cpp5
-rw-r--r--src/server/game/Entities/Item/Item.h5
-rw-r--r--src/server/game/Entities/Object/Object.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp73
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp28
-rw-r--r--src/server/game/Groups/Group.cpp4
-rw-r--r--src/server/game/Handlers/LootHandler.cpp106
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp1
-rw-r--r--src/server/game/Loot/Loot.cpp2
-rw-r--r--src/server/game/Loot/Loot.h2
-rw-r--r--src/server/game/Loot/LootItemStorage.cpp3
-rw-r--r--src/server/game/Mails/Mail.cpp1
-rw-r--r--src/server/game/Server/Packets/ItemPacketsCommon.cpp1
-rw-r--r--src/server/game/Spells/Spell.cpp4
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp31
-rw-r--r--src/server/scripts/Outland/zone_nagrand.cpp1
24 files changed, 186 insertions, 137 deletions
diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp
index c0e267c6b28..e5085e73849 100644
--- a/src/server/game/Entities/Corpse/Corpse.cpp
+++ b/src/server/game/Entities/Corpse/Corpse.cpp
@@ -22,6 +22,7 @@
#include "DB2Stores.h"
#include "GameTime.h"
#include "Log.h"
+#include "Loot.h"
#include "Map.h"
#include "PhasingHandler.h"
#include "Player.h"
diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h
index 5d65e858ae3..b54742c3e9c 100644
--- a/src/server/game/Entities/Corpse/Corpse.h
+++ b/src/server/game/Entities/Corpse/Corpse.h
@@ -23,7 +23,8 @@
#include "DatabaseEnvFwd.h"
#include "GridDefines.h"
#include "IteratorPair.h"
-#include "Loot.h"
+
+struct Loot;
enum CorpseType
{
@@ -124,7 +125,9 @@ class TC_GAME_API Corpse : public WorldObject, public GridObject<Corpse>
CellCoord const& GetCellCoord() const { return _cellCoord; }
void SetCellCoord(CellCoord const& cellCoord) { _cellCoord = cellCoord; }
- Loot loot; // remove insignia ONLY at BG
+ std::unique_ptr<Loot> m_loot;
+ Loot* GetLootForPlayer(Player const* /*player*/) const override { return m_loot.get(); }
+
Player* lootRecipient;
bool IsExpired(time_t t) const;
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index e0bd742ca5c..ea00b2c8e6d 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -304,7 +304,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
return true;
}
-Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), m_groupLootTimer(0), m_PlayerDamageReq(0), _pickpocketLootRestore(0),
+Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), m_PlayerDamageReq(0), _pickpocketLootRestore(0),
m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_ignoreCorpseDecayRatio(false), m_wanderDistance(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE),
m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(UI64LIT(0)), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_cannotReachTarget(false), m_cannotReachTimer(0),
m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0),
@@ -325,6 +325,8 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), m_grou
m_isTempWorldObject = false;
}
+Creature::~Creature() = default;
+
void Creature::AddToWorld()
{
///- Register the creature for guid lookup
@@ -421,7 +423,7 @@ void Creature::RemoveCorpse(bool setSpawnTime, bool destroyForNearbyPlayers)
m_corpseRemoveTime = GameTime::GetGameTime();
setDeathState(DEAD);
RemoveAllAuras();
- loot.clear();
+ m_loot = nullptr;
uint32 respawnDelay = m_respawnDelay;
if (CreatureAI* ai = AI())
ai->CorpseRemoved(respawnDelay);
@@ -516,10 +518,6 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/)
if (!cinfo)
cinfo = normalInfo;
- // Initialize loot duplicate count depending on raid difficulty
- if (GetMap()->Is25ManRaid())
- loot.maxDuplicates = 3;
-
SetEntry(entry); // normal entry always
m_creatureInfo = cinfo; // map mode related always
@@ -777,12 +775,12 @@ void Creature::Update(uint32 diff)
if (IsEngaged())
Unit::AIUpdateTick(diff);
- if (m_groupLootTimer && !lootingGroupLowGUID.IsEmpty())
+ if (m_loot && m_groupLootTimer && !lootingGroupLowGUID.IsEmpty())
{
if (m_groupLootTimer <= diff)
{
if (Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID))
- group->EndRoll(&loot, GetMap());
+ group->EndRoll(m_loot.get(), GetMap());
m_groupLootTimer = 0;
lootingGroupLowGUID.Clear();
@@ -1817,8 +1815,6 @@ bool Creature::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap,
// checked at creature_template loading
m_defaultMovementType = MovementGeneratorType(data->movementType);
- loot.SetGUID(ObjectGuid::Create<HighGuid::LootObject>(GetMapId(), data->id, GetMap()->GenerateLowGuid<HighGuid::LootObject>()));
-
if (addToMap && !GetMap()->AddToMap(this))
return false;
return true;
@@ -2209,7 +2205,7 @@ void Creature::Respawn(bool force)
TC_LOG_DEBUG("entities.unit", "Respawning creature %s (%s)", GetName().c_str(), GetGUID().ToString().c_str());
m_respawnTime = 0;
ResetPickPocketRefillTimer();
- loot.clear();
+ m_loot = nullptr;
if (m_originalEntry != GetEntry())
UpdateEntry(m_originalEntry);
@@ -2849,7 +2845,7 @@ void Creature::RefreshCanSwimFlag(bool recheck)
void Creature::AllLootRemovedFromCorpse()
{
- if (loot.loot_type != LOOT_SKINNING && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient())
+ if ((!m_loot || m_loot->loot_type != LOOT_SKINNING) && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient())
if (LootTemplates_Skinning.HaveLootFor(GetCreatureTemplate()->SkinLootId))
SetUnitFlag(UNIT_FLAG_SKINNABLE);
@@ -2862,7 +2858,7 @@ void Creature::AllLootRemovedFromCorpse()
float decayRate = m_ignoreCorpseDecayRatio ? 1.f : sWorld->getRate(RATE_CORPSE_DECAY_LOOTED);
// corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
- if (loot.loot_type == LOOT_SKINNING)
+ if (m_loot && m_loot->loot_type == LOOT_SKINNING)
m_corpseRemoveTime = now;
else
m_corpseRemoveTime = now + uint32(m_corpseDelay * decayRate);
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 0f5e4882ced..6caabee9ad0 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -23,7 +23,6 @@
#include "CreatureData.h"
#include "DatabaseEnvFwd.h"
#include "Duration.h"
-#include "Loot.h"
#include "GridObject.h"
#include "MapObject.h"
#include <list>
@@ -35,6 +34,7 @@ class Quest;
class Player;
class SpellInfo;
class WorldSession;
+struct Loot;
enum MovementGeneratorType : uint8;
@@ -70,6 +70,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
{
public:
explicit Creature(bool isWorldObject = false);
+ ~Creature();
void AddToWorld() override;
void RemoveFromWorld() override;
@@ -223,7 +224,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
virtual void SaveToDB(uint32 mapid, std::vector<Difficulty> const& spawnDifficulties);
static bool DeleteFromDB(ObjectGuid::LowType spawnId);
- Loot loot;
+ std::unique_ptr<Loot> m_loot;
void StartPickPocketRefillTimer();
void ResetPickPocketRefillTimer() { _pickpocketLootRestore = 0; }
bool CanGeneratePickPocketLoot() const;
@@ -232,6 +233,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
Group* GetLootRecipientGroup() const;
bool hasLootRecipient() const { return !m_lootRecipient.IsEmpty() || !m_lootRecipientGroup.IsEmpty(); }
bool isTappedBy(Player const* player) const; // return true if the creature is tapped by the player or a member of his party.
+ Loot* GetLootForPlayer(Player const* /*player*/) const override { return m_loot.get(); }
void SetLootRecipient (Unit* unit, bool withGroup = true);
void AllLootRemovedFromCorpse();
diff --git a/src/server/game/Entities/Creature/Trainer.cpp b/src/server/game/Entities/Creature/Trainer.cpp
index 11c7bfc57f5..24a75bfd1d3 100644
--- a/src/server/game/Entities/Creature/Trainer.cpp
+++ b/src/server/game/Entities/Creature/Trainer.cpp
@@ -17,6 +17,7 @@
#include "Trainer.h"
#include "BattlePetMgr.h"
+#include "ConditionMgr.h"
#include "Creature.h"
#include "Log.h"
#include "NPCPackets.h"
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index a3c199a4a1a..c789fc6f64b 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -825,10 +825,6 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD
LastUsedScriptID = GetGOInfo()->ScriptId;
AIM_Initialize();
- // Initialize loot duplicate count depending on raid difficulty
- if (map->Is25ManRaid())
- loot.maxDuplicates = 3;
-
if (spawnid)
m_spawnId = spawnid;
@@ -1177,12 +1173,12 @@ void GameObject::Update(uint32 diff)
}
break;
case GAMEOBJECT_TYPE_CHEST:
- if (m_groupLootTimer)
+ if (m_loot && m_groupLootTimer)
{
if (m_groupLootTimer <= diff)
{
if (Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID))
- group->EndRoll(&loot, GetMap());
+ group->EndRoll(m_loot.get(), GetMap());
m_groupLootTimer = 0;
lootingGroupLowGUID.Clear();
@@ -1269,7 +1265,7 @@ void GameObject::Update(uint32 diff)
return;
}
- loot.clear();
+ m_loot = nullptr;
// Do not delete chests or goobers that are not consumed on loot, while still allowing them to despawn when they expire if summoned
bool isSummonedAndExpired = (GetOwner() || GetSpellId()) && m_respawnTime == 0;
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index e345f9a147d..133c1c4e460 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -21,7 +21,6 @@
#include "Object.h"
#include "GridObject.h"
#include "GameObjectData.h"
-#include "Loot.h"
#include "MapObject.h"
#include "SharedDefines.h"
@@ -33,6 +32,7 @@ class OPvPCapturePoint;
class Transport;
class TransportBase;
class Unit;
+struct Loot;
struct TransportAnimation;
enum TriggerCastFlags : uint32;
@@ -279,13 +279,14 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
void SaveRespawnTime(uint32 forceDelay = 0);
- Loot loot;
+ std::unique_ptr<Loot> m_loot;
Player* GetLootRecipient() const;
Group* GetLootRecipientGroup() const;
void SetLootRecipient(Unit* unit, Group* group = nullptr);
bool IsLootAllowedFor(Player const* player) const;
bool HasLootRecipient() const { return !m_lootRecipient.IsEmpty() || !m_lootRecipientGroup.IsEmpty(); }
+ Loot* GetLootForPlayer(Player const* /*player*/) const override { return m_loot.get(); }
uint32 m_groupLootTimer; // (msecs)timer used for group loot
ObjectGuid lootingGroupLowGUID; // used to find group which is looting
diff --git a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp
index 21662ee9d96..ae86e0ab97e 100644
--- a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp
+++ b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp
@@ -17,6 +17,7 @@
#include "AzeriteItem.h"
#include "AzeritePackets.h"
+#include "ConditionMgr.h"
#include "DatabaseEnv.h"
#include "DB2Stores.h"
#include "GameObject.h"
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index d52519fa164..464706d5538 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -31,6 +31,7 @@
#include "ItemEnchantmentMgr.h"
#include "ItemPackets.h"
#include "Log.h"
+#include "Loot.h"
#include "LootItemStorage.h"
#include "LootMgr.h"
#include "Map.h"
@@ -805,7 +806,7 @@ void Item::SaveToDB(CharacterDatabaseTransaction trans)
CharacterDatabase.CommitTransaction(trans);
// Delete the items if this is a container
- if (!loot.isLooted())
+ if (m_loot && !m_loot->isLooted())
sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
delete this;
@@ -1117,7 +1118,7 @@ void Item::DeleteFromDB(CharacterDatabaseTransaction trans)
DeleteFromDB(trans, GetGUID().GetCounter());
// Delete the items if this is a container
- if (!loot.isLooted())
+ if (m_loot && !m_loot->isLooted())
sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
}
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 8e7aebc7660..6a778e0fe65 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -25,11 +25,11 @@
#include "ItemEnchantmentMgr.h"
#include "ItemTemplate.h"
#include "IteratorPair.h"
-#include "Loot.h"
class SpellInfo;
class Bag;
class Unit;
+struct Loot;
namespace WorldPackets
{
namespace Item
@@ -313,8 +313,9 @@ class TC_GAME_API Item : public Object
int32 GetSpellCharges(uint8 index/*0..5*/ = 0) const { return m_itemData->SpellCharges[index]; }
void SetSpellCharges(uint8 index/*0..5*/, int32 value) { SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::SpellCharges, index), value); }
- Loot loot;
+ std::unique_ptr<Loot> m_loot;
bool m_lootGenerated;
+ Loot* GetLootForPlayer(Player const* /*player*/) const override { return m_loot.get(); }
// Update States
ItemUpdateState GetState() const { return uState; }
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 46b3f7b8a03..85a5c829498 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -61,6 +61,7 @@ class WorldObject;
class WorldPacket;
class ZoneScript;
struct FactionTemplateEntry;
+struct Loot;
struct PositionFullTerrainStatus;
struct QuaternionData;
enum ZLiquidStatus : uint32;
@@ -259,6 +260,8 @@ class TC_GAME_API Object
virtual std::string GetDebugInfo() const;
+ virtual Loot* GetLootForPlayer([[maybe_unused]] Player const* player) const { return nullptr; }
+
protected:
Object();
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index c645129b356..5c97a5a5261 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -8755,9 +8755,22 @@ void Player::RemovedInsignia(Player* looterPlr)
// Now we must make bones lootable, and send player loot
bones->SetCorpseDynamicFlag(CORPSE_DYNFLAG_LOOTABLE);
- // We store the level of our player in the gold field
- // We retrieve this information at Player::SendLoot()
- bones->loot.gold = GetLevel();
+ bones->m_loot.reset(new Loot());
+ bones->m_loot->SetGUID(ObjectGuid::Create<HighGuid::LootObject>(GetMapId(), 0, GetMap()->GenerateLowGuid<HighGuid::LootObject>()));
+
+ // For AV Achievement
+ if (Battleground* bg = GetBattleground())
+ {
+ if (bg->GetTypeID(true) == BATTLEGROUND_AV)
+ bones->m_loot->FillLoot(PLAYER_CORPSE_LOOT_ENTRY, LootTemplates_Creature, this, true);
+ }
+ // For wintergrasp Quests
+ else if (GetZoneId() == AREA_WINTERGRASP)
+ bones->m_loot->FillLoot(PLAYER_CORPSE_LOOT_ENTRY, LootTemplates_Creature, this, true);
+
+ // It may need a better formula
+ // Now it works like this: lvl10: ~6copper, lvl70: ~9silver
+ bones->m_loot->gold = uint32(urand(50, 150) * 0.016f * std::pow(float(GetLevel()) / 5.76f, 2.5f) * sWorld->getRate(RATE_DROP_MONEY));
bones->lootRecipient = looterPlr;
looterPlr->SendLoot(bones->GetGUID(), LOOT_INSIGNIA);
}
@@ -8819,12 +8832,12 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
return;
}
- loot = &go->loot;
+ loot = go->GetLootForPlayer(this);
// loot was generated and respawntime has passed since then, allow to recreate loot
// to avoid bugs, this rule covers spawned gameobjects only
// Don't allow to regenerate chest loot inside instances and raids, to avoid exploits with duplicate boss loot being given for some encounters
- if (go->isSpawnedByDefault() && go->getLootState() == GO_ACTIVATED && !go->loot.isLooted() && !go->GetMap()->Instanceable() && go->GetLootGenerationTime() + go->GetRespawnDelay() < GameTime::GetGameTime())
+ if (go->isSpawnedByDefault() && go->getLootState() == GO_ACTIVATED && (!loot || !loot->isLooted()) && !go->GetMap()->Instanceable() && go->GetLootGenerationTime() + go->GetRespawnDelay() < GameTime::GetGameTime())
go->SetLootState(GO_READY);
if (go->getLootState() == GO_READY)
@@ -8837,6 +8850,13 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
return;
}
+ loot = new Loot();
+ loot->SetGUID(ObjectGuid::Create<HighGuid::LootObject>(go->GetMapId(), 0, go->GetMap()->GenerateLowGuid<HighGuid::LootObject>()));
+ if (go->GetMap()->Is25ManRaid())
+ loot->maxDuplicates = 3;
+
+ go->m_loot.reset(loot);
+
if (lootid)
{
loot->clear();
@@ -8852,7 +8872,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
go->SetLootGenerationTime();
// get next RR player (for next loot)
- if (groupRules && !go->loot.empty())
+ if (groupRules && !loot->empty())
group->UpdateLooterGuid(go);
}
@@ -8920,14 +8940,16 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
permission = OWNER_PERMISSION;
- loot = &item->loot;
+ loot = item->GetLootForPlayer(this);
// If item doesn't already have loot, attempt to load it. If that
// fails then this is first time opening, generate loot
if (!item->m_lootGenerated && !sLootItemStorage->LoadStoredLoot(item, this))
{
item->m_lootGenerated = true;
- loot->clear();
+ loot = new Loot();
+ loot->SetGUID(ObjectGuid::Create<HighGuid::LootObject>(GetMapId(), 0, GetMap()->GenerateLowGuid<HighGuid::LootObject>()));
+ item->m_loot.reset(loot);
switch (loot_type)
{
@@ -8963,29 +8985,9 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
return;
}
- loot = &bones->loot;
-
- if (loot->loot_type == LOOT_NONE)
- {
- uint32 pLevel = bones->loot.gold;
- bones->loot.clear();
-
- // For AV Achievement
- if (Battleground* bg = GetBattleground())
- {
- if (bg->GetTypeID(true) == BATTLEGROUND_AV)
- loot->FillLoot(PLAYER_CORPSE_LOOT_ENTRY, LootTemplates_Creature, this, true);
- }
- // For wintergrasp Quests
- else if (GetZoneId() == AREA_WINTERGRASP)
- loot->FillLoot(PLAYER_CORPSE_LOOT_ENTRY, LootTemplates_Creature, this, true);
-
- // It may need a better formula
- // Now it works like this: lvl10: ~6copper, lvl70: ~9silver
- bones->loot.gold = uint32(urand(50, 150) * 0.016f * std::pow(float(pLevel) / 5.76f, 2.5f) * sWorld->getRate(RATE_DROP_MONEY));
- }
+ loot = bones->GetLootForPlayer(this);
- if (bones->lootRecipient != this)
+ if (bones->lootRecipient && bones->lootRecipient != this)
permission = NONE_PERMISSION;
else
permission = OWNER_PERMISSION;
@@ -9007,7 +9009,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
return;
}
- loot = &creature->loot;
+ loot = creature->GetLootForPlayer(this);
if (loot_type == LOOT_PICKPOCKETING)
{
@@ -9129,7 +9131,8 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
}
// need know merged fishing/corpse loot type for achievements
- loot->loot_type = loot_type;
+ if (loot)
+ loot->loot_type = loot_type;
if (permission != NONE_PERMISSION)
{
@@ -9167,7 +9170,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
SetUnitFlag(UNIT_FLAG_LOOTING);
}
else
- SendLootError(loot->GetGUID(), guid, LOOT_ERROR_DIDNT_KILL);
+ SendLootError(loot ? loot->GetGUID() : ObjectGuid::Empty, guid, LOOT_ERROR_DIDNT_KILL);
}
void Player::SendLootError(ObjectGuid const& lootObj, ObjectGuid const& owner, LootError error) const
@@ -18186,8 +18189,8 @@ bool Player::isAllowedToLoot(const Creature* creature) const
if (HasPendingBind())
return false;
- Loot const* loot = &creature->loot;
- if (loot->isLooted()) // nothing to loot or everything looted.
+ Loot const* loot = creature->GetLootForPlayer(this);
+ if (!loot || loot->isLooted()) // nothing to loot or everything looted.
return false;
if (!loot->hasItemForAll() && !loot->hasItemFor(this)) // no loot in creature for this player
return false;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 65827ede11b..993295b668f 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -10658,24 +10658,17 @@ void Unit::SetMeleeAnimKitId(uint16 animKitId)
}
}
else
- {
player->SendDirectMessage(partyKillLog.Write());
- if (creature)
- {
- WorldPackets::Loot::LootList lootList;
- lootList.Owner = creature->GetGUID();
- lootList.LootObj = creature->loot.GetGUID();
-
- player->SendMessageToSet(lootList.Write(), true);
- }
- }
-
// Generate loot before updating looter
if (creature)
{
- Loot* loot = &creature->loot;
- loot->clear();
+ creature->m_loot.reset(new Loot());
+ Loot* loot = creature->m_loot.get();
+ loot->SetGUID(ObjectGuid::Create<HighGuid::LootObject>(creature->GetMapId(), 0, creature->GetMap()->GenerateLowGuid<HighGuid::LootObject>()));
+ if (creature->GetMap()->Is25ManRaid())
+ loot->maxDuplicates = 3;
+
if (uint32 lootid = creature->GetCreatureTemplate()->lootid)
loot->FillLoot(lootid, LootTemplates_Creature, looter, false, false, creature->GetLootMode(), creature->GetMap()->GetDifficultyLootItemContext());
@@ -10693,6 +10686,13 @@ void Unit::SetMeleeAnimKitId(uint16 animKitId)
if (!loot->empty())
group->UpdateLooterGuid(creature);
}
+ else
+ {
+ WorldPackets::Loot::LootList lootList;
+ lootList.Owner = creature->GetGUID();
+ lootList.LootObj = creature->m_loot->GetGUID();
+ player->SendMessageToSet(lootList.Write(), true);
+ }
}
player->RewardPlayerAndGroupAtKill(victim, false);
@@ -10785,7 +10785,7 @@ void Unit::SetMeleeAnimKitId(uint16 animKitId)
if (!creature->IsPet())
{
// must be after setDeathState which resets dynamic flags
- if (!creature->loot.isLooted())
+ if (creature->m_loot && !creature->m_loot->isLooted())
creature->SetDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
else
creature->AllLootRemovedFromCorpse();
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 272b21c5366..e371053dfac 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1024,9 +1024,9 @@ void Group::SendLooter(Creature* creature, Player* groupLooter)
WorldPackets::Loot::LootList lootList;
lootList.Owner = creature->GetGUID();
- lootList.LootObj = creature->loot.GetGUID();
+ lootList.LootObj = creature->m_loot->GetGUID();
- if (GetLootMethod() == MASTER_LOOT && creature->loot.hasOverThresholdItem())
+ if (GetLootMethod() == MASTER_LOOT && creature->m_loot->hasOverThresholdItem())
lootList.Master = GetMasterLooterGuid();
if (groupLooter)
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index 615f574d08e..2d161ab7694 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -78,13 +78,13 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p
GameObject* go = player->GetMap()->GetGameObject(lguid);
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
- if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player)))
+ if (!go || ((go->GetOwnerGUID() != player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(player)))
{
player->SendLootRelease(lguid);
continue;
}
- loot = &go->loot;
+ loot = go->GetLootForPlayer(player);
}
else if (lguid.IsItem())
{
@@ -96,7 +96,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p
continue;
}
- loot = &pItem->loot;
+ loot = pItem->GetLootForPlayer(player);
}
else if (lguid.IsCorpse())
{
@@ -107,20 +107,35 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p
continue;
}
- loot = &bones->loot;
+ loot = bones->GetLootForPlayer(player);
}
else
{
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
+ if (!creature)
+ {
+ player->SendLootError(req.Object, lguid, LOOT_ERROR_NO_LOOT);
+ continue;
+ }
- bool lootAllowed = creature && creature->IsAlive() == (player->GetClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
- if (!lootAllowed || !creature->IsWithinDistInMap(_player, AELootCreatureCheck::LootDistance))
+ if (!creature->IsWithinDistInMap(player, AELootCreatureCheck::LootDistance))
{
- player->SendLootError(req.Object, lguid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL);
+ player->SendLootError(req.Object, lguid, LOOT_ERROR_TOO_FAR);
continue;
}
- loot = &creature->loot;
+ loot = creature->GetLootForPlayer(player);
+ if (creature->IsAlive() != (loot && loot->loot_type == LOOT_PICKPOCKETING))
+ {
+ player->SendLootError(req.Object, lguid, LOOT_ERROR_DIDNT_KILL);
+ continue;
+ }
+ }
+
+ if (!loot)
+ {
+ player->SendLootRelease(lguid);
+ continue;
}
player->StoreLootItem(lguid, req.LootListID - 1, loot, aeResultPtr);
@@ -161,7 +176,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet
// do not check distance for GO if player is the owner of it (ex. fishing bobber)
if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player))))
- loot = &go->loot;
+ loot = go->GetLootForPlayer(player);
break;
}
@@ -171,7 +186,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet
if (bones && bones->IsWithinDistInMap(player, INTERACTION_DISTANCE))
{
- loot = &bones->loot;
+ loot = bones->GetLootForPlayer(player);
shareMoney = false;
}
@@ -181,7 +196,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet
{
if (Item* item = player->GetItemByGuid(guid))
{
- loot = &item->loot;
+ loot = item->GetLootForPlayer(player);
shareMoney = false;
}
break;
@@ -190,15 +205,27 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet
case HighGuid::Vehicle:
{
Creature* creature = player->GetMap()->GetCreature(guid);
- bool lootAllowed = creature && creature->IsAlive() == (player->GetClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
- if (lootAllowed && creature->IsWithinDistInMap(player, AELootCreatureCheck::LootDistance))
+ if (!creature)
{
- loot = &creature->loot;
- if (creature->IsAlive())
- shareMoney = false;
+ player->SendLootError(lootView.first, guid, LOOT_ERROR_NO_LOOT);
+ continue;
}
- else
- player->SendLootError(lootView.first, lootView.second, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL);
+
+ if (!creature->IsWithinDistInMap(player, AELootCreatureCheck::LootDistance))
+ {
+ player->SendLootError(lootView.first, guid, LOOT_ERROR_TOO_FAR);
+ continue;
+ }
+
+ loot = creature->GetLootForPlayer(player);
+ if (creature->IsAlive() != (loot && loot->loot_type == LOOT_PICKPOCKETING))
+ {
+ player->SendLootError(lootView.first, guid, LOOT_ERROR_DIDNT_KILL);
+ continue;
+ }
+
+ if (loot && loot->loot_type != LOOT_CORPSE)
+ shareMoney = false;
break;
}
default:
@@ -330,10 +357,10 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
GameObject* go = GetPlayer()->GetMap()->GetGameObject(lguid);
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
- if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player)))
+ if (!go || ((go->GetOwnerGUID() != player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(player)))
return;
- loot = &go->loot;
+ loot = go->GetLootForPlayer(player);
if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR)
{
@@ -368,12 +395,12 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
else if (lguid.IsCorpse()) // ONLY remove insignia at BG
{
Corpse* corpse = ObjectAccessor::GetCorpse(*player, lguid);
- if (!corpse || !corpse->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
+ if (!corpse || !corpse->IsWithinDistInMap(player, INTERACTION_DISTANCE))
return;
- loot = &corpse->loot;
+ loot = corpse->GetLootForPlayer(player);
- if (loot->isLooted())
+ if (loot && loot->isLooted())
{
loot->clear();
corpse->RemoveCorpseDynamicFlag(CORPSE_DYNFLAG_LOOTABLE);
@@ -387,11 +414,13 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
ItemTemplate const* proto = pItem->GetTemplate();
+ loot = pItem->GetLootForPlayer(player);
+
// destroy only 5 items from stack in case prospecting and milling
- if (pItem->loot.loot_type == LOOT_PROSPECTING || pItem->loot.loot_type == LOOT_MILLING)
+ if (loot && (loot->loot_type == LOOT_PROSPECTING || loot->loot_type == LOOT_MILLING))
{
pItem->m_lootGenerated = false;
- pItem->loot.clear();
+ pItem->m_loot.reset();
uint32 count = pItem->GetCount();
@@ -404,7 +433,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
else
{
// Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item
- if (pItem->loot.isLooted() || !proto->HasFlag(ITEM_FLAG_HAS_LOOT))
+ if ((loot && loot->isLooted()) || !proto->HasFlag(ITEM_FLAG_HAS_LOOT))
player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true);
}
return; // item can be looted only single player
@@ -412,21 +441,23 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
else
{
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
+ if (!creature)
+ return;
- bool lootAllowed = creature && creature->IsAlive() == (player->GetClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
- if (!lootAllowed || !creature->IsWithinDistInMap(_player, AELootCreatureCheck::LootDistance))
+ if (!creature->IsWithinDistInMap(player, AELootCreatureCheck::LootDistance))
return;
- loot = &creature->loot;
- if (loot->isLooted())
+ loot = creature->GetLootForPlayer(player);
+ if (creature->IsAlive() != (loot && loot->loot_type == LOOT_PICKPOCKETING))
+ return;
+
+ if (!loot || loot->isLooted())
{
creature->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
// skip pickpocketing loot for speed, skinning timer reduction is no-op in fact
if (!creature->IsAlive())
creature->AllLootRemovedFromCorpse();
-
- loot->clear();
}
else
{
@@ -444,7 +475,8 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
}
//Player is not looking at loot list, he doesn't need to see updates on the loot list
- loot->RemoveLooter(player->GetGUID());
+ if (loot)
+ loot->RemoveLooter(player->GetGUID());
}
void WorldSession::DoLootReleaseAll()
@@ -492,15 +524,15 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPackets::Loot::MasterLootItem
if (!creature)
return;
- loot = &creature->loot;
+ loot = creature->GetLootForPlayer(_player);
}
else if (GetPlayer()->GetLootGUID().IsGameObject())
{
- GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid);
- if (!pGO)
+ GameObject* go = GetPlayer()->GetMap()->GetGameObject(lootguid);
+ if (!go)
return;
- loot = &pGO->loot;
+ loot = go->GetLootForPlayer(_player);
}
if (!loot)
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index a189a8022b1..824676b8967 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -26,6 +26,7 @@
#include "GuildMgr.h"
#include "Item.h"
#include "Log.h"
+#include "Loot.h"
#include "Map.h"
#include "Player.h"
#include "ObjectAccessor.h"
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp
index b05156c1ba9..7445d96dc71 100644
--- a/src/server/game/Loot/Loot.cpp
+++ b/src/server/game/Loot/Loot.cpp
@@ -125,7 +125,7 @@ void LootItem::AddAllowedLooter(const Player* player)
// --------- Loot ---------
//
-Loot::Loot(uint32 _gold /*= 0*/) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_NONE), maxDuplicates(1), _itemContext(ItemContext::NONE)
+Loot::Loot() : gold(0), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_NONE), maxDuplicates(1), _itemContext(ItemContext::NONE)
{
}
diff --git a/src/server/game/Loot/Loot.h b/src/server/game/Loot/Loot.h
index d5d1f771f08..ae96d14393d 100644
--- a/src/server/game/Loot/Loot.h
+++ b/src/server/game/Loot/Loot.h
@@ -220,7 +220,7 @@ struct TC_GAME_API Loot
LootType loot_type; // required for achievement system
uint8 maxDuplicates; // Max amount of items with the same entry that can drop (default is 1; on 25 man raid mode 3)
- Loot(uint32 _gold = 0);
+ Loot();
~Loot();
ObjectGuid const& GetGUID() const { return _GUID; }
diff --git a/src/server/game/Loot/LootItemStorage.cpp b/src/server/game/Loot/LootItemStorage.cpp
index e1cf342fd4d..69b68acde70 100644
--- a/src/server/game/Loot/LootItemStorage.cpp
+++ b/src/server/game/Loot/LootItemStorage.cpp
@@ -19,6 +19,7 @@
#include "Item.h"
#include "ItemTemplate.h"
#include "Log.h"
+#include "Loot.h"
#include "LootItemStorage.h"
#include "LootMgr.h"
#include "ObjectMgr.h"
@@ -136,7 +137,7 @@ void LootItemStorage::LoadStorageFromDB()
bool LootItemStorage::LoadStoredLoot(Item* item, Player* player)
{
- Loot* loot = &item->loot;
+ Loot* loot = item->GetLootForPlayer(player);
StoredLootContainer const* container = nullptr;
// read
diff --git a/src/server/game/Mails/Mail.cpp b/src/server/game/Mails/Mail.cpp
index dfdba81f51e..7f633f5c49c 100644
--- a/src/server/game/Mails/Mail.cpp
+++ b/src/server/game/Mails/Mail.cpp
@@ -24,6 +24,7 @@
#include "GameTime.h"
#include "Item.h"
#include "Log.h"
+#include "Loot.h"
#include "LootMgr.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
diff --git a/src/server/game/Server/Packets/ItemPacketsCommon.cpp b/src/server/game/Server/Packets/ItemPacketsCommon.cpp
index 6c12a6dde1e..a022a0b3783 100644
--- a/src/server/game/Server/Packets/ItemPacketsCommon.cpp
+++ b/src/server/game/Server/Packets/ItemPacketsCommon.cpp
@@ -17,6 +17,7 @@
#include "ItemPacketsCommon.h"
#include "Item.h"
+#include "Loot.h"
#include "Player.h"
namespace WorldPackets
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index d461c4298f7..f49f0495339 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -37,6 +37,7 @@
#include "InstanceScript.h"
#include "Item.h"
#include "Log.h"
+#include "Loot.h"
#include "LootMgr.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
@@ -5996,7 +5997,8 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
return SPELL_FAILED_TARGET_UNSKINNABLE;
Creature* creature = m_targets.GetUnitTarget()->ToCreature();
- if (!creature->IsCritter() && !creature->loot.isLooted())
+ Loot* loot = creature->GetLootForPlayer(m_caster->ToPlayer());
+ if (loot && !loot->isLooted())
return SPELL_FAILED_TARGET_NOT_LOOTED;
uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill();
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index e48c800b294..9fcf544b0ec 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -32,6 +32,7 @@ EndScriptData */
#include "FollowMovementGenerator.h"
#include "GameTime.h"
#include "Language.h"
+#include "Loot.h"
#include "Map.h"
#include "MotionMaster.h"
#include "MovementDefines.h"
@@ -1198,8 +1199,8 @@ public:
return false;
}
- Loot const& loot = creatureTarget->loot;
- if (!creatureTarget->isDead() || loot.empty())
+ Loot const* loot = creatureTarget->m_loot.get();
+ if (!creatureTarget->isDead() || !loot || loot->empty())
{
handler->PSendSysMessage(LANG_COMMAND_NOT_DEAD_OR_NO_LOOT, creatureTarget->GetName().c_str());
handler->SetSentErrorMessage(true);
@@ -1207,43 +1208,43 @@ public:
}
handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_HEADER, creatureTarget->GetName().c_str(), creatureTarget->GetEntry());
- handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_MONEY, loot.gold / GOLD, (loot.gold%GOLD) / SILVER, loot.gold%SILVER);
+ handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_MONEY, loot->gold / GOLD, (loot->gold % GOLD) / SILVER, loot->gold % SILVER);
if (!all)
{
- handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Standard items", loot.items.size());
- for (LootItem const& item : loot.items)
+ handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Standard items", loot->items.size());
+ for (LootItem const& item : loot->items)
if (!item.is_looted)
_ShowLootEntry(handler, item.itemid, item.count);
- handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Quest items", loot.quest_items.size());
- for (LootItem const& item : loot.quest_items)
+ handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Quest items", loot->quest_items.size());
+ for (LootItem const& item : loot->quest_items)
if (!item.is_looted)
_ShowLootEntry(handler, item.itemid, item.count);
}
else
{
- handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Standard items", loot.items.size());
- for (LootItem const& item : loot.items)
+ handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Standard items", loot->items.size());
+ for (LootItem const& item : loot->items)
if (!item.is_looted && !item.freeforall && item.conditions.empty())
_ShowLootEntry(handler, item.itemid, item.count);
- if (!loot.GetPlayerQuestItems().empty())
+ if (!loot->GetPlayerQuestItems().empty())
{
handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "Per-player quest items");
- _IterateNotNormalLootMap(handler, loot.GetPlayerQuestItems(), loot.quest_items);
+ _IterateNotNormalLootMap(handler, loot->GetPlayerQuestItems(), loot->quest_items);
}
- if (!loot.GetPlayerFFAItems().empty())
+ if (!loot->GetPlayerFFAItems().empty())
{
handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "FFA items per allowed player");
- _IterateNotNormalLootMap(handler, loot.GetPlayerFFAItems(), loot.items);
+ _IterateNotNormalLootMap(handler, loot->GetPlayerFFAItems(), loot->items);
}
- if (!loot.GetPlayerNonQuestNonFFAConditionalItems().empty())
+ if (!loot->GetPlayerNonQuestNonFFAConditionalItems().empty())
{
handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL_2, "Per-player conditional items");
- _IterateNotNormalLootMap(handler, loot.GetPlayerNonQuestNonFFAConditionalItems(), loot.items);
+ _IterateNotNormalLootMap(handler, loot->GetPlayerNonQuestNonFFAConditionalItems(), loot->items);
}
}
diff --git a/src/server/scripts/Outland/zone_nagrand.cpp b/src/server/scripts/Outland/zone_nagrand.cpp
index 37f5ec0a41a..4d29f5e639b 100644
--- a/src/server/scripts/Outland/zone_nagrand.cpp
+++ b/src/server/scripts/Outland/zone_nagrand.cpp
@@ -27,6 +27,7 @@ npc_maghar_captive
EndContentData */
#include "ScriptMgr.h"
+#include "ConditionMgr.h"
#include "GameObjectAI.h"
#include "MotionMaster.h"
#include "Player.h"