fix(Core/Spell): spell immunity system and new separate immunities table (#24956)
Co-authored-by: ariel- <ariel-@users.noreply.github.com> Co-authored-by: Keader <keader.android@gmail.com> Co-authored-by: Shauren <shauren.trinity@gmail.com>
This commit is contained in:
@@ -643,7 +643,7 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
|
||||
SetControlled(true, UNIT_STATE_ROOT);
|
||||
UpdateMovementFlags();
|
||||
|
||||
LoadSpellTemplateImmunity();
|
||||
LoadTemplateImmunities(cInfo->CreatureImmunitiesId);
|
||||
|
||||
if (updateAI)
|
||||
{
|
||||
@@ -2132,39 +2132,55 @@ void Creature::InitializeReactState()
|
||||
SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
|
||||
bool Creature::HasMechanicTemplateImmunity(uint32 mask) const
|
||||
bool Creature::HasMechanicTemplateImmunity(uint64 mask) const
|
||||
{
|
||||
return !GetOwnerGUID().IsPlayer() && (GetCreatureTemplate()->MechanicImmuneMask & mask);
|
||||
if (GetOwnerGUID().IsPlayer())
|
||||
return false;
|
||||
|
||||
if (CreatureImmunities const* immunities = sSpellMgr->GetCreatureImmunities(_creatureImmunitiesId))
|
||||
return (immunities->Mechanic.to_ullong() & mask) != 0;
|
||||
|
||||
// no custom immunity entry => no mechanic immunity
|
||||
return false;
|
||||
}
|
||||
|
||||
void Creature::LoadSpellTemplateImmunity()
|
||||
void Creature::LoadTemplateImmunities(int32 creatureImmunitiesId)
|
||||
{
|
||||
// uint32 max used for "spell id", the immunity system will not perform SpellInfo checks against invalid spells
|
||||
// used so we know which immunities were loaded from template
|
||||
static uint32 const placeholderSpellId = std::numeric_limits<uint32>::max();
|
||||
static uint32 constexpr placeholderSpellId = std::numeric_limits<uint32>::max();
|
||||
|
||||
// unapply template immunities (in case we're updating entry)
|
||||
for (uint8 i = SPELL_SCHOOL_NORMAL; i <= SPELL_SCHOOL_ARCANE; ++i)
|
||||
auto applyCreatureImmunities = [this](CreatureImmunities const* immunities, bool apply)
|
||||
{
|
||||
ApplySpellImmune(placeholderSpellId, IMMUNITY_SCHOOL, i, false);
|
||||
}
|
||||
if (!immunities)
|
||||
return;
|
||||
for (std::size_t i = 0; i < immunities->School.size(); ++i)
|
||||
if (immunities->School[i])
|
||||
ApplySpellImmune(placeholderSpellId, IMMUNITY_SCHOOL, 1 << i, apply);
|
||||
for (std::size_t i = 0; i < immunities->DispelType.size(); ++i)
|
||||
if (immunities->DispelType[i])
|
||||
ApplySpellImmune(placeholderSpellId, IMMUNITY_DISPEL, i, apply);
|
||||
for (std::size_t i = 0; i < immunities->Mechanic.size(); ++i)
|
||||
if (immunities->Mechanic[i])
|
||||
ApplySpellImmune(placeholderSpellId, IMMUNITY_MECHANIC, i, apply);
|
||||
for (SpellEffects effect : immunities->Effect)
|
||||
ApplySpellImmune(placeholderSpellId, IMMUNITY_EFFECT, effect, apply);
|
||||
for (AuraType aura : immunities->Aura)
|
||||
ApplySpellImmune(placeholderSpellId, IMMUNITY_STATE, aura, apply);
|
||||
};
|
||||
|
||||
// don't inherit immunities for hunter pets
|
||||
if (GetOwnerGUID().IsPlayer() && IsHunterPet())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// unapply old template if any
|
||||
if (CreatureImmunities const* oldImmunities = sSpellMgr->GetCreatureImmunities(_creatureImmunitiesId))
|
||||
applyCreatureImmunities(oldImmunities, false);
|
||||
|
||||
if (uint8 mask = GetCreatureTemplate()->SpellSchoolImmuneMask)
|
||||
// apply requested immunities
|
||||
if (CreatureImmunities const* newImmunities = sSpellMgr->GetCreatureImmunities(creatureImmunitiesId))
|
||||
{
|
||||
for (uint8 i = SPELL_SCHOOL_NORMAL; i <= SPELL_SCHOOL_ARCANE; ++i)
|
||||
{
|
||||
if (mask & (1 << i))
|
||||
{
|
||||
ApplySpellImmune(placeholderSpellId, IMMUNITY_SCHOOL, 1 << i, true);
|
||||
}
|
||||
}
|
||||
_creatureImmunitiesId = creatureImmunitiesId;
|
||||
applyCreatureImmunities(newImmunities, true);
|
||||
}
|
||||
else
|
||||
_creatureImmunitiesId = 0;
|
||||
}
|
||||
|
||||
bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
|
||||
@@ -2179,11 +2195,13 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
|
||||
|
||||
// Xinef: this should exclude self casts...
|
||||
// Spells that don't have effectMechanics.
|
||||
if (spellInfo->Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(1 << (spellInfo->Mechanic - 1)))
|
||||
if (spellInfo->Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(UI64LIT(1) << spellInfo->Mechanic))
|
||||
return true;
|
||||
|
||||
// This check must be done instead of 'if (GetCreatureTemplate()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1)))' for not break
|
||||
// the check of mechanic immunity on DB (tested) because GetCreatureTemplate()->MechanicImmuneMask and m_spellImmune[IMMUNITY_MECHANIC] don't have same data.
|
||||
// The above helper uses the creature_immunities table rather than a
|
||||
// simple mask on creature_template. We can't rely on the old mask field
|
||||
// (which has been removed) because it no longer exists and did not always
|
||||
// match the runtime immunity set stored in m_spellImmune.
|
||||
bool immunedToAllEffects = true;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (spellInfo->Effects[i].IsEffect() && !IsImmunedToSpellEffect(spellInfo, i))
|
||||
@@ -2197,16 +2215,16 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
|
||||
return Unit::IsImmunedToSpell(spellInfo, spell);
|
||||
}
|
||||
|
||||
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const
|
||||
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster /*= nullptr*/) const
|
||||
{
|
||||
// Xinef: this should exclude self casts...
|
||||
if (spellInfo->Effects[index].Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(1 << (spellInfo->Effects[index].Mechanic - 1)))
|
||||
if (spellInfo->Effects[index].Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(UI64LIT(1) << spellInfo->Effects[index].Mechanic))
|
||||
return true;
|
||||
|
||||
if (GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && spellInfo->Effects[index].Effect == SPELL_EFFECT_HEAL)
|
||||
return true;
|
||||
|
||||
return Unit::IsImmunedToSpellEffect(spellInfo, index);
|
||||
return Unit::IsImmunedToSpellEffect(spellInfo, index, caster);
|
||||
}
|
||||
|
||||
SpellInfo const* Creature::reachWithSpellAttack(Unit* victim)
|
||||
|
||||
@@ -105,12 +105,11 @@ public:
|
||||
bool isCanInteractWithBattleMaster(Player* player, bool msg) const;
|
||||
bool CanResetTalents(Player* player) const;
|
||||
bool CanCreatureAttack(Unit const* victim, bool skipDistCheck = false) const;
|
||||
void LoadSpellTemplateImmunity();
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell = nullptr) override;
|
||||
|
||||
[[nodiscard]] bool HasMechanicTemplateImmunity(uint32 mask) const;
|
||||
[[nodiscard]] bool HasMechanicTemplateImmunity(uint64 mask) const;
|
||||
// redefine Unit::IsImmunedToSpell
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const override;
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster = nullptr) const override;
|
||||
// redefine Unit::IsImmunedToSpellEffect
|
||||
[[nodiscard]] bool isElite() const
|
||||
{
|
||||
@@ -186,6 +185,8 @@ public:
|
||||
void UpdateAttackPowerAndDamage(bool ranged = false) override;
|
||||
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
|
||||
|
||||
void LoadTemplateImmunities(int32 creatureImmunitiesId);
|
||||
|
||||
void LoadSparringPct();
|
||||
[[nodiscard]] float GetSparringPct() const { return _sparringPct; }
|
||||
|
||||
@@ -486,6 +487,7 @@ protected:
|
||||
|
||||
SpellSchoolMask m_meleeDamageSchoolMask;
|
||||
uint32 m_originalEntry;
|
||||
int32 _creatureImmunitiesId;
|
||||
uint32 _gossipMenuId;
|
||||
|
||||
bool m_moveInLineOfSightDisabled;
|
||||
|
||||
@@ -202,7 +202,6 @@ struct CreatureTemplate
|
||||
float speed_swim;
|
||||
float speed_flight;
|
||||
float detection_range; // Detection Range for Line of Sight aggro
|
||||
float scale;
|
||||
uint32 rank;
|
||||
uint32 dmgschool;
|
||||
float DamageModifier;
|
||||
@@ -237,8 +236,7 @@ struct CreatureTemplate
|
||||
bool RacialLeader;
|
||||
uint32 movementId;
|
||||
bool RegenHealth;
|
||||
uint32 MechanicImmuneMask;
|
||||
uint8 SpellSchoolImmuneMask;
|
||||
int32 CreatureImmunitiesId;
|
||||
uint32 flags_extra;
|
||||
uint32 ScriptID;
|
||||
WorldPacket queryData; // pussywizard
|
||||
|
||||
@@ -491,7 +491,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
|
||||
}
|
||||
|
||||
// must be after SetMinion (owner guid check)
|
||||
//LoadTemplateImmunities();
|
||||
LoadTemplateImmunities(0);
|
||||
//LoadMechanicTemplateImmunity();
|
||||
m_loading = false;
|
||||
});
|
||||
|
||||
@@ -179,7 +179,7 @@ void Totem::UnSummon(Milliseconds msTime)
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const
|
||||
bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster /*= nullptr*/) const
|
||||
{
|
||||
// xinef: immune to all positive spells, except of stoneclaw totem absorb, sentry totem bind sight and intervene
|
||||
// totems positive spells have unit_caster target
|
||||
@@ -209,5 +209,5 @@ bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) con
|
||||
break;
|
||||
}
|
||||
|
||||
return Creature::IsImmunedToSpellEffect(spellInfo, index);
|
||||
return Creature::IsImmunedToSpellEffect(spellInfo, index, caster);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
void UpdateAttackPowerAndDamage(bool /*ranged*/) override {}
|
||||
void UpdateDamagePhysical(WeaponAttackType /*attType*/) override {}
|
||||
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const override;
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster = nullptr) const override;
|
||||
|
||||
protected:
|
||||
TotemType m_type;
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
#include "Vehicle.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
float baseMoveSpeed[MAX_MOVE_TYPE] =
|
||||
@@ -372,9 +373,6 @@ Unit::Unit() : WorldObject(),
|
||||
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_auraFlatModifiersGroup[i][BASE_VALUE] = 0.0f;
|
||||
@@ -891,6 +889,29 @@ bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, Unit const* caster /*= nullptr*/)
|
||||
{
|
||||
if (!spellInfo)
|
||||
return false;
|
||||
|
||||
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (!(effectMask & (1u << i)))
|
||||
continue;
|
||||
|
||||
if (IsImmunedToSpellEffect(spellInfo, i, caster))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
if (IsImmunedToSchool(spellInfo))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura) const
|
||||
{
|
||||
AuraEffectList const& auras = GetAuraEffectsByType(type);
|
||||
@@ -2075,7 +2096,7 @@ void Unit::DealDamageShieldDamage(Unit* victim)
|
||||
}
|
||||
|
||||
// ...or immuned
|
||||
if (IsImmunedToDamageOrSchool(i_spellProto))
|
||||
if (IsImmunedToDamage(victim, i_spellProto))
|
||||
{
|
||||
victim->SendSpellDamageImmune(this, i_spellProto->Id);
|
||||
continue;
|
||||
@@ -3203,7 +3224,7 @@ void Unit::SendMeleeAttackStop(Unit* victim)
|
||||
bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType)
|
||||
{
|
||||
// These spells can't be blocked
|
||||
if (spellProto && spellProto->HasAttribute(SPELL_ATTR0_NO_ACTIVE_DEFENSE))
|
||||
if (spellProto && (spellProto->HasAttribute(SPELL_ATTR0_NO_ACTIVE_DEFENSE) || spellProto->HasAttribute(SPELL_ATTR3_ALWAYS_HIT)))
|
||||
return false;
|
||||
|
||||
if (victim->HasIgnoreHitDirectionAura() || victim->HasInArc(M_PI, this))
|
||||
@@ -3571,6 +3592,9 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
|
||||
// Resist
|
||||
SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool CanReflect)
|
||||
{
|
||||
if (spell->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
// Check for immune
|
||||
if (victim->IsImmunedToSpell(spell))
|
||||
return SPELL_MISS_IMMUNE;
|
||||
@@ -3581,11 +3605,6 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool Ca
|
||||
&& (!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
// Check for immune
|
||||
// xinef: check for school immunity only
|
||||
if (victim->IsImmunedToSchool(spell))
|
||||
return SPELL_MISS_IMMUNE;
|
||||
|
||||
if (this == victim)
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
@@ -3650,13 +3669,17 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, Spell const* spell, bool CanRef
|
||||
return SPELL_MISS_NONE;
|
||||
}
|
||||
|
||||
// Check for immune
|
||||
// xinef: check for school immunity only
|
||||
if (victim->IsImmunedToSchool(spell))
|
||||
// Check for immune to spell effects (includes school, mechanics, state, dispel immunities)
|
||||
if (victim->IsImmunedToSpell(spellInfo, MAX_EFFECT_MASK, this))
|
||||
{
|
||||
return SPELL_MISS_IMMUNE;
|
||||
}
|
||||
|
||||
// Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
|
||||
// returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit
|
||||
if (spellInfo->HasOnlyDamageEffects() && victim->IsImmunedToDamage(this, spellInfo))
|
||||
return SPELL_MISS_IMMUNE;
|
||||
|
||||
if (this == victim)
|
||||
{
|
||||
return SPELL_MISS_NONE;
|
||||
@@ -5447,7 +5470,7 @@ void Unit::RemoveMovementImpairingAuras(bool withRoot)
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode, uint32 except)
|
||||
void Unit::RemoveAurasWithMechanic(uint64 mechanic_mask, AuraRemoveMode removemode, uint32 except)
|
||||
{
|
||||
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
|
||||
{
|
||||
@@ -5466,7 +5489,7 @@ void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemo
|
||||
|
||||
void Unit::RemoveAurasByShapeShift()
|
||||
{
|
||||
uint32 mechanic_mask = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
|
||||
uint64 mechanic_mask = (UI64LIT(1) << MECHANIC_SNARE) | (UI64LIT(1) << MECHANIC_ROOT);
|
||||
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
|
||||
{
|
||||
Aura const* aura = iter->second->GetBase();
|
||||
@@ -6015,17 +6038,17 @@ bool Unit::HasNegativeAuraWithAttribute(uint32 flag, ObjectGuid guid)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::HasAuraWithMechanic(uint32 mechanicMask) const
|
||||
bool Unit::HasAuraWithMechanic(uint64 mechanicMask) const
|
||||
{
|
||||
for (AuraApplicationMap::const_iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
|
||||
{
|
||||
SpellInfo const* spellInfo = iter->second->GetBase()->GetSpellInfo();
|
||||
if (spellInfo->Mechanic && (mechanicMask & (1 << spellInfo->Mechanic)))
|
||||
if (spellInfo->Mechanic && (mechanicMask & (UI64LIT(1) << spellInfo->Mechanic)))
|
||||
return true;
|
||||
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (iter->second->HasEffect(i) && spellInfo->Effects[i].Effect && spellInfo->Effects[i].Mechanic)
|
||||
if (mechanicMask & (1 << spellInfo->Effects[i].Mechanic))
|
||||
if (mechanicMask & (UI64LIT(1) << spellInfo->Effects[i].Mechanic))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8833,7 +8856,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
|
||||
});
|
||||
}
|
||||
|
||||
if (uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask())
|
||||
if (uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask())
|
||||
{
|
||||
int32 modifierMax = 0;
|
||||
int32 modifierMin = 0;
|
||||
@@ -8848,7 +8871,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
|
||||
if (!caster || caster->GetGUID() != (*i)->GetCasterGUID())
|
||||
continue;
|
||||
|
||||
if (mechanicMask & uint32(1 << (*i)->GetMiscValue()))
|
||||
if (mechanicMask & uint64(UI64LIT(1) << (*i)->GetMiscValue()))
|
||||
{
|
||||
if ((*i)->GetAmount() > 0)
|
||||
{
|
||||
@@ -9739,107 +9762,90 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask)
|
||||
return AdvertisedBenefit;
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
|
||||
uint32 Unit::GetDamageImmunityMask() const
|
||||
{
|
||||
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 & meleeSchoolMask) == meleeSchoolMask)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
uint32 mask = 0;
|
||||
SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
|
||||
for (auto const& [immunitySchoolMask, _] : damageList)
|
||||
mask |= immunitySchoolMask;
|
||||
return mask;
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
|
||||
bool Unit::IsImmunedToDamage(SpellSchoolMask schoolMask) const
|
||||
{
|
||||
if (!spellInfo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 schoolMask = spellInfo->GetSchoolMask();
|
||||
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 & schoolMask) == schoolMask)
|
||||
// If m_immuneToSchool type contains all requested schools, IMMUNE damage.
|
||||
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
|
||||
for (auto const& itr : schoolList)
|
||||
if (IsImmuneMaskFully(SpellSchoolMask(itr.first), schoolMask))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
// If m_immuneToDamage type contains all requested schools, IMMUNE damage.
|
||||
SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
|
||||
return std::ranges::any_of(damageList, [schoolMask](auto const& immune)
|
||||
{
|
||||
return Unit::IsImmuneMaskFully(SpellSchoolMask(immune.first), schoolMask);
|
||||
});
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToDamage(Spell const* spell) const
|
||||
bool Unit::IsImmunedToDamage(Unit const* caster, SpellInfo const* spellInfo) const
|
||||
{
|
||||
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
||||
if (!spellInfo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 schoolMask = spell->GetSpellSchoolMask();
|
||||
SpellSchoolMask schoolMask = SpellSchoolMask(spellInfo->GetSchoolMask());
|
||||
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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)
|
||||
auto hasImmunity = [&](SpellImmuneContainer const& container)
|
||||
{
|
||||
if ((itr->type & schoolMask) == schoolMask)
|
||||
uint32 schoolImmunityMask = 0;
|
||||
for (auto const& [immunitySchoolMask, immunityAuraId] : container)
|
||||
{
|
||||
return true;
|
||||
SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId);
|
||||
if (immuneAuraInfo && !immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && caster && caster->IsFriendlyTo(this))
|
||||
continue;
|
||||
|
||||
if (immuneAuraInfo && spellInfo->CanPierceImmuneAura(immuneAuraInfo))
|
||||
continue;
|
||||
|
||||
schoolImmunityMask |= immunitySchoolMask;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToSchool(SpellSchoolMask meleeSchoolMask) const
|
||||
{
|
||||
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// We need to be immune to all types
|
||||
return (schoolImmunityMask & schoolMask) == schoolMask;
|
||||
};
|
||||
|
||||
// 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 & meleeSchoolMask) == meleeSchoolMask)
|
||||
return true;
|
||||
if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
|
||||
return true;
|
||||
|
||||
// If m_immuneToDamage type contain magic, IMMUNE damage.
|
||||
if (hasImmunity(m_spellImmune[IMMUNITY_DAMAGE]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToSchool(SpellSchoolMask schoolMask) const
|
||||
{
|
||||
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
|
||||
return false;
|
||||
|
||||
// Check IMMUNITY_SCHOOL: returns true if ALL schools in the mask are covered by at least one immunity
|
||||
// (e.g., Anti-Magic Shell provides school immunity to all magic schools)
|
||||
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
|
||||
return std::ranges::any_of(schoolList, [schoolMask](auto const& immune)
|
||||
{
|
||||
return (immune.first & schoolMask) == schoolMask;
|
||||
});
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToSchool(SpellInfo const* spellInfo) const
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
|
||||
@@ -9853,10 +9859,10 @@ bool Unit::IsImmunedToSchool(SpellInfo const* spellInfo) const
|
||||
|
||||
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
|
||||
{
|
||||
// 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 & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->spellId)))
|
||||
// Check IMMUNITY_SCHOOL: returns true if ALL schools in the mask are covered and spell can't pierce
|
||||
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
|
||||
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
|
||||
if ((itr->first & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second)))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9879,11 +9885,11 @@ bool Unit::IsImmunedToSchool(Spell const* spell) const
|
||||
|
||||
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
|
||||
{
|
||||
// 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)
|
||||
// Check IMMUNITY_SCHOOL: returns true if ALL schools in the mask are covered and spell can't pierce
|
||||
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
|
||||
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
|
||||
{
|
||||
if ((itr->type & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->spellId)))
|
||||
if ((itr->first & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -9893,19 +9899,49 @@ bool Unit::IsImmunedToSchool(Spell const* spell) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToDamageOrSchool(SpellSchoolMask meleeSchoolMask) const
|
||||
bool Unit::IsImmunedToDamageOrSchool(SpellSchoolMask schoolMask) const
|
||||
{
|
||||
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
|
||||
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsImmunedToDamage(meleeSchoolMask) || IsImmunedToSchool(meleeSchoolMask);
|
||||
return IsImmunedToDamage(schoolMask) || IsImmunedToSchool(schoolMask);
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToDamageOrSchool(SpellInfo const* spellInfo) const
|
||||
bool Unit::IsImmunedToAuraPeriodicTick(Unit const* caster, SpellInfo const* spellInfo) const
|
||||
{
|
||||
return IsImmunedToDamage(spellInfo) || IsImmunedToSchool(spellInfo);
|
||||
if (!spellInfo)
|
||||
return false;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
return false;
|
||||
|
||||
SpellSchoolMask schoolMask = SpellSchoolMask(spellInfo->GetSchoolMask());
|
||||
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
|
||||
return false;
|
||||
|
||||
auto hasImmunity = [&](SpellImmuneContainer const& container)
|
||||
{
|
||||
uint32 schoolImmunityMask = 0;
|
||||
for (auto const& [immunitySchoolMask, immunityAuraId] : container)
|
||||
{
|
||||
SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId);
|
||||
if (immuneAuraInfo && !immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && caster && caster->IsFriendlyTo(this))
|
||||
continue;
|
||||
|
||||
schoolImmunityMask |= immunitySchoolMask;
|
||||
}
|
||||
|
||||
// We need to be immune to all types
|
||||
return (schoolImmunityMask & schoolMask) == schoolMask;
|
||||
};
|
||||
|
||||
// If m_immuneToSchool type contain this school type, IMMUNE periodic tick.
|
||||
if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
|
||||
@@ -9914,39 +9950,35 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
|
||||
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;
|
||||
SpellImmuneContainer const& idList = m_spellImmune[IMMUNITY_ID];
|
||||
if (idList.count(spellInfo->Id) > 0)
|
||||
return true;
|
||||
|
||||
// xinef: my special immunity, if spellid is not on this list it means npc is immune
|
||||
SpellImmuneList const& allowIdList = m_spellImmune[IMMUNITY_ALLOW_ID];
|
||||
SpellImmuneContainer const& allowIdList = m_spellImmune[IMMUNITY_ALLOW_ID];
|
||||
if (!allowIdList.empty())
|
||||
{
|
||||
for (SpellImmuneList::const_iterator itr = allowIdList.begin(); itr != allowIdList.end(); ++itr)
|
||||
if (itr->type == spellInfo->Id)
|
||||
return false;
|
||||
return true;
|
||||
if (allowIdList.count(spellInfo->Id) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
|
||||
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;
|
||||
SpellImmuneContainer 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;
|
||||
SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
|
||||
if (mechanicList.count(mechanic) > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool immuneToAllEffects = true;
|
||||
@@ -9971,7 +10003,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
|
||||
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
|
||||
return true;
|
||||
|
||||
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
SpellSchoolMask spellSchoolMask = spellInfo->GetSchoolMask();
|
||||
if (spell)
|
||||
@@ -9981,16 +10013,24 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
|
||||
|
||||
if (spellSchoolMask != SPELL_SCHOOL_MASK_NONE)
|
||||
{
|
||||
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
|
||||
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
|
||||
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
|
||||
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
|
||||
{
|
||||
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->spellId);
|
||||
if (((itr->type & spellSchoolMask) == spellSchoolMask)
|
||||
&& (!immuneSpellInfo || immuneSpellInfo->IsPositive()) && !spellInfo->IsPositive()
|
||||
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
|
||||
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
|
||||
if (!(itr->first & spellSchoolMask))
|
||||
continue;
|
||||
|
||||
if (immuneSpellInfo && !immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS))
|
||||
{
|
||||
return true;
|
||||
Unit const* spellCaster = spell ? spell->GetCaster() : nullptr;
|
||||
if (spellCaster && spellCaster->IsFriendlyTo(this))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
|
||||
continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9998,7 +10038,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const
|
||||
bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster /*= nullptr*/) const
|
||||
{
|
||||
if (!spellInfo || !spellInfo->Effects[index].IsEffect())
|
||||
return false;
|
||||
@@ -10010,12 +10050,16 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
|
||||
return false;
|
||||
|
||||
// Special-case handling for Vezax's Aura of Despair.
|
||||
static constexpr uint32 SPELL_AURA_OF_DESPAIR_1 = 62692;
|
||||
static constexpr uint32 SPELL_AURA_OF_DESPAIR_2 = 64848;
|
||||
|
||||
//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)
|
||||
SpellImmuneContainer const& effectList = m_spellImmune[IMMUNITY_EFFECT];
|
||||
for (SpellImmuneContainer::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
|
||||
{
|
||||
if (itr->type == effect && (itr->spellId != 62692 || (spellInfo->Effects[index].MiscValue == POWER_MANA && !CanRestoreMana(spellInfo))))
|
||||
if (itr->first == effect && (itr->second != SPELL_AURA_OF_DESPAIR_1 || (spellInfo->Effects[index].MiscValue == POWER_MANA && !CanRestoreMana(spellInfo))))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -10023,41 +10067,32 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
|
||||
|
||||
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)
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
|
||||
{
|
||||
SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
|
||||
for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
|
||||
if (uint32 aura = spellInfo->Effects[index].ApplyAuraName)
|
||||
{
|
||||
if (itr->type == aura && (itr->spellId != 64848 || (spellInfo->Effects[index].MiscValue == POWER_MANA && !CanRestoreMana(spellInfo))))
|
||||
SpellImmuneContainer const& list = m_spellImmune[IMMUNITY_STATE];
|
||||
for (SpellImmuneContainer::const_iterator itr = list.begin(); itr != list.end(); ++itr)
|
||||
{
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
|
||||
{
|
||||
if (itr->blockType == SPELL_BLOCK_TYPE_ALL || spellInfo->IsPositive()) // xinef: added for pet scaling
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
// Check for immune to application of harmful magical effects
|
||||
AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
|
||||
for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
|
||||
{
|
||||
if (/*(spellInfo->Dispel == DISPEL_MAGIC || spellInfo->Dispel == DISPEL_CURSE || spellInfo->Dispel == DISPEL_DISEASE) &&*/ // Magic debuff, xinef: all kinds?
|
||||
((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
|
||||
!spellInfo->IsPositiveEffect(index) && // Harmful
|
||||
spellInfo->Effects[index].Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA) // Not Persistent area auras
|
||||
{
|
||||
if (itr->first == aura && (itr->second != SPELL_AURA_OF_DESPAIR_2 || (spellInfo->Effects[index].MiscValue == POWER_MANA && !CanRestoreMana(spellInfo))))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||
{
|
||||
// Check for immune to application of harmful magical effects
|
||||
for (AuraEffect* immuneAuraApply : GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL))
|
||||
{
|
||||
if (!(immuneAuraApply->GetMiscValue() & spellInfo->GetSchoolMask())) // Check school
|
||||
continue;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || (caster && !IsFriendlyTo(caster))) // Harmful
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10286,17 +10321,17 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
|
||||
});
|
||||
|
||||
// Mod damage from spell mechanic
|
||||
uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask();
|
||||
uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask();
|
||||
|
||||
// Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
|
||||
if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
|
||||
mechanicMask |= (1 << MECHANIC_BLEED);
|
||||
mechanicMask |= (UI64LIT(1) << MECHANIC_BLEED);
|
||||
|
||||
if (mechanicMask)
|
||||
{
|
||||
TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
|
||||
{
|
||||
if (mechanicMask & uint32(1 << (aurEff->GetMiscValue())))
|
||||
if (mechanicMask & uint64(UI64LIT(1) << (aurEff->GetMiscValue())))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
@@ -10364,51 +10399,17 @@ private:
|
||||
uint32 _type;
|
||||
};
|
||||
|
||||
void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply, SpellImmuneBlockType blockType)
|
||||
void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply, SpellImmuneBlockType /*blockType*/)
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
// xinef: immunities with spellId 0 are intended to be applied only once (script purposes mosty)
|
||||
if (spellId == 0 && std::find_if(m_spellImmune[op].begin(), m_spellImmune[op].end(), spellIdImmunityPredicate(type)) != m_spellImmune[op].end())
|
||||
return;
|
||||
|
||||
SpellImmune immune;
|
||||
immune.spellId = spellId;
|
||||
immune.type = type;
|
||||
immune.blockType = blockType;
|
||||
m_spellImmune[op].push_back(std::move(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(SpellInfo const* spellProto, DispelType type, bool apply)
|
||||
{
|
||||
ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply);
|
||||
|
||||
if (apply && spellProto->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
@@ -11174,8 +11175,9 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
|
||||
{
|
||||
if (Creature* creature = ToCreature())
|
||||
{
|
||||
uint32 immuneMask = creature->GetCreatureTemplate()->MechanicImmuneMask;
|
||||
if (immuneMask & (1 << (MECHANIC_SNARE - 1)) || immuneMask & (1 << (MECHANIC_DAZE - 1)))
|
||||
// use creature helper which now consults creature_immunities table
|
||||
if (creature->HasMechanicTemplateImmunity(UI64LIT(1) << MECHANIC_SNARE) ||
|
||||
creature->HasMechanicTemplateImmunity(UI64LIT(1) << MECHANIC_DAZE))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11196,7 +11198,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
|
||||
if (creature
|
||||
&& !IsPet()
|
||||
&& !(IsControlledByPlayer() && IsVehicle())
|
||||
&& !(creature->HasMechanicTemplateImmunity(MECHANIC_SNARE))
|
||||
&& !(creature->HasMechanicTemplateImmunity(UI64LIT(1) << MECHANIC_SNARE))
|
||||
&& !(creature->IsDungeonBoss()))
|
||||
{
|
||||
// 1.6% for each % under 30.
|
||||
@@ -15075,7 +15077,7 @@ Aura* Unit::AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target)
|
||||
{
|
||||
if (!(effMask & (1 << i)))
|
||||
continue;
|
||||
if (target->IsImmunedToSpellEffect(spellInfo, i))
|
||||
if (target->IsImmunedToSpellEffect(spellInfo, i, this))
|
||||
effMask &= ~(1 << i);
|
||||
}
|
||||
|
||||
|
||||
@@ -1408,7 +1408,7 @@ public:
|
||||
void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except = 0, bool isAutoshot = false);
|
||||
void RemoveAurasWithAttribute(uint32 flags);
|
||||
void RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, ObjectGuid casterGUID);
|
||||
void RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode = AURA_REMOVE_BY_DEFAULT, uint32 except = 0);
|
||||
void RemoveAurasWithMechanic(uint64 mechanic_mask, AuraRemoveMode removemode = AURA_REMOVE_BY_DEFAULT, uint32 except = 0);
|
||||
void RemoveMovementImpairingAuras(bool withRoot);
|
||||
void RemoveAurasByShapeShift();
|
||||
|
||||
@@ -1500,7 +1500,7 @@ public:
|
||||
bool HasNegativeAuraWithInterruptFlag(uint32 flag, ObjectGuid guid = ObjectGuid::Empty);
|
||||
[[nodiscard]] bool HasVisibleAuraType(AuraType auraType) const;
|
||||
bool HasNegativeAuraWithAttribute(uint32 flag, ObjectGuid guid = ObjectGuid::Empty);
|
||||
[[nodiscard]] bool HasAuraWithMechanic(uint32 mechanicMask) const;
|
||||
[[nodiscard]] bool HasAuraWithMechanic(uint64 mechanicMask) const;
|
||||
|
||||
[[nodiscard]] bool HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint32 familyFlags) const;
|
||||
|
||||
@@ -1636,17 +1636,22 @@ public:
|
||||
|
||||
// Spells immunities
|
||||
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply, SpellImmuneBlockType blockType = SPELL_BLOCK_TYPE_ALL);
|
||||
void ApplySpellDispelImmunity(SpellInfo const* spellProto, DispelType type, bool apply);
|
||||
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell = nullptr);
|
||||
[[nodiscard]] bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const;
|
||||
[[nodiscard]] bool IsImmunedToDamage(SpellInfo const* spellInfo) const;
|
||||
[[nodiscard]] bool IsImmunedToDamage(Spell const* spell) const;
|
||||
[[nodiscard]] bool IsImmunedToSchool(SpellSchoolMask meleeSchoolMask) const;
|
||||
bool IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, Unit const* caster = nullptr);
|
||||
[[nodiscard]] bool IsImmunedToDamage(SpellSchoolMask schoolMask) const;
|
||||
[[nodiscard]] bool IsImmunedToDamage(Unit const* caster, SpellInfo const* spellInfo) const;
|
||||
[[nodiscard]] bool IsImmunedToSchool(SpellSchoolMask schoolMask) const;
|
||||
|
||||
static bool IsImmuneMaskFully(SpellSchoolMask immuneMask, SpellSchoolMask schoolMask) { return (immuneMask & schoolMask) == schoolMask; }
|
||||
|
||||
[[nodiscard]] uint32 GetSchoolImmunityMask() const;
|
||||
[[nodiscard]] uint32 GetDamageImmunityMask() const;
|
||||
|
||||
[[nodiscard]] bool IsImmunedToSchool(SpellInfo const* spellInfo) const;
|
||||
[[nodiscard]] bool IsImmunedToSchool(Spell const* spell) const;
|
||||
[[nodiscard]] bool IsImmunedToDamageOrSchool(SpellSchoolMask meleeSchoolMask) const;
|
||||
bool IsImmunedToDamageOrSchool(SpellInfo const* spellInfo) const;
|
||||
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const;
|
||||
[[nodiscard]] bool IsImmunedToDamageOrSchool(SpellSchoolMask schoolMask) const;
|
||||
[[nodiscard]] bool IsImmunedToAuraPeriodicTick(Unit const* caster, SpellInfo const* spellInfo) const;
|
||||
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster = nullptr) const;
|
||||
|
||||
// Critic chances
|
||||
bool isBlockCritical();
|
||||
@@ -2080,7 +2085,8 @@ public:
|
||||
|
||||
float m_modAttackSpeedPct[3];
|
||||
|
||||
SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY];
|
||||
typedef std::unordered_multimap<uint32 /*type*/, uint32 /*spellId*/> SpellImmuneContainer;
|
||||
SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY];
|
||||
uint32 m_lastSanctuaryTime;
|
||||
|
||||
// pet auras
|
||||
|
||||
Reference in New Issue
Block a user