aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Entities')
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp439
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h57
2 files changed, 218 insertions, 278 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 44659254e7c..ab0eb074506 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -1548,6 +1548,8 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
if (!pVictim || !pVictim->isAlive() || !damage)
return;
+ DamageInfo dmgInfo = DamageInfo(this, pVictim, damage, spellInfo, schoolMask, damagetype);
+
// Magic damage, check for resists
if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
{
@@ -1591,32 +1593,25 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
probabilitySum += discreteResistProbability[i];
}
- uint32 damageResisted = damage * i / 10;
-
- *resist += damageResisted;
+ float damageResisted = damage * i / 10;
AuraEffectList const &ResIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
for (AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j)
{
if ((*j)->GetMiscValue() & schoolMask
&& (*j)->IsAffectedOnSpell(spellInfo))
- AddPctN(*resist, -(*j)->GetAmount());
+ AddPctN(damageResisted, -(*j)->GetAmount());
}
AuraEffectList const &ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
for (AuraEffectList::const_iterator j = ResIgnoreAuras.begin(); j != ResIgnoreAuras.end(); ++j)
{
if ((*j)->GetMiscValue() & schoolMask)
- AddPctN(*resist, -(*j)->GetAmount());
+ AddPctN(damageResisted, -(*j)->GetAmount());
}
+ dmgInfo.ResistDamage(damageResisted);
}
- else
- *resist = 0;
- int32 RemainingDamage = damage - *resist;
- int32 TotalAbsorb = RemainingDamage;
- // Get unit state (need for some absorb check)
- uint32 unitflag = pVictim->GetUInt32Value(UNIT_FIELD_FLAGS);
// Death Prevention Aura
SpellEntry const* preventDeathSpell = NULL;
int32 preventDeathAmount = 0;
@@ -1625,7 +1620,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
int32 incanterAbsorption = 0;
// Ignore Absorption Auras
- int32 auraAbsorbMod = 0;
+ float auraAbsorbMod = 0;
AuraEffectList const & AbsIgnoreAurasA = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL);
for (AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr)
{
@@ -1645,6 +1640,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectedOnSpell(spellInfo))
auraAbsorbMod = (*itr)->GetAmount();
}
+ RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
// 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
@@ -1652,80 +1648,39 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
vSchoolAbsorbCopy.sort(Trinity::AbsorbAuraOrderPred());
// absorb without mana cost
- for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (RemainingDamage > 0); ++itr)
+ for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
{
AuraEffect * absorbAurEff = (*itr);
// Check if aura was removed during iteration - we don't need to work on such auras
- if (!(absorbAurEff->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
+ AuraApplication const * aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(pVictim->GetGUID());
+ if (!aurApp)
continue;
if (!(absorbAurEff->GetMiscValue() & schoolMask))
continue;
SpellEntry const * spellProto = absorbAurEff->GetSpellProto();
- // Frost Warding
- // Chaos Bolt ignore the absorption but still proc Frost Warding mana return
- if ((spellProto->SpellFamilyName == SPELLFAMILY_MAGE) && (spellProto->Category == 56))
- if (AuraEffect * aurEff = pVictim->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_MAGE, 501, EFFECT_0))
- {
- int32 chance = SpellMgr::CalculateSpellEffectAmount(aurEff->GetSpellProto(), EFFECT_1);
+ // get amount which can be still absorbed by the aura
+ int32 currentAbsorb = absorbAurEff->GetAmount();
+ // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
+ if (currentAbsorb < 0)
+ currentAbsorb = 0;
- if (roll_chance_i(chance))
- {
- pVictim->CastCustomSpell(pVictim, 57776, &RemainingDamage, NULL, NULL, true, NULL, absorbAurEff);
- RemainingDamage = RemainingDamage * auraAbsorbMod / 100;
- continue;
- }
- }
+ uint32 absorb = currentAbsorb;
- if (auraAbsorbMod >= 100) // Do nothing if 100% absorb ignore
- continue;
+ bool defaultPrevented = false;
- // Max Amount can be absorbed by this aura
- int32 currentAbsorb = absorbAurEff->GetAmount();
- // Found empty aura
- if (currentAbsorb <= 0)
- {
- absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
- continue;
- }
-
- currentAbsorb = (100 - auraAbsorbMod) * currentAbsorb / 100;
+ absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, absorb, defaultPrevented);
- // Handle custom absorb auras
- // TODO: try find better way
+ currentAbsorb = absorb;
switch (spellProto->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
- // Astral Shift
- if (spellProto->SpellIconID == 3066)
- {
- //reduces all damage taken while stun, fear or silence
- if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED))
- AddPctN(RemainingDamage, -currentAbsorb);
- continue;
- }
- // Nerves of Steel
- if (spellProto->SpellIconID == 2115)
- {
- // while affected by Stun and Fear
- if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING))
- AddPctN(RemainingDamage, -currentAbsorb);
- continue;
- }
- // Spell Deflection
- if (spellProto->SpellIconID == 3006)
- {
- // You have a chance equal to your Parry chance
- if ((damagetype == DIRECT_DAMAGE) && roll_chance_f(pVictim->GetUnitParryChance()))
- AddPctN(RemainingDamage, -currentAbsorb);
- continue;
- }
// Reflective Shield (Lady Malande boss)
if (spellProto->Id == 41475)
{
- int32 bp = std::min(RemainingDamage, currentAbsorb) / 2;
+ int32 bp = std::min(int32(dmgInfo.GetDamage()), currentAbsorb) / 2;
pVictim->CastCustomSpell(this, 33619, &bp, NULL, NULL, true, NULL, *itr);
break;
}
@@ -1740,34 +1695,25 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
}
break;
}
- case SPELLFAMILY_DRUID:
+ case SPELLFAMILY_MAGE:
{
- // Primal Tenacity
- if (spellProto->SpellIconID == 2253)
+ // possibly create BeforeEffectAbsorb for this?
+ // Frost ward and Fire Ward
+ if (spellProto->Category == 56)
{
- //reduces all damage taken while Stunned
- if ((pVictim->GetShapeshiftForm() == FORM_CAT) && (unitflag & UNIT_FLAG_STUNNED))
- AddPctN(RemainingDamage, -currentAbsorb);
- continue;
- }
- // Savage Defense
- if (spellProto->SpellIconID == 146)
- {
- if (RemainingDamage < currentAbsorb)
- currentAbsorb = RemainingDamage;
-
- RemainingDamage -= currentAbsorb;
+ // Frost Warding
+ if (AuraEffect * aurEff = pVictim->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_MAGE, 501, EFFECT_0))
+ {
+ int32 chance = SpellMgr::CalculateSpellEffectAmount(aurEff->GetSpellProto(), EFFECT_1);
- absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL); // guarantee removal
- continue;
- }
- // Moonkin Form passive
- if (spellProto->Id == 69366)
- {
- //reduces all damage taken while Stunned
- if (unitflag & UNIT_FLAG_STUNNED)
- AddPctN(RemainingDamage, -currentAbsorb);
- continue;
+ if (roll_chance_i(chance))
+ {
+ int32 bp = dmgInfo.GetDamage();
+ pVictim->CastCustomSpell(pVictim, 57776, &bp, NULL, NULL, true, NULL, absorbAurEff);
+ dmgInfo.AbsorbDamage(dmgInfo.GetDamage());
+ continue;
+ }
+ }
}
break;
}
@@ -1809,7 +1755,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
case 5065: // Rank 1
case 5064: // Rank 2
{
- int32 bp = CalculatePctN(std::min(RemainingDamage, currentAbsorb), aurEff->GetAmount());
+ int32 bp = CalculatePctN(std::min(int32(dmgInfo.GetDamage()), currentAbsorb), aurEff->GetAmount());
pVictim->CastCustomSpell(this, 33619, &bp, NULL, NULL, true, NULL, *itr);
break;
}
@@ -1828,13 +1774,13 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
if (!pVictim->ToPlayer())
continue;
- int32 remainingHealth = pVictim->GetHealth() - RemainingDamage;
+ int32 remainingHealth = pVictim->GetHealth() - dmgInfo.GetDamage();
uint32 allowedHealth = pVictim->CountPctFromMaxHealth(35);
// If damage kills us
if (remainingHealth <= 0 && !pVictim->ToPlayer()->HasSpellCooldown(66235))
{
// Cast healing spell, completely avoid damage
- RemainingDamage = 0;
+ dmgInfo.AbsorbDamage(dmgInfo.GetDamage());
uint32 defenseSkillValue = pVictim->GetDefenseSkillValue();
// Max heal when defense skill denies critical hits from raid bosses
@@ -1852,26 +1798,14 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
{
// Reduce damage that brings us under 35% (or full damage if we are already under 35%) by x%
uint32 damageToReduce = (pVictim->GetHealth() < allowedHealth)
- ? RemainingDamage
+ ? dmgInfo.GetDamage()
: allowedHealth - remainingHealth;
- RemainingDamage -= CalculatePctN(damageToReduce, currentAbsorb);
+ dmgInfo.AbsorbDamage(CalculatePctN(damageToReduce, currentAbsorb));
}
continue;
}
break;
}
- case SPELLFAMILY_SHAMAN:
- {
- // Astral Shift
- if (spellProto->SpellIconID == 3066)
- {
- //reduces all damage taken while stun, fear or silence
- if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED))
- AddPctN(RemainingDamage, -currentAbsorb);
- continue;
- }
- break;
- }
case SPELLFAMILY_DEATHKNIGHT:
{
switch (spellProto->Id)
@@ -1885,14 +1819,14 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
if (AuraEffect const * aurEff = caster->GetAuraEffect(58635, 0))
AddPctN(absorbed, aurEff->GetAmount());
- RemainingDamage -= absorbed;
+ dmgInfo.AbsorbDamage(absorbed);
}
continue;
case 52284: // Will of the Necropolis
case 52285:
case 52286:
{
- int32 remainingHp = int32(pVictim->GetHealth() - RemainingDamage);
+ int32 remainingHp = int32(pVictim->GetHealth() - dmgInfo.GetDamage());
// min pct of hp is stored in effect 0 of talent spell
uint32 rank = sSpellMgr->GetSpellRank(spellProto->Id);
@@ -1902,8 +1836,8 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
// Damage that would take you below [effect0] health or taken while you are at [effect0]
if (remainingHp < minHp)
{
- uint32 absorbed = uint32(currentAbsorb * RemainingDamage * 0.01f);
- RemainingDamage -= absorbed;
+ uint32 absorbed = uint32(currentAbsorb * dmgInfo.GetDamage() * 0.01f);
+ dmgInfo.AbsorbDamage(absorbed);
}
continue;
}
@@ -1911,24 +1845,24 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
{
// damage absorbed by Anti-Magic Shell energizes the DK with additional runic power.
// This, if I'm not mistaken, shows that we get back ~2% of the absorbed damage as runic power.
- int32 absorbed = CalculatePctN(RemainingDamage, currentAbsorb);
- RemainingDamage -= absorbed;
+ int32 absorbed = CalculatePctN(dmgInfo.GetDamage(), currentAbsorb);
+ dmgInfo.AbsorbDamage(absorbed);
int32 bp = absorbed * 2 / 10;
pVictim->CastCustomSpell(pVictim, 49088, &bp, NULL, NULL, true, NULL, *itr);
continue;
}
case 50462: // Anti-Magic Shell (on single party/raid member)
- AddPctN(RemainingDamage, -currentAbsorb);
+ dmgInfo.AbsorbDamage(CalculatePctN(dmgInfo.GetDamage(), currentAbsorb));
continue;
case 50461: // Anti-Magic Zone
if (Unit * caster = absorbAurEff->GetCaster())
{
- int32 absorbed = CalculatePctN(RemainingDamage, currentAbsorb);
+ int32 absorbed = CalculatePctN(dmgInfo.GetDamage(), currentAbsorb);
int32 canabsorb = caster->GetHealth();
if (canabsorb < absorbed)
absorbed = canabsorb;
- RemainingDamage -= absorbed;
+ dmgInfo.AbsorbDamage(absorbed);
}
continue;
default:
@@ -1940,163 +1874,154 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
break;
}
- // currentAbsorb - damage can be absorbed by shield
- // If need absorb less damage
- if (RemainingDamage < currentAbsorb)
- currentAbsorb = RemainingDamage;
+ if (defaultPrevented)
+ continue;
+
+ // Apply absorb mod auras
+ AddPctF(currentAbsorb, -auraAbsorbMod);
+
+ // absorb must be smaller than the damage itself
+ currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
- RemainingDamage -= currentAbsorb;
+ dmgInfo.AbsorbDamage(currentAbsorb);
// Fire Ward or Frost Ward or Ice Barrier (or Mana Shield)
// for Incanter's Absorption converting to spell power
- if (spellProto->SpellFamilyName == SPELLFAMILY_MAGE && spellProto->SpellFamilyFlags[EFFECT_2] & 0x8)
+ if (spellProto->SpellFamilyName == SPELLFAMILY_MAGE && spellProto->SpellFamilyFlags[2] & 0x8)
incanterAbsorption += currentAbsorb;
- // Reduce shield amount
- absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
- // Need remove it later
- if (absorbAurEff->GetAmount() <= 0)
- absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
+ // Check if our aura is using amount to count damage
+ if (absorbAurEff->GetAmount() >= 0)
+ {
+ // Reduce shield amount
+ absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
+ // Aura cannot absorb anything more - remove it
+ if (absorbAurEff->GetAmount() <= 0)
+ absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
+ }
}
-
if (auraAbsorbMod < 100) // Do nothing if 100% absorb ignore
{
- bool existExpired = false;
-
// absorb by mana cost
- AuraEffectList const & vManaShield = pVictim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD);
-
- for (AuraEffectList::const_iterator itr = vManaShield.begin(); (itr != vManaShield.end()) && (RemainingDamage > 0); ++itr)
+ AuraEffectList vManaShieldCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD));
+ for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
{
+ AuraEffect * absorbAurEff = *itr;
+ // Check if aura was removed during iteration - we don't need to work on such auras
+ if (!(absorbAurEff->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
+ continue;
// check damage school mask
- if (!((*itr)->GetMiscValue() & schoolMask))
+ if (!(absorbAurEff->GetMiscValue() & schoolMask))
continue;
- int32 currentAbsorb;
+ // get amount which can be still absorbed by the aura
+ int32 currentAbsorb = absorbAurEff->GetAmount();
- if (RemainingDamage >= (*itr)->GetAmount())
- currentAbsorb = (*itr)->GetAmount();
- else
- currentAbsorb = RemainingDamage;
+ AddPctF(currentAbsorb, -auraAbsorbMod);
- currentAbsorb = (100 - auraAbsorbMod) * currentAbsorb / 100;
+ // absorb must be smaller than the damage itself
+ currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
- if (float manaMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier((*itr)->GetSpellProto(), (*itr)->GetEffIndex(), (*itr)->GetCaster()))
- {
- int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier);
- if (currentAbsorb > maxAbsorb)
- currentAbsorb = maxAbsorb;
+ int32 manaReduction = currentAbsorb;
- int32 manaReduction = int32(currentAbsorb * manaMultiplier);
- pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false);
- }
+ // lower absorb amount by talents
+ if (float manaMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(absorbAurEff->GetSpellProto(), absorbAurEff->GetEffIndex(), absorbAurEff->GetCaster()))
+ manaReduction = float(manaReduction) * manaMultiplier;
+
+ int32 manaTaken = -pVictim->ModifyPower(POWER_MANA, -manaReduction);
+
+ // take case when mana has ended up into account
+ currentAbsorb = float(currentAbsorb)*(float(manaTaken) / float(manaReduction));
// Mana Shield (or Fire Ward or Frost Ward or Ice Barrier)
// for Incanter's Absorption converting to spell power
- if ((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_MAGE && (*itr)->GetSpellProto()->SpellFamilyFlags[EFFECT_2] & 0x8)
+ if (absorbAurEff->GetSpellProto()->SpellFamilyName == SPELLFAMILY_MAGE && absorbAurEff->GetSpellProto()->SpellFamilyFlags[2] & 0x8)
incanterAbsorption += currentAbsorb;
- (*itr)->SetAmount((*itr)->GetAmount() - currentAbsorb);
- if (((*itr)->GetAmount() <= 0) || (pVictim->GetPower(POWER_MANA) <= 1))
- existExpired = true;
+ dmgInfo.AbsorbDamage(currentAbsorb);
- RemainingDamage -= currentAbsorb;
+ absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
+ if ((absorbAurEff->GetAmount() <= 0))
+ absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
}
-
- if (existExpired)
- for (AuraEffectList::const_iterator itr = vManaShield.begin(); itr != vManaShield.end();)
- {
- AuraEffect * auraEff = (*itr);
- ++itr;
-
- if ((auraEff->GetAmount() <= 0) || (pVictim->GetPower(POWER_MANA) <= 1))
- {
- uint32 removedAuras = pVictim->m_removedAurasCount;
- auraEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
- if (removedAuras + 1 < pVictim->m_removedAurasCount)
- itr = vManaShield.begin();
- }
- }
}
- // Do nothing if 100% absorb ignore
- if (auraAbsorbMod < 100)
- if (pVictim != this) // only split damage if not damaging yourself
+ // split damage auras - only when not damaging self
+ if (pVictim != 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 vSplitDamageFlatCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT));
+ for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
{
- // 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 vSplitDamageFlatCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT));
- for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (RemainingDamage >= 0); ++itr)
- {
- // Check if aura was removed during iteration - we don't need to work on such auras
- if (!((*itr)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
- continue;
- // check damage school mask
- if (!((*itr)->GetMiscValue() & schoolMask))
- continue;
+ // Check if aura was removed during iteration - we don't need to work on such auras
+ if (!((*itr)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
+ continue;
+ // check damage school mask
+ if (!((*itr)->GetMiscValue() & schoolMask))
+ continue;
- // Damage can be splitted only if aura has an alive caster
- Unit * caster = (*itr)->GetCaster();
- if (!caster || (caster == pVictim) || !caster->IsInWorld() || !caster->isAlive())
- continue;
+ // Damage can be splitted only if aura has an alive caster
+ Unit * caster = (*itr)->GetCaster();
+ if (!caster || (caster == pVictim) || !caster->IsInWorld() || !caster->isAlive())
+ continue;
- int32 currentAbsorb;
- if (RemainingDamage >= (*itr)->GetAmount())
- currentAbsorb = (*itr)->GetAmount();
- else
- currentAbsorb = RemainingDamage;
- currentAbsorb = (100 - auraAbsorbMod) * currentAbsorb / 100;
+ int32 splitDamage = (*itr)->GetAmount();
- RemainingDamage -= currentAbsorb;
+ // absorb must be smaller than the damage itself
+ splitDamage = RoundToInterval(splitDamage, 0, int32(dmgInfo.GetDamage()));
- uint32 splitted = currentAbsorb;
- uint32 splitted_absorb = 0;
- DealDamageMods(caster, splitted, &splitted_absorb);
+ dmgInfo.ModifyDamage(-splitDamage);
- SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
+ uint32 splitted = splitDamage;
+ uint32 splitted_absorb = 0;
+ DealDamageMods(caster, splitted, &splitted_absorb);
- CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false);
- }
+ SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
- // 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(pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT));
- for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(), next; (itr != vSplitDamagePctCopy.end()) && (RemainingDamage >= 0); ++itr)
- {
- // Check if aura was removed during iteration - we don't need to work on such auras
- if (!((*itr)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
- continue;
- // check damage school mask
- if (!((*itr)->GetMiscValue() & schoolMask))
- continue;
+ CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
+ DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false);
+ }
- // Damage can be splitted only if aura has an alive caster
- Unit * caster = (*itr)->GetCaster();
- if (!caster || (caster == pVictim) || !caster->IsInWorld() || !caster->isAlive())
- continue;
+ // 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(pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT));
+ for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(), next; (itr != vSplitDamagePctCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
+ {
+ // Check if aura was removed during iteration - we don't need to work on such auras
+ if (!((*itr)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
+ continue;
+ // check damage school mask
+ if (!((*itr)->GetMiscValue() & schoolMask))
+ continue;
- uint32 splitted = CalculatePctN(RemainingDamage, (*itr)->GetAmount());
- AddPctN(splitted, -auraAbsorbMod);
+ // Damage can be splitted only if aura has an alive caster
+ Unit * caster = (*itr)->GetCaster();
+ if (!caster || (caster == pVictim) || !caster->IsInWorld() || !caster->isAlive())
+ continue;
- RemainingDamage -= int32(splitted);
+ int32 splitDamage = CalculatePctN(dmgInfo.GetDamage(), (*itr)->GetAmount());
- uint32 split_absorb = 0;
- DealDamageMods(caster, splitted, &split_absorb);
+ // absorb must be smaller than the damage itself
+ splitDamage = RoundToInterval(splitDamage, 0, int32(dmgInfo.GetDamage()));
- SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
+ dmgInfo.ModifyDamage(-splitDamage);
- CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false);
- }
- }
+ uint32 splitted = splitDamage;
+ uint32 split_absorb = 0;
+ DealDamageMods(caster, splitted, &split_absorb);
- TotalAbsorb = (TotalAbsorb - RemainingDamage > 0) ? TotalAbsorb - RemainingDamage : 0;
+ SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
+
+ CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
+ DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false);
+ }
+ }
// Apply death prevention spells effects
if (auraAbsorbMod < 100) // Do nothing if 100% absorb ignore
- if (preventDeathSpell && (RemainingDamage >= int32(pVictim->GetHealth())))
+ if (preventDeathSpell && (dmgInfo.GetDamage() >= int32(pVictim->GetHealth())))
{
switch(preventDeathSpell->SpellFamilyName)
{
@@ -2108,9 +2033,14 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
pVictim->CastSpell(pVictim, 31231, true);
pVictim->ToPlayer()->AddSpellCooldown(31231, 0, time(NULL) + 60);
- // with health > 10% lost health until health == 10%, in other case no losses
uint32 health10 = pVictim->CountPctFromMaxHealth(10);
- RemainingDamage = pVictim->GetHealth() > health10 ? pVictim->GetHealth() - health10 : 0;
+
+ // hp > 10% - absorb hp till 10%
+ if (pVictim->GetHealth() > health10)
+ dmgInfo.AbsorbDamage(dmgInfo.GetDamage() - pVictim->GetHealth() + health10);
+ // hp lower than 10% - absorb everything
+ else
+ dmgInfo.AbsorbDamage(dmgInfo.GetDamage());
}
break;
}
@@ -2122,14 +2052,15 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff
int32 healAmount = int32(pVictim->CountPctFromMaxHealth(preventDeathAmount));
pVictim->RemoveAurasDueToSpell(preventDeathSpell->Id);
pVictim->CastCustomSpell(pVictim, 48153, &healAmount, NULL, NULL, true);
- RemainingDamage = 0;
+ dmgInfo.AbsorbDamage(dmgInfo.GetDamage());
}
break;
}
}
}
- *absorb = RemainingDamage > 0 ? (damage - RemainingDamage - *resist) : (damage - *resist);
+ *resist = dmgInfo.GetResist();
+ *absorb = dmgInfo.GetAbsorb();
// Incanter's Absorption, if have affective absorbing
if (incanterAbsorption)
@@ -13550,50 +13481,6 @@ void Unit::SetMaxPower(Powers power, uint32 val)
SetPower(power, val);
}
-void Unit::ApplyPowerMod(Powers power, uint32 val, bool apply)
-{
- ApplyModUInt32Value(UNIT_FIELD_POWER1+power, val, apply);
-
- // group update
- if (GetTypeId() == TYPEID_PLAYER)
- {
- if (this->ToPlayer()->GetGroup())
- this->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
- }
- else if (this->ToCreature()->isPet())
- {
- Pet *pet = ((Pet*)this);
- if (pet->isControlled())
- {
- Unit *owner = GetOwner();
- if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
- owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
- }
- }
-}
-
-void Unit::ApplyMaxPowerMod(Powers power, uint32 val, bool apply)
-{
- ApplyModUInt32Value(UNIT_FIELD_MAXPOWER1+power, val, apply);
-
- // group update
- if (GetTypeId() == TYPEID_PLAYER)
- {
- if (this->ToPlayer()->GetGroup())
- this->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER);
- }
- else if (this->ToCreature()->isPet())
- {
- Pet *pet = ((Pet*)this);
- if (pet->isControlled())
- {
- Unit *owner = GetOwner();
- if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
- owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
- }
- }
-}
-
uint32 Unit::GetCreatePowers(Powers power) const
{
// POWER_FOCUS and POWER_HAPPINESS only have hunter pet
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 15b248a5fff..465ab7aa729 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -806,6 +806,60 @@ struct CleanDamage
MeleeHitOutcome hitOutCome;
};
+class DamageInfo
+{
+private:
+ Unit * const m_attacker;
+ Unit * const m_victim;
+ DamageEffectType const m_damageType;
+ SpellEntry const * const m_spellInfo;
+ SpellSchoolMask const m_schoolMask;
+ uint32 m_damage;
+ uint32 m_absorb;
+ uint32 m_resist;
+ uint32 m_block;
+public:
+ explicit DamageInfo(Unit * _attacker, Unit * _victim, uint32 _damage, SpellEntry const * _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType)
+ : m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask), m_damageType(_damageType)
+ {
+ m_absorb = 0;
+ m_resist = 0;
+ m_block = 0;
+ }
+ void ModifyDamage(int32 amount)
+ {
+ amount = std::min(amount, int32(GetDamage()));
+ m_damage += amount;
+ }
+ void AbsorbDamage(uint32 amount)
+ {
+ amount = std::min(amount, GetDamage());
+ m_absorb += amount;
+ m_damage -= amount;
+ }
+ void ResistDamage(uint32 amount)
+ {
+ amount = std::min(amount, GetDamage());
+ m_resist += amount;
+ m_damage -= amount;
+ }
+ void BlockDamage(uint32 amount)
+ {
+ amount = std::min(amount, GetDamage());
+ m_block += amount;
+ m_damage -= amount;
+ }
+ Unit * GetAttacker() const { return m_attacker; };
+ Unit * GetVictim() const { return m_victim; };
+ DamageEffectType const GetDamageType() const { return m_damageType; };
+ SpellEntry const * GetSpellInfo() const { return m_spellInfo; };
+ SpellSchoolMask const GetSchoolMask() const { return m_schoolMask; };
+ uint32 GetDamage() const { return m_damage; };
+ uint32 GetAbsorb() const { return m_absorb; };
+ uint32 GetResist() const { return m_resist; };
+ uint32 GetBlock() const { return m_block; };
+};
+
// Struct for use in Unit::CalculateMeleeDamage
// Need create structure like in SMSG_ATTACKERSTATEUPDATE opcode
struct CalcDamageInfo
@@ -1214,9 +1268,8 @@ class Unit : public WorldObject
uint32 GetMaxPower(Powers power) const { return GetUInt32Value(UNIT_FIELD_MAXPOWER1+power); }
void SetPower(Powers power, uint32 val);
void SetMaxPower(Powers power, uint32 val);
+ // returns the change in power
int32 ModifyPower(Powers power, int32 val);
- void ApplyPowerMod(Powers power, uint32 val, bool apply);
- void ApplyMaxPowerMod(Powers power, uint32 val, bool apply);
uint32 GetAttackTime(WeaponAttackType att) const
{