From 3544577e48f3cf4fe4eae670facb3e5f77608e68 Mon Sep 17 00:00:00 2001 From: ariel- Date: Mon, 23 Jan 2017 18:33:34 -0300 Subject: Core/Spell: unified handling of SPELL_ATTR5_USABLE_WHILE_* attributes Allowed mechanic mask is calculated on startup and auras checked against those mechanics Closes #18798 --- src/server/game/Spells/Spell.cpp | 99 ++++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 28 deletions(-) (limited to 'src/server/game/Spells/Spell.cpp') diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 22c10368326..2de0df007ce 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5733,8 +5733,16 @@ SpellCastResult Spell::CheckCasterAuras(uint32* param1) const if (m_spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_AURAS)) return SPELL_CAST_OK; + // these attributes only show the spell as usable on the client when it has related aura applied + // still they need to be checked against certain mechanics + + // SPELL_ATTR5_USABLE_WHILE_STUNNED by default only MECHANIC_STUN (ie no sleep, knockout, freeze, etc.) bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED); + + // SPELL_ATTR5_USABLE_WHILE_FEARED by default only fear (ie no horror) bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED); + + // SPELL_ATTR5_USABLE_WHILE_CONFUSED by default only disorient (ie no polymorph) bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED); // Glyph of Pain Suppression @@ -5759,39 +5767,56 @@ SpellCastResult Spell::CheckCasterAuras(uint32* param1) const } */ - if (unitflag & UNIT_FLAG_STUNNED) + // spell has attribute usable while having a cc state, check if caster has allowed mechanic auras, another mechanic types must prevent cast spell + auto mechanicCheck = [&](AuraType type) -> SpellCastResult { - // spell is usable while stunned, check if caster has allowed stun auras, another stun types must prevent cast spell - if (usableWhileStunned) + bool foundNotMechanic = false; + Unit::AuraEffectList const& auras = m_caster->GetAuraEffectsByType(type); + for (AuraEffect const* aurEff : auras) { - static uint32 const allowedStunMask = - 1 << MECHANIC_STUN - | 1 << MECHANIC_SLEEP; - - bool foundNotStun = false; - Unit::AuraEffectList const& stunAuras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_STUN); - for (AuraEffect const* stunEff : stunAuras) + uint32 const mechanicMask = aurEff->GetSpellInfo()->GetAllEffectsMechanicMask(); + if (mechanicMask && !(mechanicMask & GetSpellInfo()->GetAllowedMechanicMask())) { - uint32 const stunMechanicMask = stunEff->GetSpellInfo()->GetAllEffectsMechanicMask(); - if (stunMechanicMask && !(stunMechanicMask & allowedStunMask)) + foundNotMechanic = true; + + // fill up aura mechanic info to send client proper error message + if (param1) { - foundNotStun = true; + *param1 = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].Mechanic; + if (!*param1) + *param1 = aurEff->GetSpellInfo()->Mechanic; + } + break; + } - // fill up aura mechanic info to send client proper error message - if (param1) - { - *param1 = stunEff->GetSpellInfo()->Effects[stunEff->GetEffIndex()].Mechanic; - if (!*param1) - *param1 = stunEff->GetSpellInfo()->Mechanic; - } - break; + if (foundNotMechanic) + { + switch (type) + { + case SPELL_AURA_MOD_STUN: + return SPELL_FAILED_STUNNED; + case SPELL_AURA_MOD_FEAR: + return SPELL_FAILED_FLEEING; + case SPELL_AURA_MOD_CONFUSE: + return SPELL_FAILED_CONFUSED; + default: + ABORT(); + return SPELL_FAILED_NOT_KNOWN; } } - if (foundNotStun) - result = SPELL_FAILED_STUNNED; + return SPELL_CAST_OK; + } + }; + + if (unitflag & UNIT_FLAG_STUNNED) + { + if (usableWhileStunned) + { + SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_STUN); + if (mechanicResult != SPELL_CAST_OK) + result = mechanicResult; } - // Not usable while stunned, however spell might provide some immunity that allows to cast it anyway else if (!CheckSpellCancelsStun(param1)) result = SPELL_FAILED_STUNNED; } @@ -5799,10 +5824,28 @@ SpellCastResult Spell::CheckCasterAuras(uint32* param1) const result = SPELL_FAILED_SILENCED; else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && !CheckSpellCancelsPacify(param1)) result = SPELL_FAILED_PACIFIED; - else if (unitflag & UNIT_FLAG_FLEEING && !usableWhileFeared && !CheckSpellCancelsFear(param1)) - result = SPELL_FAILED_FLEEING; - else if (unitflag & UNIT_FLAG_CONFUSED && !usableWhileConfused && !CheckSpellCancelsConfuse(param1)) - result = SPELL_FAILED_CONFUSED; + else if (unitflag & UNIT_FLAG_FLEEING) + { + if (usableWhileFeared) + { + SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_FEAR); + if (mechanicResult != SPELL_CAST_OK) + result = mechanicResult; + } + else if (!CheckSpellCancelsFear(param1)) + result = SPELL_FAILED_FLEEING; + } + else if (unitflag & UNIT_FLAG_CONFUSED) + { + if (usableWhileConfused) + { + SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_CONFUSE); + if (mechanicResult != SPELL_CAST_OK) + result = mechanicResult; + } + else if (!CheckSpellCancelsConfuse(param1)) + result = SPELL_FAILED_CONFUSED; + } // Attr must make flag drop spell totally immune from all effects if (result != SPELL_CAST_OK) -- cgit v1.2.3