Core/Loot: Allocate Loot separately from objects
Port From (https://github.com/TrinityCore/TrinityCore/commit/7957e2d380e08fa831765f610c0e29d2f3e11a04)
This commit is contained in:
@@ -38,7 +38,7 @@ namespace Game.Entities
|
||||
|
||||
m_updateFlag.Stationary = true;
|
||||
|
||||
m_corpseData = new CorpseData();
|
||||
m_corpseData = new();
|
||||
|
||||
m_time = GameTime.GetGameTime();
|
||||
}
|
||||
@@ -323,9 +323,11 @@ namespace Game.Entities
|
||||
public CellCoord GetCellCoord() { return _cellCoord; }
|
||||
public void SetCellCoord(CellCoord cellCoord) { _cellCoord = cellCoord; }
|
||||
|
||||
public override Loot GetLootForPlayer(Player player) { return loot; }
|
||||
|
||||
public CorpseData m_corpseData;
|
||||
|
||||
public Loot loot = new();
|
||||
public Loot loot;
|
||||
public Player lootRecipient;
|
||||
|
||||
CorpseType m_type;
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Game.Entities
|
||||
// vendor items
|
||||
List<VendorItemCount> m_vendorItemCounts = new();
|
||||
|
||||
public Loot loot = new();
|
||||
public Loot loot;
|
||||
public uint m_groupLootTimer; // (msecs)timer used for group loot
|
||||
public ObjectGuid lootingGroupLowGUID; // used to find group which is looting corpse
|
||||
ObjectGuid m_lootRecipient;
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace Game.Entities
|
||||
SetDeathState(DeathState.Dead);
|
||||
RemoveAllAuras();
|
||||
//DestroyForNearbyPlayers(); // old UpdateObjectVisibility()
|
||||
loot.Clear();
|
||||
loot = null;
|
||||
uint respawnDelay = m_respawnDelay;
|
||||
CreatureAI ai = GetAI();
|
||||
if (ai != null)
|
||||
@@ -256,10 +256,6 @@ namespace Game.Entities
|
||||
if (cInfo == null)
|
||||
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
|
||||
|
||||
@@ -511,7 +507,7 @@ namespace Game.Entities
|
||||
if (IsEngaged())
|
||||
AIUpdateTick(diff);
|
||||
|
||||
if (m_groupLootTimer != 0 && !lootingGroupLowGUID.IsEmpty())
|
||||
if (loot != null && m_groupLootTimer != 0 && !lootingGroupLowGUID.IsEmpty())
|
||||
{
|
||||
if (m_groupLootTimer <= diff)
|
||||
{
|
||||
@@ -1941,7 +1937,7 @@ namespace Game.Entities
|
||||
Log.outDebug(LogFilter.Unit, "Respawning creature {0} ({1})", GetName(), GetGUID().ToString());
|
||||
m_respawnTime = 0;
|
||||
ResetPickPocketRefillTimer();
|
||||
loot.Clear();
|
||||
loot = null;
|
||||
|
||||
if (m_originalEntry != GetEntry())
|
||||
UpdateEntry(m_originalEntry);
|
||||
@@ -2578,7 +2574,7 @@ namespace Game.Entities
|
||||
|
||||
public void AllLootRemovedFromCorpse()
|
||||
{
|
||||
if (loot.loot_type != LootType.Skinning && !IsPet() && GetCreatureTemplate().SkinLootId != 0 && HasLootRecipient())
|
||||
if ((loot == null || loot.loot_type != LootType.Skinning) && !IsPet() && GetCreatureTemplate().SkinLootId != 0 && HasLootRecipient())
|
||||
if (LootStorage.Skinning.HaveLootFor(GetCreatureTemplate().SkinLootId))
|
||||
SetUnitFlag(UnitFlags.Skinnable);
|
||||
|
||||
@@ -2591,7 +2587,7 @@ namespace Game.Entities
|
||||
float decayRate = m_ignoreCorpseDecayRatio ? 1.0f : WorldConfig.GetFloatValue(WorldCfg.RateCorpseDecayLooted);
|
||||
|
||||
// corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
|
||||
if (loot.loot_type == LootType.Skinning)
|
||||
if (loot != null && loot.loot_type == LootType.Skinning)
|
||||
m_corpseRemoveTime = now;
|
||||
else
|
||||
m_corpseRemoveTime = now + (uint)(m_corpseDelay * decayRate);
|
||||
@@ -3280,8 +3276,6 @@ namespace Game.Entities
|
||||
// checked at creature_template loading
|
||||
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;
|
||||
|
||||
@@ -373,10 +373,6 @@ namespace Game.Entities
|
||||
LastUsedScriptID = GetGoInfo().ScriptId;
|
||||
AIM_Initialize();
|
||||
|
||||
// Initialize loot duplicate count depending on raid difficulty
|
||||
if (map.Is25ManRaid())
|
||||
loot.maxDuplicates = 3;
|
||||
|
||||
if (spawnid != 0)
|
||||
m_spawnId = spawnid;
|
||||
|
||||
@@ -701,7 +697,7 @@ namespace Game.Entities
|
||||
}
|
||||
break;
|
||||
case GameObjectTypes.Chest:
|
||||
if (m_groupLootTimer != 0)
|
||||
if (loot != null && m_groupLootTimer != 0)
|
||||
{
|
||||
if (m_groupLootTimer <= diff)
|
||||
{
|
||||
@@ -805,7 +801,7 @@ namespace Game.Entities
|
||||
return;
|
||||
}
|
||||
|
||||
loot.Clear();
|
||||
loot = null;
|
||||
|
||||
// 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() != null || GetSpellId() != 0) && m_respawnTime == 0;
|
||||
@@ -3314,7 +3310,9 @@ namespace Game.Entities
|
||||
uint GetUniqueUseCount() { return (uint)m_unique_users.Count; }
|
||||
|
||||
bool HasLootRecipient() { return !m_lootRecipient.IsEmpty() || !m_lootRecipientGroup.IsEmpty(); }
|
||||
|
||||
|
||||
public override Loot GetLootForPlayer(Player player) { return loot; }
|
||||
|
||||
public override uint GetLevelForTarget(WorldObject target)
|
||||
{
|
||||
Unit owner = GetOwner();
|
||||
@@ -3441,7 +3439,7 @@ namespace Game.Entities
|
||||
Dictionary<uint, ObjectGuid> ChairListSlots = new();
|
||||
List<ObjectGuid> m_SkillupList = new();
|
||||
|
||||
public Loot loot = new();
|
||||
public Loot loot;
|
||||
|
||||
public GameObjectModel m_model;
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@ namespace Game.Entities
|
||||
uState = ItemUpdateState.New;
|
||||
uQueuePos = -1;
|
||||
m_lastPlayedTimeUpdate = GameTime.GetGameTime();
|
||||
|
||||
loot = new Loot();
|
||||
}
|
||||
|
||||
public virtual bool Create(ulong guidlow, uint itemId, ItemContext context, Player owner)
|
||||
@@ -386,7 +384,7 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
// Delete the items if this is a container
|
||||
if (!loot.IsLooted())
|
||||
if (loot != null && !loot.IsLooted())
|
||||
Global.LootItemStorage.RemoveStoredLootForContainer(GetGUID().GetCounter());
|
||||
|
||||
Dispose();
|
||||
@@ -689,7 +687,7 @@ namespace Game.Entities
|
||||
DeleteFromDB(trans, GetGUID().GetCounter());
|
||||
|
||||
// Delete the items if this is a container
|
||||
if (!loot.IsLooted())
|
||||
if (loot != null && !loot.IsLooted())
|
||||
Global.LootItemStorage.RemoveStoredLootForContainer(GetGUID().GetCounter());
|
||||
}
|
||||
|
||||
@@ -2667,6 +2665,8 @@ namespace Game.Entities
|
||||
public void SetChildItem(ObjectGuid childItem) { m_childItem = childItem; }
|
||||
|
||||
public ItemEffectRecord[] GetEffects() { return _bonusData.Effects[0.._bonusData.EffectCount]; }
|
||||
|
||||
public override Loot GetLootForPlayer(Player player) { return loot; }
|
||||
|
||||
//Static
|
||||
public static bool ItemCanGoIntoBag(ItemTemplate pProto, ItemTemplate pBagProto)
|
||||
|
||||
@@ -20,6 +20,7 @@ using Framework.Dynamic;
|
||||
using Game.AI;
|
||||
using Game.BattleFields;
|
||||
using Game.DataStorage;
|
||||
using Game.Loots;
|
||||
using Game.Maps;
|
||||
using Game.Movement;
|
||||
using Game.Networking;
|
||||
@@ -28,7 +29,6 @@ using Game.Scenarios;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Game.Entities
|
||||
@@ -779,6 +779,8 @@ namespace Game.Entities
|
||||
return $"{base.GetDebugInfo()}\n{GetGUID()} Entry: {GetEntry()}\nName: { GetName()}";
|
||||
}
|
||||
|
||||
public virtual Loot GetLootForPlayer(Player player) { return null; }
|
||||
|
||||
public abstract void BuildValuesCreate(WorldPacket data, Player target);
|
||||
public abstract void BuildValuesUpdate(WorldPacket data, Player target);
|
||||
|
||||
|
||||
@@ -6105,9 +6105,23 @@ namespace Game.Entities
|
||||
// Now we must make bones lootable, and send player loot
|
||||
bones.SetCorpseDynamicFlag(CorpseDynFlags.Lootable);
|
||||
|
||||
// We store the level of our player in the gold field
|
||||
// We retrieve this information at Player.SendLoot()
|
||||
bones.loot.gold = GetLevel();
|
||||
bones.loot = new Loot();
|
||||
bones.loot.SetGUID(ObjectGuid.Create(HighGuid.LootObject, GetMapId(), 0, GetMap().GenerateLowGuid(HighGuid.LootObject)));
|
||||
|
||||
// For AV Achievement
|
||||
Battleground bg = GetBattleground();
|
||||
if (bg != null)
|
||||
{
|
||||
if (bg.GetTypeID(true) == BattlegroundTypeId.AV)
|
||||
bones.loot.FillLoot(1, LootStorage.Creature, this, true);
|
||||
}
|
||||
// For wintergrasp Quests
|
||||
else if (GetZoneId() == (uint)AreaId.Wintergrasp)
|
||||
bones.loot.FillLoot(1, LootStorage.Creature, this, true);
|
||||
|
||||
// It may need a better formula
|
||||
// Now it works like this: lvl10: ~6copper, lvl70: ~9silver
|
||||
bones.loot.gold = (uint)(RandomHelper.URand(50, 150) * 0.016f * Math.Pow((float)GetLevel() / 5.76f, 2.5f) * WorldConfig.GetFloatValue(WorldCfg.RateDropMoney));
|
||||
bones.lootRecipient = looterPlr;
|
||||
looterPlr.SendLoot(bones.GetGUID(), LootType.Insignia);
|
||||
}
|
||||
@@ -6168,12 +6182,12 @@ namespace Game.Entities
|
||||
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() == LootState.Activated && !go.loot.IsLooted() && !go.GetMap().Instanceable() && go.GetLootGenerationTime() + go.GetRespawnDelay() < GameTime.GetGameTime())
|
||||
if (go.IsSpawnedByDefault() && go.GetLootState() == LootState.Activated && (loot == null || loot.IsLooted()) && !go.GetMap().Instanceable() && go.GetLootGenerationTime() + go.GetRespawnDelay() < GameTime.GetGameTime())
|
||||
go.SetLootState(LootState.Ready);
|
||||
|
||||
if (go.GetLootState() == LootState.Ready)
|
||||
@@ -6189,6 +6203,13 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
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.loot = loot;
|
||||
|
||||
if (lootid != 0)
|
||||
{
|
||||
loot.Clear();
|
||||
@@ -6204,7 +6225,7 @@ namespace Game.Entities
|
||||
go.SetLootGenerationTime();
|
||||
|
||||
// get next RR player (for next loot)
|
||||
if (groupRules)
|
||||
if (groupRules && !loot.Empty())
|
||||
group.UpdateLooterGuid(go);
|
||||
}
|
||||
|
||||
@@ -6277,14 +6298,16 @@ namespace Game.Entities
|
||||
|
||||
permission = PermissionTypes.Owner;
|
||||
|
||||
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 && !Global.LootItemStorage.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.loot = loot;
|
||||
|
||||
switch (loot_type)
|
||||
{
|
||||
@@ -6320,29 +6343,9 @@ namespace Game.Entities
|
||||
return;
|
||||
}
|
||||
|
||||
loot = bones.loot;
|
||||
loot = bones.GetLootForPlayer(this);
|
||||
|
||||
if (loot.loot_type == LootType.None)
|
||||
{
|
||||
uint pLevel = bones.loot.gold;
|
||||
bones.loot.Clear();
|
||||
|
||||
// For AV Achievement
|
||||
Battleground bg = GetBattleground();
|
||||
if (bg)
|
||||
{
|
||||
if (bg.GetTypeID(true) == BattlegroundTypeId.AV)
|
||||
loot.FillLoot(SharedConst.PlayerCorpseLootEntry, LootStorage.Creature, this, true);
|
||||
}
|
||||
else if (GetZoneId() == (uint)AreaId.Wintergrasp)
|
||||
loot.FillLoot(SharedConst.PlayerCorpseLootEntry, LootStorage.Creature, this, true);
|
||||
|
||||
// It may need a better formula
|
||||
// Now it works like this: lvl10: ~6copper, lvl70: ~9silver
|
||||
bones.loot.gold = (uint)(RandomHelper.URand(50, 150) * 0.016f * Math.Pow(pLevel / 5.76f, 2.5f) * WorldConfig.GetFloatValue(WorldCfg.RateDropMoney));
|
||||
}
|
||||
|
||||
if (bones.lootRecipient != this)
|
||||
if (bones.lootRecipient != null && bones.lootRecipient != this)
|
||||
permission = PermissionTypes.None;
|
||||
else
|
||||
permission = PermissionTypes.Owner;
|
||||
@@ -6364,7 +6367,7 @@ namespace Game.Entities
|
||||
return;
|
||||
}
|
||||
|
||||
loot = creature.loot;
|
||||
loot = creature.GetLootForPlayer(this);
|
||||
|
||||
if (loot_type == LootType.Pickpocketing)
|
||||
{
|
||||
@@ -6491,7 +6494,8 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
// need know merged fishing/corpse loot type for achievements
|
||||
loot.loot_type = loot_type;
|
||||
if (loot != null)
|
||||
loot.loot_type = loot_type;
|
||||
|
||||
if (permission != PermissionTypes.None)
|
||||
{
|
||||
@@ -6532,7 +6536,7 @@ namespace Game.Entities
|
||||
SetUnitFlag(UnitFlags.Looting);
|
||||
}
|
||||
else
|
||||
SendLootError(loot.GetGUID(), guid, LootError.DidntKill);
|
||||
SendLootError(loot != null ? loot.GetGUID() : ObjectGuid.Empty, guid, LootError.DidntKill);
|
||||
}
|
||||
|
||||
public void SendLootError(ObjectGuid lootObj, ObjectGuid owner, LootError error)
|
||||
|
||||
@@ -3085,8 +3085,8 @@ namespace Game.Entities
|
||||
if (HasPendingBind())
|
||||
return false;
|
||||
|
||||
Loot loot = creature.loot;
|
||||
if (loot.IsLooted()) // nothing to loot or everything looted.
|
||||
Loot loot = creature.GetLootForPlayer(this);
|
||||
if (loot == null || 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;
|
||||
|
||||
@@ -772,23 +772,16 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player.SendPacket(partyKillLog);
|
||||
|
||||
if (creature != null)
|
||||
{
|
||||
LootList lootList = new();
|
||||
lootList.Owner = creature.GetGUID();
|
||||
lootList.LootObj = creature.loot.GetGUID();
|
||||
player.SendMessageToSet(lootList, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (creature)
|
||||
{
|
||||
creature.loot = new Loot();
|
||||
Loot loot = creature.loot;
|
||||
loot.SetGUID(ObjectGuid.Create(HighGuid.LootObject, creature.GetMapId(), 0, creature.GetMap().GenerateLowGuid(HighGuid.LootObject)));
|
||||
if (creature.GetMap().Is25ManRaid())
|
||||
loot.maxDuplicates = 3;
|
||||
|
||||
loot.Clear();
|
||||
uint lootid = creature.GetCreatureTemplate().LootId;
|
||||
if (lootid != 0)
|
||||
loot.FillLoot(lootid, LootStorage.Creature, looter, false, false, creature.GetLootMode(), creature.GetMap().GetDifficultyLootItemContext());
|
||||
@@ -807,6 +800,13 @@ namespace Game.Entities
|
||||
if (!loot.Empty())
|
||||
group.UpdateLooterGuid(creature);
|
||||
}
|
||||
else
|
||||
{
|
||||
LootList lootList = new();
|
||||
lootList.Owner = creature.GetGUID();
|
||||
lootList.LootObj = creature.loot.GetGUID();
|
||||
player.SendMessageToSet(lootList, true);
|
||||
}
|
||||
}
|
||||
|
||||
player.RewardPlayerAndGroupAtKill(victim, false);
|
||||
@@ -907,7 +907,7 @@ namespace Game.Entities
|
||||
if (!creature.IsPet())
|
||||
{
|
||||
// must be after setDeathState which resets dynamic flags
|
||||
if (!creature.loot.IsLooted())
|
||||
if (creature.loot != null && !creature.loot.IsLooted())
|
||||
creature.SetDynamicFlag(UnitDynFlags.Lootable);
|
||||
else
|
||||
creature.AllLootRemovedFromCorpse();
|
||||
|
||||
Reference in New Issue
Block a user