diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index c577e67bb..2043d6833 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -5896,7 +5896,7 @@ namespace Game.Entities public void AutoStoreLoot(uint loot_id, LootStore store, ItemContext context = 0, bool broadcast = false, bool createdByPlayer = false) { AutoStoreLoot(ItemConst.NullBag, ItemConst.NullSlot, loot_id, store, context, broadcast); } void AutoStoreLoot(byte bag, byte slot, uint loot_id, LootStore store, ItemContext context = 0, bool broadcast = false, bool createdByPlayer = false) { - Loot loot = new(); + Loot loot = new(null, ObjectGuid.Empty, LootType.None); loot.FillLoot(loot_id, store, this, true, false, LootModes.Default, context); uint max_slot = loot.GetMaxSlotInLootFor(this); @@ -6015,9 +6015,9 @@ namespace Game.Entities qitem.is_looted = true; //freeforall is 1 if everyone's supposed to get the quest item. if (item.freeforall || loot.GetPlayerQuestItems().Count == 1) - SendNotifyLootItemRemoved(loot.GetGUID(), lootSlot); + SendNotifyLootItemRemoved(loot.GetGUID(), loot.GetOwnerGUID(), lootSlot); else - loot.NotifyQuestItemRemoved(qitem.index); + loot.NotifyQuestItemRemoved(qitem.index, GetMap()); } else { @@ -6025,14 +6025,14 @@ namespace Game.Entities { //freeforall case, notify only one player of the removal ffaitem.is_looted = true; - SendNotifyLootItemRemoved(loot.GetGUID(), lootSlot); + SendNotifyLootItemRemoved(loot.GetGUID(), loot.GetOwnerGUID(), lootSlot); } else { //not freeforall, notify everyone if (conditem != null) conditem.is_looted = true; - loot.NotifyItemRemoved(lootSlot); + loot.NotifyItemRemoved(lootSlot, GetMap()); } } @@ -6105,8 +6105,7 @@ namespace Game.Entities // Now we must make bones lootable, and send player loot bones.SetCorpseDynamicFlag(CorpseDynFlags.Lootable); - bones.loot = new Loot(); - bones.loot.SetGUID(ObjectGuid.Create(HighGuid.LootObject, GetMapId(), 0, GetMap().GenerateLowGuid(HighGuid.LootObject))); + bones.loot = new Loot(GetMap(), bones.GetGUID(), LootType.Insignia); // For AV Achievement Battleground bg = GetBattleground(); @@ -6203,8 +6202,7 @@ namespace Game.Entities } } - loot = new Loot(); - loot.SetGUID(ObjectGuid.Create(HighGuid.LootObject, go.GetMapId(), 0, go.GetMap().GenerateLowGuid(HighGuid.LootObject))); + loot = new Loot(GetMap(), guid, loot_type); if (go.GetMap().Is25ManRaid()) loot.maxDuplicates = 3; @@ -6305,8 +6303,7 @@ namespace Game.Entities if (!item.m_lootGenerated && !Global.LootItemStorage.LoadStoredLoot(item, this)) { item.m_lootGenerated = true; - loot = new Loot(); - loot.SetGUID(ObjectGuid.Create(HighGuid.LootObject, GetMapId(), 0, GetMap().GenerateLowGuid(HighGuid.LootObject))); + loot = new Loot(GetMap(), guid, loot_type); item.loot = loot; switch (loot_type) @@ -6480,10 +6477,6 @@ namespace Game.Entities } } - // need know merged fishing/corpse loot type for achievements - if (loot != null) - loot.loot_type = loot_type; - if (permission != PermissionTypes.None) { LootMethod _lootMethod = LootMethod.FreeForAll; @@ -6543,11 +6536,11 @@ namespace Game.Entities SendPacket(packet); } - public void SendNotifyLootItemRemoved(ObjectGuid lootObj, byte lootSlot) + public void SendNotifyLootItemRemoved(ObjectGuid lootObj, ObjectGuid owner, byte lootSlot) { LootRemoved packet = new(); - packet.Owner = GetLootWorldObjectGUID(lootObj); packet.LootObj = lootObj; + packet.Owner = owner; packet.LootListID = (byte)(lootSlot + 1); SendPacket(packet); } diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index 4a81040e2..d2f543f60 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -776,9 +776,8 @@ namespace Game.Entities if (creature) { - creature.loot = new Loot(); + creature.loot = new Loot(creature.GetMap(), creature.GetGUID(), LootType.Corpse); 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; diff --git a/Source/Game/Groups/Group.cs b/Source/Game/Groups/Group.cs index 1731cc063..14501f234 100644 --- a/Source/Game/Groups/Group.cs +++ b/Source/Game/Groups/Group.cs @@ -1272,7 +1272,7 @@ namespace Game.Groups if (msg == InventoryResult.Ok) { item.is_looted = true; - roll.GetLoot().NotifyItemRemoved(roll.itemSlot); + roll.GetLoot().NotifyItemRemoved(roll.itemSlot, allowedMap); roll.GetLoot().unlootedCount--; player.StoreNewItem(dest, roll.itemid, true, item.randomBonusListId, item.GetAllowedLooters(), item.context, item.BonusListIDs); } @@ -1338,7 +1338,7 @@ namespace Game.Groups if (msg == InventoryResult.Ok) { item.is_looted = true; - roll.GetLoot().NotifyItemRemoved(roll.itemSlot); + roll.GetLoot().NotifyItemRemoved(roll.itemSlot, allowedMap); roll.GetLoot().unlootedCount--; player.StoreNewItem(dest, roll.itemid, true, item.randomBonusListId, item.GetAllowedLooters(), item.context, item.BonusListIDs); } @@ -1352,7 +1352,7 @@ namespace Game.Groups else if (rollVote == RollType.Disenchant) { item.is_looted = true; - roll.GetLoot().NotifyItemRemoved(roll.itemSlot); + roll.GetLoot().NotifyItemRemoved(roll.itemSlot, allowedMap); roll.GetLoot().unlootedCount--; player.UpdateCriteria(CriteriaType.CastSpell, 13262); // Disenchant @@ -1364,7 +1364,7 @@ namespace Game.Groups player.AutoStoreLoot(disenchant.Id, LootStorage.Disenchant, ItemContext.None, true); else // If the player's inventory is full, send the disenchant result in a mail. { - Loot loot = new(); + Loot loot = new(allowedMap, roll.GetLoot().GetOwnerGUID(), LootType.Disenchanting); loot.FillLoot(disenchant.Id, LootStorage.Disenchant, player, true); uint max_slot = loot.GetMaxSlotInLootFor(player); diff --git a/Source/Game/Handlers/LootHandler.cs b/Source/Game/Handlers/LootHandler.cs index 9048d83e7..1aea81577 100644 --- a/Source/Game/Handlers/LootHandler.cs +++ b/Source/Game/Handlers/LootHandler.cs @@ -207,7 +207,7 @@ namespace Game if (loot == null) continue; - loot.NotifyMoneyRemoved(); + loot.NotifyMoneyRemoved(player.GetMap()); if (shareMoney && player.GetGroup() != null) //item, pickpocket and players can be looted only single player { @@ -578,7 +578,7 @@ namespace Game item.count = 0; item.is_looted = true; - loot.NotifyItemRemoved(slotid); + loot.NotifyItemRemoved(slotid, GetPlayer().GetMap()); --loot.unlootedCount; } diff --git a/Source/Game/Loot/Loot.cs b/Source/Game/Loot/Loot.cs index 9bdf0710e..c2cdcb352 100644 --- a/Source/Game/Loot/Loot.cs +++ b/Source/Game/Loot/Loot.cs @@ -23,6 +23,7 @@ using Game.Groups; using Game.Networking.Packets; using System; using System.Collections.Generic; +using Game.Maps; namespace Game.Loots { @@ -165,16 +166,17 @@ namespace Game.Loots public class Loot { - public Loot() + public Loot(Map map, ObjectGuid owner, LootType type) { - gold = 0; - unlootedCount = 0; - loot_type = LootType.None; + loot_type = type; maxDuplicates = 1; + _guid = map ? ObjectGuid.Create(HighGuid.LootObject, map.GetId(), 0, map.GenerateLowGuid(HighGuid.LootObject)) : ObjectGuid.Empty; + _owner = owner; + _itemContext = ItemContext.None; } // Inserts the item into the loot (called by LootTemplate processors) - public void AddItem(LootStoreItem item) + public void AddItem(LootStoreItem item, Player player) { ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item.itemid); if (proto == null) @@ -202,23 +204,19 @@ namespace Game.Loots // In some cases, a dropped item should be visible/lootable only for some players in group bool canSeeItemInLootWindow = false; - Player player = Global.ObjAccessor.FindPlayer(lootOwnerGUID); - if (player != null) + Group group = player.GetGroup(); + if (group != null) { - Group group = player.GetGroup(); - if (group != null) + for (GroupReference itr = group.GetFirstMember(); itr != null; itr = itr.Next()) { - for (GroupReference itr = group.GetFirstMember(); itr != null; itr = itr.Next()) - { - Player member = itr.GetSource(); - if (member != null) - if (generatedLoot.AllowedForPlayer(member)) - canSeeItemInLootWindow = true; - } + Player member = itr.GetSource(); + if (member != null) + if (generatedLoot.AllowedForPlayer(member)) + canSeeItemInLootWindow = true; } - else if (generatedLoot.AllowedForPlayer(player)) - canSeeItemInLootWindow = true; } + else if (generatedLoot.AllowedForPlayer(player)) + canSeeItemInLootWindow = true; if (!canSeeItemInLootWindow) continue; @@ -250,8 +248,6 @@ namespace Game.Loots if (lootOwner == null) return false; - lootOwnerGUID = lootOwner.GetGUID(); - LootTemplate tab = store.GetLootFor(lootId); if (tab == null) { @@ -262,7 +258,7 @@ namespace Game.Loots _itemContext = context; - tab.Process(this, store.IsRatesAllowed(), (byte)lootMode); // Processing is done there, callback via Loot.AddItem() + tab.Process(this, store.IsRatesAllowed(), (byte)lootMode, 0, lootOwner); // Processing is done there, callback via Loot.AddItem() // Setting access rights for group loot case Group group = lootOwner.GetGroup(); @@ -396,34 +392,21 @@ namespace Game.Loots return ql; } - public void NotifyItemRemoved(byte lootIndex) + public void NotifyItemRemoved(byte lootIndex, Map map) { // notify all players that are looting this that the item was removed // convert the index to the slot the player sees for (int i = 0; i < PlayersLooting.Count; ++i) { - Player player = Global.ObjAccessor.FindPlayer(PlayersLooting[i]); + Player player = Global.ObjAccessor.GetPlayer(map, PlayersLooting[i]); if (player != null) - player.SendNotifyLootItemRemoved(GetGUID(), lootIndex); + player.SendNotifyLootItemRemoved(GetGUID(), GetOwnerGUID(), lootIndex); else PlayersLooting.RemoveAt(i); } } - public void NotifyMoneyRemoved() - { - // notify all players that are looting this that the money was removed - for (var i = 0; i < PlayersLooting.Count; ++i) - { - Player player = Global.ObjAccessor.FindPlayer(PlayersLooting[i]); - if (player != null) - player.SendNotifyLootMoneyRemoved(GetGUID()); - else - PlayersLooting.RemoveAt(i); - } - } - - public void NotifyQuestItemRemoved(byte questIndex) + public void NotifyQuestItemRemoved(byte questIndex, Map map) { // when a free for all questitem is looted // all players will get notified of it being removed @@ -431,7 +414,7 @@ namespace Game.Loots // bit inefficient but isn't called often for (var i = 0; i < PlayersLooting.Count; ++i) { - Player player = Global.ObjAccessor.FindPlayer(PlayersLooting[i]); + Player player = Global.ObjAccessor.GetPlayer(map, PlayersLooting[i]); if (player) { var pql = PlayerQuestItems.LookupByKey(player.GetGUID()); @@ -443,7 +426,7 @@ namespace Game.Loots break; if (j < pql.Count) - player.SendNotifyLootItemRemoved(GetGUID(), (byte)(items.Count + j)); + player.SendNotifyLootItemRemoved(GetGUID(), GetOwnerGUID(), (byte)(items.Count + j)); } } else @@ -451,6 +434,19 @@ namespace Game.Loots } } + public void NotifyMoneyRemoved(Map map) + { + // notify all players that are looting this that the money was removed + for (var i = 0; i < PlayersLooting.Count; ++i) + { + Player player = Global.ObjAccessor.GetPlayer(map, PlayersLooting[i]); + if (player != null) + player.SendNotifyLootMoneyRemoved(GetGUID()); + else + PlayersLooting.RemoveAt(i); + } + } + public void GenerateMoneyLoot(uint minAmount, uint maxAmount) { if (maxAmount > 0) @@ -835,9 +831,9 @@ namespace Game.Loots public void AddLooter(ObjectGuid guid) { PlayersLooting.Add(guid); } public void RemoveLooter(ObjectGuid guid) { PlayersLooting.Remove(guid); } - public ObjectGuid GetGUID() { return _GUID; } - public void SetGUID(ObjectGuid guid) { _GUID = guid; } - + public ObjectGuid GetGUID() { return _guid; } + public ObjectGuid GetOwnerGUID() { return _owner; } + public MultiMap GetPlayerQuestItems() { return PlayerQuestItems; } public MultiMap GetPlayerFFAItems() { return PlayerFFAItems; } public MultiMap GetPlayerNonQuestNonFFAConditionalItems() { return PlayerNonQuestNonFFAConditionalItems; } @@ -847,7 +843,6 @@ namespace Game.Loots public uint gold; public byte unlootedCount; public ObjectGuid roundRobinPlayer; // GUID of the player having the Round-Robin ownership for the loot. If 0, round robin owner has released. - ObjectGuid lootOwnerGUID; public LootType loot_type; // required for achievement system public byte maxDuplicates; // Max amount of items with the same entry that can drop (default is 1; on 25 man raid mode 3) @@ -860,7 +855,8 @@ namespace Game.Loots LootValidatorRefManager i_LootValidatorRefManager = new(); // Loot GUID - ObjectGuid _GUID; + ObjectGuid _guid; + ObjectGuid _owner; // The WorldObject that holds this loot ItemContext _itemContext; } diff --git a/Source/Game/Loot/LootManager.cs b/Source/Game/Loot/LootManager.cs index 19c9c5221..02dee4d74 100644 --- a/Source/Game/Loot/LootManager.cs +++ b/Source/Game/Loot/LootManager.cs @@ -707,7 +707,7 @@ namespace Game.Loots Entries.Add(item); } - public void Process(Loot loot, bool rate, ushort lootMode, byte groupId = 0) + public void Process(Loot loot, bool rate, ushort lootMode, byte groupId, Player player) { if (groupId != 0) // Group reference uses own processing of the group { @@ -717,7 +717,7 @@ namespace Game.Loots if (Groups[groupId - 1] == null) return; - Groups[groupId - 1].Process(loot, lootMode); + Groups[groupId - 1].Process(loot, lootMode, player); return; } @@ -738,17 +738,17 @@ namespace Game.Loots uint maxcount = (uint)(item.maxcount * WorldConfig.GetFloatValue(WorldCfg.RateDropItemReferencedAmount)); for (uint loop = 0; loop < maxcount; ++loop) // Ref multiplicator - Referenced.Process(loot, rate, lootMode, item.groupid); + Referenced.Process(loot, rate, lootMode, item.groupid, player); } else // Plain entries (not a reference, not grouped) - loot.AddItem(item); // Chance is already checked, just add + loot.AddItem(item, player); // Chance is already checked, just add } // Now processing groups foreach (var group in Groups.Values) { if (group != null) - group.Process(loot, lootMode); + group.Process(loot, lootMode, player); } } public void CopyConditions(List conditions) @@ -971,11 +971,11 @@ namespace Game.Loots return false; } - public void Process(Loot loot, ushort lootMode) + public void Process(Loot loot, ushort lootMode, Player player) { LootStoreItem item = Roll(loot, lootMode); if (item != null) - loot.AddItem(item); + loot.AddItem(item, player); } float RawTotalChance() { diff --git a/Source/Game/Mails/MailDraft.cs b/Source/Game/Mails/MailDraft.cs index 5b693d920..dce3888ca 100644 --- a/Source/Game/Mails/MailDraft.cs +++ b/Source/Game/Mails/MailDraft.cs @@ -60,7 +60,7 @@ namespace Game.Mails if (m_mailTemplateId == 123) m_money = 1000000; - Loot mailLoot = new(); + Loot mailLoot = new(null, ObjectGuid.Empty, LootType.None); // can be empty mailLoot.FillLoot(m_mailTemplateId, LootStorage.Mail, receiver, true, true, LootModes.Default, ItemContext.None);