From d6ccdbea10a29091afc20471331f50260f65ac46 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 12 Apr 2024 23:37:24 +0200 Subject: [PATCH] Core/Spells: SPELL_ATTR1_REQUIRE_ALL_TARGETS should require that each unique (targetA, targetB) pair has at least one target, not that each effect has a target * Fixed Mind Flay on creatures immune to slow --- src/server/game/Spells/Spell.cpp | 108 ++++++++++++++++--------------- src/server/game/Spells/Spell.h | 6 +- 2 files changed, 60 insertions(+), 54 deletions(-) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 4694b85abaf75..e83c236ad6916 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -738,7 +738,7 @@ void Spell::SelectSpellTargets() // select targets for cast phase SelectExplicitTargets(); - uint32 processedAreaEffectsMask = 0; + uint32 processedEffectsMaskForSpell = 0; for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects()) { // not call for empty effect. @@ -753,8 +753,10 @@ void Spell::SelectSpellTargets() if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM)) m_targets.SetTargetFlag(TARGET_FLAG_GAMEOBJECT); - SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetA, processedAreaEffectsMask); - SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetB, processedAreaEffectsMask); + uint32 currentlyProcessedEffectMask = processedEffectsMaskForSpell; + SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetA, processedEffectsMaskForSpell); + SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetB, processedEffectsMaskForSpell); + currentlyProcessedEffectMask = processedEffectsMaskForSpell & ~currentlyProcessedEffectMask; // Select targets of effect based on effect type // those are used when no valid target could be added for spell effect based on spell target type @@ -766,16 +768,17 @@ 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 (currentlyProcessedEffectMask + && (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) + bool noTargetFound = std::ranges::none_of(m_UniqueTargetInfo, [currentlyProcessedEffectMask](TargetInfo const& target) { - return target.EffectMask & effectMask; + return target.EffectMask & currentlyProcessedEffectMask; }); if (noTargetFound) @@ -787,9 +790,9 @@ void Spell::SelectSpellTargets() } 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) + bool anyNonImmuneTargetFound = std::ranges::any_of(m_UniqueTargetInfo, [currentlyProcessedEffectMask](TargetInfo const& target) { - return target.EffectMask & effectMask && target.MissCondition != SPELL_MISS_IMMUNE && target.MissCondition != SPELL_MISS_IMMUNE2; + return target.EffectMask & currentlyProcessedEffectMask && target.MissCondition != SPELL_MISS_IMMUNE && target.MissCondition != SPELL_MISS_IMMUNE2; }); if (!anyNonImmuneTargetFound) @@ -882,42 +885,45 @@ void Spell::SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, return; uint32 effectMask = 1 << spellEffectInfo.EffectIndex; + + // targets for effect already selected + if (effectMask & processedEffectMask) + return; + // set the same target list for all effects // some spells appear to need this, however this requires more research - switch (targetType.GetSelectionCategory()) - { - case TARGET_SELECT_CATEGORY_NEARBY: - case TARGET_SELECT_CATEGORY_CONE: - case TARGET_SELECT_CATEGORY_AREA: - { - // targets for effect already selected - if (effectMask & processedEffectMask) - return; - std::array const& effects = GetSpellInfo()->GetEffects(); - // choose which targets we can select at once - for (uint32 j = spellEffectInfo.EffectIndex + 1; j < effects.size(); ++j) - { - if (effects[j].IsEffect() && - spellEffectInfo.TargetA.GetTarget() == effects[j].TargetA.GetTarget() && - spellEffectInfo.TargetB.GetTarget() == effects[j].TargetB.GetTarget() && - spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions && - spellEffectInfo.CalcRadius(m_caster) == effects[j].CalcRadius(m_caster) && - CheckScriptEffectImplicitTargets(spellEffectInfo.EffectIndex, j)) - { - effectMask |= 1 << j; - } + std::array const& effects = GetSpellInfo()->GetEffects(); + // choose which targets we can select at once + for (uint32 j = spellEffectInfo.EffectIndex + 1; j < effects.size(); ++j) + { + if (effects[j].IsEffect() && + spellEffectInfo.TargetA.GetTarget() == effects[j].TargetA.GetTarget() && + spellEffectInfo.TargetB.GetTarget() == effects[j].TargetB.GetTarget() && + spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions && + CheckScriptEffectImplicitTargets(spellEffectInfo.EffectIndex, j)) + { + switch (targetType.GetSelectionCategory()) + { + case TARGET_SELECT_CATEGORY_NEARBY: + case TARGET_SELECT_CATEGORY_CONE: + case TARGET_SELECT_CATEGORY_AREA: + if (spellEffectInfo.CalcRadius(m_caster) != effects[j].CalcRadius(m_caster)) + continue; + break; + default: + break; } - processedEffectMask |= effectMask; - break; + + effectMask |= 1 << j; } - default: - break; } + processedEffectMask |= effectMask; + switch (targetType.GetSelectionCategory()) { case TARGET_SELECT_CATEGORY_CHANNEL: - SelectImplicitChannelTargets(spellEffectInfo, targetType); + SelectImplicitChannelTargets(spellEffectInfo, targetType, effectMask); break; case TARGET_SELECT_CATEGORY_NEARBY: SelectImplicitNearbyTargets(spellEffectInfo, targetType, effectMask); @@ -969,10 +975,10 @@ void Spell::SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, switch (targetType.GetReferenceType()) { case TARGET_REFERENCE_TYPE_CASTER: - SelectImplicitCasterObjectTargets(spellEffectInfo, targetType); + SelectImplicitCasterObjectTargets(spellEffectInfo, targetType, effectMask); break; case TARGET_REFERENCE_TYPE_TARGET: - SelectImplicitTargetObjectTargets(spellEffectInfo, targetType); + SelectImplicitTargetObjectTargets(spellEffectInfo, targetType, effectMask); break; default: ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT"); @@ -990,7 +996,7 @@ void Spell::SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, } } -void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType) +void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask) { if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER) { @@ -1012,7 +1018,7 @@ void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo, CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType); // unit target may be no longer avalible - teleported out of map for example if (target && target->ToUnit()) - AddUnitTarget(target->ToUnit(), 1 << spellEffectInfo.EffectIndex); + AddUnitTarget(target->ToUnit(), effMask); else TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex)); break; @@ -1511,7 +1517,7 @@ void Spell::SelectImplicitDestDestTargets(SpellEffectInfo const& spellEffectInfo m_targets.ModDst(dest); } -void Spell::SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType) +void Spell::SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask) { WorldObject* target = nullptr; bool checkIfValid = true; @@ -1559,13 +1565,13 @@ void Spell::SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffect if (target) { if (Unit* unit = target->ToUnit()) - AddUnitTarget(unit, 1 << spellEffectInfo.EffectIndex, checkIfValid); + AddUnitTarget(unit, effMask, checkIfValid); else if (GameObject* go = target->ToGameObject()) - AddGOTarget(go, 1 << spellEffectInfo.EffectIndex); + AddGOTarget(go, effMask); } } -void Spell::SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType) +void Spell::SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask) { ASSERT((m_targets.GetObjectTarget() || m_targets.GetItemTarget()) && "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!"); @@ -1576,17 +1582,17 @@ void Spell::SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffect if (target) { if (Unit* unit = target->ToUnit()) - AddUnitTarget(unit, 1 << spellEffectInfo.EffectIndex, true, false); + AddUnitTarget(unit, effMask, true, false); else if (GameObject* gobj = target->ToGameObject()) - AddGOTarget(gobj, 1 << spellEffectInfo.EffectIndex); + AddGOTarget(gobj, effMask); else if (Corpse* corpse = target->ToCorpse()) - AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex); + AddCorpseTarget(corpse, effMask); - SelectImplicitChainTargets(spellEffectInfo, targetType, target, 1 << spellEffectInfo.EffectIndex); + SelectImplicitChainTargets(spellEffectInfo, targetType, target, effMask); } // Script hook can remove object target and we would wrongly land here else if (Item* item = m_targets.GetItemTarget()) - AddItemTarget(item, 1 << spellEffectInfo.EffectIndex); + AddItemTarget(item, effMask); } void Spell::SelectImplicitChainTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 8dbcdd9ad7d8e..5f36ea02b850b 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -288,15 +288,15 @@ class TC_GAME_API Spell void SelectSpellTargets(); void SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32& processedEffectMask); - void SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); + void SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask); void SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask); void SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask); void SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask); void SelectImplicitCasterDestTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); void SelectImplicitTargetDestTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); void SelectImplicitDestDestTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); - void SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); - void SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); + void SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask); + void SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask); void SelectImplicitChainTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask); void SelectImplicitTrajTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType);