Core/Loot: Allocate Loot separately from objects

Port From (https://github.com/TrinityCore/TrinityCore/commit/7957e2d380e08fa831765f610c0e29d2f3e11a04)
This commit is contained in:
hondacrx
2022-09-02 14:14:04 -04:00
parent 0e4832809c
commit 7bba4bdd79
15 changed files with 160 additions and 126 deletions
+4 -2
View File
@@ -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;
+5 -11
View File
@@ -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;
+4 -4
View File
@@ -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)
+3 -1
View File
@@ -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);
+37 -33
View File
@@ -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)
+2 -2
View File
@@ -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;
+12 -12
View File
@@ -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();