diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 119f5c8f304..b7372fdb23b 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -3196,7 +3196,7 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint // remove all flag auras (they are positive, but they must be removed when you are immune) if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) - && GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD)) + && GetSpellInfo()->HasAttribute(SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE)) target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); if (apply) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 78964578568..4694b85abaf 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -766,6 +766,41 @@ void Spell::SelectSpellTargets() if (m_targets.HasDst()) AddDestTarget(*m_targets.GetDst(), spellEffectInfo.EffectIndex); + if (spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT + || spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST + || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT + || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST) + { + if (m_spellInfo->HasAttribute(SPELL_ATTR1_REQUIRE_ALL_TARGETS)) + { + bool noTargetFound = std::none_of(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effectMask = 1u << spellEffectInfo.EffectIndex](TargetInfo const& target) + { + return target.EffectMask & effectMask; + }); + + if (noTargetFound) + { + SendCastResult(SPELL_FAILED_BAD_IMPLICIT_TARGETS); + finish(false); + return; + } + } + if (m_spellInfo->HasAttribute(SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE)) + { + bool anyNonImmuneTargetFound = std::any_of(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effectMask = 1u << spellEffectInfo.EffectIndex](TargetInfo const& target) + { + return target.EffectMask & effectMask && target.MissCondition != SPELL_MISS_IMMUNE && target.MissCondition != SPELL_MISS_IMMUNE2; + }); + + if (!anyNonImmuneTargetFound) + { + SendCastResult(SPELL_FAILED_IMMUNE); + finish(false); + return; + } + } + } + if (m_spellInfo->IsChanneled()) { // maybe do this for all spells? diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index a26fa70e95c..7c2001f8f64 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -466,7 +466,7 @@ enum SpellAttr1 : uint32 SPELL_ATTR1_UNK23 = 0x00800000, // TITLE Unknwon attribute 23@Attr1 SPELL_ATTR1_IS_FISHING = 0x01000000, // TITLE Fishing (client only) SPELL_ATTR1_UNK25 = 0x02000000, // TITLE Unknown attribute 25@Attr1 - SPELL_ATTR1_UNK26 = 0x04000000, // TITLE Unknown attribute 26@Attr1 DESCRIPTION Related to [target=focus] and [target=mouseover] macros? + SPELL_ATTR1_REQUIRE_ALL_TARGETS = 0x04000000, // TITLE Require All Targets SPELL_ATTR1_UNK27 = 0x08000000, // TITLE Unknown attribute 27@Attr1 DESCRIPTION Melee spell? SPELL_ATTR1_DONT_DISPLAY_IN_AURA_BAR = 0x10000000, // TITLE Hide in aura bar (client only) SPELL_ATTR1_CHANNEL_DISPLAY_SPELL_NAME = 0x20000000, // TITLE Show spell name during channel (client only) @@ -498,7 +498,7 @@ enum SpellAttr2 : uint32 SPELL_ATTR2_REQ_DEAD_PET = 0x00040000, // TITLE Requires dead pet SPELL_ATTR2_NOT_NEED_SHAPESHIFT = 0x00080000, // TITLE Also allow outside shapeshift DESCRIPTION Even if Stances are nonzero, allow spell to be cast outside of shapeshift (though not in a different shapeshift) SPELL_ATTR2_UNK20 = 0x00100000, // TITLE Unknown attribute 20@Attr2 - SPELL_ATTR2_DAMAGE_REDUCED_SHIELD = 0x00200000, // TITLE Damage reduction ability DESCRIPTION Causes BG flags to be dropped if combined with ATTR1_DISPEL_AURAS_ON_IMMUNITY + SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE = 0x00200000, // TITLE Fail on all targets immune DESCRIPTION Causes BG flags to be dropped if combined with ATTR1_DISPEL_AURAS_ON_IMMUNITY SPELL_ATTR2_UNK22 = 0x00400000, // TITLE Unknown attribute 22@Attr2 SPELL_ATTR2_IS_ARCANE_CONCENTRATION = 0x00800000, // TITLE Arcane Concentration SPELL_ATTR2_UNK24 = 0x01000000, // TITLE Unknown attribute 24@Attr2 diff --git a/src/server/shared/enuminfo_SharedDefines.cpp b/src/server/shared/enuminfo_SharedDefines.cpp index db473c9cc24..c29d65018a6 100644 --- a/src/server/shared/enuminfo_SharedDefines.cpp +++ b/src/server/shared/enuminfo_SharedDefines.cpp @@ -423,7 +423,7 @@ TC_API_EXPORT EnumText EnumUtils::ToString(SpellAttr1 value) case SPELL_ATTR1_UNK23: return { "SPELL_ATTR1_UNK23", "Unknwon attribute 23@Attr1", "" }; case SPELL_ATTR1_IS_FISHING: return { "SPELL_ATTR1_IS_FISHING", "Fishing (client only)", "" }; case SPELL_ATTR1_UNK25: return { "SPELL_ATTR1_UNK25", "Unknown attribute 25@Attr1", "" }; - case SPELL_ATTR1_UNK26: return { "SPELL_ATTR1_UNK26", "Unknown attribute 26@Attr1", "Related to [target=focus] and [target=mouseover] macros?" }; + case SPELL_ATTR1_REQUIRE_ALL_TARGETS: return { "SPELL_ATTR1_REQUIRE_ALL_TARGETS", "Require All Targets", "" }; case SPELL_ATTR1_UNK27: return { "SPELL_ATTR1_UNK27", "Unknown attribute 27@Attr1", "Melee spell?" }; case SPELL_ATTR1_DONT_DISPLAY_IN_AURA_BAR: return { "SPELL_ATTR1_DONT_DISPLAY_IN_AURA_BAR", "Hide in aura bar (client only)", "" }; case SPELL_ATTR1_CHANNEL_DISPLAY_SPELL_NAME: return { "SPELL_ATTR1_CHANNEL_DISPLAY_SPELL_NAME", "Show spell name during channel (client only)", "" }; @@ -467,7 +467,7 @@ TC_API_EXPORT SpellAttr1 EnumUtils::FromIndex(size_t index) case 23: return SPELL_ATTR1_UNK23; case 24: return SPELL_ATTR1_IS_FISHING; case 25: return SPELL_ATTR1_UNK25; - case 26: return SPELL_ATTR1_UNK26; + case 26: return SPELL_ATTR1_REQUIRE_ALL_TARGETS; case 27: return SPELL_ATTR1_UNK27; case 28: return SPELL_ATTR1_DONT_DISPLAY_IN_AURA_BAR; case 29: return SPELL_ATTR1_CHANNEL_DISPLAY_SPELL_NAME; @@ -508,7 +508,7 @@ TC_API_EXPORT size_t EnumUtils::ToIndex(SpellAttr1 value) case SPELL_ATTR1_UNK23: return 23; case SPELL_ATTR1_IS_FISHING: return 24; case SPELL_ATTR1_UNK25: return 25; - case SPELL_ATTR1_UNK26: return 26; + case SPELL_ATTR1_REQUIRE_ALL_TARGETS: return 26; case SPELL_ATTR1_UNK27: return 27; case SPELL_ATTR1_DONT_DISPLAY_IN_AURA_BAR: return 28; case SPELL_ATTR1_CHANNEL_DISPLAY_SPELL_NAME: return 29; @@ -547,7 +547,7 @@ TC_API_EXPORT EnumText EnumUtils::ToString(SpellAttr2 value) case SPELL_ATTR2_REQ_DEAD_PET: return { "SPELL_ATTR2_REQ_DEAD_PET", "Requires dead pet", "" }; case SPELL_ATTR2_NOT_NEED_SHAPESHIFT: return { "SPELL_ATTR2_NOT_NEED_SHAPESHIFT", "Also allow outside shapeshift", "Even if Stances are nonzero, allow spell to be cast outside of shapeshift (though not in a different shapeshift)" }; case SPELL_ATTR2_UNK20: return { "SPELL_ATTR2_UNK20", "Unknown attribute 20@Attr2", "" }; - case SPELL_ATTR2_DAMAGE_REDUCED_SHIELD: return { "SPELL_ATTR2_DAMAGE_REDUCED_SHIELD", "Damage reduction ability", "Causes BG flags to be dropped if combined with ATTR1_DISPEL_AURAS_ON_IMMUNITY" }; + case SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE: return { "SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE", "Fail on all targets immune", "Causes BG flags to be dropped if combined with ATTR1_DISPEL_AURAS_ON_IMMUNITY" }; case SPELL_ATTR2_UNK22: return { "SPELL_ATTR2_UNK22", "Unknown attribute 22@Attr2", "" }; case SPELL_ATTR2_IS_ARCANE_CONCENTRATION: return { "SPELL_ATTR2_IS_ARCANE_CONCENTRATION", "Arcane Concentration", "" }; case SPELL_ATTR2_UNK24: return { "SPELL_ATTR2_UNK24", "Unknown attribute 24@Attr2", "" }; @@ -591,7 +591,7 @@ TC_API_EXPORT SpellAttr2 EnumUtils::FromIndex(size_t index) case 18: return SPELL_ATTR2_REQ_DEAD_PET; case 19: return SPELL_ATTR2_NOT_NEED_SHAPESHIFT; case 20: return SPELL_ATTR2_UNK20; - case 21: return SPELL_ATTR2_DAMAGE_REDUCED_SHIELD; + case 21: return SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE; case 22: return SPELL_ATTR2_UNK22; case 23: return SPELL_ATTR2_IS_ARCANE_CONCENTRATION; case 24: return SPELL_ATTR2_UNK24; @@ -632,7 +632,7 @@ TC_API_EXPORT size_t EnumUtils::ToIndex(SpellAttr2 value) case SPELL_ATTR2_REQ_DEAD_PET: return 18; case SPELL_ATTR2_NOT_NEED_SHAPESHIFT: return 19; case SPELL_ATTR2_UNK20: return 20; - case SPELL_ATTR2_DAMAGE_REDUCED_SHIELD: return 21; + case SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE: return 21; case SPELL_ATTR2_UNK22: return 22; case SPELL_ATTR2_IS_ARCANE_CONCENTRATION: return 23; case SPELL_ATTR2_UNK24: return 24;