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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.]
|
||||
|
||||
@@ -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
@@ -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, ¶m1, ¶m2);
|
||||
// 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, ¶m1, ¶m2);
|
||||
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, ¶m1, ¶m2);
|
||||
if (castResult != SPELL_CAST_OK)
|
||||
{
|
||||
SendCastResult(castResult);
|
||||
SendCastResult(castResult, ¶m1, ¶m2);
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -711,6 +711,7 @@ class TC_GAME_API SpellMgr
|
||||
void LoadSpellInfoCorrections();
|
||||
void LoadSpellInfoSpellSpecificAndAuraState();
|
||||
void LoadSpellInfoDiminishing();
|
||||
void LoadSpellInfoImmunities();
|
||||
|
||||
private:
|
||||
SpellDifficultySearcherMap mSpellDifficultySearcherMap;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user