mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-13 03:32:28 -04:00
Core/Spells: Only check spell immunity against effects that will apply to each target
This commit is contained in:
@@ -2591,10 +2591,10 @@ SpellMissInfo WorldObject::MagicSpellHitResult(Unit* victim, SpellInfo const* sp
|
||||
// Parry
|
||||
// For spells
|
||||
// Resist
|
||||
SpellMissInfo WorldObject::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect /*= false*/) const
|
||||
SpellMissInfo WorldObject::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect, bool canImmune) const
|
||||
{
|
||||
// Check for immune
|
||||
if (victim->IsImmunedToSpell(spellInfo, this))
|
||||
if (canImmune && victim->IsImmunedToSpell(spellInfo, MAX_EFFECT_MASK, this))
|
||||
return SPELL_MISS_IMMUNE;
|
||||
|
||||
// Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
|
||||
|
||||
@@ -837,7 +837,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
virtual float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo) const;
|
||||
virtual SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const;
|
||||
SpellMissInfo MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const;
|
||||
SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect = false) const;
|
||||
SpellMissInfo SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect, bool canImmune) const;
|
||||
void SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo);
|
||||
|
||||
virtual uint32 GetFaction() const = 0;
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "Loot.h"
|
||||
#include "LootMgr.h"
|
||||
#include "LootPackets.h"
|
||||
#include "MapUtils.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "MovementGenerator.h"
|
||||
@@ -1597,7 +1598,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
|
||||
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
||||
|
||||
// Damage shield can be resisted...
|
||||
SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false);
|
||||
SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false, true);
|
||||
if (missInfo != SPELL_MISS_NONE)
|
||||
{
|
||||
victim->SendSpellMiss(this, spellInfo->Id, missInfo);
|
||||
@@ -7743,7 +7744,7 @@ int32 Unit::SpellAbsorbBonusTaken(Unit* caster, SpellInfo const* spellProto, int
|
||||
return static_cast<int32>(std::round(absorb));
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
|
||||
bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
|
||||
{
|
||||
if (!spellInfo)
|
||||
return false;
|
||||
@@ -7754,14 +7755,14 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
|
||||
if (!requireImmunityPurgesEffectAttribute)
|
||||
return range.begin() != range.end();
|
||||
|
||||
return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
|
||||
return std::ranges::any_of(range, [](uint32 immunitySpellId)
|
||||
{
|
||||
if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
|
||||
if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(immunitySpellId, DIFFICULTY_NONE))
|
||||
if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
}, Trinity::Containers::MapValue);
|
||||
};
|
||||
|
||||
// Single spell immunity.
|
||||
@@ -7792,7 +7793,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
|
||||
{
|
||||
// State/effect immunities applied by aura expect full spell immunity
|
||||
// Ignore effects with mechanic, they are supposed to be checked separately
|
||||
if (!spellEffectInfo.IsEffect())
|
||||
if (!spellEffectInfo.IsEffect() || !(effectMask & (1 << spellEffectInfo.EffectIndex)))
|
||||
continue;
|
||||
if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
|
||||
{
|
||||
@@ -7820,7 +7821,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
|
||||
if (!immuneSpellInfo || !immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
|
||||
continue;
|
||||
|
||||
if (spellInfo->IsPositive() && !(immuneSpellInfo && immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
|
||||
if ((spellInfo->NegativeEffects & std::bitset<MAX_SPELL_EFFECTS>(effectMask)).none() && !(immuneSpellInfo && immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
|
||||
continue;
|
||||
|
||||
if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
|
||||
@@ -7955,14 +7956,14 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo co
|
||||
if (!requireImmunityPurgesEffectAttribute)
|
||||
return range.begin() != range.end();
|
||||
|
||||
return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
|
||||
return std::ranges::any_of(range, [](uint32 immunitySpellId)
|
||||
{
|
||||
if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
|
||||
if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(immunitySpellId, DIFFICULTY_NONE))
|
||||
if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
}, Trinity::Containers::MapValue);
|
||||
};
|
||||
|
||||
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
|
||||
@@ -12283,7 +12284,7 @@ Aura* Unit::AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target)
|
||||
if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_ALLOW_DEAD_TARGET))
|
||||
return nullptr;
|
||||
|
||||
if (target->IsImmunedToSpell(spellInfo, this))
|
||||
if (target->IsImmunedToSpell(spellInfo, effMask, this))
|
||||
return nullptr;
|
||||
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
|
||||
@@ -1677,7 +1677,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
static uint32 SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim);
|
||||
|
||||
void ApplySpellImmune(uint32 spellId, SpellImmunity op, uint32 type, bool apply);
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const;
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const;
|
||||
uint32 GetSchoolImmunityMask() const;
|
||||
uint32 GetDamageImmunityMask() const;
|
||||
uint64 GetMechanicImmunityMask() const;
|
||||
|
||||
@@ -5629,7 +5629,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
|
||||
// Consecrate ticks can miss and will not show up in the combat log
|
||||
// dynobj auras must always have a caster
|
||||
if (GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) &&
|
||||
ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE)
|
||||
ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false, true) != SPELL_MISS_NONE)
|
||||
return;
|
||||
|
||||
CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
|
||||
@@ -5763,7 +5763,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
|
||||
|
||||
// dynobj auras must always have a caster
|
||||
if (GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) &&
|
||||
ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE)
|
||||
ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false, true) != SPELL_MISS_NONE)
|
||||
return;
|
||||
|
||||
CleanDamage cleanDamage = CleanDamage(0, 0, GetSpellInfo()->GetAttackType(), MELEE_HIT_NORMAL);
|
||||
@@ -5953,7 +5953,7 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con
|
||||
}
|
||||
|
||||
if (GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) &&
|
||||
caster->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE)
|
||||
caster->SpellHitResult(target, GetSpellInfo(), false, true) != SPELL_MISS_NONE)
|
||||
return;
|
||||
|
||||
// ignore negative values (can be result apply spellmods to aura damage
|
||||
|
||||
@@ -684,7 +684,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
|
||||
{
|
||||
// needs readding - remove now, will be applied in next update cycle
|
||||
// (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed)
|
||||
if (itr->first->IsImmunedToSpell(GetSpellInfo(), caster, true) || !CanBeAppliedOn(itr->first))
|
||||
if (itr->first->IsImmunedToSpell(GetSpellInfo(), itr->second, caster, true) || !CanBeAppliedOn(itr->first))
|
||||
{
|
||||
targetsToRemove.push_back(applicationPair.second->GetTarget());
|
||||
continue;
|
||||
@@ -717,7 +717,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
|
||||
if (itr->first->IsImmunedToSpellEffect(GetSpellInfo(), spellEffectInfo, caster))
|
||||
itr->second &= ~(1 << spellEffectInfo.EffectIndex);
|
||||
|
||||
if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo(), caster) || !CanBeAppliedOn(itr->first))
|
||||
if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo(), itr->second, caster) || !CanBeAppliedOn(itr->first))
|
||||
addUnit = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2434,7 +2434,9 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
|
||||
|
||||
// Calculate hit result
|
||||
WorldObject* caster = m_originalCaster ? m_originalCaster : m_caster;
|
||||
targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo, m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)));
|
||||
targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo,
|
||||
m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)),
|
||||
false /*immunity will be checked after complete EffectMask is known*/);
|
||||
|
||||
// Spell have speed - need calculate incoming time
|
||||
// Incoming time is zero for self casts. At least I think so.
|
||||
@@ -2479,7 +2481,9 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
|
||||
{
|
||||
// Calculate reflected spell result on caster (shouldn't be able to reflect gameobject spells)
|
||||
Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
|
||||
targetInfo.ReflectResult = unitCaster->SpellHitResult(unitCaster, m_spellInfo, false); // can't reflect twice
|
||||
targetInfo.ReflectResult = unitCaster->SpellHitResult(unitCaster, m_spellInfo,
|
||||
false /*can't reflect twice*/,
|
||||
false /*immunity will be checked after complete EffectMask is known*/);
|
||||
|
||||
// Proc spell reflect aura when missile hits the original target
|
||||
target->m_Events.AddEvent(new ProcReflectDelayed(target, m_originalCasterGUID), target->m_Events.CalculateTime(Milliseconds(targetInfo.TimeDelay)));
|
||||
@@ -3099,7 +3103,7 @@ SpellMissInfo Spell::PreprocessSpellHit(Unit* unit, TargetInfo& hitInfo)
|
||||
return SPELL_MISS_EVADE;
|
||||
|
||||
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
|
||||
if (hitInfo.TimeDelay && unit->IsImmunedToSpell(m_spellInfo, m_caster))
|
||||
if (hitInfo.TimeDelay && unit->IsImmunedToSpell(m_spellInfo, hitInfo.EffectMask, m_caster))
|
||||
return SPELL_MISS_IMMUNE;
|
||||
|
||||
CallScriptBeforeHitHandlers(hitInfo.MissCondition);
|
||||
@@ -8612,6 +8616,10 @@ void Spell::PreprocessSpellLaunch(TargetInfo& targetInfo)
|
||||
if (!targetUnit)
|
||||
return;
|
||||
|
||||
// Check immunity now that EffectMask is known
|
||||
if (targetUnit->IsImmunedToSpell(GetSpellInfo(), targetInfo.EffectMask, m_caster))
|
||||
targetInfo.MissCondition = SPELL_MISS_IMMUNE;
|
||||
|
||||
// This will only cause combat - the target will engage once the projectile hits (in Spell::TargetInfo::PreprocessTarget)
|
||||
if (m_originalCaster && targetInfo.MissCondition != SPELL_MISS_EVADE && !m_originalCaster->IsFriendlyTo(targetUnit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)) && (m_spellInfo->HasInitialAggro() || targetUnit->IsEngaged()))
|
||||
m_originalCaster->SetInCombatWith(targetUnit, true);
|
||||
@@ -8622,7 +8630,11 @@ void Spell::PreprocessSpellLaunch(TargetInfo& targetInfo)
|
||||
unit = targetUnit;
|
||||
// In case spell reflect from target, do all effect on caster (if hit)
|
||||
else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
|
||||
{
|
||||
unit = m_caster->ToUnit();
|
||||
if (unit && unit->IsImmunedToSpell(GetSpellInfo(), targetInfo.EffectMask, unit))
|
||||
targetInfo.ReflectResult = SPELL_MISS_IMMUNE;
|
||||
}
|
||||
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user