From 536f72d0773186449aa2906b43f500c171e2a725 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Tue, 5 Mar 2024 18:33:31 -0500 Subject: [PATCH] Core/Creatures: Implemented CREATURE_STATIC_FLAG_2_IGNORE_SANCTUARY (ignore SPELL_EFFECT_SANCTUARY, used by Vanish) Port From (https://github.com/TrinityCore/TrinityCore/commit/1369b8708458fb5020b6ab7a9608123459d4eb26) --- Source/Framework/Constants/CreatureConst.cs | 2 +- Source/Game/Combat/CombatManager.cs | 51 ++++++++++++++------- Source/Game/Combat/ThreatManager.cs | 12 +++-- Source/Game/Entities/Creature/Creature.cs | 2 + Source/Game/Entities/Unit/Unit.Combat.cs | 22 +++++---- Source/Game/Spells/SpellEffects.cs | 13 ++++-- 6 files changed, 69 insertions(+), 33 deletions(-) diff --git a/Source/Framework/Constants/CreatureConst.cs b/Source/Framework/Constants/CreatureConst.cs index ad4aee9dd..ddc5db13c 100644 --- a/Source/Framework/Constants/CreatureConst.cs +++ b/Source/Framework/Constants/CreatureConst.cs @@ -316,7 +316,7 @@ namespace Framework.Constants NoWoundedSlowdown = 0x00000040, UseCreatorBonuses = 0x00000080, IgnoreFeignDeath = 0x00000100, // CreatureFlagExtraIgnoreFeignDeath - IgnoreSanctuary = 0x00000200, + IgnoreSanctuary = 0x00000200, // Ignores SPELL_EFFECT_SANCTUARY ActionTriggersWhileCharmed = 0x00000400, InteractWhileDead = 0x00000800, // CreatureTypeFlagInteractWhileDead NoInterruptSchoolCooldown = 0x00001000, diff --git a/Source/Game/Combat/CombatManager.cs b/Source/Game/Combat/CombatManager.cs index 14697be8b..004ee6c70 100644 --- a/Source/Game/Combat/CombatManager.cs +++ b/Source/Game/Combat/CombatManager.cs @@ -4,6 +4,7 @@ using Framework.Constants; using Game.AI; using Game.Entities; +using System; using System.Collections.Generic; using System.Linq; @@ -58,9 +59,9 @@ namespace Game.Combat public void Update(uint tdiff) { - foreach(var pair in _pvpRefs.ToList()) + foreach (var pair in _pvpRefs.ToList()) { - PvPCombatReference refe = pair.Value; + PvPCombatReference refe = pair.Value; if (refe.first == _owner && !refe.Update(tdiff)) // only update if we're the first unit involved (otherwise double decrement) { _pvpRefs.Remove(pair.Key); @@ -76,7 +77,7 @@ namespace Game.Combat return true; return false; } - + public bool HasPvECombatWithPlayers() { foreach (var reference in _pveRefs) @@ -85,7 +86,7 @@ namespace Game.Combat return false; } - + public bool HasPvPCombat() { foreach (var pair in _pvpRefs) @@ -217,10 +218,11 @@ namespace Game.Combat } } - public void SuppressPvPCombat() + public void SuppressPvPCombat(Func unitFilter = null) { - foreach (var pair in _pvpRefs) - pair.Value.Suppress(_owner); + foreach (var (_, combatRef) in _pvpRefs) + if (unitFilter == null || unitFilter(combatRef.GetOther(_owner))) + combatRef.Suppress(_owner); if (UpdateOwnerCombatState()) { @@ -230,18 +232,24 @@ namespace Game.Combat } } - public void EndAllPvECombat() + public void EndAllPvECombat(Func unitFilter = null) { // cannot have threat without combat - _owner.GetThreatManager().RemoveMeFromThreatLists(); + _owner.GetThreatManager().RemoveMeFromThreatLists(unitFilter); _owner.GetThreatManager().ClearAllThreat(); - while (!_pveRefs.Empty()) - _pveRefs.First().Value.EndCombat(); + + List combatReferencesToRemove = new(); + foreach (var (_, combatRef) in _pveRefs) + if (unitFilter == null || unitFilter(combatRef.GetOther(_owner))) + combatReferencesToRemove.Add(combatRef); + + foreach (CombatReference combatRef in combatReferencesToRemove) + combatRef.EndCombat(); } public void RevalidateCombat() { - foreach(var (guid, refe) in _pveRefs.ToList()) + foreach (var (guid, refe) in _pveRefs.ToList()) { if (!CanBeginCombat(_owner, refe.GetOther(_owner))) { @@ -260,10 +268,21 @@ namespace Game.Combat } } - void EndAllPvPCombat() + public void EndAllPvPCombat(Func unitFilter = null) { - while (!_pvpRefs.Empty()) - _pvpRefs.First().Value.EndCombat(); + List combatReferencesToRemove = new(); + foreach (var (_, combatRef) in _pvpRefs) + if (unitFilter == null || unitFilter(combatRef.GetOther(_owner))) + combatReferencesToRemove.Add(combatRef); + + foreach (CombatReference combatRef in combatReferencesToRemove) + combatRef.EndCombat(); + } + + void EndAllCombat(Func unitFilter = null) + { + EndAllPvECombat(unitFilter); + EndAllPvPCombat(unitFilter); } public static void NotifyAICombat(Unit me, Unit other) @@ -343,7 +362,7 @@ namespace Game.Combat public Unit first; public Unit second; public bool _isPvP; - + bool _suppressFirst; bool _suppressSecond; diff --git a/Source/Game/Combat/ThreatManager.cs b/Source/Game/Combat/ThreatManager.cs index 4d57a460b..1987349f9 100644 --- a/Source/Game/Combat/ThreatManager.cs +++ b/Source/Game/Combat/ThreatManager.cs @@ -610,13 +610,15 @@ namespace Game.Combat threatened.GetThreatManager().AddThreat(assistant, 0.0f, spell, true); } - public void RemoveMeFromThreatLists() + public void RemoveMeFromThreatLists(Func unitFilter) { - while (!_threatenedByMe.Empty()) - { - var refe = _threatenedByMe.FirstOrDefault().Value; + List threatReferencesToRemove = new(); + foreach (var (_, refe) in _threatenedByMe) + if (unitFilter == null || unitFilter(refe.GetOwner())) + threatReferencesToRemove.Add(refe); + + foreach (ThreatReference refe in threatReferencesToRemove) refe._mgr.ClearThreat(_owner); - } } public void UpdateMyTempModifiers() diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 7a6d67e13..5b537b157 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -3564,6 +3564,8 @@ namespace Game.Entities public void SetNoSearchAssistance(bool val) { m_AlreadySearchedAssistance = val; } public bool HasSearchedAssistance() { return m_AlreadySearchedAssistance; } public bool CanIgnoreFeignDeath() { return GetCreatureTemplate().FlagsExtra.HasFlag(CreatureFlagsExtra.IgnoreFeighDeath); } + public bool IsIgnoringSanctuarySpellEffect() { return _staticFlags.HasFlag(CreatureStaticFlags2.IgnoreSanctuary); } + public void SetIngoreSanctuarySpellEffect(bool ignoreSanctuary) { _staticFlags.ApplyFlag(CreatureStaticFlags2.IgnoreSanctuary, ignoreSanctuary); } public override MovementGeneratorType GetDefaultMovementType() { return DefaultMovementType; } public void SetDefaultMovementType(MovementGeneratorType mgt) { DefaultMovementType = mgt; } diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index 156b0196b..8887deec3 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -55,23 +55,29 @@ namespace Game.Entities public virtual void AtDisengage() { } - public void CombatStop(bool includingCast = false, bool mutualPvP = true) + public void CombatStop(bool includingCast = false, bool mutualPvP = true, Func unitFilter = null) { if (includingCast && IsNonMeleeSpellCast(false)) InterruptNonMeleeSpells(false); AttackStop(); - RemoveAllAttackers(); + if (unitFilter == null) + RemoveAllAttackers(); + else + { + List attackersToRemove = attackerList.Where(unitFilter).ToList(); + foreach (Unit attacker in attackersToRemove) + attacker.AttackStop(); + } + if (IsTypeId(TypeId.Player)) ToPlayer().SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel + m_combatManager.EndAllPvECombat(unitFilter); if (mutualPvP) - ClearInCombat(); - else - { // vanish and brethren are weird - m_combatManager.EndAllPvECombat(); - m_combatManager.SuppressPvPCombat(); - } + m_combatManager.EndAllPvPCombat(unitFilter); + else // vanish and brethren are weird + m_combatManager.SuppressPvPCombat(unitFilter); } public void CombatStopWithPets(bool includingCast = false) diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 2eb70b219..5612b139a 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -2840,16 +2840,23 @@ namespace Game.Spells if (unitTarget == null) return; + var isAffectedBySanctuary = bool (Unit attacker) => + { + Creature attackerCreature = attacker.ToCreature(); + return attackerCreature == null || !attackerCreature.IsIgnoringSanctuarySpellEffect(); + }; + if (unitTarget.IsPlayer() && !unitTarget.GetMap().IsDungeon()) { // stop all pve combat for players outside dungeons, suppress pvp combat - unitTarget.CombatStop(false, false); + unitTarget.CombatStop(false, false, isAffectedBySanctuary); } else { // in dungeons (or for nonplayers), reset this unit on all enemies' threat lists - foreach (var pair in unitTarget.GetThreatManager().GetThreatenedByMeList()) - pair.Value.ScaleThreat(0.0f); + foreach (var (_, refe) in unitTarget.GetThreatManager().GetThreatenedByMeList()) + if (isAffectedBySanctuary(refe.GetOwner())) + refe.ScaleThreat(0.0f); } // makes spells cast before this time fizzle