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
This commit is contained in:
ariel-
2017-01-23 18:33:34 -03:00
parent 077b5aec9e
commit 3544577e48
3 changed files with 110 additions and 29 deletions

View File

@@ -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))
{
foundNotStun = true;
foundNotMechanic = true;
// 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;
// fill up aura mechanic info to send client proper error message
if (param1)
{
*param1 = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].Mechanic;
if (!*param1)
*param1 = aurEff->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)