aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxinef1 <w.szyszko2@gmail.com>2017-02-04 23:50:32 +0100
committerariel- <ariel-@users.noreply.github.com>2017-02-04 19:50:32 -0300
commit93746e8c4a79c8256cd4896533315683f143508c (patch)
treefc593ddd9a6bc026b6842f52446f1e9bc9a8dcb3 /src
parent86da1a19bb36edf3242dafac6e45e87434ddff73 (diff)
Implemented binary resistances and some more (#18933)
- Fixed possible exploit with tamed pets having template immunities - Implemented binary resistances - Corrected resistances calculations - Pets properly inherit players spell penetration - Fixed doubled block calculation for damaging melee spells - Auras removing snare effects will only remove the snaring component - Shapeshifting will properly remove movement impairing auras only and not crowd control (dragon's breath) - Immunities are properly checked versus all schools appearing in spell, unit is immune only if immune to all schools - Spells with melee and magic school mask should compare armor reduction with resistances and select smaller reduction - Demonic Circle: Teleport no longer removes root effects
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp14
-rw-r--r--src/server/game/Entities/Creature/Creature.h1
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp236
-rw-r--r--src/server/game/Entities/Unit/Unit.h9
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp4
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp6
-rw-r--r--src/server/game/Spells/SpellInfo.cpp8
-rw-r--r--src/server/game/Spells/SpellInfo.h3
-rw-r--r--src/server/game/Spells/SpellMgr.cpp144
-rw-r--r--src/server/scripts/Spells/spell_priest.cpp2
-rw-r--r--src/server/scripts/Spells/spell_warlock.cpp2
12 files changed, 347 insertions, 84 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 3c6fae376fc..482d3a121be 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -1823,13 +1823,18 @@ void Creature::DespawnOrUnsummon(uint32 msTimeToDespawn /*= 0*/, Seconds const&
ForcedDespawn(msTimeToDespawn, forceRespawnTimer);
}
+bool Creature::HasMechanicTemplateImmunity(uint32 mask) const
+{
+ return !GetOwnerGUID().IsPlayer() && (GetCreatureTemplate()->MechanicImmuneMask & mask);
+}
+
bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const
{
if (!spellInfo)
return false;
// Creature is immune to main mechanic of the spell
- if (GetCreatureTemplate()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1)))
+ if (spellInfo->Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(1 << (spellInfo->Mechanic - 1)))
return true;
// This check must be done instead of 'if (GetCreatureTemplate()->MechanicImmuneMask & (1 << (spellInfo->Mechanic - 1)))' for not break
@@ -1837,14 +1842,13 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const
bool immunedToAllEffects = true;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (!spellInfo->Effects[i].IsEffect())
- continue;
- if (!IsImmunedToSpellEffect(spellInfo, i, caster))
+ if (spellInfo->Effects[i].IsEffect() && !IsImmunedToSpellEffect(spellInfo, i, caster))
{
immunedToAllEffects = false;
break;
}
}
+
if (immunedToAllEffects)
return true;
@@ -1853,7 +1857,7 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const
bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const
{
- if (GetCreatureTemplate()->MechanicImmuneMask & (1 << (spellInfo->Effects[index].Mechanic - 1)))
+ if (spellInfo->Effects[index].Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(1 << (spellInfo->Effects[index].Mechanic - 1)))
return true;
if (GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && spellInfo->Effects[index].Effect == SPELL_EFFECT_HEAL)
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 2eba6fe1857..304d2129f36 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -470,6 +470,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool isCanInteractWithBattleMaster(Player* player, bool msg) const;
bool isCanTrainingAndResetTalentsOf(Player* player) const;
bool CanCreatureAttack(Unit const* victim, bool force = true) const;
+ bool HasMechanicTemplateImmunity(uint32 mask) const;
bool IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const override;
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const override;
bool isElite() const;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 61cfa0322fd..730c4e2ff4b 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -1110,8 +1110,12 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
// Physical Damage
if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)
{
- // Get blocked status
- blocked = isSpellBlocked(victim, spellInfo, attackType);
+ // Spells with this attribute were already calculated in MeleeSpellHitResult
+ if (!spellInfo->HasAttribute(SPELL_ATTR3_BLOCKABLE_SPELL))
+ {
+ // Get blocked status
+ blocked = isSpellBlocked(victim, spellInfo, attackType);
+ }
}
if (crit)
@@ -1593,7 +1597,7 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s
return true;
}
-uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType)
+uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType) const
{
float armor = float(victim->GetArmor());
@@ -1658,56 +1662,28 @@ uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo
return std::max<uint32>(damage * (1.0f - damageReduction), 1);
}
-uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const
+uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const
{
// Magic damage, check for resists
- if (!(schoolMask & SPELL_SCHOOL_MASK_SPELL))
+ if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
return 0;
- // Ignore spells that can't be resisted
- if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_RESISTANCES))
+ // Npcs can have holy resistance
+ if ((schoolMask & SPELL_SCHOOL_MASK_HOLY) && victim->GetTypeId() != TYPEID_UNIT)
return 0;
- uint32 const BOSS_LEVEL = 83;
- uint32 const BOSS_RESISTANCE_CONSTANT = 510;
- uint32 resistanceConstant = 0;
- uint8 level = victim->getLevel();
-
- if (level == BOSS_LEVEL)
- resistanceConstant = BOSS_RESISTANCE_CONSTANT;
- else
- resistanceConstant = level * 5;
-
- int32 baseVictimResistance = victim->GetResistance(schoolMask);
- baseVictimResistance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask);
-
- if (Player const* player = ToPlayer())
- baseVictimResistance -= player->GetSpellPenetrationItemMod();
-
- // Resistance can't be lower then 0
- int32 victimResistance = std::max<int32>(baseVictimResistance, 0);
-
- if (victimResistance > 0)
+ // Ignore spells that can't be resisted
+ if (spellInfo)
{
- int32 ignoredResistance = 0;
-
- ignoredResistance += GetTotalAuraModifier(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST, [schoolMask, spellInfo](AuraEffect const* aurEff) -> bool
- {
- if ((aurEff->GetMiscValue() & schoolMask) && aurEff->IsAffectedOnSpell(spellInfo))
- return true;
- return false;
- });
-
- ignoredResistance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
+ if (spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_RESISTANCES))
+ return 0;
- ignoredResistance = std::min<int32>(ignoredResistance, 100);
- ApplyPct(victimResistance, 100 - ignoredResistance);
+ // Binary spells can't have damage part resisted
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
+ return 0;
}
- if (victimResistance <= 0)
- return 0;
-
- float averageResist = float(victimResistance) / float(victimResistance + resistanceConstant);
+ float averageResist = Unit::GetEffectiveResistChance(this, schoolMask, victim, spellInfo);
float discreteResistProbability[11];
for (uint32 i = 0; i < 11; ++i)
@@ -1731,7 +1707,75 @@ uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, Spell
while (r >= probabilitySum && resistance < 10)
probabilitySum += discreteResistProbability[++resistance];
- return resistance * 10;
+ float damageResisted = float(damage * resistance / 10);
+ if (damageResisted > 0.0f) // if any damage was resisted
+ {
+ int32 ignoredResistance = 0;
+ ignoredResistance += GetTotalAuraModifier(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST, [schoolMask, spellInfo](AuraEffect const* aurEff) -> bool
+ {
+ if ((aurEff->GetMiscValue() & schoolMask) && aurEff->IsAffectedOnSpell(spellInfo))
+ return true;
+ return false;
+ });
+
+ ignoredResistance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
+
+ ignoredResistance = std::min<int32>(ignoredResistance, 100);
+ ApplyPct(damageResisted, 100 - ignoredResistance);
+
+ // Spells with melee and magic school mask, decide whether resistance or armor absorb is higher
+ if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC))
+ {
+ uint32 damageAfterArmor = CalcArmorReducedDamage(victim, damage, spellInfo, BASE_ATTACK);
+ uint32 armorReduction = damage - damageAfterArmor;
+ if (armorReduction < damageResisted) // pick the lower one, the weakest resistance counts
+ damageResisted = armorReduction;
+ }
+ }
+
+ return damageResisted;
+}
+
+float Unit::GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo)
+{
+ float victimResistance = float(victim->GetResistance(schoolMask));
+ if (owner)
+ {
+ // pets inherit 100% of masters penetration
+ // excluding traps
+ Player const* player = owner->GetSpellModOwner();
+ if (player && owner->GetEntry() != WORLD_TRIGGER)
+ {
+ victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
+ victimResistance -= float(player->GetSpellPenetrationItemMod());
+ }
+ else
+ victimResistance += float(owner->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
+ }
+
+ // holy resistance exists in pve and comes from level difference, ignore template values
+ if (schoolMask & SPELL_SCHOOL_MASK_HOLY)
+ victimResistance = 0.0f;
+
+ // Chaos Bolt exception, ignore all target resistances (unknown attribute?)
+ if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && spellInfo->SpellIconID == 3178)
+ victimResistance = 0.0f;
+
+ victimResistance = std::max(victimResistance, 0.0f);
+ if (owner)
+ victimResistance += std::max((float(victim->getLevelForTarget(owner)) - float(owner->getLevelForTarget(victim))) * 5.0f, 0.0f);
+
+ static uint32 const BOSS_LEVEL = 83;
+ static float const BOSS_RESISTANCE_CONSTANT = 510.0f;
+ uint32 level = victim->getLevel();
+ float resistanceConstant = 0.0f;
+
+ if (level == BOSS_LEVEL)
+ resistanceConstant = BOSS_RESISTANCE_CONSTANT;
+ else
+ resistanceConstant = level * 5.0f;
+
+ return victimResistance / (victimResistance + resistanceConstant);
}
void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
@@ -1739,8 +1783,8 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
return;
- uint32 spellResistance = CalcSpellResistance(damageInfo.GetVictim(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
- damageInfo.ResistDamage(CalculatePct(damageInfo.GetDamage(), spellResistance));
+ uint32 resistedDamage = CalcSpellResistedDamage(damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
+ damageInfo.ResistDamage(resistedDamage);
// Ignore Absorption Auras
float auraAbsorbMod(GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask()));
@@ -2616,7 +2660,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
tmp += resist_chance;
// Chance resist debuff
- if (!spellInfo->IsPositive())
+ if (!spellInfo->IsPositive() && !spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_RESISTANCES))
{
bool hasAura = false;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -2629,7 +2673,15 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
}
if (hasAura)
- tmp += victim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, static_cast<int32>(spellInfo->Dispel)) * 100;
+ {
+ tmp += victim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, static_cast<int32>(spellInfo->Dispel)) * 100;
+ tmp += victim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, static_cast<int32>(spellInfo->Dispel)) * 100;
+ }
+
+ // resistance for binary spells
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL) && (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_NORMAL) == 0)
+ if ((spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_HOLY) == 0 || victim->GetTypeId() == TYPEID_UNIT)
+ tmp += int32(Unit::GetEffectiveResistChance(this, spellInfo->GetSchoolMask(), victim, spellInfo) * 10000.0f); // 100 for spell calculations, and 100 for return value percentage
}
// Roll chance
@@ -4206,9 +4258,28 @@ void Unit::RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, ui
}
}
-void Unit::RemoveMovementImpairingAuras()
+void Unit::RemoveMovementImpairingAuras(bool withRoot)
{
- RemoveAurasWithMechanic((1<<MECHANIC_SNARE)|(1<<MECHANIC_ROOT));
+ if (withRoot)
+ RemoveAurasWithMechanic(1 << MECHANIC_ROOT);
+
+ // Snares
+ for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
+ {
+ Aura const* aura = iter->second->GetBase();
+ if (aura->GetSpellInfo()->Mechanic == MECHANIC_SNARE)
+ {
+ RemoveAura(iter);
+ continue;
+ }
+
+ // turn off snare auras by setting amount to 0
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (((1 << i) & iter->second->GetEffectMask()) && aura->GetSpellInfo()->Effects[i].Mechanic == MECHANIC_SNARE)
+ aura->GetEffect(i)->ChangeAmount(0);
+
+ ++iter;
+ }
}
void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode, uint32 except)
@@ -4228,6 +4299,21 @@ void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemo
}
}
+void Unit::RemoveAurasByShapeShift()
+{
+ uint32 mechanic_mask = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
+ for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
+ {
+ Aura const* aura = iter->second->GetBase();
+ if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & mechanic_mask) && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_AURA_CC))
+ {
+ RemoveAura(iter);
+ continue;
+ }
+ ++iter;
+ }
+}
+
void Unit::RemoveAreaAurasDueToLeaveWorld()
{
// make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
@@ -7862,16 +7948,14 @@ int32 Unit::SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const
bool Unit::IsImmunedToDamage(SpellSchoolMask schoolMask) const
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
- SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
- if ((itr->first & schoolMask) != 0)
- return true;
+ uint32 schoolImmunityMask = GetSchoolImmunityMask();
+ if ((schoolImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
+ return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
- SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
- for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
- if ((itr->first & schoolMask) != 0)
- return true;
+ uint32 damageImmunityMask = GetDamageImmunityMask();
+ if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
+ return true;
return false;
}
@@ -7890,16 +7974,20 @@ bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
uint32 schoolMask = spellInfo->GetSchoolMask();
// If m_immuneToSchool type contain this school type, IMMUNE damage.
+ uint32 schoolImmunityMask = 0;
SpellImmuneContainer 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;
+ schoolImmunityMask |= itr->first;
+
+ // // We need to be immune to all types
+ if ((schoolImmunityMask & schoolMask) == schoolMask)
+ return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
- SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
- for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
- if ((itr->first & schoolMask) != 0)
- return true;
+ uint32 damageImmunityMask = GetDamageImmunityMask();
+ if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
+ return true;
return false;
}
@@ -7950,26 +8038,40 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
return true;
+ uint32 schoolImmunityMask = 0;
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
- if (!(itr->first & spellInfo->GetSchoolMask()))
+ if ((itr->first & spellInfo->GetSchoolMask()) == 0)
continue;
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
if (!(immuneSpellInfo && immuneSpellInfo->IsPositive() && spellInfo->IsPositive() && caster && IsFriendlyTo(caster)))
if (!spellInfo->CanPierceImmuneAura(immuneSpellInfo))
- return true;
+ schoolImmunityMask |= itr->first;
}
+ if ((schoolImmunityMask & spellInfo->GetSchoolMask()) == spellInfo->GetSchoolMask())
+ return true;
+
return false;
}
uint32 Unit::GetSchoolImmunityMask() const
{
uint32 mask = 0;
- SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_SCHOOL];
- for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
+ SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
+ for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
+ mask |= itr->first;
+
+ return mask;
+}
+
+uint32 Unit::GetDamageImmunityMask() const
+{
+ uint32 mask = 0;
+ SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
+ for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
mask |= itr->first;
return mask;
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index c2d9b62d902..0456d213887 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1386,6 +1386,7 @@ class TC_GAME_API Unit : public WorldObject
uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(UNIT_FIELD_RESISTANCES+school); }
uint32 GetResistance(SpellSchoolMask mask) const;
void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(UNIT_FIELD_RESISTANCES+school, val); }
+ static float GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr);
uint32 GetHealth() const { return GetUInt32Value(UNIT_FIELD_HEALTH); }
uint32 GetMaxHealth() const { return GetUInt32Value(UNIT_FIELD_MAXHEALTH); }
@@ -1792,7 +1793,8 @@ class TC_GAME_API Unit : public WorldObject
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 RemoveMovementImpairingAuras();
+ void RemoveMovementImpairingAuras(bool withRoot);
+ void RemoveAurasByShapeShift();
void RemoveAreaAurasDueToLeaveWorld();
void RemoveAllAuras();
@@ -2057,6 +2059,7 @@ class TC_GAME_API Unit : public WorldObject
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply);
virtual bool IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const; // redefined in Creature
uint32 GetSchoolImmunityMask() const;
+ uint32 GetDamageImmunityMask() const;
uint32 GetMechanicImmunityMask() const;
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const;
@@ -2064,8 +2067,8 @@ class TC_GAME_API Unit : public WorldObject
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const; // redefined in Creature
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = NULL, uint8 effIndex = MAX_SPELL_EFFECTS);
- uint32 CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK);
- uint32 CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const;
+ uint32 CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK) const;
+ uint32 CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const;
void CalcAbsorbResist(DamageInfo& damageInfo);
void CalcHealAbsorb(HealInfo& healInfo) const;
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 85b900acab4..b2af560c0d8 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -1708,7 +1708,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
case FORM_MOONKIN:
{
// remove movement affects
- target->RemoveMovementImpairingAuras();
+ target->RemoveAurasByShapeShift();
// and polymorphic affects
if (target->IsPolymorphed())
@@ -1799,7 +1799,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
{
target->setPowerType(POWER_MANA);
// Remove movement impairing effects also when shifting out
- target->RemoveMovementImpairingAuras();
+ target->RemoveAurasByShapeShift();
}
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 32fd73e1073..3f220229486 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -5254,7 +5254,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
{
// Warbringer - can't be handled in proc system - should be done before checkcast root check and charge effect process
if (strict && m_caster->IsScriptOverriden(m_spellInfo, 6953))
- m_caster->RemoveMovementImpairingAuras();
+ m_caster->RemoveMovementImpairingAuras(true);
}
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS) && m_caster->HasUnitState(UNIT_STATE_ROOT))
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 3c7390b54c6..d5ab9e75efb 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -766,7 +766,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
// Vanish (not exist)
case 18461:
{
- unitTarget->RemoveMovementImpairingAuras();
+ unitTarget->RemoveMovementImpairingAuras(true);
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
// If this spell is given to an NPC, it must handle the rest using its own AI
@@ -787,7 +787,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
// Demonic Empowerment -- succubus
case 54437:
{
- unitTarget->RemoveMovementImpairingAuras();
+ unitTarget->RemoveMovementImpairingAuras(true);
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STUN);
@@ -3624,7 +3624,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
case 30918: // Improved Sprint
{
// Removes snares and roots.
- unitTarget->RemoveMovementImpairingAuras();
+ unitTarget->RemoveMovementImpairingAuras(true);
break;
}
// Plant Warmaul Ogre Banner
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 5b766d2426c..a6bdeeba9d0 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -2841,7 +2841,13 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool app
target->ApplySpellImmune(Id, IMMUNITY_MECHANIC, i, apply);
if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
- target->RemoveAurasWithMechanic(mechanicImmunity, AURA_REMOVE_BY_DEFAULT, Id);
+ {
+ // exception for purely snare mechanic (eg. hands of freedom)!
+ if (mechanicImmunity == (1 << MECHANIC_SNARE))
+ target->RemoveMovementImpairingAuras(false);
+ else
+ target->RemoveAurasWithMechanic(mechanicImmunity, AURA_REMOVE_BY_DEFAULT, Id);
+ }
}
if (uint32 dispelImmunity = immuneInfo->DispelImmune)
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index f2fd3100aaa..736caf7d4c6 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -180,6 +180,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_CONE_LINE = 0x00000004,
SPELL_ATTR0_CU_SHARE_DAMAGE = 0x00000008,
SPELL_ATTR0_CU_NO_INITIAL_THREAT = 0x00000010,
+ SPELL_ATTR0_CU_AURA_CC = 0x00000020,
SPELL_ATTR0_CU_DONT_BREAK_STEALTH = 0x00000040,
SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100,
SPELL_ATTR0_CU_CHARGE = 0x00000200,
@@ -192,6 +193,8 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000,
SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET = 0x00040000,
SPELL_ATTR0_CU_NEEDS_AMMO_DATA = 0x00080000,
+ SPELL_ATTR0_CU_BINARY_SPELL = 0x00100000,
+ SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC = 0x00200000,
SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2
};
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 71553fbab0b..382490dd5e4 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2491,6 +2491,14 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
{
switch (spellInfo->Effects[j].ApplyAuraName)
{
+ case SPELL_AURA_MOD_POSSESS:
+ case SPELL_AURA_MOD_CONFUSE:
+ case SPELL_AURA_MOD_CHARM:
+ case SPELL_AURA_AOE_CHARM:
+ case SPELL_AURA_MOD_FEAR:
+ case SPELL_AURA_MOD_STUN:
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
+ break;
case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_PERIODIC_DAMAGE:
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
@@ -2571,6 +2579,84 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
}
}
+ // spells ignoring hit result should not be binary
+ if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ {
+ bool setFlag = false;
+ for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
+ {
+ if (spellInfo->Effects[j].IsEffect())
+ {
+ switch (spellInfo->Effects[j].Effect)
+ {
+ case SPELL_EFFECT_SCHOOL_DAMAGE:
+ case SPELL_EFFECT_WEAPON_DAMAGE:
+ case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
+ case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
+ case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
+ case SPELL_EFFECT_TRIGGER_SPELL:
+ case SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE:
+ break;
+ case SPELL_EFFECT_PERSISTENT_AREA_AURA:
+ case SPELL_EFFECT_APPLY_AURA:
+ case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
+ case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
+ case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
+ case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
+ case SPELL_EFFECT_APPLY_AREA_AURA_PET:
+ case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
+ {
+ if (spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE ||
+ spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE_PERCENT ||
+ spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_DUMMY ||
+ spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_LEECH ||
+ spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_HEALTH_FUNNEL ||
+ spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_DUMMY)
+ break;
+ }
+ default:
+ {
+ // No value and not interrupt cast or crowd control without SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY flag
+ if (!spellInfo->Effects[j].CalcValue() && !((spellInfo->Effects[j].Effect == SPELL_EFFECT_INTERRUPT_CAST || spellInfo->HasAttribute(SPELL_ATTR0_CU_AURA_CC)) && !spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)))
+ break;
+
+ // Sindragosa Frost Breath
+ if (spellInfo->Id == 69649 || spellInfo->Id == 71056 || spellInfo->Id == 71057 || spellInfo->Id == 71058 || spellInfo->Id == 73061 || spellInfo->Id == 73062 || spellInfo->Id == 73063 || spellInfo->Id == 73064)
+ break;
+
+ // Frostbolt
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->SpellFamilyFlags[0] & 0x20))
+ break;
+
+ // Frost Fever
+ if (spellInfo->Id == 55095)
+ break;
+
+ // Haunt
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellInfo->SpellFamilyFlags[1] & 0x40000))
+ break;
+
+ setFlag = true;
+ break;
+ }
+ }
+
+ if (setFlag)
+ {
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY_SPELL;
+ break;
+ }
+ }
+ }
+ }
+
+ // Remove normal school mask to properly calculate damage
+ if ((spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) && (spellInfo->SchoolMask & SPELL_SCHOOL_MASK_MAGIC))
+ {
+ spellInfo->SchoolMask &= ~SPELL_SCHOOL_MASK_NORMAL;
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC;
+ }
+
if (!spellInfo->_IsPositiveEffect(EFFECT_0, false))
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0;
@@ -2583,9 +2669,67 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
if (spellInfo->SpellVisual[0] == 3879)
spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_BACK;
+ switch (spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_WARRIOR:
+ // Shout / Piercing Howl
+ if (spellInfo->SpellFamilyFlags[0] & 0x20000/* || spellInfo->SpellFamilyFlags[1] & 0x20*/)
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
+ break;
+ case SPELLFAMILY_DRUID:
+ // Roar
+ if (spellInfo->SpellFamilyFlags[0] & 0x8)
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
+ break;
+ case SPELLFAMILY_GENERIC:
+ // Stoneclaw Totem effect
+ if (spellInfo->Id == 5729)
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
+ break;
+ default:
+ break;
+ }
+
spellInfo->_InitializeExplicitTargetMask();
}
+ // addition for binary spells, ommit spells triggering other spells
+ for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
+ {
+ spellInfo = mSpellInfoMap[i];
+ if (!spellInfo)
+ continue;
+
+ if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
+ continue;
+
+ bool allNonBinary = true;
+ bool overrideAttr = false;
+ for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
+ {
+ if (spellInfo->Effects[j].IsAura() && spellInfo->Effects[j].TriggerSpell)
+ {
+ switch (spellInfo->Effects[j].ApplyAuraName)
+ {
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
+ if (SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(spellInfo->Effects[j].TriggerSpell))
+ {
+ overrideAttr = true;
+ if (triggerSpell->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
+ allNonBinary = false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (overrideAttr && allNonBinary)
+ spellInfo->AttributesCu &= ~SPELL_ATTR0_CU_BINARY_SPELL;
+ }
+
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo custom attributes in %u ms", GetMSTimeDiffToNow(oldMSTime));
}
diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp
index 4ba3d28ffb0..cd8aa4138a0 100644
--- a/src/server/scripts/Spells/spell_priest.cpp
+++ b/src/server/scripts/Spells/spell_priest.cpp
@@ -583,7 +583,7 @@ class spell_pri_imp_shadowform : public SpellScriptLoader
{
PreventDefaultAction();
if (roll_chance_i(aurEff->GetAmount()))
- eventInfo.GetActor()->RemoveMovementImpairingAuras();
+ eventInfo.GetActor()->RemoveMovementImpairingAuras(true);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp
index 52feff073bf..5daf8bd8fa9 100644
--- a/src/server/scripts/Spells/spell_warlock.cpp
+++ b/src/server/scripts/Spells/spell_warlock.cpp
@@ -367,7 +367,7 @@ class spell_warl_demonic_circle_teleport : public SpellScriptLoader
if (GameObject* circle = player->GetGameObject(SPELL_WARLOCK_DEMONIC_CIRCLE_SUMMON))
{
player->NearTeleportTo(circle->GetPositionX(), circle->GetPositionY(), circle->GetPositionZ(), circle->GetOrientation());
- player->RemoveMovementImpairingAuras();
+ player->RemoveMovementImpairingAuras(false);
}
}
}