Core/Loot: Allocate Loot separately from objects
Port From (https://github.com/TrinityCore/TrinityCore/commit/7957e2d380e08fa831765f610c0e29d2f3e11a04)
This commit is contained in:
@@ -325,7 +325,7 @@ namespace Game.Chat
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loot loot = creatureTarget.loot;
|
Loot loot = creatureTarget.loot;
|
||||||
if (!creatureTarget.IsDead() || loot.Empty())
|
if (!creatureTarget.IsDead() || loot == null || loot.Empty())
|
||||||
{
|
{
|
||||||
handler.SendSysMessage(CypherStrings.CommandNotDeadOrNoLoot, creatureTarget.GetName());
|
handler.SendSysMessage(CypherStrings.CommandNotDeadOrNoLoot, creatureTarget.GetName());
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
m_updateFlag.Stationary = true;
|
m_updateFlag.Stationary = true;
|
||||||
|
|
||||||
m_corpseData = new CorpseData();
|
m_corpseData = new();
|
||||||
|
|
||||||
m_time = GameTime.GetGameTime();
|
m_time = GameTime.GetGameTime();
|
||||||
}
|
}
|
||||||
@@ -323,9 +323,11 @@ namespace Game.Entities
|
|||||||
public CellCoord GetCellCoord() { return _cellCoord; }
|
public CellCoord GetCellCoord() { return _cellCoord; }
|
||||||
public void SetCellCoord(CellCoord cellCoord) { _cellCoord = cellCoord; }
|
public void SetCellCoord(CellCoord cellCoord) { _cellCoord = cellCoord; }
|
||||||
|
|
||||||
|
public override Loot GetLootForPlayer(Player player) { return loot; }
|
||||||
|
|
||||||
public CorpseData m_corpseData;
|
public CorpseData m_corpseData;
|
||||||
|
|
||||||
public Loot loot = new();
|
public Loot loot;
|
||||||
public Player lootRecipient;
|
public Player lootRecipient;
|
||||||
|
|
||||||
CorpseType m_type;
|
CorpseType m_type;
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ namespace Game.Entities
|
|||||||
// vendor items
|
// vendor items
|
||||||
List<VendorItemCount> m_vendorItemCounts = new();
|
List<VendorItemCount> m_vendorItemCounts = new();
|
||||||
|
|
||||||
public Loot loot = new();
|
public Loot loot;
|
||||||
public uint m_groupLootTimer; // (msecs)timer used for group loot
|
public uint m_groupLootTimer; // (msecs)timer used for group loot
|
||||||
public ObjectGuid lootingGroupLowGUID; // used to find group which is looting corpse
|
public ObjectGuid lootingGroupLowGUID; // used to find group which is looting corpse
|
||||||
ObjectGuid m_lootRecipient;
|
ObjectGuid m_lootRecipient;
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ namespace Game.Entities
|
|||||||
SetDeathState(DeathState.Dead);
|
SetDeathState(DeathState.Dead);
|
||||||
RemoveAllAuras();
|
RemoveAllAuras();
|
||||||
//DestroyForNearbyPlayers(); // old UpdateObjectVisibility()
|
//DestroyForNearbyPlayers(); // old UpdateObjectVisibility()
|
||||||
loot.Clear();
|
loot = null;
|
||||||
uint respawnDelay = m_respawnDelay;
|
uint respawnDelay = m_respawnDelay;
|
||||||
CreatureAI ai = GetAI();
|
CreatureAI ai = GetAI();
|
||||||
if (ai != null)
|
if (ai != null)
|
||||||
@@ -256,10 +256,6 @@ namespace Game.Entities
|
|||||||
if (cInfo == null)
|
if (cInfo == null)
|
||||||
cInfo = normalInfo;
|
cInfo = normalInfo;
|
||||||
|
|
||||||
// Initialize loot duplicate count depending on raid difficulty
|
|
||||||
if (GetMap().Is25ManRaid())
|
|
||||||
loot.maxDuplicates = 3;
|
|
||||||
|
|
||||||
SetEntry(entry); // normal entry always
|
SetEntry(entry); // normal entry always
|
||||||
m_creatureInfo = cInfo; // map mode related always
|
m_creatureInfo = cInfo; // map mode related always
|
||||||
|
|
||||||
@@ -511,7 +507,7 @@ namespace Game.Entities
|
|||||||
if (IsEngaged())
|
if (IsEngaged())
|
||||||
AIUpdateTick(diff);
|
AIUpdateTick(diff);
|
||||||
|
|
||||||
if (m_groupLootTimer != 0 && !lootingGroupLowGUID.IsEmpty())
|
if (loot != null && m_groupLootTimer != 0 && !lootingGroupLowGUID.IsEmpty())
|
||||||
{
|
{
|
||||||
if (m_groupLootTimer <= diff)
|
if (m_groupLootTimer <= diff)
|
||||||
{
|
{
|
||||||
@@ -1941,7 +1937,7 @@ namespace Game.Entities
|
|||||||
Log.outDebug(LogFilter.Unit, "Respawning creature {0} ({1})", GetName(), GetGUID().ToString());
|
Log.outDebug(LogFilter.Unit, "Respawning creature {0} ({1})", GetName(), GetGUID().ToString());
|
||||||
m_respawnTime = 0;
|
m_respawnTime = 0;
|
||||||
ResetPickPocketRefillTimer();
|
ResetPickPocketRefillTimer();
|
||||||
loot.Clear();
|
loot = null;
|
||||||
|
|
||||||
if (m_originalEntry != GetEntry())
|
if (m_originalEntry != GetEntry())
|
||||||
UpdateEntry(m_originalEntry);
|
UpdateEntry(m_originalEntry);
|
||||||
@@ -2578,7 +2574,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public void AllLootRemovedFromCorpse()
|
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))
|
if (LootStorage.Skinning.HaveLootFor(GetCreatureTemplate().SkinLootId))
|
||||||
SetUnitFlag(UnitFlags.Skinnable);
|
SetUnitFlag(UnitFlags.Skinnable);
|
||||||
|
|
||||||
@@ -2591,7 +2587,7 @@ namespace Game.Entities
|
|||||||
float decayRate = m_ignoreCorpseDecayRatio ? 1.0f : WorldConfig.GetFloatValue(WorldCfg.RateCorpseDecayLooted);
|
float decayRate = m_ignoreCorpseDecayRatio ? 1.0f : WorldConfig.GetFloatValue(WorldCfg.RateCorpseDecayLooted);
|
||||||
|
|
||||||
// corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
|
// 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;
|
m_corpseRemoveTime = now;
|
||||||
else
|
else
|
||||||
m_corpseRemoveTime = now + (uint)(m_corpseDelay * decayRate);
|
m_corpseRemoveTime = now + (uint)(m_corpseDelay * decayRate);
|
||||||
@@ -3280,8 +3276,6 @@ namespace Game.Entities
|
|||||||
// checked at creature_template loading
|
// checked at creature_template loading
|
||||||
DefaultMovementType = (MovementGeneratorType)data.movementType;
|
DefaultMovementType = (MovementGeneratorType)data.movementType;
|
||||||
|
|
||||||
loot.SetGUID(ObjectGuid.Create(HighGuid.LootObject, GetMapId(), data.Id, GetMap().GenerateLowGuid(HighGuid.LootObject)));
|
|
||||||
|
|
||||||
if (addToMap && !GetMap().AddToMap(this))
|
if (addToMap && !GetMap().AddToMap(this))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -373,10 +373,6 @@ namespace Game.Entities
|
|||||||
LastUsedScriptID = GetGoInfo().ScriptId;
|
LastUsedScriptID = GetGoInfo().ScriptId;
|
||||||
AIM_Initialize();
|
AIM_Initialize();
|
||||||
|
|
||||||
// Initialize loot duplicate count depending on raid difficulty
|
|
||||||
if (map.Is25ManRaid())
|
|
||||||
loot.maxDuplicates = 3;
|
|
||||||
|
|
||||||
if (spawnid != 0)
|
if (spawnid != 0)
|
||||||
m_spawnId = spawnid;
|
m_spawnId = spawnid;
|
||||||
|
|
||||||
@@ -701,7 +697,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GameObjectTypes.Chest:
|
case GameObjectTypes.Chest:
|
||||||
if (m_groupLootTimer != 0)
|
if (loot != null && m_groupLootTimer != 0)
|
||||||
{
|
{
|
||||||
if (m_groupLootTimer <= diff)
|
if (m_groupLootTimer <= diff)
|
||||||
{
|
{
|
||||||
@@ -805,7 +801,7 @@ namespace Game.Entities
|
|||||||
return;
|
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
|
// 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;
|
bool isSummonedAndExpired = (GetOwner() != null || GetSpellId() != 0) && m_respawnTime == 0;
|
||||||
@@ -3314,7 +3310,9 @@ namespace Game.Entities
|
|||||||
uint GetUniqueUseCount() { return (uint)m_unique_users.Count; }
|
uint GetUniqueUseCount() { return (uint)m_unique_users.Count; }
|
||||||
|
|
||||||
bool HasLootRecipient() { return !m_lootRecipient.IsEmpty() || !m_lootRecipientGroup.IsEmpty(); }
|
bool HasLootRecipient() { return !m_lootRecipient.IsEmpty() || !m_lootRecipientGroup.IsEmpty(); }
|
||||||
|
|
||||||
|
public override Loot GetLootForPlayer(Player player) { return loot; }
|
||||||
|
|
||||||
public override uint GetLevelForTarget(WorldObject target)
|
public override uint GetLevelForTarget(WorldObject target)
|
||||||
{
|
{
|
||||||
Unit owner = GetOwner();
|
Unit owner = GetOwner();
|
||||||
@@ -3441,7 +3439,7 @@ namespace Game.Entities
|
|||||||
Dictionary<uint, ObjectGuid> ChairListSlots = new();
|
Dictionary<uint, ObjectGuid> ChairListSlots = new();
|
||||||
List<ObjectGuid> m_SkillupList = new();
|
List<ObjectGuid> m_SkillupList = new();
|
||||||
|
|
||||||
public Loot loot = new();
|
public Loot loot;
|
||||||
|
|
||||||
public GameObjectModel m_model;
|
public GameObjectModel m_model;
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ namespace Game.Entities
|
|||||||
uState = ItemUpdateState.New;
|
uState = ItemUpdateState.New;
|
||||||
uQueuePos = -1;
|
uQueuePos = -1;
|
||||||
m_lastPlayedTimeUpdate = GameTime.GetGameTime();
|
m_lastPlayedTimeUpdate = GameTime.GetGameTime();
|
||||||
|
|
||||||
loot = new Loot();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool Create(ulong guidlow, uint itemId, ItemContext context, Player owner)
|
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
|
// Delete the items if this is a container
|
||||||
if (!loot.IsLooted())
|
if (loot != null && !loot.IsLooted())
|
||||||
Global.LootItemStorage.RemoveStoredLootForContainer(GetGUID().GetCounter());
|
Global.LootItemStorage.RemoveStoredLootForContainer(GetGUID().GetCounter());
|
||||||
|
|
||||||
Dispose();
|
Dispose();
|
||||||
@@ -689,7 +687,7 @@ namespace Game.Entities
|
|||||||
DeleteFromDB(trans, GetGUID().GetCounter());
|
DeleteFromDB(trans, GetGUID().GetCounter());
|
||||||
|
|
||||||
// Delete the items if this is a container
|
// Delete the items if this is a container
|
||||||
if (!loot.IsLooted())
|
if (loot != null && !loot.IsLooted())
|
||||||
Global.LootItemStorage.RemoveStoredLootForContainer(GetGUID().GetCounter());
|
Global.LootItemStorage.RemoveStoredLootForContainer(GetGUID().GetCounter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2667,6 +2665,8 @@ namespace Game.Entities
|
|||||||
public void SetChildItem(ObjectGuid childItem) { m_childItem = childItem; }
|
public void SetChildItem(ObjectGuid childItem) { m_childItem = childItem; }
|
||||||
|
|
||||||
public ItemEffectRecord[] GetEffects() { return _bonusData.Effects[0.._bonusData.EffectCount]; }
|
public ItemEffectRecord[] GetEffects() { return _bonusData.Effects[0.._bonusData.EffectCount]; }
|
||||||
|
|
||||||
|
public override Loot GetLootForPlayer(Player player) { return loot; }
|
||||||
|
|
||||||
//Static
|
//Static
|
||||||
public static bool ItemCanGoIntoBag(ItemTemplate pProto, ItemTemplate pBagProto)
|
public static bool ItemCanGoIntoBag(ItemTemplate pProto, ItemTemplate pBagProto)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ using Framework.Dynamic;
|
|||||||
using Game.AI;
|
using Game.AI;
|
||||||
using Game.BattleFields;
|
using Game.BattleFields;
|
||||||
using Game.DataStorage;
|
using Game.DataStorage;
|
||||||
|
using Game.Loots;
|
||||||
using Game.Maps;
|
using Game.Maps;
|
||||||
using Game.Movement;
|
using Game.Movement;
|
||||||
using Game.Networking;
|
using Game.Networking;
|
||||||
@@ -28,7 +29,6 @@ using Game.Scenarios;
|
|||||||
using Game.Spells;
|
using Game.Spells;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Game.Entities
|
namespace Game.Entities
|
||||||
@@ -779,6 +779,8 @@ namespace Game.Entities
|
|||||||
return $"{base.GetDebugInfo()}\n{GetGUID()} Entry: {GetEntry()}\nName: { GetName()}";
|
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 BuildValuesCreate(WorldPacket data, Player target);
|
||||||
public abstract void BuildValuesUpdate(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
|
// Now we must make bones lootable, and send player loot
|
||||||
bones.SetCorpseDynamicFlag(CorpseDynFlags.Lootable);
|
bones.SetCorpseDynamicFlag(CorpseDynFlags.Lootable);
|
||||||
|
|
||||||
// We store the level of our player in the gold field
|
bones.loot = new Loot();
|
||||||
// We retrieve this information at Player.SendLoot()
|
bones.loot.SetGUID(ObjectGuid.Create(HighGuid.LootObject, GetMapId(), 0, GetMap().GenerateLowGuid(HighGuid.LootObject)));
|
||||||
bones.loot.gold = GetLevel();
|
|
||||||
|
// 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;
|
bones.lootRecipient = looterPlr;
|
||||||
looterPlr.SendLoot(bones.GetGUID(), LootType.Insignia);
|
looterPlr.SendLoot(bones.GetGUID(), LootType.Insignia);
|
||||||
}
|
}
|
||||||
@@ -6168,12 +6182,12 @@ namespace Game.Entities
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loot = go.loot;
|
loot = go.GetLootForPlayer(this);
|
||||||
|
|
||||||
// loot was generated and respawntime has passed since then, allow to recreate loot
|
// loot was generated and respawntime has passed since then, allow to recreate loot
|
||||||
// to avoid bugs, this rule covers spawned gameobjects only
|
// 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
|
// 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);
|
go.SetLootState(LootState.Ready);
|
||||||
|
|
||||||
if (go.GetLootState() == 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)
|
if (lootid != 0)
|
||||||
{
|
{
|
||||||
loot.Clear();
|
loot.Clear();
|
||||||
@@ -6204,7 +6225,7 @@ namespace Game.Entities
|
|||||||
go.SetLootGenerationTime();
|
go.SetLootGenerationTime();
|
||||||
|
|
||||||
// get next RR player (for next loot)
|
// get next RR player (for next loot)
|
||||||
if (groupRules)
|
if (groupRules && !loot.Empty())
|
||||||
group.UpdateLooterGuid(go);
|
group.UpdateLooterGuid(go);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6277,14 +6298,16 @@ namespace Game.Entities
|
|||||||
|
|
||||||
permission = PermissionTypes.Owner;
|
permission = PermissionTypes.Owner;
|
||||||
|
|
||||||
loot = item.loot;
|
loot = item.GetLootForPlayer(this);
|
||||||
|
|
||||||
// If item doesn't already have loot, attempt to load it. If that
|
// If item doesn't already have loot, attempt to load it. If that
|
||||||
// fails then this is first time opening, generate loot
|
// fails then this is first time opening, generate loot
|
||||||
if (!item.m_lootGenerated && !Global.LootItemStorage.LoadStoredLoot(item, this))
|
if (!item.m_lootGenerated && !Global.LootItemStorage.LoadStoredLoot(item, this))
|
||||||
{
|
{
|
||||||
item.m_lootGenerated = true;
|
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)
|
switch (loot_type)
|
||||||
{
|
{
|
||||||
@@ -6320,29 +6343,9 @@ namespace Game.Entities
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loot = bones.loot;
|
loot = bones.GetLootForPlayer(this);
|
||||||
|
|
||||||
if (loot.loot_type == LootType.None)
|
if (bones.lootRecipient != null && bones.lootRecipient != this)
|
||||||
{
|
|
||||||
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)
|
|
||||||
permission = PermissionTypes.None;
|
permission = PermissionTypes.None;
|
||||||
else
|
else
|
||||||
permission = PermissionTypes.Owner;
|
permission = PermissionTypes.Owner;
|
||||||
@@ -6364,7 +6367,7 @@ namespace Game.Entities
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loot = creature.loot;
|
loot = creature.GetLootForPlayer(this);
|
||||||
|
|
||||||
if (loot_type == LootType.Pickpocketing)
|
if (loot_type == LootType.Pickpocketing)
|
||||||
{
|
{
|
||||||
@@ -6491,7 +6494,8 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
// need know merged fishing/corpse loot type for achievements
|
// 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)
|
if (permission != PermissionTypes.None)
|
||||||
{
|
{
|
||||||
@@ -6532,7 +6536,7 @@ namespace Game.Entities
|
|||||||
SetUnitFlag(UnitFlags.Looting);
|
SetUnitFlag(UnitFlags.Looting);
|
||||||
}
|
}
|
||||||
else
|
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)
|
public void SendLootError(ObjectGuid lootObj, ObjectGuid owner, LootError error)
|
||||||
|
|||||||
@@ -3085,8 +3085,8 @@ namespace Game.Entities
|
|||||||
if (HasPendingBind())
|
if (HasPendingBind())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Loot loot = creature.loot;
|
Loot loot = creature.GetLootForPlayer(this);
|
||||||
if (loot.IsLooted()) // nothing to loot or everything looted.
|
if (loot == null || loot.IsLooted()) // nothing to loot or everything looted.
|
||||||
return false;
|
return false;
|
||||||
if (!loot.HasItemForAll() && !loot.HasItemFor(this)) // no loot in creature for this player
|
if (!loot.HasItemForAll() && !loot.HasItemFor(this)) // no loot in creature for this player
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -772,23 +772,16 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
player.SendPacket(partyKillLog);
|
player.SendPacket(partyKillLog);
|
||||||
|
|
||||||
if (creature != null)
|
|
||||||
{
|
|
||||||
LootList lootList = new();
|
|
||||||
lootList.Owner = creature.GetGUID();
|
|
||||||
lootList.LootObj = creature.loot.GetGUID();
|
|
||||||
player.SendMessageToSet(lootList, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (creature)
|
if (creature)
|
||||||
{
|
{
|
||||||
|
creature.loot = new Loot();
|
||||||
Loot loot = creature.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;
|
uint lootid = creature.GetCreatureTemplate().LootId;
|
||||||
if (lootid != 0)
|
if (lootid != 0)
|
||||||
loot.FillLoot(lootid, LootStorage.Creature, looter, false, false, creature.GetLootMode(), creature.GetMap().GetDifficultyLootItemContext());
|
loot.FillLoot(lootid, LootStorage.Creature, looter, false, false, creature.GetLootMode(), creature.GetMap().GetDifficultyLootItemContext());
|
||||||
@@ -807,6 +800,13 @@ namespace Game.Entities
|
|||||||
if (!loot.Empty())
|
if (!loot.Empty())
|
||||||
group.UpdateLooterGuid(creature);
|
group.UpdateLooterGuid(creature);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LootList lootList = new();
|
||||||
|
lootList.Owner = creature.GetGUID();
|
||||||
|
lootList.LootObj = creature.loot.GetGUID();
|
||||||
|
player.SendMessageToSet(lootList, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.RewardPlayerAndGroupAtKill(victim, false);
|
player.RewardPlayerAndGroupAtKill(victim, false);
|
||||||
@@ -907,7 +907,7 @@ namespace Game.Entities
|
|||||||
if (!creature.IsPet())
|
if (!creature.IsPet())
|
||||||
{
|
{
|
||||||
// must be after setDeathState which resets dynamic flags
|
// must be after setDeathState which resets dynamic flags
|
||||||
if (!creature.loot.IsLooted())
|
if (creature.loot != null && !creature.loot.IsLooted())
|
||||||
creature.SetDynamicFlag(UnitDynFlags.Lootable);
|
creature.SetDynamicFlag(UnitDynFlags.Lootable);
|
||||||
else
|
else
|
||||||
creature.AllLootRemovedFromCorpse();
|
creature.AllLootRemovedFromCorpse();
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ namespace Game.Groups
|
|||||||
leader.SetPlayerFlag(PlayerFlags.GroupLeader);
|
leader.SetPlayerFlag(PlayerFlags.GroupLeader);
|
||||||
|
|
||||||
if (IsBGGroup() || IsBFGroup())
|
if (IsBGGroup() || IsBFGroup())
|
||||||
{
|
{
|
||||||
m_groupFlags = GroupFlags.MaskBgRaid;
|
m_groupFlags = GroupFlags.MaskBgRaid;
|
||||||
m_groupCategory = GroupCategory.Instance;
|
m_groupCategory = GroupCategory.Instance;
|
||||||
}
|
}
|
||||||
@@ -992,7 +992,7 @@ namespace Game.Groups
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GroupLoot(Loot loot, WorldObject lootedObject)
|
public void GroupLoot(Loot loot, WorldObject lootedObject)
|
||||||
{
|
{
|
||||||
byte itemSlot = 0;
|
byte itemSlot = 0;
|
||||||
@@ -2525,7 +2525,7 @@ namespace Game.Groups
|
|||||||
{
|
{
|
||||||
return GetMemberFlags(guid).HasAnyFlag(GroupMemberFlags.Assistant);
|
return GetMemberFlags(guid).HasAnyFlag(GroupMemberFlags.Assistant);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectGuid GetMemberGUID(string name)
|
public ObjectGuid GetMemberGUID(string name)
|
||||||
{
|
{
|
||||||
foreach (var member in m_memberSlots)
|
foreach (var member in m_memberSlots)
|
||||||
@@ -2778,7 +2778,7 @@ namespace Game.Groups
|
|||||||
RaidMarker[] m_markers = new RaidMarker[MapConst.RaidMarkersCount];
|
RaidMarker[] m_markers = new RaidMarker[MapConst.RaidMarkersCount];
|
||||||
uint m_activeMarkers;
|
uint m_activeMarkers;
|
||||||
|
|
||||||
public static implicit operator bool (Group group)
|
public static implicit operator bool(Group group)
|
||||||
{
|
{
|
||||||
return group != null;
|
return group != null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace Game
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
loot = go.loot;
|
loot = go.GetLootForPlayer(player);
|
||||||
}
|
}
|
||||||
else if (lguid.IsItem())
|
else if (lguid.IsItem())
|
||||||
{
|
{
|
||||||
@@ -65,7 +65,7 @@ namespace Game
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
loot = pItem.loot;
|
loot = pItem.GetLootForPlayer(player);
|
||||||
}
|
}
|
||||||
else if (lguid.IsCorpse())
|
else if (lguid.IsCorpse())
|
||||||
{
|
{
|
||||||
@@ -76,20 +76,35 @@ namespace Game
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
loot = bones.loot;
|
loot = bones.GetLootForPlayer(player);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Creature creature = player.GetMap().GetCreature(lguid);
|
Creature creature = player.GetMap().GetCreature(lguid);
|
||||||
|
if (creature == null)
|
||||||
bool lootAllowed = creature && creature.IsAlive() == (player.GetClass() == Class.Rogue && creature.loot.loot_type == LootType.Pickpocketing);
|
|
||||||
if (!lootAllowed || !creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
|
|
||||||
{
|
{
|
||||||
player.SendLootError(req.Object, lguid, lootAllowed ? LootError.TooFar : LootError.DidntKill);
|
player.SendLootError(req.Object, lguid, LootError.NoLoot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
loot = creature.loot;
|
if (!creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
|
||||||
|
{
|
||||||
|
player.SendLootError(req.Object, lguid, LootError.TooFar);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
loot = creature.GetLootForPlayer(player);
|
||||||
|
if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing))
|
||||||
|
{
|
||||||
|
player.SendLootError(req.Object, lguid, LootError.DidntKill);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loot == null)
|
||||||
|
{
|
||||||
|
player.SendLootRelease(lguid);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.StoreLootItem(lguid, (byte)(req.LootListID - 1), loot, aeResult);
|
player.StoreLootItem(lguid, (byte)(req.LootListID - 1), loot, aeResult);
|
||||||
@@ -132,9 +147,9 @@ namespace Game
|
|||||||
|
|
||||||
// do not check distance for GO if player is the owner of it (ex. fishing bobber)
|
// 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)))
|
if (go && (go.GetOwnerGUID() == player.GetGUID() || go.IsWithinDistInMap(player)))
|
||||||
loot = go.loot;
|
loot = go.GetLootForPlayer(player);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HighGuid.Corpse: // remove insignia ONLY in BG
|
case HighGuid.Corpse: // remove insignia ONLY in BG
|
||||||
{
|
{
|
||||||
@@ -142,8 +157,8 @@ namespace Game
|
|||||||
|
|
||||||
if (bones && bones.IsWithinDistInMap(player, SharedConst.InteractionDistance))
|
if (bones && bones.IsWithinDistInMap(player, SharedConst.InteractionDistance))
|
||||||
{
|
{
|
||||||
loot = bones.loot;
|
loot = bones.GetLootForPlayer(player);
|
||||||
shareMoney = false;
|
shareMoney = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -153,26 +168,38 @@ namespace Game
|
|||||||
Item item = player.GetItemByGuid(guid);
|
Item item = player.GetItemByGuid(guid);
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
loot = item.loot;
|
loot = item.GetLootForPlayer(player);
|
||||||
shareMoney = false;
|
shareMoney = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HighGuid.Creature:
|
case HighGuid.Creature:
|
||||||
case HighGuid.Vehicle:
|
case HighGuid.Vehicle:
|
||||||
|
{
|
||||||
|
Creature creature = player.GetMap().GetCreature(guid);
|
||||||
|
if (creature == null)
|
||||||
{
|
{
|
||||||
Creature creature = player.GetMap().GetCreature(guid);
|
player.SendLootError(lootView.Key, guid, LootError.NoLoot);
|
||||||
bool lootAllowed = creature && creature.IsAlive() == (player.GetClass() == Class.Rogue && creature.loot.loot_type == LootType.Pickpocketing);
|
continue;
|
||||||
if (lootAllowed && creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
|
|
||||||
{
|
|
||||||
loot = creature.loot;
|
|
||||||
if (creature.IsAlive())
|
|
||||||
shareMoney = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
player.SendLootError(lootView.Key, guid, lootAllowed ? LootError.TooFar : LootError.DidntKill);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
|
||||||
|
{
|
||||||
|
player.SendLootError(lootView.Key, guid, LootError.TooFar);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
loot = creature.GetLootForPlayer(player);
|
||||||
|
if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing))
|
||||||
|
{
|
||||||
|
player.SendLootError(lootView.Key, guid, LootError.DidntKill);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loot != null && loot.loot_type != LootType.Corpse)
|
||||||
|
shareMoney = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
continue; // unlootable type
|
continue; // unlootable type
|
||||||
}
|
}
|
||||||
@@ -336,7 +363,7 @@ namespace Game
|
|||||||
if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player)))
|
if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loot = go.loot;
|
loot = go.GetLootForPlayer(player);
|
||||||
|
|
||||||
if (go.GetGoType() == GameObjectTypes.Door)
|
if (go.GetGoType() == GameObjectTypes.Door)
|
||||||
{
|
{
|
||||||
@@ -374,9 +401,9 @@ namespace Game
|
|||||||
if (!corpse || !corpse.IsWithinDistInMap(player, SharedConst.InteractionDistance))
|
if (!corpse || !corpse.IsWithinDistInMap(player, SharedConst.InteractionDistance))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loot = corpse.loot;
|
loot = corpse.GetLootForPlayer(player);
|
||||||
|
|
||||||
if (loot.IsLooted())
|
if (loot != null && loot.IsLooted())
|
||||||
{
|
{
|
||||||
loot.Clear();
|
loot.Clear();
|
||||||
corpse.RemoveCorpseDynamicFlag(CorpseDynFlags.Lootable);
|
corpse.RemoveCorpseDynamicFlag(CorpseDynFlags.Lootable);
|
||||||
@@ -390,11 +417,13 @@ namespace Game
|
|||||||
|
|
||||||
ItemTemplate proto = pItem.GetTemplate();
|
ItemTemplate proto = pItem.GetTemplate();
|
||||||
|
|
||||||
|
loot = pItem.GetLootForPlayer(player);
|
||||||
|
|
||||||
// destroy only 5 items from stack in case prospecting and milling
|
// destroy only 5 items from stack in case prospecting and milling
|
||||||
if (pItem.loot.loot_type == LootType.Prospecting || pItem.loot.loot_type == LootType.Milling)
|
if (loot != null && (loot.loot_type == LootType.Prospecting || loot.loot_type == LootType.Milling))
|
||||||
{
|
{
|
||||||
pItem.m_lootGenerated = false;
|
pItem.m_lootGenerated = false;
|
||||||
pItem.loot.Clear();
|
pItem.loot = null;
|
||||||
|
|
||||||
uint count = pItem.GetCount();
|
uint count = pItem.GetCount();
|
||||||
|
|
||||||
@@ -406,7 +435,8 @@ namespace Game
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (pItem.loot.IsLooted() || !proto.HasFlag(ItemFlags.HasLoot)) // Only delete item if no loot or money (unlooted loot is saved to db)
|
// Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item
|
||||||
|
if ((loot != null && loot.IsLooted()) || !proto.HasFlag(ItemFlags.HasLoot))
|
||||||
player.DestroyItem(pItem.GetBagSlot(), pItem.GetSlot(), true);
|
player.DestroyItem(pItem.GetBagSlot(), pItem.GetSlot(), true);
|
||||||
}
|
}
|
||||||
return; // item can be looted only single player
|
return; // item can be looted only single player
|
||||||
@@ -414,21 +444,23 @@ namespace Game
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Creature creature = player.GetMap().GetCreature(lguid);
|
Creature creature = player.GetMap().GetCreature(lguid);
|
||||||
|
if (creature == null)
|
||||||
bool lootAllowed = creature && creature.IsAlive() == (player.GetClass() == Class.Rogue && creature.loot.loot_type == LootType.Pickpocketing);
|
|
||||||
if (!lootAllowed || !creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loot = creature.loot;
|
if (!creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
|
||||||
if (loot.IsLooted())
|
return;
|
||||||
|
|
||||||
|
loot = creature.GetLootForPlayer(player);
|
||||||
|
if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (loot == null || loot.IsLooted())
|
||||||
{
|
{
|
||||||
creature.RemoveDynamicFlag(UnitDynFlags.Lootable);
|
creature.RemoveDynamicFlag(UnitDynFlags.Lootable);
|
||||||
|
|
||||||
// skip pickpocketing loot for speed, skinning timer reduction is no-op in fact
|
// skip pickpocketing loot for speed, skinning timer reduction is no-op in fact
|
||||||
if (!creature.IsAlive())
|
if (!creature.IsAlive())
|
||||||
creature.AllLootRemovedFromCorpse();
|
creature.AllLootRemovedFromCorpse();
|
||||||
|
|
||||||
loot.Clear();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -451,7 +483,8 @@ namespace Game
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Player is not looking at loot list, he doesn't need to see updates on the loot list
|
//Player is not looking at loot list, he doesn't need to see updates on the loot list
|
||||||
loot.RemoveLooter(player.GetGUID());
|
if (loot != null)
|
||||||
|
loot.RemoveLooter(player.GetGUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DoLootReleaseAll()
|
public void DoLootReleaseAll()
|
||||||
@@ -498,15 +531,15 @@ namespace Game
|
|||||||
if (!creature)
|
if (!creature)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loot = creature.loot;
|
loot = creature.GetLootForPlayer(_player);
|
||||||
}
|
}
|
||||||
else if (GetPlayer().GetLootGUID().IsGameObject())
|
else if (GetPlayer().GetLootGUID().IsGameObject())
|
||||||
{
|
{
|
||||||
GameObject pGO = GetPlayer().GetMap().GetGameObject(lootguid);
|
GameObject go = GetPlayer().GetMap().GetGameObject(lootguid);
|
||||||
if (!pGO)
|
if (!go)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loot = pGO.loot;
|
loot = go.GetLootForPlayer(_player);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loot == null)
|
if (loot == null)
|
||||||
|
|||||||
@@ -165,9 +165,9 @@ namespace Game.Loots
|
|||||||
|
|
||||||
public class Loot
|
public class Loot
|
||||||
{
|
{
|
||||||
public Loot(uint _gold = 0)
|
public Loot()
|
||||||
{
|
{
|
||||||
gold = _gold;
|
gold = 0;
|
||||||
unlootedCount = 0;
|
unlootedCount = 0;
|
||||||
loot_type = LootType.None;
|
loot_type = LootType.None;
|
||||||
maxDuplicates = 1;
|
maxDuplicates = 1;
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ namespace Game.Loots
|
|||||||
|
|
||||||
public bool LoadStoredLoot(Item item, Player player)
|
public bool LoadStoredLoot(Item item, Player player)
|
||||||
{
|
{
|
||||||
Loot loot = item.loot;
|
Loot loot = item.GetLootForPlayer(player);
|
||||||
if (!_lootItemStorage.ContainsKey(item.GetGUID().GetCounter()))
|
if (!_lootItemStorage.ContainsKey(item.GetGUID().GetCounter()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -5187,7 +5187,8 @@ namespace Game.Spells
|
|||||||
return SpellCastResult.TargetUnskinnable;
|
return SpellCastResult.TargetUnskinnable;
|
||||||
|
|
||||||
Creature creature = m_targets.GetUnitTarget().ToCreature();
|
Creature creature = m_targets.GetUnitTarget().ToCreature();
|
||||||
if (!creature.IsCritter() && !creature.loot.IsLooted())
|
Loot loot = creature.GetLootForPlayer(m_caster.ToPlayer());
|
||||||
|
if (loot != null && !loot.IsLooted())
|
||||||
return SpellCastResult.TargetNotLooted;
|
return SpellCastResult.TargetNotLooted;
|
||||||
|
|
||||||
SkillType skill = creature.GetCreatureTemplate().GetRequiredLootSkill();
|
SkillType skill = creature.GetCreatureTemplate().GetRequiredLootSkill();
|
||||||
|
|||||||
Reference in New Issue
Block a user