Skip to content

Commit

Permalink
Core/Spells: SPELL_ATTR1_REQUIRE_ALL_TARGETS should require that each…
Browse files Browse the repository at this point in the history
… unique (targetA, targetB) pair has at least one target, not that each effect has a target

* Fixed Mind Flay on creatures immune to slow
  • Loading branch information
Shauren committed Apr 12, 2024
1 parent d8d863a commit d6ccdbe
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 54 deletions.
108 changes: 57 additions & 51 deletions src/server/game/Spells/Spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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<SpellEffectInfo, MAX_SPELL_EFFECTS> 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<SpellEffectInfo, MAX_SPELL_EFFECTS> 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);
Expand Down Expand Up @@ -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");
Expand All @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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!");

Expand All @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions src/server/game/Spells/Spell.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit d6ccdbe

Please sign in to comment.