diff options
| author | Shauren <shauren.trinity@gmail.com> | 2025-12-25 16:48:32 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2025-12-25 16:48:32 +0100 |
| commit | 6cff1622e501ddeb6e690443ac21f9178cc0d09b (patch) | |
| tree | bc0388759d62272ba24cd3aec858107d0d600490 /src | |
| parent | 42ebe3b0dc71c915539e458e82e6eed226d79c39 (diff) | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 4 | ||||
| -rw-r--r-- | src/server/game/Entities/Object/Object.h | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 23 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 6 | ||||
| -rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 4 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 18 |
7 files changed, 36 insertions, 23 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index ac2219ed5cf..48ed667e545 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -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 diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 72b3a5dd448..5a6782dcddb 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -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; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 6e888db12d1..b50131ce6df 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -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()) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 881aee786cb..10e719d343a 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -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; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 25397d69d62..73fcbe1cefe 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -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 diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 7a4722f9cef..3a68549f238 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -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; } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 50db01b3fec..8cc94e2f59d 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -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; |
