From 39e9e73277667414c79d5db9ea30cf17369a7aa2 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 6 Oct 2022 20:50:10 -0400 Subject: [PATCH] Core/Loot: Prevent looting bosses by players that have already completed that encounter Port From (https://github.com/TrinityCore/TrinityCore/commit/9ce47e6809eecc891904e272b368596fdc55e6a4) --- Source/Game/Entities/Player/Player.Items.cs | 2 +- Source/Game/Entities/Player/Player.Map.cs | 13 +++++++++ Source/Game/Entities/Player/Player.cs | 3 ++- Source/Game/Handlers/LootHandler.cs | 21 ++++++++++----- Source/Game/Loot/Loot.cs | 30 +++++++++++++++++---- Source/Game/Loot/LootItemStorage.cs | 2 +- 6 files changed, 57 insertions(+), 14 deletions(-) diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index 8dd6461b4..a93bd179f 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -5973,7 +5973,7 @@ namespace Game.Entities return; } - if (!item.AllowedForPlayer(this)) + if (!item.HasAllowedLooter(GetGUID())) { SendLootReleaseAll(); return; diff --git a/Source/Game/Entities/Player/Player.Map.cs b/Source/Game/Entities/Player/Player.Map.cs index ae67bbe28..7b75a5cfe 100644 --- a/Source/Game/Entities/Player/Player.Map.cs +++ b/Source/Game/Entities/Player/Player.Map.cs @@ -558,6 +558,19 @@ namespace Game.Entities SendPacket(transferAborted); } + public bool IsLockedToDungeonEncounter(uint dungeonEncounterId) + { + DungeonEncounterRecord dungeonEncounter = CliDB.DungeonEncounterStorage.LookupByKey(dungeonEncounterId); + if (dungeonEncounter == null) + return false; + + InstanceLock instanceLock = Global.InstanceLockMgr.FindActiveInstanceLock(GetGUID(), new MapDb2Entries(GetMap().GetEntry(), GetMap().GetMapDifficulty())); + if (instanceLock == null) + return false; + + return (instanceLock.GetData().CompletedEncountersMask & (1u << dungeonEncounter.Bit)) != 0; + } + public override void ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, LiquidData newLiquidData) { // process liquid auras using generic unit code diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 3de77cfdf..c6700ad2b 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -3130,7 +3130,8 @@ namespace Game.Entities 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 + + if (!loot.HasAllowedLooter(GetGUID()) || (!loot.HasItemForAll() && !loot.HasItemFor(this))) // no loot in creature for this player return false; if (loot.loot_type == LootType.Skinning) diff --git a/Source/Game/Handlers/LootHandler.cs b/Source/Game/Handlers/LootHandler.cs index a9ab7b4d4..588c85b95 100644 --- a/Source/Game/Handlers/LootHandler.cs +++ b/Source/Game/Handlers/LootHandler.cs @@ -119,6 +119,9 @@ namespace Game if (!member) continue; + if (!loot.HasAllowedLooter(member.GetGUID())) + continue; + if (player.IsAtGroupRewardDistance(member)) playersNear.Add(member); } @@ -406,15 +409,21 @@ namespace Game { Loot loot = _player.GetAELootView().LookupByKey(req.Object); + if (loot == null || loot.GetLootMethod() != LootMethod.MasterLoot) + return; + if (!_player.IsInRaidWith(target) || !_player.IsInMap(target)) { - _player.SendLootError(req.Object, ObjectGuid.Empty, LootError.MasterOther); + _player.SendLootError(req.Object, loot.GetOwnerGUID(), LootError.MasterOther); Log.outInfo(LogFilter.Cheat, $"MasterLootItem: Player {GetPlayer().GetName()} tried to give an item to ineligible player {target.GetName()} !"); return; } - if (loot == null || loot.GetLootMethod() != LootMethod.MasterLoot) + if (!loot.HasAllowedLooter(masterLootItem.Target)) + { + _player.SendLootError(req.Object, loot.GetOwnerGUID(), LootError.MasterOther); return; + } if (req.LootListID >= loot.items.Count) { @@ -426,16 +435,16 @@ namespace Game List dest = new(); InventoryResult msg = target.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item.itemid, item.count); - if (!item.AllowedForPlayer(target, true)) + if (!item.HasAllowedLooter(target.GetGUID())) msg = InventoryResult.CantEquipEver; if (msg != InventoryResult.Ok) { if (msg == InventoryResult.ItemMaxCount) - _player.SendLootError(req.Object, ObjectGuid.Empty, LootError.MasterUniqueItem); + _player.SendLootError(req.Object, loot.GetOwnerGUID(), LootError.MasterUniqueItem); else if (msg == InventoryResult.InvFull) - _player.SendLootError(req.Object, ObjectGuid.Empty, LootError.MasterInvFull); + _player.SendLootError(req.Object, loot.GetOwnerGUID(), LootError.MasterInvFull); else - _player.SendLootError(req.Object, ObjectGuid.Empty, LootError.MasterOther); + _player.SendLootError(req.Object, loot.GetOwnerGUID(), LootError.MasterOther); return; } diff --git a/Source/Game/Loot/Loot.cs b/Source/Game/Loot/Loot.cs index 9cdb1c6f8..31f6dee34 100644 --- a/Source/Game/Loot/Loot.cs +++ b/Source/Game/Loot/Loot.cs @@ -45,7 +45,13 @@ namespace Game.Loots randomBonusListId = ItemEnchantmentManager.GenerateItemRandomBonusListId(itemid); } - public bool AllowedForPlayer(Player player, bool isGivenByMasterLooter = false) + /// + /// Basic checks for player/item compatibility - if false no chance to see the item in the loot - used only for loot generation + /// + /// + /// + /// + public bool AllowedForPlayer(Player player, Loot loot) { // DB conditions check if (!Global.ConditionMgr.IsObjectMeetToConditions(player, conditions)) @@ -63,7 +69,7 @@ namespace Game.Loots return false; // Master looter can see all items even if the character can't loot them - if (!isGivenByMasterLooter && player.GetGroup() && player.GetGroup().GetMasterLooterGuid() == player.GetGUID()) + if (loot.GetLootMethod() == LootMethod.MasterLoot && follow_loot_rules && player.GetGroup() != null && player.GetGroup().GetMasterLooterGuid() == player.GetGUID()) return true; // Don't allow loot for players without profession or those who already know the recipe @@ -108,6 +114,11 @@ namespace Game.Loots allowedGUIDs.Add(player.GetGUID()); } + public bool HasAllowedLooter(ObjectGuid looter) + { + return allowedGUIDs.Contains(looter); + } + public LootSlotType? GetUiTypeForPlayer(Player player, Loot loot) { if (is_looted) @@ -439,7 +450,7 @@ namespace Game.Loots foreach (ObjectGuid allowedLooter in m_lootItem.GetAllowedLooters()) { Player plr = Global.ObjAccessor.GetPlayer(m_map, allowedLooter); - if (!plr || !m_lootItem.AllowedForPlayer(plr)) // check if player meet the condition to be able to roll this item + if (!plr || !m_lootItem.HasAllowedLooter(plr.GetGUID())) // check if player meet the condition to be able to roll this item { m_rollVoteMap[allowedLooter].Vote = RollVote.NotValid; continue; @@ -692,7 +703,7 @@ namespace Game.Loots if (lootItem == null || lootItem.is_looted) continue; - if (!lootItem.AllowedForPlayer(player)) + if (!lootItem.HasAllowedLooter(GetGUID())) continue; if (lootItem.is_blocked) @@ -817,6 +828,10 @@ namespace Game.Loots void FillNotNormalLootFor(Player player) { + if (_dungeonEncounterId != 0) + if (player.IsLockedToDungeonEncounter(_dungeonEncounterId)) + return; + ObjectGuid plguid = player.GetGUID(); _allowedLooters.Add(plguid); @@ -824,7 +839,7 @@ namespace Game.Loots foreach (LootItem item in items) { - if (!item.AllowedForPlayer(player)) + if (!item.AllowedForPlayer(player, this)) continue; if (item.freeforall) @@ -921,6 +936,11 @@ namespace Game.Loots } } + public bool HasAllowedLooter(ObjectGuid looter) + { + return _allowedLooters.Contains(looter); + } + public void GenerateMoneyLoot(uint minAmount, uint maxAmount) { if (maxAmount > 0) diff --git a/Source/Game/Loot/LootItemStorage.cs b/Source/Game/Loot/LootItemStorage.cs index 30e1d5458..11109ded2 100644 --- a/Source/Game/Loot/LootItemStorage.cs +++ b/Source/Game/Loot/LootItemStorage.cs @@ -208,7 +208,7 @@ namespace Game.Loots // saved to the DB that the player never should have gotten. This check prevents that, so that only // items that the player should get in loot are in the DB. // IE: Horde items are not saved to the DB for Ally players. - if (!li.AllowedForPlayer(player)) + if (!li.AllowedForPlayer(player, loot)) continue; // Don't save currency tokens