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)
This commit is contained in:
Aokromes committed 2016-11-19 06:10:14 +01:00
1 parent ab289e8494
commit e4dd97765e
11 files changed
+874 -692

No files matched your search

+64 -116
View File
@@ -224,9 +224,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;
@@ -3006,10 +3003,14 @@ 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
@@ -9703,18 +9704,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)
auto 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)
auto const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
if ((itr->first & schoolMask) != 0)
return true;
return false;
@@ -9722,23 +9723,17 @@ bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const
bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
{
if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
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;
}
uint32 schoolMask = spellInfo->GetSchoolMask();
// If m_immuneToSchool type contain this school type, IMMUNE damage.
auto 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)
auto const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
if ((itr->first & schoolMask) != 0)
return true;
return false;
@@ -9750,29 +9745,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;
auto 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;
auto 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;
auto const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
if (mechanicList.count(mechanic) > 0)
return true;
}
bool immuneToAllEffects = true;
@@ -9780,8 +9772,6 @@ 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 (!spellInfo->Effects[i].IsEffect())
continue;
if (!IsImmunedToSpellEffect(spellInfo, i))
{
immuneToAllEffects = false;
@@ -9792,17 +9782,14 @@ 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)
auto const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->spellId);
if ((itr->type & spellInfo->GetSchoolMask())
&& !(immuneSpellInfo && immuneSpellInfo->IsPositive() && spellInfo->IsPositive())
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
return true;
}
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
if ((itr->first & spellInfo->GetSchoolMask())
&& !(immuneSpellInfo && immuneSpellInfo->IsPositive() && spellInfo->IsPositive())
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
return true;
}
return false;
@@ -9811,9 +9798,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;
auto const& mechanicList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
mask |= itr->first;
return mask;
}
@@ -9821,9 +9808,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);
auto const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
mask |= (1 << itr->first);
return mask;
}
@@ -9838,26 +9825,25 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
uint32 effect = spellInfo->Effects[index].Effect;
SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
if (itr->type == effect)
return true;
auto const& effectList = m_spellImmune[IMMUNITY_EFFECT];
if (effectList.count(effect) > 0)
return true;
if (uint32 mechanic = spellInfo->Effects[index].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 = spellInfo->Effects[index].ApplyAuraName)
{
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;
if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
{
auto const& list = m_spellImmune[IMMUNITY_STATE];
if (list.count(aura) > 0)
return true;
}
// Check for immune to application of harmful magical effects
AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
@@ -10103,52 +10089,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;
}