diff options
| author | QAston <none@none> | 2010-12-27 20:14:54 +0100 |
|---|---|---|
| committer | QAston <none@none> | 2010-12-27 20:14:54 +0100 |
| commit | ef968f4b1552c2f1673a2ec79d8cd6b1ec9c2d11 (patch) | |
| tree | d9909a464e9131ffdbe3a6577f0c907560e5f799 /src/server/game/Entities/Unit | |
| parent | da8d794f4bd6765c45847d93626057e272f7358e (diff) | |
Core/Unit: Big cleanup in Unit::CalcAbsorbResist
Core/AuraScript:
Fix compile time check for AuraScript functions
Remove AuraApplication from hook functions parameter list, use GetTarget() and GetTargetApplication() instead
Add OnEffectAbsorb hook
Scripts: move handlers of Spell Deflection, Savage Defense, Primal Tenacity, Nerves of Steel, Astral shift from core to scripts.
--HG--
branch : trunk
Diffstat (limited to 'src/server/game/Entities/Unit')
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.cpp | 439 | ||||
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.h | 57 |
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 { |
