diff options
| author | Shauren <shauren.trinity@gmail.com> | 2022-09-01 20:07:58 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2022-09-01 20:07:58 +0200 |
| commit | 7957e2d380e08fa831765f610c0e29d2f3e11a04 (patch) | |
| tree | 55632f7f94edb3096360c983abbdd448d8dc79d7 /src/server/game/Entities | |
| parent | 62e5b52d2b91832889f02edc7bbd83ad474923e3 (diff) | |
Core/Loot: Allocate Loot separately from objects
Diffstat (limited to 'src/server/game/Entities')
| -rw-r--r-- | src/server/game/Entities/Corpse/Corpse.cpp | 1 | ||||
| -rw-r--r-- | src/server/game/Entities/Corpse/Corpse.h | 7 | ||||
| -rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 22 | ||||
| -rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 6 | ||||
| -rw-r--r-- | src/server/game/Entities/Creature/Trainer.cpp | 1 | ||||
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 10 | ||||
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp | 1 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/Item.h | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/Object/Object.h | 3 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 73 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 28 |
13 files changed, 88 insertions, 79 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(); |
