Core/Spell: revamp of immunities system

- Spell attributes research
- Container optimization
- Do not skip damage immunity checks on SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY present
- Added additonal arguments support to SendCastResult / CheckCast, spells can now send proper error messages
- Loads spell immune masks/states/effects at startup.
- This cached info is used whenever a spell cast requires immunities to be known beforehand (to see if an aura could be applied for example)

Closes #16658
Closes #16901
Closes #18114

(cherry picked from commit 50a3ce5703bdaa4fe16e2e773eabafa9a4818083)

Core/Spell: fix warning

(cherry picked from commit 3588ff894bef2fc1f1600c73ad67fbdceecf8e2a)

Core/Unit: misc codestyle

use typedef for constant reference

(cherry picked from commit 7943150dcb20597f30259354563d79fb1606b21f)

Core/Spell: Fixed immunities for some spells (they were broken before rewrite too)

- Warlord's Presence, Uncontrollable Frenzy, Free Friend
- Overload, Lightning Tendrils
- Fervor, Berserk
- Determination

(cherry picked from commit fc6844173f70f436b92fb0dbc4398290ce935038)

Core/Spell: fix typos

(cherry picked from commit f060efbdb4c51a7fe22cb6a9012cc76477a1f92b)

Core/Unit: improved handling of some spell attributes

- SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE
- SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE
- SPELL_ATTR3_IGNORE_HIT_RESULT

(cherry picked from commit 352c84943c4495631a5dd1e9285cde35fdc23c37)

Core/Spell: fix typo

Closes #18248

(cherry picked from commit 1ad9c7d3fd4e7cfb2a6b12fc37bd748cf5fd772b)

Core/Spell: perform charmer check against player controlling unit. Fixes spellcasts while charmed

(cherry picked from commit 425f6c3c34b72190e481ba89fd4757df238475d8)

Core/Unit: don't use damage immunity to calculate hit result for the whole spell. Should be used only for damage

(cherry picked from commit 9f5df023b746d324588f175e264c62205b69e165)

Core/Spell: fix a potential null dereference crash

(cherry picked from commit 64304d8b2b33ac04d3013d47b2f50c5023300c2e)
This commit is contained in:
ariel-
2017-12-26 17:11:18 +01:00
committed by joschiwald
parent 03082db810
commit 5a91e1e31b
12 changed files with 949 additions and 708 deletions
+88 -127
View File
@@ -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;
}
+2 -9
View File
@@ -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;
@@ -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.]
+14 -325
View File
@@ -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);
}
/*********************************************************/
@@ -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;
+294 -218
View File
@@ -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 itemid = spellInfo->Reagent[i];
uint32 itemcount = spellInfo->ReagentCount[i];
if (!caster->HasItemCount(itemid, itemcount))
uint32 missingItem = 0;
for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
{
missingItem = itemid;
break;
}
}
if (spellInfo->Reagent[i] <= 0)
continue;
packet.FailedArg1 = missingItem; // first missing item
uint32 itemid = spellInfo->Reagent[i];
uint32 itemcount = spellInfo->ReagentCount[i];
if (!caster->HasItemCount(itemid, itemcount))
{
missingItem = itemid;
break;
}
}
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,144 +5864,112 @@ 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;
SpellCastResult result = SPELL_CAST_OK;
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;
// 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_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;
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;
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;
}
}
}
}
}
// You are prevented from casting and the spell cast does not grant immunity. Return a failed error.
else
return prevented_reason;
}
return SPELL_CAST_OK;
}
// 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;
}
return true;
}
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()
{
bool isRatedBattleground = false; // NYI
@@ -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;
+18 -10
View File
@@ -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;
+481 -11
View File
@@ -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)
+26 -2
View File
@@ -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();
+15
View File
@@ -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;
+1
View File
@@ -711,6 +711,7 @@ class TC_GAME_API SpellMgr
void LoadSpellInfoCorrections();
void LoadSpellInfoSpellSpecificAndAuraState();
void LoadSpellInfoDiminishing();
void LoadSpellInfoImmunities();
private:
SpellDifficultySearcherMap mSpellDifficultySearcherMap;
+3
View File
@@ -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();