mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
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:
@@ -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)
|
||||
|
||||
@@ -858,6 +858,8 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry)
|
||||
|
||||
_spellSpecific = SPELL_SPECIFIC_NORMAL;
|
||||
_auraState = AURA_STATE_NONE;
|
||||
|
||||
_allowedMechanicMask = 0;
|
||||
}
|
||||
|
||||
SpellInfo::~SpellInfo()
|
||||
@@ -2787,7 +2789,34 @@ void SpellInfo::_LoadImmunityInfo()
|
||||
|
||||
immuneInfo.AuraTypeImmune.shrink_to_fit();
|
||||
immuneInfo.SpellEffectImmune.shrink_to_fit();
|
||||
|
||||
_allowedMechanicMask |= immuneInfo.MechanicImmuneMask;
|
||||
}
|
||||
|
||||
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, uint8 effIndex, bool apply) const
|
||||
@@ -2979,6 +3008,11 @@ bool SpellInfo::SpellCancelsAuraEffect(SpellInfo const* auraSpellInfo, uint8 aur
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 SpellInfo::GetAllowedMechanicMask() const
|
||||
{
|
||||
return _allowedMechanicMask;
|
||||
}
|
||||
|
||||
float SpellInfo::GetMinRange(bool positive) const
|
||||
{
|
||||
if (!RangeEntry)
|
||||
|
||||
@@ -524,6 +524,8 @@ class TC_GAME_API SpellInfo
|
||||
bool CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInfo) const;
|
||||
bool SpellCancelsAuraEffect(SpellInfo const* auraSpellInfo, uint8 auraEffIndex) const;
|
||||
|
||||
uint32 GetAllowedMechanicMask() const;
|
||||
|
||||
private:
|
||||
// loading helpers
|
||||
void _InitializeExplicitTargetMask();
|
||||
@@ -544,6 +546,8 @@ class TC_GAME_API SpellInfo
|
||||
SpellDiminishInfo _diminishInfoNonTriggered;
|
||||
SpellDiminishInfo _diminishInfoTriggered;
|
||||
|
||||
uint32 _allowedMechanicMask;
|
||||
|
||||
ImmunityInfo _immunityInfo[MAX_SPELL_EFFECTS];
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user