diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 14 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 236 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 9 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 3 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 144 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_priest.cpp | 2 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_warlock.cpp | 2 |
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); } } } |