diff options
Diffstat (limited to 'src/server/game')
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.cpp | 439 | ||||
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.h | 57 | ||||
| -rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.h | 2 | ||||
| -rwxr-xr-x | src/server/game/Spells/Auras/SpellAuras.cpp | 35 | ||||
| -rwxr-xr-x | src/server/game/Spells/Auras/SpellAuras.h | 1 | ||||
| -rwxr-xr-x | src/server/game/Spells/SpellScript.cpp | 44 | ||||
| -rwxr-xr-x | src/server/game/Spells/SpellScript.h | 76 |
7 files changed, 337 insertions, 317 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 { diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 80809c9d0bb..02b5825d5ec 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -60,6 +60,7 @@ class AuraEffect void ResetPeriodic(bool resetPeriodicTimer = false) { if (resetPeriodicTimer) m_periodicTimer = m_amplitude; m_tickNumber = 0;} bool IsPeriodic() const { return m_isPeriodic; } + void SetPeriodic(bool isPeriodic) { m_isPeriodic = isPeriodic; } bool IsAffectedOnSpell(SpellEntry const *spell) const; void SendTickImmune(Unit * target, Unit *caster) const; @@ -72,7 +73,6 @@ class AuraEffect void CleanupTriggeredSpells(Unit * target); - static bool IsPeriodicAuraType(uint32 type); // add/remove SPELL_AURA_MOD_SHAPESHIFT (36) linked auras void HandleShapeshiftBoosts(Unit * target, bool apply) const; private: diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 4a7ec595f28..5068de484af 100755 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1656,12 +1656,12 @@ bool Aura::CallScriptEffectApplyHandlers(AuraEffect const * aurEff, AuraApplicat bool preventDefault = false; for(std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) { - (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY); + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY, aurApp); std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin(); for(; effItr != effEndItr ; ++effItr) { if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, aurApp, mode); + (*effItr).Call(*scritr, aurEff, mode); } if (!preventDefault) preventDefault = (*scritr)->_IsDefaultActionPrevented(); @@ -1675,12 +1675,12 @@ bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const * aurEff, AuraApplica bool preventDefault = false; for(std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) { - (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE); + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE, aurApp); std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin(); for(; effItr != effEndItr ; ++effItr) { if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, aurApp, mode); + (*effItr).Call(*scritr, aurEff, mode); } if (!preventDefault) preventDefault = (*scritr)->_IsDefaultActionPrevented(); @@ -1694,12 +1694,12 @@ bool Aura::CallScriptEffectPeriodicHandlers(AuraEffect const * aurEff, AuraAppli bool preventDefault = false; for(std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) { - (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PERIODIC); + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PERIODIC, aurApp); std::list<AuraScript::EffectPeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin(); for(; effItr != effEndItr ; ++effItr) { if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, aurApp); + (*effItr).Call(*scritr, aurEff); } if (!preventDefault) preventDefault = (*scritr)->_IsDefaultActionPrevented(); @@ -1728,7 +1728,7 @@ void Aura::CallScriptEffectCalcAmountHandlers(AuraEffect const * aurEff, int32 & for(std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_AMOUNT); - std::list<AuraScript::EffectCalcAmountHandler>::iterator effEndItr = (*scritr)->OnEffectCalcAmount.end(), effItr = (*scritr)->OnEffectCalcAmount.begin(); + std::list<AuraScript::EffectCalcAmountHandler>::iterator effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin(); for(; effItr != effEndItr ; ++effItr) { if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex())) @@ -1743,7 +1743,7 @@ void Aura::CallScriptEffectCalcPeriodicHandlers(AuraEffect const * aurEff, bool for(std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC); - std::list<AuraScript::EffectCalcPeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectCalcPeriodic.end(), effItr = (*scritr)->OnEffectCalcPeriodic.begin(); + std::list<AuraScript::EffectCalcPeriodicHandler>::iterator effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin(); for(; effItr != effEndItr ; ++effItr) { if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex())) @@ -1758,7 +1758,7 @@ void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const * aurEff, Spell for(std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD); - std::list<AuraScript::EffectCalcSpellModHandler>::iterator effEndItr = (*scritr)->OnEffectCalcSpellMod.end(), effItr = (*scritr)->OnEffectCalcSpellMod.begin(); + std::list<AuraScript::EffectCalcSpellModHandler>::iterator effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin(); for(; effItr != effEndItr ; ++effItr) { if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex())) @@ -1768,6 +1768,23 @@ void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const * aurEff, Spell } } +void Aura::CallScriptEffectAbsorbHandlers(AuraEffect * aurEff, AuraApplication const * aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool & defaultPrevented) +{ + for(std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_ABSORB, aurApp); + std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin(); + for(; effItr != effEndItr ; ++effItr) + { + if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex())) + (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount); + } + if (!defaultPrevented) + defaultPrevented = (*scritr)->_IsDefaultActionPrevented(); + (*scritr)->_FinishScriptCall(); + } +} + UnitAura::UnitAura(SpellEntry const* spellproto, uint8 effMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID) : Aura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID) { diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 6b619ef2e9a..ab9a56be7fc 100755 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -174,6 +174,7 @@ class Aura void CallScriptEffectCalcAmountHandlers(AuraEffect const * aurEff, int32 & amount, bool & canBeRecalculated); void CallScriptEffectCalcPeriodicHandlers(AuraEffect const * aurEff, bool & isPeriodic, int32 & amplitude); void CallScriptEffectCalcSpellModHandlers(AuraEffect const * aurEff, SpellModifier *& spellMod); + void CallScriptEffectAbsorbHandlers(AuraEffect * aurEff, AuraApplication const * aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool & defaultPrevented); std::list<AuraScript *> m_loadedScripts; private: void _DeleteRemovedApplications(); diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index ade0c63b2b8..482a185f590 100755 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -431,15 +431,19 @@ bool AuraScript::_Validate(SpellEntry const * entry) if (!(*itr).GetAffectedEffectsMask(entry)) sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); - for (std::list<EffectCalcAmountHandler>::iterator itr = OnEffectCalcAmount.begin(); itr != OnEffectCalcAmount.end(); ++itr) + for (std::list<EffectCalcAmountHandler>::iterator itr = DoEffectCalcAmount.begin(); itr != DoEffectCalcAmount.end(); ++itr) if (!(*itr).GetAffectedEffectsMask(entry)) sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); - for (std::list<EffectCalcPeriodicHandler>::iterator itr = OnEffectCalcPeriodic.begin(); itr != OnEffectCalcPeriodic.end(); ++itr) + for (std::list<EffectCalcPeriodicHandler>::iterator itr = DoEffectCalcPeriodic.begin(); itr != DoEffectCalcPeriodic.end(); ++itr) if (!(*itr).GetAffectedEffectsMask(entry)) sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); - for (std::list<EffectCalcSpellModHandler>::iterator itr = OnEffectCalcSpellMod.begin(); itr != OnEffectCalcSpellMod.end(); ++itr) + for (std::list<EffectCalcSpellModHandler>::iterator itr = DoEffectCalcSpellMod.begin(); itr != DoEffectCalcSpellMod.end(); ++itr) + if (!(*itr).GetAffectedEffectsMask(entry)) + sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); + + for (std::list<EffectAbsorbHandler>::iterator itr = OnEffectAbsorb.begin(); itr != OnEffectAbsorb.end(); ++itr) if (!(*itr).GetAffectedEffectsMask(entry)) sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); @@ -467,9 +471,9 @@ AuraScript::EffectPeriodicHandler::EffectPeriodicHandler(AuraEffectPeriodicFnTyp pEffectHandlerScript = _pEffectHandlerScript; } -void AuraScript::EffectPeriodicHandler::Call(AuraScript * auraScript, AuraEffect const * _aurEff, AuraApplication const * _aurApp) +void AuraScript::EffectPeriodicHandler::Call(AuraScript * auraScript, AuraEffect const * _aurEff) { - (auraScript->*pEffectHandlerScript)(_aurEff, _aurApp); + (auraScript->*pEffectHandlerScript)(_aurEff); } AuraScript::EffectUpdatePeriodicHandler::EffectUpdatePeriodicHandler(AuraEffectUpdatePeriodicFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName) @@ -523,10 +527,21 @@ AuraScript::EffectApplyHandler::EffectApplyHandler(AuraEffectApplicationModeFnTy mode = _mode; } -void AuraScript::EffectApplyHandler::Call(AuraScript * auraScript, AuraEffect const * _aurEff, AuraApplication const * _aurApp, AuraEffectHandleModes _mode) +void AuraScript::EffectApplyHandler::Call(AuraScript * auraScript, AuraEffect const * _aurEff, AuraEffectHandleModes _mode) { if (_mode & mode) - (auraScript->*pEffectHandlerScript)(_aurEff, _aurApp, _mode); + (auraScript->*pEffectHandlerScript)(_aurEff, _mode); +} + +AuraScript::EffectAbsorbHandler::EffectAbsorbHandler(AuraEffectAbsorbFnType _pEffectHandlerScript,uint8 _effIndex) + : AuraScript::EffectBase(_effIndex, SPELL_AURA_SCHOOL_ABSORB) +{ + pEffectHandlerScript = _pEffectHandlerScript; +} + +void AuraScript::EffectAbsorbHandler::Call(AuraScript * auraScript, AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) +{ + (auraScript->*pEffectHandlerScript)(aurEff, dmgInfo, absorbAmount); } bool AuraScript::_Load(Aura * aura) @@ -538,7 +553,7 @@ bool AuraScript::_Load(Aura * aura) return load; } -void AuraScript::_PrepareScriptCall(AuraScriptHookType hookType) +void AuraScript::_PrepareScriptCall(AuraScriptHookType hookType, AuraApplication const * aurApp) { m_currentScriptState = hookType; switch (m_currentScriptState) @@ -546,16 +561,19 @@ void AuraScript::_PrepareScriptCall(AuraScriptHookType hookType) case AURA_SCRIPT_HOOK_EFFECT_APPLY: case AURA_SCRIPT_HOOK_EFFECT_REMOVE: case AURA_SCRIPT_HOOK_EFFECT_PERIODIC: + case AURA_SCRIPT_HOOK_EFFECT_ABSORB: m_defaultActionPrevented = false; break; default: break; } + m_auraApplication = aurApp; } void AuraScript::_FinishScriptCall() { m_currentScriptState = SPELL_SCRIPT_STATE_NONE; + m_auraApplication = NULL; } bool AuraScript::_IsDefaultActionPrevented() @@ -733,3 +751,13 @@ bool AuraScript::HasEffectType(AuraType type) const return m_aura->HasEffectType(type); } +Unit * AuraScript::GetTarget() const +{ + return m_auraApplication->GetTarget(); +} + +AuraApplication const * AuraScript::GetTargetApplication() const +{ + return m_auraApplication; +} + diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 48971ffa64a..972f6794436 100755 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -282,6 +282,7 @@ enum AuraScriptHookType AURA_SCRIPT_HOOK_EFFECT_CALC_AMOUNT, AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC, AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD, + AURA_SCRIPT_HOOK_EFFECT_ABSORB, /*AURA_SCRIPT_HOOK_APPLY, AURA_SCRIPT_HOOK_REMOVE,*/ }; @@ -296,12 +297,14 @@ class AuraScript : public _SpellScript public: #define AURASCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) \ - typedef void(CLASSNAME::*AuraEffectApplicationModeFnType)(AuraEffect const *, AuraApplication const *, AuraEffectHandleModes mode); \ - typedef void(CLASSNAME::*AuraEffectPeriodicFnType)(AuraEffect const *, AuraApplication const *); \ + typedef void(CLASSNAME::*AuraEffectApplicationModeFnType)(AuraEffect const *, AuraEffectHandleModes); \ + typedef void(CLASSNAME::*AuraEffectPeriodicFnType)(AuraEffect const *); \ typedef void(CLASSNAME::*AuraEffectUpdatePeriodicFnType)(AuraEffect *); \ typedef void(CLASSNAME::*AuraEffectCalcAmountFnType)(AuraEffect const *, int32 &, bool &); \ typedef void(CLASSNAME::*AuraEffectCalcPeriodicFnType)(AuraEffect const *, bool &, int32 &); \ typedef void(CLASSNAME::*AuraEffectCalcSpellModFnType)(AuraEffect const *, SpellModifier *&); \ + typedef void(CLASSNAME::*AuraEffectAbsorbFnType)(AuraEffect *, DamageInfo &, uint32 &); \ + //typedef void(CLASSNAME::*AuraAbsorbFnType)(AuraEffect *, DamageInfo &); \ AURASCRIPT_FUNCTION_TYPE_DEFINES(AuraScript) @@ -316,7 +319,7 @@ class AuraScript : public _SpellScript { public: EffectPeriodicHandler(AuraEffectPeriodicFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName); - void Call(AuraScript * auraScript, AuraEffect const * _aurEff, AuraApplication const * _aurApp); + void Call(AuraScript * auraScript, AuraEffect const * _aurEff); private: AuraEffectPeriodicFnType pEffectHandlerScript; }; @@ -356,11 +359,19 @@ class AuraScript : public _SpellScript { public: EffectApplyHandler(AuraEffectApplicationModeFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName, AuraEffectHandleModes _mode); - void Call(AuraScript * auraScript, AuraEffect const * _aurEff, AuraApplication const * _aurApp, AuraEffectHandleModes _mode); + void Call(AuraScript * auraScript, AuraEffect const * _aurEff, AuraEffectHandleModes _mode); private: AuraEffectApplicationModeFnType pEffectHandlerScript; AuraEffectHandleModes mode; }; + class EffectAbsorbHandler : public EffectBase + { + public: + EffectAbsorbHandler(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex); + void Call(AuraScript * auraScript, AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount); + private: + AuraEffectAbsorbFnType pEffectHandlerScript; + }; #define AURASCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) \ class EffectPeriodicHandlerFunction : public AuraScript::EffectPeriodicHandler { public: EffectPeriodicHandlerFunction(AuraEffectPeriodicFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName) : AuraScript::EffectPeriodicHandler((AuraScript::AuraEffectPeriodicFnType)_pEffectHandlerScript, _effIndex, _effName) {} }; \ @@ -369,17 +380,19 @@ class AuraScript : public _SpellScript class EffectCalcPeriodicHandlerFunction : public AuraScript::EffectCalcPeriodicHandler { public: EffectCalcPeriodicHandlerFunction(AuraEffectCalcPeriodicFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName) : AuraScript::EffectCalcPeriodicHandler((AuraScript::AuraEffectCalcPeriodicFnType)_pEffectHandlerScript, _effIndex, _effName) {} }; \ class EffectCalcSpellModHandlerFunction : public AuraScript::EffectCalcSpellModHandler { public: EffectCalcSpellModHandlerFunction(AuraEffectCalcSpellModFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName) : AuraScript::EffectCalcSpellModHandler((AuraScript::AuraEffectCalcSpellModFnType)_pEffectHandlerScript, _effIndex, _effName) {} }; \ class EffectApplyHandlerFunction : public AuraScript::EffectApplyHandler { public: EffectApplyHandlerFunction(AuraEffectApplicationModeFnType _pEffectHandlerScript,uint8 _effIndex, uint16 _effName, AuraEffectHandleModes _mode) : AuraScript::EffectApplyHandler((AuraScript::AuraEffectApplicationModeFnType)_pEffectHandlerScript, _effIndex, _effName, _mode) {} }; \ + class EffectAbsorbFunction : public AuraScript::EffectAbsorbHandler { public: EffectAbsorbFunction(AuraEffectAbsorbFnType _pEffectHandlerScript,uint8 _effIndex) : AuraScript::EffectAbsorbHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \ #define PrepareAuraScript(CLASSNAME) AURASCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) AURASCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) public: bool _Validate(SpellEntry const * entry); bool _Load(Aura * aura); - void _PrepareScriptCall(AuraScriptHookType hookType); + void _PrepareScriptCall(AuraScriptHookType hookType, AuraApplication const * aurApp = NULL); void _FinishScriptCall(); bool _IsDefaultActionPrevented(); private: Aura * m_aura; + AuraApplication const * m_auraApplication; bool m_defaultActionPrevented; public: // @@ -388,44 +401,57 @@ class AuraScript : public _SpellScript // // executed when periodic aura effect is applied with specified mode to target // example: OnEffectApply += AuraEffectApplyFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier, AuraEffectHandleModes); + // where function is: void function (AuraEffect const * aurEff, AuraEffectHandleModes mode); HookList<EffectApplyHandler> OnEffectApply; - #define AuraEffectApplyFn(F, I, N, M) EffectApplyHandlerFunction((AuraEffectApplicationModeFnType)&F, I, N, M) + #define AuraEffectApplyFn(F, I, N, M) EffectApplyHandlerFunction(&F, I, N, M) // executed when periodic aura effect is removed with specified mode from target // example: OnEffectRemove += AuraEffectRemoveFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier, AuraEffectHandleModes); - // where function is: void function (AuraEffect const * aurEff, AuraApplication const * aurApp, AuraEffectHandleModes mode); + // where function is: void function (AuraEffect const * aurEff, AuraEffectHandleModes mode); HookList<EffectApplyHandler> OnEffectRemove; - #define AuraEffectRemoveFn(F, I, N, M) EffectApplyHandlerFunction((AuraEffectApplicationModeFnType)&F, I, N, M) + #define AuraEffectRemoveFn(F, I, N, M) EffectApplyHandlerFunction(&F, I, N, M) // executed when periodic aura effect ticks on target // example: OnEffectPeriodic += AuraEffectPeriodicFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); - // where function is: void function (AuraEffect const * aurEff, AuraApplication const * aurApp, AuraEffectHandleModes mode); + // where function is: void function (AuraEffect const * aurEff, AuraEffectHandleModes mode); HookList<EffectPeriodicHandler> OnEffectPeriodic; - #define AuraEffectPeriodicFn(F, I, N) EffectPeriodicHandlerFunction((AuraEffectPeriodicFnType)&F, I, N) + #define AuraEffectPeriodicFn(F, I, N) EffectPeriodicHandlerFunction(&F, I, N) // executed when periodic aura effect is updated // example: OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); - // where function is: void function (AuraEffect const * aurEff, AuraApplication const * aurApp); + // where function is: void function (AuraEffect const * aurEff); HookList<EffectUpdatePeriodicHandler> OnEffectUpdatePeriodic; - #define AuraEffectUpdatePeriodicFn(F, I, N) EffectUpdatePeriodicHandlerFunction((AuraEffectUpdatePeriodicFnType)&F, I, N) + #define AuraEffectUpdatePeriodicFn(F, I, N) EffectUpdatePeriodicHandlerFunction(&F, I, N) // executed when aura effect calculates amount - // example: OnEffectCalcAmount += AuraEffectCalcAmounFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); + // example: DoEffectCalcAmount += AuraEffectCalcAmounFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect * aurEff, int32 & amount, bool & canBeRecalculated); - HookList<EffectCalcAmountHandler> OnEffectCalcAmount; - #define AuraEffectCalcAmountFn(F, I, N) EffectCalcAmountHandlerFunction((AuraEffectCalcAmountFnType)&F, I, N) + HookList<EffectCalcAmountHandler> DoEffectCalcAmount; + #define AuraEffectCalcAmountFn(F, I, N) EffectCalcAmountHandlerFunction(&F, I, N) // executed when aura effect calculates periodic data - // example: OnEffectCalcPeriodic += AuraEffectCalcPeriodicFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); + // example: DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect const * aurEff, bool & isPeriodic, int32 & amplitude); - HookList<EffectCalcPeriodicHandler> OnEffectCalcPeriodic; - #define AuraEffectCalcPeriodicFn(F, I, N) EffectCalcPeriodicHandlerFunction((AuraEffectCalcPeriodicFnType)&F, I, N) + HookList<EffectCalcPeriodicHandler> DoEffectCalcPeriodic; + #define AuraEffectCalcPeriodicFn(F, I, N) EffectCalcPeriodicHandlerFunction(&F, I, N) // executed when aura effect calculates spellmod - // example: OnEffectCalcSpellMod += AuraEffectCalcSpellModFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); + // example: DoEffectCalcSpellMod += AuraEffectCalcSpellModFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect const * aurEff, SpellModifier *& spellMod); - HookList<EffectCalcSpellModHandler> OnEffectCalcSpellMod; - #define AuraEffectCalcSpellModFn(F, I, N) EffectCalcSpellModHandlerFunction((AuraEffectCalcSpellModFnType)&F, I, N) + HookList<EffectCalcSpellModHandler> DoEffectCalcSpellMod; + #define AuraEffectCalcSpellModFn(F, I, N) EffectCalcSpellModHandlerFunction(&F, I, N) + + // executed when absorb aura effect is going to reduce damage + // example: OnEffectAbsorb += AuraEffectAbsorbFn(class::function, EffectIndexSpecifier); + // where function is: void function (AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount); + HookList<EffectAbsorbHandler> OnEffectAbsorb; + #define AuraEffectAbsorbFn(F, I) EffectAbsorbFunction(&F, I) + + // executed after aura absorbtions reduced damage + // example: AfterAbsorb += AuraAbsorbFn(class::function); + // where function is: void function (AuraEffect * aurEff, DamageInfo & dmgInfo); + //HookList<AbsorbHandler> AfterAbsorb; + //#define AuraAbsorbFn(F) EffectAbsorbFunction(&F) // AuraScript interface - hook/effect execution manipulators @@ -494,6 +520,14 @@ class AuraScript : public _SpellScript // check if aura has effect of given aura type bool HasEffectType(AuraType type) const; + + // AuraScript interface - functions which are redirecting to AuraApplication class + // Do not call these in hooks in which AuraApplication is not avalible, otherwise result will differ from expected (the functions will return NULL) + + // returns currently processed target of an aura + Unit * GetTarget() const; + // returns AuraApplication object of currently processed target + AuraApplication const * GetTargetApplication() const; }; // |
