aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorclick <none@none>2010-12-11 12:00:57 +0100
committerclick <none@none>2010-12-11 12:00:57 +0100
commit81db111ffd70338de973fa8b1969367d8ca9624e (patch)
tree18219a1b8308bd07a8dca3cb953006d6c42e7556
parent0e33e73d3966057966d71b802e153ae100f7e463 (diff)
Core/Spells: Fix mage talent Frost Warding (and a little cleanup on CalcAbsorbResist) - patch by DrTenma
Fixes issue 2715. Closes issue 3770. --HG-- branch : trunk
-rw-r--r--sql/base/world_database.sql1
-rw-r--r--sql/updates/10623_world_spell_bonus_data.sql3
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp416
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h1
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h60
5 files changed, 301 insertions, 180 deletions
diff --git a/sql/base/world_database.sql b/sql/base/world_database.sql
index fe2102b5ba6..cfcd30f5359 100644
--- a/sql/base/world_database.sql
+++ b/sql/base/world_database.sql
@@ -16887,6 +16887,7 @@ INSERT INTO `spell_bonus_data` (`entry`,`direct_bonus`,`dot_bonus`,`ap_bonus`,`a
(26573, -1, 0.04, -1, 0.04, 'Paladin - Consecration'),
(879, 0.15, -1, 0.15, -1, 'Paladin - Exorcism'),
(19750, 1, -1, -1, -1, 'Paladin - Flash of Light'),
+(66922, 0, 0, 0, 0, 'Paladin - Flash of Light'),
(53595, 0, 0, 0, 0, 'Paladin - Hammer of the Righteous'),
(24275, 0.15, -1, 0.15, -1, 'Paladin - Hammer of Wrath'),
(62124, 0.085, -1, -1, -1, 'Paladin - Hand of Reckoning'),
diff --git a/sql/updates/10623_world_spell_bonus_data.sql b/sql/updates/10623_world_spell_bonus_data.sql
new file mode 100644
index 00000000000..c9e24105e53
--- /dev/null
+++ b/sql/updates/10623_world_spell_bonus_data.sql
@@ -0,0 +1,3 @@
+DELETE FROM `spell_bonus_data` WHERE `entry` IN (66922);
+INSERT INTO `spell_bonus_data` (`entry`, `direct_bonus`, `dot_bonus`, `ap_bonus`, `ap_dot_bonus`, `comments`) VALUES
+(66922, 0, 0, 0, 0, 'Paladin - Flash of Light');
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