Core/Spells: use DamageInfo struct to calc spell absorbs and resists, and use calculated proc hitMask on aura ticks

This commit is contained in:
ariel- authored and roc13x committed 2017-05-04 01:07:05 +01:00
1 parent 8bf21ad927
commit 3d9c4fd3fc
6 files changed
+114 -109

No files matched your search

+57 -70
View File
@@ -644,7 +644,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons
|| HasBreakableByDamageAuraType(SPELL_AURA_TRANSFORM, excludeAura));
}
void Unit::DealDamageMods(Unit* victim, uint32 &damage, uint32* absorb)
void Unit::DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) const
{
if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
{
@@ -1151,15 +1151,13 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage);
// Calculate absorb resist
if (damage > 0)
{
CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo);
damage -= damageInfo->absorb + damageInfo->resist;
}
else
if (damage < 0)
damage = 0;
damageInfo->damage = damage;
DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, PROC_HIT_NONE);
CalcAbsorbResist(dmgInfo);
damageInfo->damage = dmgInfo.GetDamage();
}
void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)
@@ -1351,15 +1349,17 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
{
damageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE;
// Calculate absorb & resists
CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist);
DamageInfo dmgInfo(*damageInfo);
CalcAbsorbResist(dmgInfo);
damageInfo->absorb = dmgInfo.GetAbsorb();
damageInfo->resist = dmgInfo.GetResist();
damageInfo->damage = dmgInfo.GetDamage();
if (damageInfo->absorb)
damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
if (damageInfo->resist)
damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
damageInfo->damage -= damageInfo->absorb + damageInfo->resist;
}
else // Impossible get negative result but....
damageInfo->damage = 0;
@@ -1665,57 +1665,49 @@ uint32 Unit::CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, Spell
return resistance * 10;
}
void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo /*= NULL*/)
void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
{
if (!victim || !victim->IsAlive() || !damage)
if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
return;
DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype, BASE_ATTACK);
uint32 spellResistance = CalcSpellResistance(victim, schoolMask, spellInfo);
dmgInfo.ResistDamage(CalculatePct(damage, spellResistance));
uint32 spellResistance = CalcSpellResistance(damageInfo.GetVictim(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
damageInfo.ResistDamage(CalculatePct(damageInfo.GetDamage(), spellResistance));
// Ignore Absorption Auras
float auraAbsorbMod = 0;
AuraEffectList const& AbsIgnoreAurasA = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL);
for (AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr)
float auraAbsorbMod(GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask()));
AuraEffectList const& abilityAbsorbAuras = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL);
for (AuraEffect const* aurEff : abilityAbsorbAuras)
{
if (!((*itr)->GetMiscValue() & schoolMask))
if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
continue;
if ((*itr)->GetAmount() > auraAbsorbMod)
auraAbsorbMod = float((*itr)->GetAmount());
}
AuraEffectList const& AbsIgnoreAurasB = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL);
for (AuraEffectList::const_iterator itr = AbsIgnoreAurasB.begin(); itr != AbsIgnoreAurasB.end(); ++itr)
{
if (!((*itr)->GetMiscValue() & schoolMask))
if (!aurEff->IsAffectingSpell(damageInfo.GetSpellInfo()))
continue;
if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectingSpell(spellInfo))
auraAbsorbMod = float((*itr)->GetAmount());
if ((aurEff->GetAmount() > auraAbsorbMod))
auraAbsorbMod = float(aurEff->GetAmount());
}
RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
int32 absorbIgnoringDamage = CalculatePct(dmgInfo.GetDamage(), auraAbsorbMod);
dmgInfo.ModifyDamage(-absorbIgnoringDamage);
int32 absorbIgnoringDamage = CalculatePct(damageInfo.GetDamage(), auraAbsorbMod);
damageInfo.ModifyDamage(-absorbIgnoringDamage);
// We're going to call functions which can modify content of the list during iteration over it's elements
// Let's copy the list so we can prevent iterator invalidation
AuraEffectList vSchoolAbsorbCopy(victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB));
AuraEffectList vSchoolAbsorbCopy(damageInfo.GetVictim()->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB));
vSchoolAbsorbCopy.sort(Trinity::AbsorbAuraOrderPred());
// absorb without mana cost
for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
{
AuraEffect* absorbAurEff = *itr;
// Check if aura was removed during iteration - we don't need to work on such auras
AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
if (!aurApp)
continue;
if (!(absorbAurEff->GetMiscValue() & schoolMask))
if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
continue;
// get amount which can be still absorbed by the aura
@@ -1728,19 +1720,19 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
bool defaultPrevented = false;
absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb, defaultPrevented);
absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
currentAbsorb = tempAbsorb;
if (defaultPrevented)
continue;
// absorb must be smaller than the damage itself
currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
dmgInfo.AbsorbDamage(currentAbsorb);
damageInfo.AbsorbDamage(currentAbsorb);
tempAbsorb = currentAbsorb;
absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb);
absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
// Check if our aura is using amount to count damage
if (absorbAurEff->GetAmount() >= 0)
@@ -1754,16 +1746,16 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
}
// absorb by mana cost
AuraEffectList vManaShieldCopy(victim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD));
for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
AuraEffectList vManaShieldCopy(damageInfo.GetVictim()->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD));
for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
{
AuraEffect* absorbAurEff = *itr;
// Check if aura was removed during iteration - we don't need to work on such auras
AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
if (!aurApp)
continue;
// check damage school mask
if (!(absorbAurEff->GetMiscValue() & schoolMask))
if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
continue;
// get amount which can be still absorbed by the aura
@@ -1776,14 +1768,14 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
bool defaultPrevented = false;
absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb, defaultPrevented);
absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
currentAbsorb = tempAbsorb;
if (defaultPrevented)
continue;
// absorb must be smaller than the damage itself
currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
int32 manaReduction = currentAbsorb;
@@ -1791,15 +1783,15 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
if (float manaMultiplier = absorbAurEff->GetSpellInfo()->Effects[absorbAurEff->GetEffIndex()].CalcValueMultiplier(absorbAurEff->GetCaster()))
manaReduction = int32(float(manaReduction) * manaMultiplier);
int32 manaTaken = -victim->ModifyPower(POWER_MANA, -manaReduction);
int32 manaTaken = -damageInfo.GetVictim()->ModifyPower(POWER_MANA, -manaReduction);
// take case when mana has ended up into account
currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
dmgInfo.AbsorbDamage(currentAbsorb);
damageInfo.AbsorbDamage(currentAbsorb);
tempAbsorb = currentAbsorb;
absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, tempAbsorb);
absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
// Check if our aura is using amount to count damage
if (absorbAurEff->GetAmount() >= 0)
@@ -1810,66 +1802,61 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
}
}
dmgInfo.ModifyDamage(absorbIgnoringDamage);
damageInfo.ModifyDamage(absorbIgnoringDamage);
// split damage auras - only when not damaging self
if (victim != this)
if (damageInfo.GetVictim() != this)
{
// We're going to call functions which can modify content of the list during iteration over it's elements
// Let's copy the list so we can prevent iterator invalidation
AuraEffectList vSplitDamagePctCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT));
for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && dmgInfo.GetDamage() > 0; ++itr)
AuraEffectList vSplitDamagePctCopy(damageInfo.GetVictim()->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT));
for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && damageInfo.GetDamage() > 0; ++itr)
{
// Check if aura was removed during iteration - we don't need to work on such auras
AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(victim->GetGUID());
AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
if (!aurApp)
continue;
// check damage school mask
if (!((*itr)->GetMiscValue() & schoolMask))
if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
continue;
// Damage can be splitted only if aura has an alive caster
Unit* caster = (*itr)->GetCaster();
if (!caster || (caster == victim) || !caster->IsInWorld() || !caster->IsAlive())
if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
continue;
uint32 splitDamage = CalculatePct(dmgInfo.GetDamage(), (*itr)->GetAmount());
uint32 splitDamage = CalculatePct(damageInfo.GetDamage(), (*itr)->GetAmount());
(*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, dmgInfo, splitDamage);
(*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, damageInfo, splitDamage);
// absorb must be smaller than the damage itself
splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(dmgInfo.GetDamage()));
splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(damageInfo.GetDamage()));
dmgInfo.AbsorbDamage(splitDamage);
damageInfo.AbsorbDamage(splitDamage);
// check if caster is immune to damage
if (caster->IsImmunedToDamage(schoolMask))
if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
{
victim->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
continue;
}
uint32 split_absorb = 0;
DealDamageMods(caster, splitDamage, &split_absorb);
SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, schoolMask, split_absorb, 0, false, 0, false);
SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, damageInfo.GetSchoolMask(), split_absorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
DealDamage(caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellInfo(), false);
DealDamage(caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
// break 'Fear' and similar auras
DamageInfo damageInfo(caster, this, splitDamage, (*itr)->GetSpellInfo(), schoolMask, DIRECT_DAMAGE, BASE_ATTACK);
ProcSkillsAndAuras(caster, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, PROC_HIT_NONE, nullptr, &damageInfo, nullptr);
}
}
*resist = dmgInfo.GetResist();
*absorb = dmgInfo.GetAbsorb();
}
void Unit::CalcHealAbsorb(HealInfo& healInfo)
void Unit::CalcHealAbsorb(HealInfo& healInfo) const
{
if (!healInfo.GetHeal())
return;