From cb21664b4f8748eefe8718e17d4512032a73ed4d Mon Sep 17 00:00:00 2001 From: Hondacrx Date: Sun, 8 Jun 2025 19:31:53 -0400 Subject: [PATCH] Core/Spells: Implemented SpellEffectAttributes::DontFailSpellOnTargetingFailure Port From (https://github.com/TrinityCore/TrinityCore/commit/195945742105fa8dbd061f3b62b755d722655931) --- .../Framework/Constants/Spells/SpellConst.cs | 2 +- Source/Game/Spells/Spell.cs | 4 ++- Source/Game/Spells/SpellInfo.cs | 31 ++++++++++++------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index 6b588ceb9..c314e11f6 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -2163,7 +2163,7 @@ namespace Framework.Constants Unk12 = 0x1000, // 12 Unk13 = 0x2000, // 13 Unk14 = 0x4000, // 14 - Unk15 = 0x8000, // 15 + DoNotFailIfNoTarget = 0x8000, // 15 Do Not Fail if No Target Unk16 = 0x10000, // 16 Unk17 = 0x20000, // 17 ActivatesRequiredShapeshift = 0x40000, // 18 diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 32753eaff..253043420 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -1199,6 +1199,8 @@ namespace Game.Spells void SelectImplicitTargetDestTargets(SpellEffectInfo spellEffectInfo, SpellImplicitTargetInfo targetType, SpellTargetIndex targetIndex) { WorldObject target = m_targets.GetObjectTarget(); + if (target == null) + return; SpellDestination dest = new(target); @@ -6513,7 +6515,7 @@ namespace Game.Spells if (result == SpellCastResult.SpellCastOk || result == SpellCastResult.UnitNotInfront) { // do not check targets for ground-targeted spells (we target them on top of the intended target anyway) - if (GetSpellInfo().ExplicitTargetMask.HasAnyFlag((uint)SpellCastTargetFlags.DestLocation)) + if (GetSpellInfo().GetExplicitTargetMask().HasAnyFlag(SpellCastTargetFlags.DestLocation)) return true; SelectSpellTargets(); //check if among target units, our WANTED target is as well (.only self cast spells return false) diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index c3c996e45..d9fc1ceb2 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -1193,7 +1193,7 @@ namespace Game.Spells public SpellCastResult CheckExplicitTarget(WorldObject caster, WorldObject target, Item itemTarget = null) { - SpellCastTargetFlags neededTargets = GetExplicitTargetMask(); + SpellCastTargetFlags neededTargets = (SpellCastTargetFlags)RequiredExplicitTargetMask; if (target == null) { if (Convert.ToBoolean(neededTargets & (SpellCastTargetFlags.UnitMask | SpellCastTargetFlags.GameobjectMask | SpellCastTargetFlags.CorpseMask))) @@ -3221,31 +3221,39 @@ namespace Game.Spells { bool srcSet = false; bool dstSet = false; - SpellCastTargetFlags targetMask = Targets; + // prepare target mask using effect target entries foreach (var effectInfo in GetEffects()) { if (!effectInfo.IsEffect()) continue; + SpellCastTargetFlags targetMask = 0; targetMask |= effectInfo.TargetA.GetExplicitTargetMask(ref srcSet, ref dstSet); targetMask |= effectInfo.TargetB.GetExplicitTargetMask(ref srcSet, ref dstSet); // add explicit target flags based on spell effects which have SpellEffectImplicitTargetTypes.Explicit and no valid target provided - if (effectInfo.GetImplicitTargetType() != SpellEffectImplicitTargetTypes.Explicit) - continue; + if (effectInfo.GetImplicitTargetType() == SpellEffectImplicitTargetTypes.Explicit) + { - // extend explicit target mask only if valid targets for effect could not be provided by target types - SpellCastTargetFlags effectTargetMask = effectInfo.GetMissingTargetMask(srcSet, dstSet, targetMask); + // extend explicit target mask only if valid targets for effect could not be provided by target types + SpellCastTargetFlags effectTargetMask = effectInfo.GetMissingTargetMask(srcSet, dstSet, targetMask); - // don't add explicit object/dest flags when spell has no max range - if (GetMaxRange(true) == 0.0f && GetMaxRange(false) == 0.0f) - effectTargetMask &= ~(SpellCastTargetFlags.UnitMask | SpellCastTargetFlags.Gameobject | SpellCastTargetFlags.CorpseMask | SpellCastTargetFlags.DestLocation); + // don't add explicit object/dest flags when spell has no max range + if (GetMaxRange(true) == 0.0f && GetMaxRange(false) == 0.0f) + effectTargetMask &= ~(SpellCastTargetFlags.UnitMask | SpellCastTargetFlags.Gameobject | SpellCastTargetFlags.CorpseMask | SpellCastTargetFlags.DestLocation); - targetMask |= effectTargetMask; + targetMask |= effectTargetMask; + } + + ExplicitTargetMask |= (uint)targetMask; + if (!effectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.DontFailSpellOnTargetingFailure)) + RequiredExplicitTargetMask |= (uint)targetMask; } - ExplicitTargetMask = (uint)targetMask; + ExplicitTargetMask |= (uint)Targets; + if (!HasAttribute(SpellAttr13.DoNotFailIfNoTarget)) + RequiredExplicitTargetMask |= (uint)Targets; } public bool _isPositiveTarget(SpellEffectInfo effect) @@ -3954,6 +3962,7 @@ namespace Game.Spells // SpellScalingEntry public ScalingInfo Scaling; public uint ExplicitTargetMask { get; set; } + public uint RequiredExplicitTargetMask { get; set; } public SpellChainNode ChainEntry { get; set; } public SqrtDamageAndHealingDiminishingStruct SqrtDamageAndHealingDiminishing;