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:
xinef1
2017-02-04 23:50:32 +01:00
committed by Shauren
parent ad008c43b7
commit ca26c33145
13 changed files with 373 additions and 69 deletions
+150 -54
View File
@@ -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;