mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
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
(cherrypicked from 93746e8c4a)
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
|
||||
DELETE FROM `spell_custom_attr` WHERE `entry` IN (63124) AND `attributes`= 131072;
|
||||
INSERT INTO `spell_custom_attr` VALUES (63124, 131072); -- quest "There's Something About the Squire" (13654)
|
||||
|
||||
DELETE FROM `spell_custom_attr` WHERE `entry` IN (63293, 68873, 70324, 64619) AND `attributes`= 4;
|
||||
INSERT INTO `spell_custom_attr` VALUES
|
||||
(63293, 4), -- Mimiron - spinning damage
|
||||
(68873, 4), -- Wailing Souls
|
||||
(70324, 4), -- Wailing Souls
|
||||
(64619, 4); -- Ulduar, Mimiron, Emergency Fire Bot, Water Spray
|
||||
|
||||
DELETE FROM `spell_custom_attr` WHERE `entry` IN (66809, 67331, 66765, 67333) AND `attributes`=8;
|
||||
INSERT INTO `spell_custom_attr` VALUES
|
||||
(66809, 8), -- Meteor Fists
|
||||
(67331, 8), -- Meteor Fists
|
||||
(66765, 8), -- Meteor Fists
|
||||
(67333, 8); -- Meteor Fists
|
||||
|
||||
DELETE FROM `spell_custom_attr` WHERE `entry` IN (66378, 67097, 67098, 67099, 64125, 64126, 72409, 72447, 72448, 72449, 62775) AND `attributes`=32768;
|
||||
INSERT INTO `spell_custom_attr` VALUES
|
||||
(66378, 32768), -- Trial of the Crusader, Jaraxxus, Shivan Slash
|
||||
(67097, 32768), -- Trial of the Crusader, Jaraxxus, Shivan Slash
|
||||
(67098, 32768), -- Trial of the Crusader, Jaraxxus, Shivan Slash
|
||||
(67099, 32768), -- Trial of the Crusader, Jaraxxus, Shivan Slash
|
||||
(64125, 32768), -- Ulduar, Yogg-Saron, Squeeze
|
||||
(64126, 32768), -- Ulduar, Yogg-Saron, Squeeze
|
||||
(72409, 32768), -- Rune of Blood (Deathbringer Saurfang)
|
||||
(72447, 32768), -- Rune of Blood (Deathbringer Saurfang)
|
||||
(72448, 32768), -- Rune of Blood (Deathbringer Saurfang)
|
||||
(72449, 32768), -- Rune of Blood (Deathbringer Saurfang)
|
||||
(62775, 32768); -- Ulduar: XT-002 Tympanic Tamparum
|
||||
|
||||
DELETE FROM `spell_custom_attr` WHERE `entry` IN (45145) AND `attributes`= 1048576;
|
||||
INSERT INTO `spell_custom_attr` VALUES (45145, 1048576); -- Snake Trap Effect
|
||||
|
||||
-- Remove old SPELL_ATTR0_CU_IS_TALENT (0x00000020 conflict with 335) and add new SPELL_ATTR0_CU_IS_TALENT (0x00800000)
|
||||
UPDATE `spell_custom_attr` SET attributes = attributes & ~32 | 8388608 WHERE `attributes` & 32 = 32;
|
||||
@@ -1924,13 +1924,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
|
||||
@@ -1940,12 +1945,14 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const
|
||||
{
|
||||
if (!effect || !effect->IsEffect())
|
||||
continue;
|
||||
|
||||
if (!IsImmunedToSpellEffect(spellInfo, effect->EffectIndex, caster))
|
||||
{
|
||||
immunedToAllEffects = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (immunedToAllEffects)
|
||||
return true;
|
||||
|
||||
@@ -1957,7 +1964,8 @@ bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index,
|
||||
SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficultyID(), index);
|
||||
if (!effect)
|
||||
return true;
|
||||
if (GetCreatureTemplate()->MechanicImmuneMask & (1 << (effect->Mechanic - 1)))
|
||||
|
||||
if (effect->Mechanic > MECHANIC_NONE && HasMechanicTemplateImmunity(1 << (effect->Mechanic - 1)))
|
||||
return true;
|
||||
|
||||
if (GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && effect->Effect == SPELL_EFFECT_HEAL)
|
||||
|
||||
@@ -109,6 +109,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
bool isCanInteractWithBattleMaster(Player* player, bool msg) const;
|
||||
bool CanResetTalents(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;
|
||||
|
||||
@@ -1115,8 +1115,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)
|
||||
@@ -1584,7 +1588,7 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 Unit::CalcArmorReducedDamage(Unit* attacker, Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType /*attackType*/)
|
||||
uint32 Unit::CalcArmorReducedDamage(Unit* attacker, Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType /*attackType*/) const
|
||||
{
|
||||
float armor = float(victim->GetArmor());
|
||||
|
||||
@@ -1647,49 +1651,28 @@ uint32 Unit::CalcArmorReducedDamage(Unit* attacker, Unit* victim, const uint32 d
|
||||
return std::max<uint32>(damage * (1.0f - mitigation), 1);
|
||||
}
|
||||
|
||||
uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const
|
||||
uint32 Unit::CalcSpellResistedDamage(Unit* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo)
|
||||
{
|
||||
// Magic damage, check for resists
|
||||
if (!(schoolMask & SPELL_SCHOOL_MASK_SPELL))
|
||||
if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
|
||||
return 0;
|
||||
|
||||
// Npcs can have holy resistance
|
||||
if ((schoolMask & SPELL_SCHOOL_MASK_HOLY) && victim->GetTypeId() != TYPEID_UNIT)
|
||||
return 0;
|
||||
|
||||
// Ignore spells that can't be resisted
|
||||
if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_RESISTANCES))
|
||||
return 0;
|
||||
|
||||
uint8 const bossLevel = 83;
|
||||
uint32 const bossResistanceConstant = 510;
|
||||
uint32 resistanceConstant = 0;
|
||||
uint8 level = victim->GetLevelForTarget(this);
|
||||
|
||||
if (level == bossLevel)
|
||||
resistanceConstant = bossResistanceConstant;
|
||||
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)
|
||||
if (spellInfo)
|
||||
{
|
||||
int32 ignoredResistance = 0;
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR4_IGNORE_RESISTANCES))
|
||||
return 0;
|
||||
|
||||
ignoredResistance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
|
||||
|
||||
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 = GetEffectiveResistChance(this, schoolMask, victim, spellInfo);
|
||||
|
||||
float discreteResistProbability[11];
|
||||
for (uint32 i = 0; i < 11; ++i)
|
||||
@@ -1713,7 +1696,69 @@ 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 += 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(attacker, 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->Id == 116858)
|
||||
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 bossLevel = 83;
|
||||
static float const bossResistanceConstant = 510.0f;
|
||||
uint32 level = victim->GetLevelForTarget(this);
|
||||
float resistanceConstant = 0.0f;
|
||||
|
||||
if (level == bossLevel)
|
||||
resistanceConstant = bossResistanceConstant;
|
||||
else
|
||||
resistanceConstant = level * 5.0f;
|
||||
|
||||
return victimResistance / (victimResistance + resistanceConstant);
|
||||
}
|
||||
|
||||
void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
|
||||
@@ -1721,8 +1766,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.GetAttacker(), 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()));
|
||||
@@ -3983,9 +4028,33 @@ void Unit::RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyF
|
||||
}
|
||||
}
|
||||
|
||||
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 (SpellEffectInfo const* effect : aura->GetSpellInfo()->GetEffectsForDifficulty(GetMap()->GetDifficultyID()))
|
||||
{
|
||||
if (!effect || !effect->IsEffect())
|
||||
continue;
|
||||
|
||||
if (((1 << effect->EffectIndex) & iter->second->GetEffectMask()))
|
||||
aura->GetEffect(effect->EffectIndex)->ChangeAmount(0);
|
||||
}
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode, uint32 except)
|
||||
@@ -4005,6 +4074,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
|
||||
@@ -7126,16 +7210,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;
|
||||
}
|
||||
@@ -7213,26 +7295,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;
|
||||
|
||||
@@ -1057,6 +1057,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
int32 GetResistance(SpellSchoolMask mask) const;
|
||||
void SetResistance(SpellSchools school, int32 val) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::Resistances, school), val); }
|
||||
void SetBonusResistanceMod(SpellSchools school, int32 val) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::BonusResistanceMods, school), val); }
|
||||
float GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr);
|
||||
|
||||
uint64 GetHealth() const { return m_unitData->Health; }
|
||||
uint64 GetMaxHealth() const { return m_unitData->MaxHealth; }
|
||||
@@ -1537,7 +1538,8 @@ class TC_GAME_API Unit : public WorldObject
|
||||
void RemoveAurasWithAttribute(uint32 flags);
|
||||
void RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyFlag, 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();
|
||||
@@ -1846,6 +1848,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;
|
||||
@@ -1853,8 +1856,8 @@ class TC_GAME_API Unit : public WorldObject
|
||||
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const; // redefined in Creature
|
||||
|
||||
bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = nullptr, int8 effIndex = -1);
|
||||
uint32 CalcArmorReducedDamage(Unit* attacker, 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* attacker, Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK) const;
|
||||
uint32 CalcSpellResistedDamage(Unit* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo);
|
||||
void CalcAbsorbResist(DamageInfo& damageInfo);
|
||||
void CalcHealAbsorb(HealInfo& healInfo) const;
|
||||
|
||||
|
||||
@@ -1700,7 +1700,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
case FORM_MOONKIN_FORM:
|
||||
{
|
||||
// remove movement affects
|
||||
target->RemoveMovementImpairingAuras();
|
||||
target->RemoveAurasByShapeShift();
|
||||
|
||||
// and polymorphic affects
|
||||
if (target->IsPolymorphed())
|
||||
@@ -1741,7 +1741,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo
|
||||
if (target->getClass() == CLASS_DRUID)
|
||||
{
|
||||
// Remove movement impairing effects also when shifting out
|
||||
target->RemoveMovementImpairingAuras();
|
||||
target->RemoveAurasByShapeShift();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -636,14 +636,14 @@ void Spell::EffectTriggerSpell(SpellEffIndex /*effIndex*/)
|
||||
// Vanish (not exist)
|
||||
case 18461:
|
||||
{
|
||||
unitTarget->RemoveMovementImpairingAuras();
|
||||
unitTarget->RemoveMovementImpairingAuras(true);
|
||||
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
|
||||
return;
|
||||
}
|
||||
// Demonic Empowerment -- succubus
|
||||
case 54437:
|
||||
{
|
||||
unitTarget->RemoveMovementImpairingAuras();
|
||||
unitTarget->RemoveMovementImpairingAuras(true);
|
||||
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
|
||||
unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STUN);
|
||||
|
||||
@@ -3179,7 +3179,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
|
||||
case 30918: // Improved Sprint
|
||||
{
|
||||
// Removes snares and roots.
|
||||
unitTarget->RemoveMovementImpairingAuras();
|
||||
unitTarget->RemoveMovementImpairingAuras(true);
|
||||
break;
|
||||
}
|
||||
// Plant Warmaul Ogre Banner
|
||||
|
||||
@@ -3441,7 +3441,13 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, SpellEffectInfo const* e
|
||||
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)
|
||||
|
||||
@@ -185,7 +185,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_IS_TALENT = 0x00000020,
|
||||
SPELL_ATTR0_CU_AURA_CC = 0x00000020,
|
||||
SPELL_ATTR0_CU_DONT_BREAK_STEALTH = 0x00000040,
|
||||
SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100,
|
||||
SPELL_ATTR0_CU_CHARGE = 0x00000200,
|
||||
@@ -198,6 +198,10 @@ 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_LIQUID_AURA = 0x00400000,
|
||||
SPELL_ATTR0_CU_IS_TALENT = 0x00800000,
|
||||
|
||||
SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2
|
||||
};
|
||||
|
||||
@@ -2402,6 +2402,14 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
|
||||
|
||||
switch (effect->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:
|
||||
@@ -2482,6 +2490,87 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
|
||||
}
|
||||
}
|
||||
|
||||
// spells ignoring hit result should not be binary
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
|
||||
{
|
||||
bool setFlag = false;
|
||||
for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
|
||||
{
|
||||
if (!effect)
|
||||
continue;
|
||||
|
||||
if (effect->IsEffect())
|
||||
{
|
||||
switch (effect->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 (effect->ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE ||
|
||||
effect->ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE_PERCENT ||
|
||||
effect->ApplyAuraName == SPELL_AURA_DUMMY ||
|
||||
effect->ApplyAuraName == SPELL_AURA_PERIODIC_LEECH ||
|
||||
effect->ApplyAuraName == SPELL_AURA_PERIODIC_HEALTH_FUNNEL ||
|
||||
effect->ApplyAuraName == SPELL_AURA_PERIODIC_DUMMY)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// No value and not interrupt cast or crowd control without SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY flag
|
||||
if (!effect->CalcValue() && !((effect->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;
|
||||
|
||||
@@ -2494,10 +2583,70 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
|
||||
if (talentSpells.count(spellInfo->Id))
|
||||
spellInfo->AttributesCu |= SPELL_ATTR0_CU_IS_TALENT;
|
||||
|
||||
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 (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
|
||||
{
|
||||
if (!effect)
|
||||
continue;
|
||||
|
||||
if (effect->IsAura() && effect->TriggerSpell)
|
||||
{
|
||||
switch (effect->ApplyAuraName)
|
||||
{
|
||||
case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
|
||||
case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
|
||||
if (SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(effect->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));
|
||||
}
|
||||
|
||||
|
||||
@@ -1055,7 +1055,7 @@ class spell_pri_phantasm : public SpellScriptLoader
|
||||
void HandleEffectProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
GetTarget()->RemoveMovementImpairingAuras();
|
||||
GetTarget()->RemoveMovementImpairingAuras(true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -699,7 +699,7 @@ class spell_rog_vanish : public SpellScriptLoader
|
||||
|
||||
Unit* target = GetHitUnit();
|
||||
|
||||
target->RemoveMovementImpairingAuras();
|
||||
target->RemoveMovementImpairingAuras(true);
|
||||
target->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
|
||||
if (target->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
@@ -344,7 +344,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user