diff options
author | ariel- <ariel-@users.noreply.github.com> | 2017-01-23 18:33:34 -0300 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2019-06-15 18:41:09 +0200 |
commit | 2b0c73960b431acb25ddfba916017fbfe84f065b (patch) | |
tree | fe8d0d7bee4094346af0e63f6f20d6ae663a6da6 /src | |
parent | 6135ee1ad7052992093ad392347f4ef2c2ef4cf6 (diff) |
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
(cherrypicked from 3544577e48f3cf4fe4eae670facb3e5f77608e68)
(cherrypicked from 53eb6ec61628147046f1e8996e05921a00726c11)
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 109 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 1 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 34 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 3 |
4 files changed, 117 insertions, 30 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 778d4d1be6b..066ffe84c9d 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5800,8 +5800,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); // Check whether the cast should be prevented by any state you might have. @@ -5821,39 +5829,57 @@ 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()->GetEffect(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()->GetEffect(aurEff->GetEffIndex())->Mechanic; + if (!*param1) + *param1 = aurEff->GetSpellInfo()->Mechanic; } + + break; } + } - if (foundNotStun) - result = SPELL_FAILED_STUNNED; + 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; + } + } + + 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; } @@ -5861,11 +5887,29 @@ 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 (m_caster->HasUnitFlag2(UNIT_FLAG2_NO_ACTIONS) && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_NO_ACTIONS) + 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; + } + else if (m_caster->HasUnitFlag2(UNIT_FLAG2_NO_ACTIONS) && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_NO_ACTIONS && !CheckSpellCancelsNoActions(param1)) result = SPELL_FAILED_NO_ACTIONS; // Attr must make flag drop spell totally immune from all effects @@ -5935,6 +5979,11 @@ bool Spell::CheckSpellCancelsConfuse(uint32* param1) const return CheckSpellCancelsAuraEffect(SPELL_AURA_MOD_CONFUSE, param1); } +bool Spell::CheckSpellCancelsNoActions(uint32* param1) const +{ + return CheckSpellCancelsAuraEffect(SPELL_AURA_MOD_NO_ACTIONS, param1); +} + SpellCastResult Spell::CheckArenaAndRatedBattlegroundCastRules() { bool isRatedBattleground = false; // NYI diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 74b3eee8691..259af5c2885 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -551,6 +551,7 @@ class TC_GAME_API Spell bool CheckSpellCancelsPacify(uint32* param1) const; bool CheckSpellCancelsFear(uint32* param1) const; bool CheckSpellCancelsConfuse(uint32* param1) const; + bool CheckSpellCancelsNoActions(uint32* param1) const; int32 CalculateDamage(uint8 i, Unit const* target, float* var = nullptr) const; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index f264e72c52a..bbd597b9096 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1203,6 +1203,8 @@ SpellInfo::SpellInfo(SpellInfoLoadHelper const& data, SpellEffectEntryMap const& _spellSpecific = SPELL_SPECIFIC_NORMAL; _auraState = AURA_STATE_NONE; + + _allowedMechanicMask = 0; } SpellInfo::~SpellInfo() @@ -3370,6 +3372,8 @@ void SpellInfo::_LoadImmunityInfo() immuneInfo.AuraTypeImmune.shrink_to_fit(); immuneInfo.SpellEffectImmune.shrink_to_fit(); + + _allowedMechanicMask |= immuneInfo.MechanicImmuneMask; }; for (auto const& effects : _effects) @@ -3382,6 +3386,31 @@ void SpellInfo::_LoadImmunityInfo() loadImmunityInfoFn(const_cast<SpellEffectInfo*>(effect)); } } + + if (HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED)) + { + switch (Id) + { + case 22812: // Barkskin + _allowedMechanicMask |= + (1 << MECHANIC_STUN) | + (1 << MECHANIC_FREEZE) | + (1 << MECHANIC_KNOCKOUT) | + (1 << MECHANIC_SLEEP); + break; + case 49039: // Lichborne, don't allow normal stuns + break; + default: + _allowedMechanicMask |= (1 << MECHANIC_STUN); + break; + } + } + + if (HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED)) + _allowedMechanicMask |= (1 << MECHANIC_DISORIENTED); + + if (HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED)) + _allowedMechanicMask |= (1 << MECHANIC_FEAR); } void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, SpellEffectInfo const* effect, bool apply) const @@ -3582,6 +3611,11 @@ bool SpellInfo::SpellCancelsAuraEffect(AuraEffect const* aurEff) const return false; } +uint32 SpellInfo::GetAllowedMechanicMask() const +{ + return _allowedMechanicMask; +} + float SpellInfo::GetMinRange(bool positive) const { if (!RangeEntry) diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 97fa181fb36..ff053e0550b 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -668,6 +668,8 @@ class TC_GAME_API SpellInfo bool CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInfo) const; bool SpellCancelsAuraEffect(AuraEffect const* aurEff) const; + uint32 GetAllowedMechanicMask() const; + private: // loading helpers void _InitializeExplicitTargetMask(); @@ -691,6 +693,7 @@ class TC_GAME_API SpellInfo AuraStateType _auraState; SpellDiminishInfo _diminishInfo; + uint32 _allowedMechanicMask; }; #endif // _SPELLINFO_H |