aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp215
-rw-r--r--src/server/game/Entities/Unit/Unit.h11
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h11
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp339
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h2
-rw-r--r--src/server/game/Spells/Spell.cpp508
-rw-r--r--src/server/game/Spells/Spell.h28
-rw-r--r--src/server/game/Spells/SpellInfo.cpp492
-rw-r--r--src/server/game/Spells/SpellInfo.h28
-rw-r--r--src/server/game/Spells/SpellMgr.cpp15
-rw-r--r--src/server/game/Spells/SpellMgr.h1
-rw-r--r--src/server/game/World/World.cpp3
12 files changed, 947 insertions, 706 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 7430ea90499..91714961018 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -323,9 +323,6 @@ Unit::Unit(bool isWorldObject) :
m_transform = 0;
m_canModifyStats = false;
- for (uint8 i = 0; i < MAX_SPELL_IMMUNITY; ++i)
- m_spellImmune[i].clear();
-
for (uint8 i = 0; i < UNIT_MOD_END; ++i)
{
m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
@@ -706,6 +703,12 @@ void Unit::DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) co
uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
{
+ if (victim->IsImmunedToDamage(spellProto))
+ {
+ SendSpellDamageImmune(victim, spellProto->Id, false);
+ return 0;
+ }
+
if (victim->IsAIEnabled)
victim->GetAI()->DamageTaken(this, damage);
@@ -2231,7 +2234,7 @@ void Unit::SendMeleeAttackStop(Unit* victim)
bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType)
{
// These spells can't be blocked
- if (spellProto && spellProto->HasAttribute(SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK))
+ if (spellProto && (spellProto->HasAttribute(SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK) || spellProto->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT)))
return false;
// Can't block when casting/controlled
@@ -2296,11 +2299,6 @@ bool Unit::CanUseAttackType(uint8 attacktype) const
// Melee based spells hit result calculations
SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const
{
- // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
- // resist and deflect chances
- if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
- return SPELL_MISS_NONE;
-
WeaponAttackType attType = BASE_ATTACK;
// Check damage class instead of attack type to correctly handle judgements
@@ -2440,7 +2438,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const
{
// Can`t miss on dead target (on skinning for example)
- if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER) || spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ if ((!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER))
return SPELL_MISS_NONE;
SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
@@ -2525,6 +2523,9 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
// Resist
SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool CanReflect)
{
+ if (spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ return SPELL_MISS_NONE;
+
// Check for immune
if (victim->IsImmunedToSpell(spellInfo))
return SPELL_MISS_IMMUNE;
@@ -2534,10 +2535,6 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, boo
if (spellInfo->IsPositive() && !IsHostileTo(victim)) // prevent from affecting enemy by "positive" spell
return SPELL_MISS_NONE;
- // Check for immune
- if (victim->IsImmunedToDamage(spellInfo))
- return SPELL_MISS_IMMUNE;
-
if (this == victim)
return SPELL_MISS_NONE;
@@ -3027,10 +3024,13 @@ int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
bool Unit::CanMoveDuringChannel() const
{
if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
- if (spell->getState() != SPELL_STATE_FINISHED)
- return spell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING) && spell->IsChannelActive();
+ {
+ if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
+ if (!spell->GetSpellInfo()->IsMoveAllowedChannel())
+ return false;
+ }
- return false;
+ return true;
}
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
@@ -7173,18 +7173,18 @@ int32 Unit::SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const
return advertisedBenefit;
}
-bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const
+bool Unit::IsImmunedToDamage(SpellSchoolMask schoolMask) const
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
- if (itr->type & shoolMask)
+ SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ if ((itr->first & schoolMask) != 0)
return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
- SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
- for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
- if (itr->type & shoolMask)
+ SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
+ for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
+ if ((itr->first & schoolMask) != 0)
return true;
return false;
@@ -7192,23 +7192,23 @@ bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const
bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
{
- if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ if (!spellInfo)
return false;
- uint32 shoolMask = spellInfo->GetSchoolMask();
- if (spellInfo->Id != 42292 && spellInfo->Id != 59752)
- {
- // If m_immuneToSchool type contain this school type, IMMUNE damage.
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
- if (itr->type & shoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->spellId)))
- return true;
- }
+ if (spellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) || spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
+ return false;
+
+ uint32 schoolMask = spellInfo->GetSchoolMask();
+ // If m_immuneToSchool type contain this school type, IMMUNE damage.
+ SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ if ((itr->first & schoolMask) && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second)))
+ return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
- SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
- for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
- if (itr->type & shoolMask)
+ SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
+ for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
+ if ((itr->first & schoolMask) != 0)
return true;
return false;
@@ -7220,29 +7220,26 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
return false;
// Single spell immunity.
- SpellImmuneList const& idList = m_spellImmune[IMMUNITY_ID];
- for (SpellImmuneList::const_iterator itr = idList.begin(); itr != idList.end(); ++itr)
- if (itr->type == spellInfo->Id)
- return true;
+ SpellImmuneContainer const& idList = m_spellImmune[IMMUNITY_ID];
+ if (idList.count(spellInfo->Id) > 0)
+ return true;
if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
- if (spellInfo->Dispel)
+ if (uint32 dispel = spellInfo->Dispel)
{
- SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
- for (SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
- if (itr->type == spellInfo->Dispel)
- return true;
+ SpellImmuneContainer const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
+ if (dispelList.count(dispel) > 0)
+ return true;
}
// Spells that don't have effectMechanics.
- if (spellInfo->Mechanic)
+ if (uint32 mechanic = spellInfo->Mechanic)
{
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- if (itr->type == spellInfo->Mechanic)
- return true;
+ SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
+ if (mechanicList.count(mechanic) > 0)
+ return true;
}
bool immuneToAllEffects = true;
@@ -7250,7 +7247,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
{
// State/effect immunities applied by aura expect full spell immunity
// Ignore effects with mechanic, they are supposed to be checked separately
- if (!effect || !effect->IsEffect())
+ if (!effect)
continue;
if (!IsImmunedToSpellEffect(spellInfo, effect->EffectIndex))
{
@@ -7262,13 +7259,13 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
return true;
- if (spellInfo->Id != 42292 && spellInfo->Id != 59752)
+ if (!spellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
{
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
- SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->spellId);
- if ((itr->type & spellInfo->GetSchoolMask())
+ SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
+ if ((itr->first & spellInfo->GetSchoolMask())
&& !(immuneSpellInfo && immuneSpellInfo->IsPositive() && spellInfo->IsPositive())
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
return true;
@@ -7281,9 +7278,9 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const
uint32 Unit::GetSchoolImmunityMask() const
{
uint32 mask = 0;
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_SCHOOL];
- for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- mask |= itr->type;
+ SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
+ mask |= itr->first;
return mask;
}
@@ -7291,9 +7288,9 @@ uint32 Unit::GetSchoolImmunityMask() const
uint32 Unit::GetMechanicImmunityMask() const
{
uint32 mask = 0;
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- mask |= (1 << itr->type);
+ SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
+ for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
+ mask |= (1 << itr->first);
return mask;
}
@@ -7304,7 +7301,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
return false;
SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficultyID(), index);
- if (!effect || !effect->IsEffect())
+ if (!effect)
return false;
if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
@@ -7312,33 +7309,35 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
uint32 eff = effect->Effect;
- SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
- for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
- if (itr->type == eff)
- return true;
+ auto const& effectList = m_spellImmune[IMMUNITY_EFFECT];
+ if (effectList.count(eff) > 0)
+ return true;
if (uint32 mechanic = effect->Mechanic)
{
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- if (itr->type == mechanic)
- return true;
+ auto const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
+ if (mechanicList.count(mechanic) > 0)
+ return true;
}
- if (uint32 aura = effect->ApplyAuraName)
+ if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
{
- SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
- for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
- if (itr->type == aura)
- if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
- return true;
-
- // Check for immune to application of harmful magical effects
- AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
- for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
- if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
- !spellInfo->IsPositiveEffect(index)) // Harmful
+ if (uint32 aura = effect->ApplyAuraName)
+ {
+ SpellImmuneContainer const& list = m_spellImmune[IMMUNITY_STATE];
+ if (list.count(aura) > 0)
return true;
+
+ if (!spellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
+ {
+ // Check for immune to application of harmful magical effects
+ AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
+ for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
+ if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
+ !spellInfo->IsPositiveEffect(index)) // Harmful
+ return true;
+ }
+ }
}
return false;
@@ -7541,52 +7540,14 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
{
if (apply)
- {
- for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
- {
- next = itr; ++next;
- if (itr->type == type)
- {
- m_spellImmune[op].erase(itr);
- next = m_spellImmune[op].begin();
- }
- }
- SpellImmune Immune;
- Immune.spellId = spellId;
- Immune.type = type;
- m_spellImmune[op].push_back(Immune);
- }
+ m_spellImmune[op].emplace(type, spellId);
else
{
- for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
+ auto bounds = m_spellImmune[op].equal_range(type);
+ for (auto itr = bounds.first; itr != bounds.second;)
{
- if (itr->spellId == spellId && itr->type == type)
- {
- m_spellImmune[op].erase(itr);
- break;
- }
- }
- }
-}
-
-void Unit::ApplySpellDispelImmunity(const SpellInfo* spellProto, DispelType type, bool apply)
-{
- ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply);
-
- if (apply && spellProto->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
- {
- // Create dispel mask by dispel type
- uint32 dispelMask = SpellInfo::GetDispelMask(type);
- // Dispel all existing auras vs current dispel type
- AuraApplicationMap& auras = GetAppliedAuras();
- for (AuraApplicationMap::iterator itr = auras.begin(); itr != auras.end();)
- {
- SpellInfo const* spell = itr->second->GetBase()->GetSpellInfo();
- if (spell->GetDispelMask() & dispelMask)
- {
- // Dispel aura
- RemoveAura(itr);
- }
+ if (itr->second == spellId)
+ itr = m_spellImmune[op].erase(itr);
else
++itr;
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 36bb07a8442..72646e28651 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -229,13 +229,7 @@ namespace WorldPackets
typedef std::list<Unit*> UnitList;
typedef std::list<std::pair<Aura*, uint8>> DispelChargesList;
-struct SpellImmune
-{
- uint32 type;
- uint32 spellId;
-};
-
-typedef std::list<SpellImmune> SpellImmuneList;
+typedef std::unordered_multimap<uint32 /*type*/, uint32 /*spellId*/> SpellImmuneContainer;
enum UnitModifierType
{
@@ -1623,7 +1617,7 @@ class TC_GAME_API Unit : public WorldObject
bool SetInPhase(uint32 id, bool update, bool apply) override;
void UpdateObjectVisibility(bool forced = true) override;
- SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY];
+ SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY];
uint32 m_lastSanctuaryTime;
// Threat related methods
@@ -1720,7 +1714,6 @@ class TC_GAME_API Unit : public WorldObject
uint32 GetRemainingPeriodicAmount(ObjectGuid caster, uint32 spellId, AuraType auraType, uint8 effectIndex = 0) const;
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply);
- void ApplySpellDispelImmunity(const SpellInfo* spellProto, DispelType type, bool apply);
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo) const; // redefined in Creature
uint32 GetSchoolImmunityMask() const;
uint32 GetMechanicImmunityMask() const;
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 105735b1ffd..8fdcc413ff2 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -483,9 +483,9 @@ enum SpellAttr2
SPELL_ATTR2_IS_ARCANE_CONCENTRATION = 0x00800000, // 23 Only mage Arcane Concentration have this flag
SPELL_ATTR2_UNK24 = 0x01000000, // 24
SPELL_ATTR2_UNK25 = 0x02000000, // 25
- SPELL_ATTR2_UNK26 = 0x04000000, // 26 unaffected by school immunity
+ SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE = 0x04000000, // 26 unaffected by school immunity
SPELL_ATTR2_UNK27 = 0x08000000, // 27
- SPELL_ATTR2_UNK28 = 0x10000000, // 28
+ SPELL_ATTR2_IGNORE_ITEM_CHECK = 0x10000000, // 28 Spell is cast without checking item requirements (charges/reagents/totem)
SPELL_ATTR2_CANT_CRIT = 0x20000000, // 29 Spell can't crit
SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC = 0x40000000, // 30 spell can trigger even if triggered
SPELL_ATTR2_FOOD_BUFF = 0x80000000 // 31 Food or Drink Buff (like Well Fed)
@@ -657,7 +657,7 @@ enum SpellAttr7
SPELL_ATTR7_UNK17 = 0x00020000, // 17 Only 27965 (Suicide) spell.
SPELL_ATTR7_HAS_CHARGE_EFFECT = 0x00040000, // 18 Only spells that have Charge among effects.
SPELL_ATTR7_ZONE_TELEPORT = 0x00080000, // 19 Teleports to specific zones.
- SPELL_ATTR7_UNK20 = 0x00100000, // 20 Blink, Divine Shield, Ice Block
+ SPELL_ATTR7_USABLE_IN_STUN_FEAR_CONFUSION = 0x00100000, // 20 Blink, Divine Shield, Ice Block
SPELL_ATTR7_UNK21 = 0x00200000, // 21 Not set
SPELL_ATTR7_UNK22 = 0x00400000, // 22
SPELL_ATTR7_UNK23 = 0x00800000, // 23 Motivate, Mutilate, Shattering Throw
@@ -2128,10 +2128,11 @@ enum SpellImmunity
IMMUNITY_DAMAGE = 3, // enum SpellSchoolMask
IMMUNITY_DISPEL = 4, // enum DispelType
IMMUNITY_MECHANIC = 5, // enum Mechanics
- IMMUNITY_ID = 6
+ IMMUNITY_ID = 6,
+
+ MAX_SPELL_IMMUNITY
};
-#define MAX_SPELL_IMMUNITY 7
// target enum name consist of:
// TARGET_[OBJECT_TYPE]_[REFERENCE_TYPE(skipped for caster)]_[SELECTION_TYPE(skipped for default)]_[additional specifiers(friendly, BACK_LEFT, etc.]
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 076452542ff..66fbb32fd2a 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -212,7 +212,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes
&AuraEffect::HandleNULL, //145 used by 5 spells in 6.2.4 dbc but the meaning of this aura changed (it's used by mind control spells but isn't the control itself)
&AuraEffect::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE
- &AuraEffect::HandleModStateImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
+ &AuraEffect::HandleModMechanicImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
&AuraEffect::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS
&AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK
&AuraEffect::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
@@ -3094,257 +3094,13 @@ void AuraEffect::HandleAuraModMinimumSpeedRate(AuraApplication const* aurApp, ui
/*** IMMUNITY ***/
/*********************************************************/
-void AuraEffect::HandleModStateImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const
+void AuraEffect::HandleModMechanicImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const
{
if (!(mode & AURA_EFFECT_HANDLE_REAL))
return;
Unit* target = aurApp->GetTarget();
- std::list <AuraType> aura_immunity_list;
- uint32 mechanic_immunity_list = 0;
- int32 miscVal = GetMiscValue();
-
- switch (miscVal)
- {
- case 27:
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SILENCE, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_SILENCE);
- break;
- case 96:
- case 1615:
- {
- if (GetAmount())
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT_2);
- }
- break;
- }
- case 679:
- {
- if (GetId() == 57742)
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT_2);
- }
- break;
- }
- case 1557:
- {
- if (GetId() == 64187)
- {
- mechanic_immunity_list = (1 << MECHANIC_STUN);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- }
- else
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT_2);
- }
- break;
- }
- case 1614:
- case 1694:
- {
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_TAUNT);
- break;
- }
- case 1630:
- {
- if (!GetAmount())
- {
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_TAUNT);
- }
- else
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT_2);
- }
- break;
- }
- case 477:
- case 1733:
- {
- if (!GetAmount())
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT)
- | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM)
- | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR)
- | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED)
- | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT_2);
- }
- break;
- }
- case 878:
- {
- if (GetAmount() == 1)
- {
- mechanic_immunity_list = (1 << MECHANIC_SNARE) | (1 << MECHANIC_STUN)
- | (1 << MECHANIC_DISORIENTED) | (1 << MECHANIC_FREEZE);
-
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- }
- break;
- }
- default:
- break;
- }
-
- if (aura_immunity_list.empty())
- {
- if (miscVal & (1<<10))
- aura_immunity_list.push_back(SPELL_AURA_MOD_STUN);
- if (miscVal & (1<<1))
- aura_immunity_list.push_back(SPELL_AURA_TRANSFORM);
-
- // These flag can be recognized wrong:
- if (miscVal & (1<<6))
- aura_immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED);
- if (miscVal & (1<<0))
- {
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT);
- aura_immunity_list.push_back(SPELL_AURA_MOD_ROOT_2);
- }
- if (miscVal & (1<<2))
- aura_immunity_list.push_back(SPELL_AURA_MOD_CONFUSE);
- if (miscVal & (1<<9))
- aura_immunity_list.push_back(SPELL_AURA_MOD_FEAR);
- if (miscVal & (1<<7))
- aura_immunity_list.push_back(SPELL_AURA_MOD_DISARM);
- }
-
- // apply immunities
- for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter)
- target->ApplySpellImmune(GetId(), IMMUNITY_STATE, *iter, apply);
-
- if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
- {
- target->RemoveAurasWithMechanic(mechanic_immunity_list, AURA_REMOVE_BY_DEFAULT, GetId());
- for (std::list <AuraType>::iterator iter = aura_immunity_list.begin(); iter != aura_immunity_list.end(); ++iter)
- target->RemoveAurasByType(*iter);
- }
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3353,52 +3109,7 @@ void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8
return;
Unit* target = aurApp->GetTarget();
- uint32 mechanic;
-
- switch (GetId())
- {
- case 34471: // The Beast Within
- case 19574: // Bestial Wrath
- mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_KNOCKOUT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_BANISH, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SHACKLE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DAZE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
- break;
- case 42292: // PvP trinket
- case 59752: // Every Man for Himself
- case 53490: // Bullheaded
- mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
- // Actually we should apply immunities here, too, but the aura has only 100 ms duration, so there is practically no point
- break;
- case 54508: // Demonic Empowerment
- mechanic = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
- break;
- default:
- if (GetMiscValue() < 1)
- return;
- mechanic = 1 << GetMiscValue();
- target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply);
- break;
- }
-
- if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
- target->RemoveAurasWithMechanic(mechanic, AURA_REMOVE_BY_DEFAULT, GetId());
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3407,8 +3118,7 @@ void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply);
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
// when removing flag aura, handle flag drop
Player* player = target->ToPlayer();
@@ -3430,11 +3140,7 @@ void AuraEffect::HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellImmune(GetId(), IMMUNITY_STATE, GetMiscValue(), apply);
-
- if (apply && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
- target->RemoveAurasByType(AuraType(GetMiscValue()), ObjectGuid::Empty, GetBase());
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3443,8 +3149,7 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellImmune(GetId(), IMMUNITY_SCHOOL, GetMiscValue(), (apply));
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
if (GetSpellInfo()->Mechanic == MECHANIC_BANISH)
{
@@ -3454,12 +3159,15 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
{
bool banishFound = false;
Unit::AuraEffectList const& banishAuras = target->GetAuraEffectsByType(GetAuraType());
- for (Unit::AuraEffectList::const_iterator i = banishAuras.begin(); i != banishAuras.end(); ++i)
- if ((*i)->GetSpellInfo()->Mechanic == MECHANIC_BANISH)
+ for (AuraEffect const* aurEff : banishAuras)
+ {
+ if (aurEff->GetSpellInfo()->Mechanic == MECHANIC_BANISH)
{
banishFound = true;
break;
}
+ }
+
if (!banishFound)
target->ClearUnitState(UNIT_STATE_ISOLATED);
}
@@ -3472,23 +3180,6 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
&& GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD))
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
-
- /// @todo optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else
- if (apply
- && GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
- && GetSpellInfo()->IsPositive()) // Only positive immunity removes auras
- {
- uint32 schoolMask = GetMiscValue();
- target->RemoveAppliedAuras([this, schoolMask](AuraApplication const* aurApp)
- {
- SpellInfo const* spell = aurApp->GetBase()->GetSpellInfo();
- return (spell->GetSchoolMask() & schoolMask) // Check for school mask
- && GetSpellInfo()->CanDispelAura(spell)
- && !aurApp->IsPositive() // Don't remove positive spells
- && !spell->IsPassive() // Don't remove passive auras
- && spell->Id != GetId(); // Don't remove self
- });
- }
}
void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3497,8 +3188,7 @@ void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 m
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellImmune(GetId(), IMMUNITY_DAMAGE, GetMiscValue(), apply);
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -3507,8 +3197,7 @@ void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint
return;
Unit* target = aurApp->GetTarget();
-
- target->ApplySpellDispelImmunity(m_spellInfo, DispelType(GetMiscValue()), (apply));
+ m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
/*********************************************************/
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index 2682d66102e..743b48b9f99 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -208,7 +208,7 @@ class TC_GAME_API AuraEffect
void HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleAuraModMinimumSpeedRate(AuraApplication const* aurApp, uint8 mode, bool apply) const;
// immunity
- void HandleModStateImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const;
+ void HandleModMechanicImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleModMechanicImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const;
void HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 5ccd5ee6e21..f8f1dc773ff 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2599,7 +2599,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
return SPELL_MISS_EVADE;
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
- if (m_spellInfo->Speed && (unit->IsImmunedToDamage(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo)))
+ if (m_spellInfo->Speed && unit->IsImmunedToSpell(m_spellInfo))
return SPELL_MISS_IMMUNE;
// disable effects to which unit is immune
@@ -3013,7 +3013,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
if ((_triggeredCastFlags & TRIGGERED_IGNORE_COMBO_POINTS) || m_CastItem || !m_caster->m_playerMovingMe)
m_needComboPoints = false;
- SpellCastResult result = CheckCast(true);
+ uint32 param1 = 0, param2 = 0;
+ SpellCastResult result = CheckCast(true, &param1, &param2);
// target is checked in too many locations and with different results to handle each of them
// handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks
if (_triggeredCastFlags & TRIGGERED_IGNORE_TARGET_CHECK && result == SPELL_FAILED_BAD_TARGETS)
@@ -3038,7 +3039,10 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
}
- SendCastResult(result);
+ if (param1 || param2)
+ SendCastResult(result, &param1, &param2);
+ else
+ SendCastResult(result);
finish(false);
return;
@@ -3227,10 +3231,11 @@ void Spell::cast(bool skipCheck)
// skip check if done already (for instant cast spells for example)
if (!skipCheck)
{
- SpellCastResult castResult = CheckCast(false);
+ uint32 param1 = 0, param2 = 0;
+ SpellCastResult castResult = CheckCast(false, &param1, &param2);
if (castResult != SPELL_CAST_OK)
{
- SendCastResult(castResult);
+ SendCastResult(castResult, &param1, &param2);
SendInterrupted(0);
//restore spell mods
if (m_caster->GetTypeId() == TYPEID_PLAYER)
@@ -3782,7 +3787,7 @@ void Spell::finish(bool ok)
}
template<class T>
-inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo const* spellInfo, SpellCastResult result, SpellCustomErrors customError, uint32* misc, Player* caster)
+inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo const* spellInfo, SpellCastResult result, SpellCustomErrors customError, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/, Player* caster)
{
packet.CastID = castId;
packet.SpellID = spellInfo->Id;
@@ -3791,109 +3796,182 @@ inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo cons
switch (result)
{
case SPELL_FAILED_NOT_READY:
- packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag)
+ if (*param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag)
break;
case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
- packet.FailedArg1 = spellInfo->RequiresSpellFocus; // SpellFocusObject.dbc id
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = spellInfo->RequiresSpellFocus; // SpellFocusObject.dbc id
break;
- case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
- // hardcode areas limitation case
- switch (spellInfo->Id)
+ case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
{
- case 41617: // Cenarion Mana Salve
- case 41619: // Cenarion Healing Salve
- packet.FailedArg1 = 3905;
- break;
- case 41618: // Bottled Nethergon Energy
- case 41620: // Bottled Nethergon Vapor
- packet.FailedArg1 = 3842;
- break;
- case 45373: // Bloodberry Elixir
- packet.FailedArg1 = 4075;
- break;
- default: // default case (don't must be)
- packet.FailedArg1 = 0;
- break;
+ // hardcode areas limitation case
+ switch (spellInfo->Id)
+ {
+ case 41617: // Cenarion Mana Salve
+ case 41619: // Cenarion Healing Salve
+ packet.FailedArg1 = 3905;
+ break;
+ case 41618: // Bottled Nethergon Energy
+ case 41620: // Bottled Nethergon Vapor
+ packet.FailedArg1 = 3842;
+ break;
+ case 45373: // Bloodberry Elixir
+ packet.FailedArg1 = 4075;
+ break;
+ default: // default case (don't must be)
+ packet.FailedArg1 = 0;
+ break;
+ }
}
break;
case SPELL_FAILED_TOTEMS:
- if (spellInfo->Totem[0])
- packet.FailedArg1 = spellInfo->Totem[0];
- if (spellInfo->Totem[1])
- packet.FailedArg2 = spellInfo->Totem[1];
+ if (param1)
+ {
+ packet.FailedArg1 = *param1;
+ if (param2)
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ if (spellInfo->Totem[0])
+ packet.FailedArg1 = spellInfo->Totem[0];
+ if (spellInfo->Totem[1])
+ packet.FailedArg2 = spellInfo->Totem[1];
+ }
break;
case SPELL_FAILED_TOTEM_CATEGORY:
- if (spellInfo->TotemCategory[0])
- packet.FailedArg1 = spellInfo->TotemCategory[0];
- if (spellInfo->TotemCategory[1])
- packet.FailedArg2 = spellInfo->TotemCategory[1];
+ if (param1)
+ {
+ packet.FailedArg1 = *param1;
+ if (param2)
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ if (spellInfo->TotemCategory[0])
+ packet.FailedArg1 = spellInfo->TotemCategory[0];
+ if (spellInfo->TotemCategory[1])
+ packet.FailedArg2 = spellInfo->TotemCategory[1];
+ }
break;
case SPELL_FAILED_EQUIPPED_ITEM_CLASS:
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND:
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND:
- packet.FailedArg1 = spellInfo->EquippedItemClass;
- packet.FailedArg2 = spellInfo->EquippedItemSubClassMask;
+ if (param1 && param2)
+ {
+ packet.FailedArg1 = *param1;
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ packet.FailedArg1 = spellInfo->EquippedItemClass;
+ packet.FailedArg2 = spellInfo->EquippedItemSubClassMask;
+ }
break;
case SPELL_FAILED_TOO_MANY_OF_ITEM:
{
- uint32 item = 0;
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(caster->GetMap()->GetDifficultyID()))
- if (effect->ItemType)
- item = effect->ItemType;
- ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
- if (proto && proto->GetItemLimitCategory())
- packet.FailedArg1 = proto->GetItemLimitCategory();
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ {
+ uint32 item = 0;
+ for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(caster->GetMap()->GetDifficultyID()))
+ if (effect->ItemType)
+ item = effect->ItemType;
+ ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
+ if (proto && proto->GetItemLimitCategory())
+ packet.FailedArg1 = proto->GetItemLimitCategory();
+ }
break;
}
case SPELL_FAILED_PREVENTED_BY_MECHANIC:
- packet.FailedArg1 = spellInfo->GetAllEffectsMechanicMask(); // SpellMechanic.dbc id
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = spellInfo->GetAllEffectsMechanicMask(); // SpellMechanic.dbc id
break;
case SPELL_FAILED_NEED_EXOTIC_AMMO:
- packet.FailedArg1 = spellInfo->EquippedItemSubClassMask; // seems correct...
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = spellInfo->EquippedItemSubClassMask; // seems correct...
break;
case SPELL_FAILED_NEED_MORE_ITEMS:
- packet.FailedArg1 = 0; // Item id
- packet.FailedArg2 = 0; // Item count?
+ if (param1 && param2)
+ {
+ packet.FailedArg1 = *param1;
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ packet.FailedArg1 = 0; // Item id
+ packet.FailedArg2 = 0; // Item count?
+ }
break;
case SPELL_FAILED_MIN_SKILL:
- packet.FailedArg1 = 0; // SkillLine.dbc id
- packet.FailedArg2 = 0; // required skill value
+ if (param1 && param2)
+ {
+ packet.FailedArg1 = *param1;
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ packet.FailedArg1 = 0; // SkillLine.dbc id
+ packet.FailedArg2 = 0; // required skill value
+ }
break;
case SPELL_FAILED_FISHING_TOO_LOW:
- packet.FailedArg1 = 0; // required fishing skill
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = 0; // required fishing skill
break;
case SPELL_FAILED_CUSTOM_ERROR:
packet.FailedArg1 = customError;
break;
case SPELL_FAILED_SILENCED:
- packet.FailedArg1 = 0; // Unknown
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = 0; // Unknown
break;
case SPELL_FAILED_REAGENTS:
{
- uint32 missingItem = 0;
- for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
{
- if (spellInfo->Reagent[i] <= 0)
- continue;
+ uint32 missingItem = 0;
+ for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
+ {
+ if (spellInfo->Reagent[i] <= 0)
+ continue;
- uint32 itemid = spellInfo->Reagent[i];
- uint32 itemcount = spellInfo->ReagentCount[i];
+ uint32 itemid = spellInfo->Reagent[i];
+ uint32 itemcount = spellInfo->ReagentCount[i];
- if (!caster->HasItemCount(itemid, itemcount))
- {
- missingItem = itemid;
- break;
+ if (!caster->HasItemCount(itemid, itemcount))
+ {
+ missingItem = itemid;
+ break;
+ }
}
+ packet.FailedArg1 = missingItem; // first missing item
}
-
- packet.FailedArg1 = missingItem; // first missing item
break;
}
case SPELL_FAILED_CANT_UNTALENT:
{
- if (misc)
- if (TalentEntry const* talent = sTalentStore.LookupEntry(misc[0]))
- packet.FailedArg1 = talent->SpellID;
+ ASSERT(param1);
+ packet.FailedArg1 = *param1;
break;
}
// TODO: SPELL_FAILED_NOT_STANDING
@@ -3902,7 +3980,7 @@ inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo cons
}
}
-void Spell::SendCastResult(SpellCastResult result)
+void Spell::SendCastResult(SpellCastResult result, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
{
if (result == SPELL_CAST_OK)
return;
@@ -3910,7 +3988,7 @@ void Spell::SendCastResult(SpellCastResult result)
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
- if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time
+ if (m_caster->ToPlayer()->IsLoading()) // don't send cast results at loading time
return;
if (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR)
@@ -3918,11 +3996,11 @@ void Spell::SendCastResult(SpellCastResult result)
WorldPackets::Spells::CastFailed castFailed;
castFailed.SpellXSpellVisualID = m_SpellVisual;
- FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, m_misc.Raw.Data, m_caster->ToPlayer());
+ FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, param1, param2, m_caster->ToPlayer());
m_caster->ToPlayer()->SendDirectMessage(castFailed.Write());
}
-void Spell::SendPetCastResult(SpellCastResult result)
+void Spell::SendPetCastResult(SpellCastResult result, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
{
if (result == SPELL_CAST_OK)
return;
@@ -3935,18 +4013,18 @@ void Spell::SendPetCastResult(SpellCastResult result)
result = SPELL_FAILED_DONT_REPORT;
WorldPackets::Spells::PetCastFailed petCastFailed;
- FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SPELL_CUSTOM_ERROR_NONE, m_misc.Raw.Data, owner->ToPlayer());
+ FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SPELL_CUSTOM_ERROR_NONE, param1, param2, owner->ToPlayer());
owner->ToPlayer()->SendDirectMessage(petCastFailed.Write());
}
-void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint32 spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, uint32* misc /*= nullptr*/)
+void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint32 spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
{
if (result == SPELL_CAST_OK)
return;
WorldPackets::Spells::CastFailed packet;
packet.SpellXSpellVisualID = spellVisual;
- FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, misc, caster);
+ FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, param1, param2, caster);
caster->GetSession()->SendPacket(packet.Write());
}
@@ -4605,7 +4683,7 @@ void Spell::TakePower()
}
}
-SpellCastResult Spell::CheckRuneCost()
+SpellCastResult Spell::CheckRuneCost() const
{
int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost)
{
@@ -4785,7 +4863,7 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT
}
}
-SpellCastResult Spell::CheckCast(bool strict)
+SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
{
// check death state
if (!m_caster->IsAlive() && !m_spellInfo->IsPassive() && !(m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
@@ -4848,13 +4926,15 @@ SpellCastResult Spell::CheckCast(bool strict)
bool checkForm = true;
// Ignore form req aura
Unit::AuraEffectList const& ignore = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
- for (Unit::AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
+ for (AuraEffect const* aurEff : ignore)
{
- if (!(*i)->IsAffectingSpell(m_spellInfo))
+ if (!aurEff->IsAffectingSpell(m_spellInfo))
continue;
+
checkForm = false;
break;
}
+
if (checkForm)
{
// Cannot be used in this stance/form
@@ -5076,7 +5156,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// always (except passive spells) check items (only player related checks)
if (!m_spellInfo->IsPassive())
{
- castResult = CheckItems();
+ castResult = CheckItems(param1, param2);
if (castResult != SPELL_CAST_OK)
return castResult;
}
@@ -5096,7 +5176,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS))
{
- castResult = CheckCasterAuras();
+ castResult = CheckCasterAuras(param1);
if (castResult != SPELL_CAST_OK)
return castResult;
}
@@ -5567,7 +5647,11 @@ SpellCastResult Spell::CheckCast(bool strict)
if (!talent)
return SPELL_FAILED_DONT_REPORT;
if (m_caster->GetSpellHistory()->HasCooldown(talent->SpellID))
+ {
+ if (param1)
+ *param1 = talent->SpellID;
return SPELL_FAILED_CANT_UNTALENT;
+ }
break;
}
case SPELL_EFFECT_GIVE_ARTIFACT_POWER:
@@ -5780,142 +5864,110 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
return CheckCast(true);
}
-SpellCastResult Spell::CheckCasterAuras() const
+SpellCastResult Spell::CheckCasterAuras(uint32* param1) const
{
// spells totally immuned to caster auras (wsg flag drop, give marks etc)
if (m_spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_AURAS))
return SPELL_CAST_OK;
- uint8 school_immune = 0;
- uint32 mechanic_immune = 0;
- uint32 dispel_immune = 0;
-
- // Check if the spell grants school or mechanic immunity.
- // We use bitmasks so the loop is done only once and not on every aura check below.
- if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
+ bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED);
+ bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED);
+ if (m_spellInfo->HasAttribute(SPELL_ATTR7_USABLE_IN_STUN_FEAR_CONFUSION))
{
- for (SpellEffectInfo const* effect : GetEffects())
- {
- if (!effect)
- continue;
-
- if (effect->ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY)
- school_immune |= uint32(effect->MiscValue);
- else if (effect->ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY)
- mechanic_immune |= 1 << uint32(effect->MiscValue);
- else if (effect->ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY)
- dispel_immune |= SpellInfo::GetDispelMask(DispelType(effect->MiscValue));
- }
- // immune movement impairment and loss of control
- if (m_spellInfo->Id == 42292 || m_spellInfo->Id == 59752 || m_spellInfo->Id == 19574 || m_spellInfo->Id == 53490)
- mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+ usableWhileStunned = true;
+ usableWhileFeared = true;
+ usableWhileConfused = true;
}
- bool usableInStun = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
-
// Check whether the cast should be prevented by any state you might have.
- SpellCastResult prevented_reason = SPELL_CAST_OK;
- // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out
- uint32 unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS); // Get unit state
- if (unitflag & UNIT_FLAG_STUNNED)
- {
- // spell is usable while stunned, check if caster has allowed stun auras, another stun types must prevent cast spell
- if (usableInStun)
- {
- static uint32 const allowedStunMask =
- 1 << MECHANIC_STUN
- | 1 << MECHANIC_FREEZE
- | 1 << MECHANIC_SAPPED
- | 1 << MECHANIC_SLEEP;
-
- bool foundNotStun = false;
- Unit::AuraEffectList const& stunAuras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_STUN);
- for (Unit::AuraEffectList::const_iterator i = stunAuras.begin(); i != stunAuras.end(); ++i)
- {
- uint32 mechanicMask = (*i)->GetSpellInfo()->GetAllEffectsMechanicMask();
- if (mechanicMask && !(mechanicMask & allowedStunMask))
- {
- foundNotStun = true;
- break;
- }
- }
- if (foundNotStun)
- prevented_reason = SPELL_FAILED_STUNNED;
- }
- else
- prevented_reason = SPELL_FAILED_STUNNED;
- }
- else if (unitflag & UNIT_FLAG_CONFUSED && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
- prevented_reason = SPELL_FAILED_CONFUSED;
- else if (unitflag & UNIT_FLAG_FLEEING && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
- prevented_reason = SPELL_FAILED_FLEEING;
- else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE)
- prevented_reason = SPELL_FAILED_SILENCED;
- else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY)
- prevented_reason = SPELL_FAILED_PACIFIED;
+ SpellCastResult result = SPELL_CAST_OK;
+
+ // Get unit state
+ uint32 const unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS);
+ if (!m_caster->GetCharmerGUID().IsEmpty())
+ {
+ if (Unit* charmer = m_caster->GetCharmer())
+ if (charmer->GetUnitBeingMoved() != m_caster && CheckCasterNotImmunedCharmAuras(param1))
+ result = SPELL_FAILED_CHARMED;
+ }
+ else if (unitflag & UNIT_FLAG_STUNNED && !usableWhileStunned && CheckCasterNotImmunedStunAuras(param1))
+ result = SPELL_FAILED_STUNNED;
+ else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE && CheckCasterNotImmunedSilenceAuras(param1))
+ result = SPELL_FAILED_SILENCED;
+ else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY && CheckCasterNotImmunedPacifyAuras(param1))
+ result = SPELL_FAILED_PACIFIED;
+ else if (unitflag & UNIT_FLAG_FLEEING && !usableWhileFeared && CheckCasterNotImmunedFearAuras(param1))
+ result = SPELL_FAILED_FLEEING;
+ else if (unitflag & UNIT_FLAG_CONFUSED && !usableWhileConfused && CheckCasterNotImmunedDisorientAuras(param1))
+ result = SPELL_FAILED_CONFUSED;
else if (m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_NO_ACTIONS) && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_NO_ACTIONS)
- prevented_reason = SPELL_FAILED_NO_ACTIONS;
+ result = SPELL_FAILED_NO_ACTIONS;
// Attr must make flag drop spell totally immune from all effects
- if (prevented_reason != SPELL_CAST_OK)
- {
- if (school_immune || mechanic_immune || dispel_immune)
- {
- //Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
- Unit::AuraApplicationMap const& auras = m_caster->GetAppliedAuras();
- for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- {
- Aura const* aura = itr->second->GetBase();
- SpellInfo const* auraInfo = aura->GetSpellInfo();
- if (auraInfo->GetAllEffectsMechanicMask() & mechanic_immune)
- continue;
- if (auraInfo->GetSchoolMask() & school_immune && !auraInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
- continue;
- if (auraInfo->GetDispelMask() & dispel_immune)
- continue;
+ if (result != SPELL_CAST_OK)
+ return (param1 && *param1) ? SPELL_FAILED_PREVENTED_BY_MECHANIC : result;
- //Make a second check for spell failed so the right SPELL_FAILED message is returned.
- //That is needed when your casting is prevented by multiple states and you are only immune to some of them.
- for (SpellEffectInfo const* effect : GetEffects())
- {
- if (!effect)
- continue;
+ return SPELL_CAST_OK;
+}
- if (AuraEffect* part = aura->GetEffect(effect->EffectIndex))
- {
- switch (part->GetAuraType())
- {
- case SPELL_AURA_MOD_STUN:
- if (!usableInStun || !(auraInfo->GetAllEffectsMechanicMask() & (1<<MECHANIC_STUN)))
- return SPELL_FAILED_STUNNED;
- break;
- case SPELL_AURA_MOD_CONFUSE:
- if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
- return SPELL_FAILED_CONFUSED;
- break;
- case SPELL_AURA_MOD_FEAR:
- if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
- return SPELL_FAILED_FLEEING;
- break;
- case SPELL_AURA_MOD_SILENCE:
- case SPELL_AURA_MOD_PACIFY:
- case SPELL_AURA_MOD_PACIFY_SILENCE:
- if (m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY)
- return SPELL_FAILED_PACIFIED;
- else if (m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE)
- return SPELL_FAILED_SILENCED;
- break;
- default: break;
- }
- }
- }
- }
+// based on sub_00804430 from 12340 client
+bool Spell::CheckCasterHasNotImmunedAuraType(AuraType auraType, uint32* param1) const
+{
+ // Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
+ Unit::AuraEffectList const& auraEffects = m_caster->GetAuraEffectsByType(auraType);
+ if (auraEffects.empty())
+ return false;
+
+ for (AuraEffect const* aurEff : auraEffects)
+ {
+ if (m_spellInfo->CanSpellCastOverrideAuraEffect(aurEff))
+ continue;
+
+ if (param1)
+ {
+ *param1 = aurEff->GetSpellEffectInfo()->Mechanic;
+ if (!*param1)
+ *param1 = aurEff->GetSpellInfo()->Mechanic;
}
- // You are prevented from casting and the spell cast does not grant immunity. Return a failed error.
- else
- return prevented_reason;
+ return true;
}
- return SPELL_CAST_OK;
+
+ return false;
+}
+
+bool Spell::CheckCasterNotImmunedCharmAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_CHARM, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_AOE_CHARM, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_POSSESS, param1);
+}
+
+bool Spell::CheckCasterNotImmunedStunAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_STUN, param1);
+}
+
+bool Spell::CheckCasterNotImmunedSilenceAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_SILENCE, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY_SILENCE, param1);
+}
+
+bool Spell::CheckCasterNotImmunedPacifyAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY_SILENCE, param1);
+}
+
+bool Spell::CheckCasterNotImmunedFearAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_FEAR, param1);
+}
+
+bool Spell::CheckCasterNotImmunedDisorientAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_CONFUSE, param1);
}
SpellCastResult Spell::CheckArenaAndRatedBattlegroundCastRules()
@@ -6025,7 +6077,7 @@ void Spell::CheckDst()
m_targets.SetDst(*m_caster);
}
-SpellCastResult Spell::CheckRange(bool strict)
+SpellCastResult Spell::CheckRange(bool strict) const
{
// Don't check for instant cast spells
if (!strict && m_casttime == 0)
@@ -6064,7 +6116,7 @@ SpellCastResult Spell::CheckRange(bool strict)
return SPELL_CAST_OK;
}
-std::pair<float, float> Spell::GetMinMaxRange(bool strict)
+std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
{
float rangeMod = 0.0f;
float minRange = 0.0f;
@@ -6110,14 +6162,14 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict)
maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f;
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, this);
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, const_cast<Spell*>(this));
maxRange += rangeMod;
return std::pair<float, float>(minRange, maxRange);
}
-SpellCastResult Spell::CheckPower()
+SpellCastResult Spell::CheckPower() const
{
// item cast not used power
if (m_CastItem)
@@ -6155,12 +6207,15 @@ SpellCastResult Spell::CheckPower()
return SPELL_CAST_OK;
}
-SpellCastResult Spell::CheckItems()
+SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
{
Player* player = m_caster->ToPlayer();
if (!player)
return SPELL_CAST_OK;
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_ITEM_CHECK))
+ return SPELL_CAST_OK;
+
if (!m_CastItem)
{
if (!m_castItemGUID.IsEmpty())
@@ -6236,10 +6291,11 @@ SpellCastResult Spell::CheckItems()
// check target item
if (!m_targets.GetItemTargetGUID().IsEmpty())
{
- if (!m_targets.GetItemTarget())
+ Item* item = m_targets.GetItemTarget();
+ if (!item)
return SPELL_FAILED_ITEM_GONE;
- if (!m_targets.GetItemTarget()->IsFitToSpellRequirements(m_spellInfo))
+ if (!item->IsFitToSpellRequirements(m_spellInfo))
return SPELL_FAILED_EQUIPPED_ITEM_CLASS;
}
// if not item target then required item must be equipped
@@ -6289,7 +6345,11 @@ SpellCastResult Spell::CheckItems()
}
}
if (!player->HasItemCount(itemid, itemcount))
+ {
+ if (param1)
+ *param1 = itemid;
return SPELL_FAILED_REAGENTS;
+ }
}
}
@@ -6496,21 +6556,29 @@ SpellCastResult Spell::CheckItems()
}
case SPELL_EFFECT_PROSPECTING:
{
- if (!m_targets.GetItemTarget())
+ Item* item = m_targets.GetItemTarget();
+ if (!item)
return SPELL_FAILED_CANT_BE_PROSPECTED;
//ensure item is a prospectable ore
- if (!(m_targets.GetItemTarget()->GetTemplate()->GetFlags() & ITEM_FLAG_IS_PROSPECTABLE))
+ if (!(item->GetTemplate()->GetFlags() & ITEM_FLAG_IS_PROSPECTABLE))
return SPELL_FAILED_CANT_BE_PROSPECTED;
//prevent prospecting in trade slot
- if (m_targets.GetItemTarget()->GetOwnerGUID() != m_caster->GetGUID())
+ if (item->GetOwnerGUID() != m_caster->GetGUID())
return SPELL_FAILED_CANT_BE_PROSPECTED;
//Check for enough skill in jewelcrafting
- uint32 item_prospectingskilllevel = m_targets.GetItemTarget()->GetTemplate()->GetRequiredSkillRank();
- if (item_prospectingskilllevel >player->GetSkillValue(SKILL_JEWELCRAFTING))
+ uint32 item_prospectingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
+ if (item_prospectingskilllevel > player->GetSkillValue(SKILL_JEWELCRAFTING))
return SPELL_FAILED_LOW_CASTLEVEL;
//make sure the player has the required ores in inventory
- if (m_targets.GetItemTarget()->GetCount() < 5)
+ if (item->GetCount() < 5)
+ {
+ if (param1 && param2)
+ {
+ *param1 = item->GetEntry();
+ *param2 = 5;
+ }
return SPELL_FAILED_NEED_MORE_ITEMS;
+ }
if (!LootTemplates_Prospecting.HaveLootFor(m_targets.GetItemTargetEntry()))
return SPELL_FAILED_CANT_BE_PROSPECTED;
@@ -6519,21 +6587,29 @@ SpellCastResult Spell::CheckItems()
}
case SPELL_EFFECT_MILLING:
{
- if (!m_targets.GetItemTarget())
+ Item* item = m_targets.GetItemTarget();
+ if (!item)
return SPELL_FAILED_CANT_BE_MILLED;
//ensure item is a millable herb
- if (!(m_targets.GetItemTarget()->GetTemplate()->GetFlags() & ITEM_FLAG_IS_MILLABLE))
+ if (!(item->GetTemplate()->GetFlags() & ITEM_FLAG_IS_MILLABLE))
return SPELL_FAILED_CANT_BE_MILLED;
//prevent milling in trade slot
- if (m_targets.GetItemTarget()->GetOwnerGUID() != m_caster->GetGUID())
+ if (item->GetOwnerGUID() != m_caster->GetGUID())
return SPELL_FAILED_CANT_BE_MILLED;
//Check for enough skill in inscription
- uint32 item_millingskilllevel = m_targets.GetItemTarget()->GetTemplate()->GetRequiredSkillRank();
+ uint32 item_millingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
if (item_millingskilllevel > player->GetSkillValue(SKILL_INSCRIPTION))
return SPELL_FAILED_LOW_CASTLEVEL;
//make sure the player has the required herbs in inventory
- if (m_targets.GetItemTarget()->GetCount() < 5)
+ if (item->GetCount() < 5)
+ {
+ if (param1 && param2)
+ {
+ *param1 = item->GetEntry();
+ *param2 = 5;
+ }
return SPELL_FAILED_NEED_MORE_ITEMS;
+ }
if (!LootTemplates_Milling.HaveLootFor(m_targets.GetItemTargetEntry()))
return SPELL_FAILED_CANT_BE_MILLED;
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 5a76cc1791d..f23a7c2b974 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -523,7 +523,7 @@ class TC_GAME_API Spell
void TakeReagents();
void TakeCastItem();
- SpellCastResult CheckCast(bool strict);
+ SpellCastResult CheckCast(bool strict, uint32* param1 = nullptr, uint32* param2 = nullptr);
SpellCastResult CheckPetCast(Unit* target);
// handlers
@@ -533,13 +533,21 @@ class TC_GAME_API Spell
void _handle_immediate_phase();
void _handle_finish_phase();
- SpellCastResult CheckItems();
- SpellCastResult CheckRange(bool strict);
- SpellCastResult CheckPower();
- SpellCastResult CheckRuneCost();
- SpellCastResult CheckCasterAuras() const;
+ SpellCastResult CheckItems(uint32* param1, uint32* param2) const;
+ SpellCastResult CheckRange(bool strict) const;
+ SpellCastResult CheckPower() const;
+ SpellCastResult CheckRuneCost() const;
+ SpellCastResult CheckCasterAuras(uint32* param1) const;
SpellCastResult CheckArenaAndRatedBattlegroundCastRules();
+ bool CheckCasterHasNotImmunedAuraType(AuraType auraType, uint32* param1) const;
+ bool CheckCasterNotImmunedCharmAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedStunAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedSilenceAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedPacifyAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedFearAuras(uint32* param1) const;
+ bool CheckCasterNotImmunedDisorientAuras(uint32* param1) const;
+
int32 CalculateDamage(uint8 i, Unit const* target, float* var = nullptr) const;
bool HaveTargetsForEffect(uint8 effect) const;
@@ -557,9 +565,9 @@ class TC_GAME_API Spell
void CheckSrc();
void CheckDst();
- static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint32 spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE, uint32* misc = nullptr);
- void SendCastResult(SpellCastResult result);
- void SendPetCastResult(SpellCastResult result);
+ static void SendCastResult(Player* caster, SpellInfo const* spellInfo, uint32 spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE, uint32* param1 = nullptr, uint32* param2 = nullptr);
+ void SendCastResult(SpellCastResult result, uint32* param1 = nullptr, uint32* param2 = nullptr) const;
+ void SendPetCastResult(SpellCastResult result, uint32* param1 = nullptr, uint32* param2 = nullptr) const;
void SendSpellStart();
void SendSpellGo();
void SendSpellCooldown();
@@ -687,7 +695,7 @@ class TC_GAME_API Spell
void CancelGlobalCooldown();
void SendLoot(ObjectGuid guid, LootType loottype);
- std::pair<float, float> GetMinMaxRange(bool strict);
+ std::pair<float, float> GetMinMaxRange(bool strict) const;
Unit* const m_caster;
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 94dac870c6e..0008a65939a 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1584,31 +1584,35 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
return IsAffected(affectSpell->SpellFamilyName, mod->mask);
}
-bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
+bool SpellInfo::CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const
{
- // these spells pierce all avalible spells (Resurrection Sickness for example)
+ // aura can't be pierced
+ if (!auraSpellInfo || auraSpellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ return false;
+
+ // these spells pierce all available spells (Resurrection Sickness for example)
if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return true;
- // these spells (Cyclone for example) can pierce all... // ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
- if (HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY || aura->Mechanic == MECHANIC_BANISH)))
+ // Dispels other auras on immunity, check if this spell makes the unit immune to aura
+ if (HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) && CanSpellProvideImmunityAgainstAura(auraSpellInfo))
return true;
return false;
}
-bool SpellInfo::CanDispelAura(SpellInfo const* aura) const
+bool SpellInfo::CanDispelAura(SpellInfo const* auraSpellInfo) const
{
- // These spells (like Mass Dispel) can dispell all auras, except death persistent ones (like Dungeon and Battleground Deserter)
- if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) && !aura->IsDeathPersistent())
- return true;
-
// These auras (like Divine Shield) can't be dispelled
- if (aura->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ if (auraSpellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
return false;
+ // These spells (like Mass Dispel) can dispel all auras
+ if (HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ return true;
+
// These auras (Cyclone for example) are not dispelable
- if (aura->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
+ if (auraSpellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) || auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
return false;
return true;
@@ -2968,6 +2972,472 @@ int32 SpellInfo::GetDiminishingReturnsLimitDuration() const
return _diminishInfo.DiminishDurationLimit;
}
+void SpellInfo::_LoadImmunityInfo()
+{
+ auto loadImmunityInfoFn = [this](SpellEffectInfo* effectInfo)
+ {
+ uint32 schoolImmunityMask = 0;
+ uint32 applyHarmfulAuraImmunityMask = 0;
+ uint32 mechanicImmunityMask = 0;
+ uint32 dispelImmunity = 0;
+ uint32 damageImmunityMask = 0;
+
+ int32 miscVal = effectInfo->MiscValue;
+ int32 amount = effectInfo->CalcValue();
+
+ ImmunityInfo& immuneInfo = *const_cast<ImmunityInfo*>(effectInfo->GetImmunityInfo());
+
+ switch (effectInfo->ApplyAuraName)
+ {
+ case SPELL_AURA_MECHANIC_IMMUNITY_MASK:
+ {
+ switch (miscVal)
+ {
+ case 96: // Free Friend, Uncontrollable Frenzy, Warlord's Presence
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT_2);
+ break;
+ }
+ case 1615: // Incite Rage, Wolf Spirit, Overload, Lightning Tendrils
+ {
+ switch (Id)
+ {
+ case 43292: // Incite Rage
+ case 49172: // Wolf Spirit
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT_2);
+ // no break intended
+ case 61869: // Overload
+ case 63481:
+ case 61887: // Lightning Tendrils
+ case 63486:
+ mechanicImmunityMask |= (1 << MECHANIC_INTERRUPT) | (1 << MECHANIC_SILENCE);
+
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_KNOCK_BACK);
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_KNOCK_BACK_DEST);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case 679: // Mind Control, Avenging Fury
+ {
+ if (Id == 57742) // Avenging Fury
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT_2);
+ }
+ break;
+ }
+ case 1557: // Startling Roar, Warlord Roar, Break Bonds, Stormshield
+ {
+ if (Id == 64187) // Stormshield
+ {
+ mechanicImmunityMask |= (1 << MECHANIC_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ }
+ else
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT_2);
+ }
+ break;
+ }
+ case 1614: // Fixate
+ case 1694: // Fixated, Lightning Tendrils
+ {
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_ATTACK_ME);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_TAUNT);
+ break;
+ }
+ case 1630: // Fervor, Berserk
+ {
+ if (Id == 64112) // Berserk
+ {
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_ATTACK_ME);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_TAUNT);
+ }
+ else
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT_2);
+ }
+ break;
+ }
+ case 477: // Bladestorm
+ case 1733: // Bladestorm, Killing Spree
+ {
+ if (!amount)
+ {
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_KNOCK_BACK);
+ immuneInfo.SpellEffectImmune.insert(SPELL_EFFECT_KNOCK_BACK_DEST);
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT_2);
+ }
+ break;
+ }
+ case 878: // Whirlwind, Fog of Corruption, Determination
+ {
+ if (Id == 66092) // Determination
+ {
+ mechanicImmunityMask |= (1 << MECHANIC_SNARE) | (1 << MECHANIC_STUN)
+ | (1 << MECHANIC_DISORIENTED) | (1 << MECHANIC_FREEZE);
+
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (immuneInfo.AuraTypeImmune.empty())
+ {
+ if (miscVal & (1 << 10))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_STUN);
+ if (miscVal & (1 << 1))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_TRANSFORM);
+
+ // These flag can be recognized wrong:
+ if (miscVal & (1 << 6))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DECREASE_SPEED);
+ if (miscVal & (1 << 0))
+ {
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT);
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_ROOT_2);
+ }
+ if (miscVal & (1 << 2))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_CONFUSE);
+ if (miscVal & (1 << 9))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_FEAR);
+ if (miscVal & (1 << 7))
+ immuneInfo.AuraTypeImmune.insert(SPELL_AURA_MOD_DISARM);
+ }
+ break;
+ }
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ {
+ switch (Id)
+ {
+ case 34471: // The Beast Within
+ case 19574: // Bestial Wrath
+ case 42292: // PvP trinket
+ case 46227: // Medallion of Immunity
+ case 59752: // Every Man for Himself
+ case 53490: // Bullheaded
+ case 65547: // PvP Trinket
+ case 134946: // Supremacy of the Alliance
+ case 134956: // Supremacy of the Horde
+ case 195710: // Honorable Medallion
+ case 208683: // Gladiator's Medallion
+ mechanicImmunityMask |= IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+ break;
+ case 54508: // Demonic Empowerment
+ mechanicImmunityMask |= (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT) | (1 << MECHANIC_STUN);
+ break;
+ default:
+ if (miscVal < 1)
+ return;
+
+ mechanicImmunityMask |= 1 << miscVal;
+ break;
+ }
+ break;
+ }
+ case SPELL_AURA_EFFECT_IMMUNITY:
+ {
+ immuneInfo.SpellEffectImmune.insert(static_cast<SpellEffectName>(miscVal));
+ break;
+ }
+ case SPELL_AURA_STATE_IMMUNITY:
+ {
+ immuneInfo.AuraTypeImmune.insert(static_cast<AuraType>(miscVal));
+ break;
+ }
+ case SPELL_AURA_SCHOOL_IMMUNITY:
+ {
+ schoolImmunityMask |= uint32(miscVal);
+ break;
+ }
+ case SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL:
+ {
+ applyHarmfulAuraImmunityMask |= uint32(miscVal);
+ break;
+ }
+ case SPELL_AURA_DAMAGE_IMMUNITY:
+ {
+ damageImmunityMask |= uint32(miscVal);
+ break;
+ }
+ case SPELL_AURA_DISPEL_IMMUNITY:
+ {
+ dispelImmunity = uint32(miscVal);
+ break;
+ }
+ default:
+ break;
+ }
+
+ immuneInfo.SchoolImmuneMask = schoolImmunityMask;
+ immuneInfo.ApplyHarmfulAuraImmuneMask = applyHarmfulAuraImmunityMask;
+ immuneInfo.MechanicImmuneMask = mechanicImmunityMask;
+ immuneInfo.DispelImmune = dispelImmunity;
+ immuneInfo.DamageSchoolMask = damageImmunityMask;
+
+ immuneInfo.AuraTypeImmune.shrink_to_fit();
+ immuneInfo.SpellEffectImmune.shrink_to_fit();
+ };
+
+ for (auto const& effects : _effects)
+ {
+ for (SpellEffectInfo const* effect : effects.second)
+ {
+ if (!effect)
+ continue;
+
+ loadImmunityInfoFn(const_cast<SpellEffectInfo*>(effect));
+ }
+ }
+}
+
+void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, SpellEffectInfo const* effect, bool apply) const
+{
+ ImmunityInfo const* immuneInfo = effect->GetImmunityInfo();
+
+ if (uint32 schoolImmunity = immuneInfo->SchoolImmuneMask)
+ {
+ target->ApplySpellImmune(Id, IMMUNITY_SCHOOL, schoolImmunity, apply);
+
+ if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ {
+ target->RemoveAppliedAuras([this, schoolImmunity](AuraApplication const* aurApp) -> bool
+ {
+ SpellInfo const* auraSpellInfo = aurApp->GetBase()->GetSpellInfo();
+ return ((auraSpellInfo->GetSchoolMask() & schoolImmunity) != 0 && // Check for school mask
+ CanDispelAura(auraSpellInfo) &&
+ (IsPositive() != aurApp->IsPositive()) && // Check spell vs aura possitivity
+ !auraSpellInfo->IsPassive() && // Don't remove passive auras
+ auraSpellInfo->Id != Id); // Don't remove self
+ });
+ }
+ }
+
+ if (uint32 mechanicImmunity = immuneInfo->MechanicImmuneMask)
+ {
+ for (uint32 i = 0; i < MAX_MECHANIC; ++i)
+ if (mechanicImmunity & (1 << i))
+ target->ApplySpellImmune(Id, IMMUNITY_MECHANIC, i, apply);
+
+ if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ target->RemoveAurasWithMechanic(mechanicImmunity, AURA_REMOVE_BY_DEFAULT, Id);
+ }
+
+ if (uint32 dispelImmunity = immuneInfo->DispelImmune)
+ {
+ target->ApplySpellImmune(Id, IMMUNITY_DISPEL, dispelImmunity, apply);
+
+ if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ {
+ target->RemoveAppliedAuras([dispelImmunity](AuraApplication const* aurApp) -> bool
+ {
+ SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
+ if (spellInfo->Dispel == dispelImmunity)
+ return true;
+
+ return false;
+ });
+ }
+ }
+
+ if (uint32 damageImmunity = immuneInfo->DamageSchoolMask)
+ target->ApplySpellImmune(Id, IMMUNITY_DAMAGE, damageImmunity, apply);
+
+ for (AuraType auraType : immuneInfo->AuraTypeImmune)
+ {
+ target->ApplySpellImmune(Id, IMMUNITY_STATE, auraType, apply);
+ if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ target->RemoveAurasByType(auraType);
+ }
+
+ for (SpellEffectName effectType : immuneInfo->SpellEffectImmune)
+ target->ApplySpellImmune(Id, IMMUNITY_EFFECT, effectType, apply);
+}
+
+bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInfo) const
+{
+ if (!auraSpellInfo)
+ return false;
+
+ for (SpellEffectInfo const* effectInfo : GetEffectsForDifficulty(DIFFICULTY_NONE))
+ {
+ if (!effectInfo)
+ continue;
+
+ ImmunityInfo const* immuneInfo = effectInfo->GetImmunityInfo();
+
+ if (!auraSpellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
+ {
+ if (uint32 schoolImmunity = immuneInfo->SchoolImmuneMask)
+ if ((auraSpellInfo->SchoolMask & schoolImmunity) != 0)
+ return true;
+ }
+
+ if (uint32 mechanicImmunity = immuneInfo->MechanicImmuneMask)
+ if ((mechanicImmunity & (1 << auraSpellInfo->Mechanic)) != 0)
+ return true;
+
+ if (uint32 dispelImmunity = immuneInfo->DispelImmune)
+ if (auraSpellInfo->Dispel == dispelImmunity)
+ return true;
+
+ bool immuneToAllEffects = true;
+ for (SpellEffectInfo const* auraSpellEffectInfo : auraSpellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ {
+ if (!auraSpellEffectInfo)
+ continue;
+
+ uint32 effectName = auraSpellEffectInfo->Effect;
+ if (!effectName)
+ continue;
+
+ auto spellImmuneItr = immuneInfo->SpellEffectImmune.find(static_cast<SpellEffectName>(effectName));
+ if (spellImmuneItr == immuneInfo->SpellEffectImmune.cend())
+ {
+ immuneToAllEffects = false;
+ break;
+ }
+
+ if (uint32 mechanic = auraSpellEffectInfo->Mechanic)
+ {
+ if (!(immuneInfo->MechanicImmuneMask & (1 << mechanic)))
+ {
+ immuneToAllEffects = false;
+ break;
+ }
+ }
+
+ if (!auraSpellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ {
+ if (uint32 auraName = auraSpellEffectInfo->ApplyAuraName)
+ {
+ bool isImmuneToAuraEffectApply = false;
+ auto auraImmuneItr = immuneInfo->AuraTypeImmune.find(static_cast<AuraType>(auraName));
+ if (auraImmuneItr != immuneInfo->AuraTypeImmune.cend())
+ isImmuneToAuraEffectApply = true;
+
+ if (!isImmuneToAuraEffectApply && !auraSpellInfo->IsPositiveEffect(auraSpellEffectInfo->EffectIndex) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
+ {
+ if (uint32 applyHarmfulAuraImmunityMask = immuneInfo->ApplyHarmfulAuraImmuneMask)
+ if ((auraSpellInfo->GetSchoolMask() & applyHarmfulAuraImmunityMask) != 0)
+ isImmuneToAuraEffectApply = true;
+ }
+
+ if (!isImmuneToAuraEffectApply)
+ {
+ immuneToAllEffects = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (immuneToAllEffects)
+ return true;
+ }
+
+ return false;
+}
+
+// based on client sub_007FDFA0
+bool SpellInfo::CanSpellCastOverrideAuraEffect(AuraEffect const* aurEff) const
+{
+ if (!HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ return false;
+
+ if (aurEff->GetSpellInfo()->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
+ return false;
+
+ for (SpellEffectInfo const* effectInfo : GetEffectsForDifficulty(DIFFICULTY_NONE))
+ {
+ if (!effectInfo)
+ continue;
+
+ if (effectInfo->Effect != SPELL_EFFECT_APPLY_AURA)
+ continue;
+
+ uint32 const miscValue = static_cast<uint32>(effectInfo->MiscValue);
+ switch (effectInfo->ApplyAuraName)
+ {
+ case SPELL_AURA_STATE_IMMUNITY:
+ if (miscValue != aurEff->GetSpellEffectInfo()->ApplyAuraName)
+ continue;
+ break;
+ case SPELL_AURA_SCHOOL_IMMUNITY:
+ case SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL:
+ if (aurEff->GetSpellInfo()->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE) || !(aurEff->GetSpellInfo()->SchoolMask & miscValue))
+ continue;
+ break;
+ case SPELL_AURA_DISPEL_IMMUNITY:
+ if (miscValue != aurEff->GetSpellInfo()->Dispel)
+ continue;
+ break;
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ if (miscValue != aurEff->GetSpellInfo()->Mechanic)
+ {
+ if (miscValue != aurEff->GetSpellEffectInfo()->Mechanic)
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
float SpellInfo::GetMinRange(bool positive) const
{
if (!RangeEntry)
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 506aa5ba6d9..db53572abe8 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -24,6 +24,8 @@
#include "Object.h"
#include "SpellAuraDefines.h"
+#include <boost/container/flat_set.hpp>
+
class Unit;
class Player;
class Item;
@@ -300,6 +302,18 @@ private:
static StaticData _data[TOTAL_SPELL_TARGETS];
};
+struct TC_GAME_API ImmunityInfo
+{
+ uint32 SchoolImmuneMask = 0;
+ uint32 ApplyHarmfulAuraImmuneMask = 0;
+ uint32 MechanicImmuneMask = 0;
+ uint32 DispelImmune = 0;
+ uint32 DamageSchoolMask = 0;
+
+ boost::container::flat_set<AuraType> AuraTypeImmune;
+ boost::container::flat_set<SpellEffectName> SpellEffectImmune;
+};
+
class TC_GAME_API SpellEffectInfo
{
SpellInfo const* _spellInfo;
@@ -368,6 +382,8 @@ public:
SpellEffectImplicitTargetTypes GetImplicitTargetType() const;
SpellTargetObjectTypes GetUsedTargetObjectType() const;
+ ImmunityInfo const* GetImmunityInfo() const { return &_immunityInfo; }
+
private:
struct StaticData
{
@@ -375,6 +391,8 @@ private:
SpellTargetObjectTypes UsedTargetObjectType; // defines valid target object type for spell effect
};
static StaticData _data[TOTAL_SPELL_EFFECTS];
+
+ ImmunityInfo _immunityInfo;
};
typedef std::vector<SpellEffectInfo const*> SpellEffectInfoVector;
@@ -573,8 +591,8 @@ class TC_GAME_API SpellInfo
bool IsAffectedBySpellMods() const;
bool IsAffectedBySpellMod(SpellModifier const* mod) const;
- bool CanPierceImmuneAura(SpellInfo const* aura) const;
- bool CanDispelAura(SpellInfo const* aura) const;
+ bool CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const;
+ bool CanDispelAura(SpellInfo const* auraSpellInfo) const;
bool IsSingleTarget() const;
bool IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const;
@@ -640,6 +658,11 @@ class TC_GAME_API SpellInfo
DiminishingLevels GetDiminishingReturnsMaxLevel() const;
int32 GetDiminishingReturnsLimitDuration() const;
+ // spell immunities
+ void ApplyAllSpellImmunitiesTo(Unit* target, SpellEffectInfo const* effect, bool apply) const;
+ bool CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInfo) const;
+ bool CanSpellCastOverrideAuraEffect(AuraEffect const* aurEff) const;
+
private:
// loading helpers
void _InitializeExplicitTargetMask();
@@ -649,6 +672,7 @@ class TC_GAME_API SpellInfo
void _LoadSpellSpecific();
void _LoadAuraState();
void _LoadSpellDiminishInfo();
+ void _LoadImmunityInfo();
// unloading helpers
void _UnloadImplicitTargetConditionLists();
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 301db11483c..492220b85f7 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3443,6 +3443,21 @@ void SpellMgr::LoadSpellInfoDiminishing()
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo diminishing infos in %u ms", GetMSTimeDiffToNow(oldMSTime));
}
+void SpellMgr::LoadSpellInfoImmunities()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (SpellInfo* spellInfo : mSpellInfoMap)
+ {
+ if (!spellInfo)
+ continue;
+
+ spellInfo->_LoadImmunityInfo();
+ }
+
+ TC_LOG_INFO("server.loading", ">> Loaded SpellInfo immunity infos in %u ms", GetMSTimeDiffToNow(oldMSTime));
+}
+
void SpellMgr::LoadPetFamilySpellsStore()
{
std::unordered_map<uint32, SpellLevelsEntry const*> levelsBySpell;
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index f2fa79f97ca..1a870f37f68 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -711,6 +711,7 @@ class TC_GAME_API SpellMgr
void LoadSpellInfoCorrections();
void LoadSpellInfoSpellSpecificAndAuraState();
void LoadSpellInfoDiminishing();
+ void LoadSpellInfoImmunities();
private:
SpellDifficultySearcherMap mSpellDifficultySearcherMap;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 58230f8f53f..f1eeb59338d 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1601,6 +1601,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading SpellInfo diminishing infos...");
sSpellMgr->LoadSpellInfoDiminishing();
+ TC_LOG_INFO("server.loading", "Loading SpellInfo immunity infos...");
+ sSpellMgr->LoadSpellInfoImmunities();
+
TC_LOG_INFO("server.loading", "Loading PetFamilySpellsStore Data...");
sSpellMgr->LoadPetFamilySpellsStore();