diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/server/game/Entities/Unit/Unit.cpp | 416 | ||||
-rwxr-xr-x | src/server/game/Entities/Unit/Unit.h | 1 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.h | 60 |
3 files changed, 297 insertions, 180 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d9ea36aaa7a..f998555f7ef 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -1042,12 +1042,8 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama // Calculate absorb resist if (damage > 0) { - // Chaos Bolt - "Chaos Bolt cannot be resisted, and pierces through all absorption effects." - if (spellInfo->SpellIconID != 3178) - { - CalcAbsorbResist(pVictim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo); - damage -= damageInfo->absorb + damageInfo->resist; - } + CalcAbsorbResist(pVictim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo); + damage -= damageInfo->absorb + damageInfo->resist; } else damage = 0; @@ -1626,24 +1622,67 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff // Incanter's Absorption, for converting to spell power int32 incanterAbsorption = 0; + // Ignore Absorption Auras + int32 auraAbsorbMod = 0; + AuraEffectList const & AbsIgnoreAurasA = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL); + for (AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr) + { + if (!((*itr)->GetMiscValue() & schoolMask)) + continue; + + if ((*itr)->GetAmount() > auraAbsorbMod) + auraAbsorbMod = (*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)) + continue; + + if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectedOnSpell(spellInfo)) + auraAbsorbMod = (*itr)->GetAmount(); + } + + AuraEffectList vSchoolAbsorb; + pVictim->FillOrderedAbsorbAuras(vSchoolAbsorb); + // absorb without mana cost - AuraEffectList const& vSchoolAbsorb = pVictim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB); - for (AuraEffectList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end() && RemainingDamage > 0; ++i) + for (AuraEffectList::const_iterator itr = vSchoolAbsorb.begin(); (itr != vSchoolAbsorb.end()) && (RemainingDamage > 0); ++itr) { - if (!((*i)->GetMiscValue() & schoolMask)) + if (!((*itr)->GetMiscValue() & schoolMask)) continue; - SpellEntry const* spellProto = (*i)->GetSpellProto(); + SpellEntry const * spellProto = (*itr)->GetSpellProto(); - // Max Amount can be absorbed by this aura - int32 currentAbsorb = (*i)->GetAmount(); + // 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); + if (roll_chance_i(chance)) + { + triggeredSpells.push_back(TriggeredSpellInfo(57776, pVictim, pVictim, RemainingDamage, (*itr))); + RemainingDamage = RemainingDamage * auraAbsorbMod / 100; + continue; + } + } + + if (auraAbsorbMod >= 100) // Do nothing if 100% absorb ignore + continue; + + // Max Amount can be absorbed by this aura + int32 currentAbsorb = (*itr)->GetAmount(); // Found empty aura (impossible but..) if (currentAbsorb <= 0) { existExpired = true; continue; } + currentAbsorb = (100 - auraAbsorbMod) * currentAbsorb / 100; + // Handle custom absorb auras // TODO: try find better way switch (spellProto->SpellFamilyName) @@ -1654,7 +1693,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff if (spellProto->SpellIconID == 3066) { //reduces all damage taken while stun, fear or silence - if (unitflag & (UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED)) + if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED)) RemainingDamage -= RemainingDamage * currentAbsorb / 100; continue; } @@ -1662,7 +1701,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff if (spellProto->SpellIconID == 2115) { // while affected by Stun and Fear - if (unitflag&(UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING)) + if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING)) RemainingDamage -= RemainingDamage * currentAbsorb / 100; continue; } @@ -1670,23 +1709,23 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff if (spellProto->SpellIconID == 3006) { // You have a chance equal to your Parry chance - if (damagetype == DIRECT_DAMAGE && // Only for direct damage - roll_chance_f(pVictim->GetUnitParryChance())) // Roll chance + if ((damagetype == DIRECT_DAMAGE) && roll_chance_f(pVictim->GetUnitParryChance())) RemainingDamage -= RemainingDamage * currentAbsorb / 100; continue; } // Reflective Shield (Lady Malande boss) if (spellProto->Id == 41475) { - triggeredSpells.push_back(TriggeredSpellInfo(33619, pVictim, this, - std::min(RemainingDamage, currentAbsorb) / 2, *i)); + triggeredSpells.push_back( + TriggeredSpellInfo(33619, pVictim, this, std::min(RemainingDamage, currentAbsorb) / 2, *itr) + ); break; } - if (spellProto->Id == 39228 || // Argussian Compass - spellProto->Id == 60218) // Essence of Gossamer + if ((spellProto->Id == 39228) || // Argussian Compass + (spellProto->Id == 60218)) // Essence of Gossamer { // Max absorb stored in 1 dummy effect - int32 maxAbsorb = SpellMgr::CalculateSpellEffectAmount(spellProto, 1); + int32 maxAbsorb = SpellMgr::CalculateSpellEffectAmount(spellProto, EFFECT_1); if (maxAbsorb < currentAbsorb) currentAbsorb = maxAbsorb; break; @@ -1699,7 +1738,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff if (spellProto->SpellIconID == 2253) { //reduces all damage taken while Stunned - if (pVictim->GetShapeshiftForm() == FORM_CAT && (unitflag & UNIT_FLAG_STUNNED)) + if ((pVictim->GetShapeshiftForm() == FORM_CAT) && (unitflag & UNIT_FLAG_STUNNED)) RemainingDamage -= RemainingDamage * currentAbsorb / 100; continue; } @@ -1709,7 +1748,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff if (RemainingDamage < currentAbsorb) currentAbsorb = RemainingDamage; - (*i)->SetAmount(0); // guarantee removal + (*itr)->SetAmount(0); // guarantee removal existExpired = true; // maybe hacky but not crashy RemainingDamage -= currentAbsorb; @@ -1730,13 +1769,9 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff // Cheat Death (make less prio with Guardian Spirit case) if (spellProto->SpellIconID == 2109) { - if (!preventDeathSpell && - pVictim->GetTypeId() == TYPEID_PLAYER && // Only players - !pVictim->ToPlayer()->HasSpellCooldown(31231) && // Only if no cooldown - roll_chance_i((*i)->GetAmount())) // Only if roll - { - preventDeathSpell = (*i)->GetSpellProto(); - } + if (!preventDeathSpell && pVictim->ToPlayer()) + if (!pVictim->ToPlayer()->HasSpellCooldown(31231) && roll_chance_i((*itr)->GetAmount())) + preventDeathSpell = (*itr)->GetSpellProto(); continue; } break; @@ -1746,42 +1781,45 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff // Guardian Spirit if (spellProto->SpellIconID == 2873) { - preventDeathSpell = (*i)->GetSpellProto(); - preventDeathAmount = (*i)->GetAmount(); + preventDeathSpell = (*itr)->GetSpellProto(); + preventDeathAmount = (*itr)->GetAmount(); continue; } - // Power Word: Shield if (spellProto->SpellFamilyFlags.IsEqual(0x1, 0, 0x400)) { if (pVictim == this) break; - Unit* caster = (*i)->GetCaster(); + + Unit * caster = (*itr)->GetCaster(); if (!caster) break; + // Reflective Shield - if (AuraEffect const * aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 566, 0)) - { + if (AuraEffect const * aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 566, EFFECT_0)) switch(aurEff->GetMiscValue()) { case 5065: // Rank 1 case 5064: // Rank 2 - triggeredSpells.push_back(TriggeredSpellInfo(33619, pVictim, this, - std::min(RemainingDamage, currentAbsorb) * aurEff->GetAmount() / 100, *i)); + triggeredSpells.push_back( + TriggeredSpellInfo(33619, pVictim, this, std::min(RemainingDamage, currentAbsorb) * aurEff->GetAmount() / 100, *itr) + ); break; default: sLog.outError("Unit::CalcAbsorbResist: unknown Reflective Shield spell %d", aurEff->GetId()); break; } - } } break; } case SPELLFAMILY_PALADIN: { // Ardent Defender - if (spellProto->SpellIconID == 2135 && pVictim->GetTypeId() == TYPEID_PLAYER) + if (spellProto->SpellIconID == 2135) { + if (!pVictim->ToPlayer()) + continue; + int32 remainingHealth = pVictim->GetHealth() - RemainingDamage; uint32 allowedHealth = pVictim->CountPctFromMaxHealth(35); // If damage kills us @@ -1798,9 +1836,9 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff ? 1.0f : float(defenseSkillValue) / float(reqDefForMaxHeal); - int32 healAmount = int32(pVictim->CountPctFromMaxHealth(uint32((*i)->GetAmount() * pctFromDefense))); + int32 healAmount = int32(pVictim->CountPctFromMaxHealth(uint32((*itr)->GetAmount() * pctFromDefense))); pVictim->CastCustomSpell(pVictim, 66235, &healAmount, NULL, NULL, true); - pVictim->ToPlayer()->AddSpellCooldown(66235,0,time(NULL) + 120); + pVictim->ToPlayer()->AddSpellCooldown(66235, 0, time(NULL) + 120); } else if (remainingHealth < int32(allowedHealth)) { @@ -1811,7 +1849,6 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff RemainingDamage -= damageToReduce * currentAbsorb / 100; } continue; - } break; } @@ -1821,7 +1858,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff if (spellProto->SpellIconID == 3066) { //reduces all damage taken while stun, fear or silence - if (unitflag & (UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED)) + if (unitflag & (UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED)) RemainingDamage -= RemainingDamage * currentAbsorb / 100; continue; } @@ -1832,12 +1869,12 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff switch (spellProto->Id) { case 51271: // Unbreakable Armor - if (Unit *caster = (*i)->GetCaster()) + if (Unit * caster = (*itr)->GetCaster()) { uint32 absorbed = uint32(currentAbsorb * caster->GetArmor() * 0.01f); // Glyph of Unbreakable Armor - if (AuraEffect *aurEff = caster->GetAuraEffect(58635, 0)) + if (AuraEffect const * aurEff = caster->GetAuraEffect(58635, 0)) absorbed += uint32(absorbed * aurEff->GetAmount() / 100); RemainingDamage -= absorbed; @@ -1847,13 +1884,13 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff case 52285: case 52286: { - int32 remainingHp = (int32)pVictim->GetHealth() - RemainingDamage; + int32 remainingHp = int32(pVictim->GetHealth() - RemainingDamage); // min pct of hp is stored in effect 0 of talent spell uint32 rank = sSpellMgr.GetSpellRank(spellProto->Id); SpellEntry const * talentProto = sSpellStore.LookupEntry(sSpellMgr.GetSpellWithRank(49189, rank)); - int32 minHp = int32(pVictim->CountPctFromMaxHealth(SpellMgr::CalculateSpellEffectAmount(talentProto, 0, (*i)->GetCaster()))); + int32 minHp = int32(pVictim->CountPctFromMaxHealth(SpellMgr::CalculateSpellEffectAmount(talentProto, EFFECT_0, (*itr)->GetCaster()))); // Damage that would take you below [effect0] health or taken while you are at [effect0] if (remainingHp < minHp) { @@ -1868,14 +1905,14 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff // This, if I'm not mistaken, shows that we get back ~2% of the absorbed damage as runic power. int32 absorbed = RemainingDamage * currentAbsorb / 100; RemainingDamage -= absorbed; - triggeredSpells.push_back(TriggeredSpellInfo(49088, pVictim, pVictim, absorbed * 2 / 10, *i)); + triggeredSpells.push_back(TriggeredSpellInfo(49088, pVictim, pVictim, absorbed * 2 / 10, *itr)); continue; } case 50462: // Anti-Magic Shell (on single party/raid member) RemainingDamage -= RemainingDamage * currentAbsorb / 100; continue; case 50461: // Anti-Magic Zone - if (Unit *caster = (*i)->GetCaster()) + if (Unit * caster = (*itr)->GetCaster()) { int32 absorbed = RemainingDamage * currentAbsorb / 100; int32 canabsorb = caster->GetHealth(); @@ -1903,18 +1940,17 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff // 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[2] & 0x000008) + if (spellProto->SpellFamilyName == SPELLFAMILY_MAGE && spellProto->SpellFamilyFlags[EFFECT_2] & 0x8) incanterAbsorption += currentAbsorb; // Reduce shield amount - (*i)->SetAmount((*i)->GetAmount() -currentAbsorb); + (*itr)->SetAmount((*itr)->GetAmount() - currentAbsorb); // Need remove it later - if ((*i)->GetAmount() <= 0) + if ((*itr)->GetAmount() <= 0) existExpired = true; } for (TriggeredSpellInfoVct::const_iterator itr = triggeredSpells.begin(); itr != triggeredSpells.end(); ++itr) - { if (itr->spell) itr->source->CastCustomSpell(itr->spell, SPELLVALUE_BASE_POINT0, itr->amount, itr->target, true, NULL, itr->auraEff); else if (itr->amount > 0) @@ -1923,177 +1959,189 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff itr->source->DealDamageMods(itr->target, damage, NULL); itr->source->DealDamage(itr->target, damage, NULL, damagetype, schoolMask, 0, false); } - } // Remove all expired absorb auras if (existExpired) { - for (AuraEffectList::const_iterator i = vSchoolAbsorb.begin(); i != vSchoolAbsorb.end();) + AuraEffectList const & vSchoolAbsorbOri = pVictim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB); + + for (AuraEffectList::const_iterator itr = vSchoolAbsorbOri.begin(); itr != vSchoolAbsorbOri.end();) { - AuraEffect * auraEff =(*i); - ++i; + AuraEffect * auraEff = (*itr); + ++itr; + if (auraEff->GetAmount() <= 0) { uint32 removedAuras = pVictim->m_removedAurasCount; auraEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL); - if (removedAuras+1<pVictim->m_removedAurasCount) - i=vSchoolAbsorb.begin(); + if (removedAuras + 1 < pVictim->m_removedAurasCount) + itr = vSchoolAbsorbOri.begin(); } } } - // absorb by mana cost - AuraEffectList const& vManaShield = pVictim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD); - for (AuraEffectList::const_iterator i = vManaShield.begin(), next; i != vManaShield.end() && RemainingDamage > 0; i = next) + if (auraAbsorbMod < 100) // Do nothing if 100% absorb ignore { - next = i; ++next; - - // check damage school mask - if (((*i)->GetMiscValue() & schoolMask) == 0) - continue; + existExpired = false; - int32 currentAbsorb; - if (RemainingDamage >= (*i)->GetAmount()) - currentAbsorb = (*i)->GetAmount(); - else - currentAbsorb = RemainingDamage; + // absorb by mana cost + AuraEffectList const & vManaShield = pVictim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD); - if (float manaMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier((*i)->GetSpellProto(), (*i)->GetEffIndex(), (*i)->GetCaster())) + for (AuraEffectList::const_iterator itr = vManaShield.begin(); (itr != vManaShield.end()) && (RemainingDamage > 0); ++itr) { - int32 maxAbsorb = int32(pVictim->GetPower(POWER_MANA) / manaMultiplier); - if (currentAbsorb > maxAbsorb) - currentAbsorb = maxAbsorb; + // check damage school mask + if (!((*itr)->GetMiscValue() & schoolMask)) + continue; - int32 manaReduction = int32(currentAbsorb * manaMultiplier); - pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false); - } + int32 currentAbsorb; - // Mana Shield (or Fire Ward or Frost Ward or Ice Barrier) - // for Incanter's Absorption converting to spell power - if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_MAGE && (*i)->GetSpellProto()->SpellFamilyFlags[2] & 0x000008) - incanterAbsorption += currentAbsorb; + if (RemainingDamage >= (*itr)->GetAmount()) + currentAbsorb = (*itr)->GetAmount(); + else + currentAbsorb = RemainingDamage; - (*i)->SetAmount((*i)->GetAmount()-currentAbsorb); - if ((*i)->GetAmount() <= 0) - { - (*i)->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL); - next = vManaShield.begin(); + currentAbsorb = (100 - auraAbsorbMod) * currentAbsorb / 100; + + 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 = int32(currentAbsorb * manaMultiplier); + pVictim->ApplyPowerMod(POWER_MANA, manaReduction, false); + } + + // 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) + incanterAbsorption += currentAbsorb; + + (*itr)->SetAmount((*itr)->GetAmount() - currentAbsorb); + if (((*itr)->GetAmount() <= 0) || (pVictim->GetPower(POWER_MANA) <= 1)) + existExpired = true; + + RemainingDamage -= currentAbsorb; } - RemainingDamage -= currentAbsorb; + 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(); + } + } } // only split damage if not damaging yourself - if (pVictim != this) - { - AuraEffectList const& vSplitDamageFlat = pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT); - for (AuraEffectList::const_iterator i = vSplitDamageFlat.begin(), next; i != vSplitDamageFlat.end() && RemainingDamage >= 0; i = next) + if (auraAbsorbMod < 100) // Do nothing if 100% absorb ignore + if (pVictim != this) { - next = i; ++next; + AuraEffectList const & vSplitDamageFlat = pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT); + for (AuraEffectList::const_iterator itr = vSplitDamageFlat.begin(), next; (itr != vSplitDamageFlat.end()) && (RemainingDamage >= 0); itr = next) + { + next = itr; ++next; - // check damage school mask - if (((*i)->GetMiscValue() & schoolMask) == 0) - continue; + // check damage school mask + if (!((*itr)->GetMiscValue() & schoolMask)) + continue; - // Damage can be splitted only if aura has an alive caster - Unit *caster = (*i)->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 >= (*i)->GetAmount()) - currentAbsorb = (*i)->GetAmount(); - else - currentAbsorb = RemainingDamage; + int32 currentAbsorb; + if (RemainingDamage >= (*itr)->GetAmount()) + currentAbsorb = (*itr)->GetAmount(); + else + currentAbsorb = RemainingDamage; + currentAbsorb = (100 - auraAbsorbMod) * currentAbsorb / 100; - RemainingDamage -= currentAbsorb; + RemainingDamage -= currentAbsorb; - uint32 splitted = currentAbsorb; - uint32 splitted_absorb = 0; - DealDamageMods(caster,splitted,&splitted_absorb); + uint32 splitted = currentAbsorb; + uint32 splitted_absorb = 0; + DealDamageMods(caster, splitted, &splitted_absorb); - SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false); + SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false); - CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); - } + CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); + DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false); + } - AuraEffectList const& vSplitDamagePct = pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT); - for (AuraEffectList::const_iterator i = vSplitDamagePct.begin(), next; i != vSplitDamagePct.end() && RemainingDamage >= 0; i = next) - { - next = i; - ++next; + AuraEffectList const & vSplitDamagePct = pVictim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT); + for (AuraEffectList::const_iterator itr = vSplitDamagePct.begin(), next; (itr != vSplitDamagePct.end()) && (RemainingDamage >= 0); itr = next) + { + next = itr; ++next; - // check damage school mask - if (((*i)->GetMiscValue() & schoolMask) == 0) - continue; + // check damage school mask + if (!((*itr)->GetMiscValue() & schoolMask)) + continue; - // Damage can be splitted only if aura has an alive caster - Unit *caster = (*i)->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; - uint32 splitted = uint32(RemainingDamage * (*i)->GetAmount() / 100.0f); + uint32 splitted = uint32(RemainingDamage * (*itr)->GetAmount() / 100.0f); + splitted = (100 - auraAbsorbMod) * splitted / 100; - RemainingDamage -= int32(splitted); + RemainingDamage -= int32(splitted); - uint32 split_absorb = 0; - DealDamageMods(caster,splitted,&split_absorb); + uint32 split_absorb = 0; + DealDamageMods(caster, splitted, &split_absorb); - SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false); + 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, (*i)->GetSpellProto(), false); + CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); + DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false); + } } - } TotalAbsorb = (TotalAbsorb - RemainingDamage > 0) ? TotalAbsorb - RemainingDamage : 0; - // TODO: School should be checked for absorbing auras or for attacks? - int32 auraAbsorbMod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL); - AuraEffectList const& AbsIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL); - for (AuraEffectList::const_iterator i = AbsIgnoreAurasAb.begin(); i != AbsIgnoreAurasAb.end(); ++i) - { - if ((*i)->GetAmount() > auraAbsorbMod - && (*i)->IsAffectedOnSpell(spellInfo)) - auraAbsorbMod = (*i)->GetAmount(); - } - - // Ignore absorb - add reduced amount again to damage - RemainingDamage += auraAbsorbMod * TotalAbsorb / 100; // Apply death prevention spells effects - if (preventDeathSpell && RemainingDamage >= int32(pVictim->GetHealth())) - { - switch(preventDeathSpell->SpellFamilyName) + if (auraAbsorbMod < 100) // Do nothing if 100% absorb ignore + if (preventDeathSpell && (RemainingDamage >= int32(pVictim->GetHealth()))) { - case SPELLFAMILY_ROGUE: + switch(preventDeathSpell->SpellFamilyName) { - // Cheat Death - if (preventDeathSpell->SpellIconID == 2109) + case SPELLFAMILY_ROGUE: { - pVictim->CastSpell(pVictim, 31231, true); - pVictim->ToPlayer()->AddSpellCooldown(31231, 0, time(NULL) + 60); + // Cheat Death + if (preventDeathSpell->SpellIconID == 2109) + { + 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; + // 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; + } + break; } - break; - } - case SPELLFAMILY_PRIEST: - { - // Guardian Spirit - if (preventDeathSpell->SpellIconID == 2873) + case SPELLFAMILY_PRIEST: { - int32 healAmount = int32(pVictim->CountPctFromMaxHealth(preventDeathAmount)); - pVictim->RemoveAurasDueToSpell(preventDeathSpell->Id); - pVictim->CastCustomSpell(pVictim, 48153, &healAmount, NULL, NULL, true); - RemainingDamage = 0; + // Guardian Spirit + if (preventDeathSpell->SpellIconID == 2873) + { + int32 healAmount = int32(pVictim->CountPctFromMaxHealth(preventDeathAmount)); + pVictim->RemoveAurasDueToSpell(preventDeathSpell->Id); + pVictim->CastCustomSpell(pVictim, 48153, &healAmount, NULL, NULL, true); + RemainingDamage = 0; + } + break; } - break; } } - } *absorb = RemainingDamage > 0 ? (damage - RemainingDamage - *resist) : (damage - *resist); @@ -2102,7 +2150,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff { // Incanter's Absorption // TODO: move this code to procflag - if (AuraEffect const * aurEff = pVictim->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2941, 0)) + if (AuraEffect const * aurEff = pVictim->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2941, EFFECT_0)) { // Get total damage bonus from auras int32 current_dmg = 0; @@ -2111,13 +2159,19 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff if (AuraEffect const * bonusEff = iter->second->GetBase()->GetEffect(0)) current_dmg += bonusEff->GetAmount(); - int32 new_dmg = (int32)*absorb * aurEff->GetAmount() / 100; + int32 new_dmg = int32(*absorb) * aurEff->GetAmount() / 100; if (new_dmg > 0) pVictim->CastCustomSpell(pVictim, 44413, &new_dmg, NULL, NULL, true); } } } +void Unit::FillOrderedAbsorbAuras(AuraEffectList & out) const +{ + out = GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB); + out.sort(Trinity::AbsorbAuraOrderPred()); +} + void Unit::CalcHealAbsorb(Unit *pVictim, const SpellEntry *healSpell, uint32 &healAmount, uint32 &absorb) { if (!healAmount) @@ -6757,23 +6811,27 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger return true; } // Sacred Shield - if (dummySpell->SpellFamilyFlags[1]&0x00080000) + if (dummySpell->SpellFamilyFlags[1] & 0x80000) { if (procFlag & PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS) { - if (procSpell->SpellFamilyName == SPELLFAMILY_PALADIN - && (procSpell->SpellFamilyFlags[0] & 0x40000000)) + if ((procSpell->SpellFamilyName == SPELLFAMILY_PALADIN) && (procSpell->SpellFamilyFlags[0] & 0x40000000)) { - basepoints0 = int32(float(damage)/12.0f); - CastCustomSpell(this,66922,&basepoints0,NULL,NULL,true,0,triggeredByAura, pVictim->GetGUID()); + basepoints0 = damage / 12; + + if (basepoints0) + CastCustomSpell(this, 66922, &basepoints0, NULL, NULL, true, 0, triggeredByAura, pVictim->GetGUID()); + return true; } else return false; } - else + else if (damage > 0) + { triggered_spell_id = 58597; - target = this; + target = this; + } break; } // Righteous Vengeance diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 347a93ebe63..15fc7473251 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1873,6 +1873,7 @@ class Unit : public WorldObject static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellEntry const *spellInfo = NULL, uint8 effIndex = MAX_SPELL_EFFECTS); uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType=MAX_ATTACK); void CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, SpellEntry const *spellInfo = NULL); + void FillOrderedAbsorbAuras(AuraEffectList & out) const; void CalcHealAbsorb(Unit *pVictim, const SpellEntry *spellProto, uint32 &healAmount, uint32 &absorb); void UpdateSpeed(UnitMoveType mtype, bool forced); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 0ceea63ad76..80809c9d0bb 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -264,4 +264,62 @@ class AuraEffect void HandleAuraModFakeInebriation(AuraApplication const * aurApp, uint8 mode, bool apply) const; }; -#endif
\ No newline at end of file +namespace Trinity +{ + // Binary predicate for sorting the priority of absorption aura effects + class AbsorbAuraOrderPred + { + public: + AbsorbAuraOrderPred() { } + bool operator() (AuraEffect * aurEffA, AuraEffect * aurEffB) const + { + SpellEntry const * spellProtoA = aurEffA->GetSpellProto(); + SpellEntry const * spellProtoB = aurEffB->GetSpellProto(); + + // Wards + if ((spellProtoA->SpellFamilyName == SPELLFAMILY_MAGE) || + (spellProtoA->SpellFamilyName == SPELLFAMILY_WARLOCK)) + if (spellProtoA->Category == 56) + return true; + if ((spellProtoB->SpellFamilyName == SPELLFAMILY_MAGE) || + (spellProtoB->SpellFamilyName == SPELLFAMILY_WARLOCK)) + if (spellProtoB->Category == 56) + return false; + + // Sacred Shield + if (spellProtoA->Id == 58597) + return true; + if (spellProtoB->Id == 58597) + return false; + + // Fel Blossom + if (spellProtoA->Id == 28527) + return true; + if (spellProtoB->Id == 28527) + return false; + + // Divine Aegis + if (spellProtoA->Id == 47753) + return true; + if (spellProtoB->Id == 47753) + return false; + + // Ice Barrier + if (spellProtoA->Category == 471) + return true; + if (spellProtoB->Category == 471) + return false; + + // Sacrifice + if ((spellProtoA->SpellFamilyName == SPELLFAMILY_WARLOCK) && + (spellProtoA->SpellIconID == 693)) + return true; + if ((spellProtoB->SpellFamilyName == SPELLFAMILY_WARLOCK) && + (spellProtoB->SpellIconID == 693)) + return false; + + return false; + } + }; +} +#endif |