mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-17 13:39:46 -04:00
Core/Loot: Allocate Loot separately from objects
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "Trainer.h"
|
||||
#include "BattlePetMgr.h"
|
||||
#include "ConditionMgr.h"
|
||||
#include "Creature.h"
|
||||
#include "Log.h"
|
||||
#include "NPCPackets.h"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "AzeriteItem.h"
|
||||
#include "AzeritePackets.h"
|
||||
#include "ConditionMgr.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "GameObject.h"
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
loot = bones->GetLootForPlayer(this);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
bool lootAllowed = creature && creature->IsAlive() == (player->GetClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
|
||||
if (!lootAllowed || !creature->IsWithinDistInMap(_player, AELootCreatureCheck::LootDistance))
|
||||
if (!creature)
|
||||
{
|
||||
player->SendLootError(req.Object, lguid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL);
|
||||
player->SendLootError(req.Object, lguid, LOOT_ERROR_NO_LOOT);
|
||||
continue;
|
||||
}
|
||||
|
||||
loot = &creature->loot;
|
||||
if (!creature->IsWithinDistInMap(player, AELootCreatureCheck::LootDistance))
|
||||
{
|
||||
player->SendLootError(req.Object, lguid, LOOT_ERROR_TOO_FAR);
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
bool lootAllowed = creature && creature->IsAlive() == (player->GetClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
|
||||
if (!lootAllowed || !creature->IsWithinDistInMap(_player, AELootCreatureCheck::LootDistance))
|
||||
if (!creature)
|
||||
return;
|
||||
|
||||
loot = &creature->loot;
|
||||
if (loot->isLooted())
|
||||
if (!creature->IsWithinDistInMap(player, AELootCreatureCheck::LootDistance))
|
||||
return;
|
||||
|
||||
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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "ItemPacketsCommon.h"
|
||||
#include "Item.h"
|
||||
#include "Loot.h"
|
||||
#include "Player.h"
|
||||
|
||||
namespace WorldPackets
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ npc_maghar_captive
|
||||
EndContentData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ConditionMgr.h"
|
||||
#include "GameObjectAI.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "Player.h"
|
||||
|
||||
Reference in New Issue
Block a user