diff options
| -rw-r--r-- | sql/base/world_database.sql | 16 | ||||
| -rw-r--r-- | sql/updates/10885_world_spell_script_names.sql | 27 | ||||
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.cpp | 250 | ||||
| -rwxr-xr-x | src/server/game/Spells/Auras/SpellAuras.cpp | 15 | ||||
| -rwxr-xr-x | src/server/game/Spells/Auras/SpellAuras.h | 1 | ||||
| -rwxr-xr-x | src/server/game/Spells/SpellScript.cpp | 4 | ||||
| -rwxr-xr-x | src/server/game/Spells/SpellScript.h | 7 | ||||
| -rw-r--r-- | src/server/scripts/Examples/example_spell.cpp | 14 | ||||
| -rw-r--r-- | src/server/scripts/Outland/BlackTemple/illidari_council.cpp | 33 | ||||
| -rw-r--r-- | src/server/scripts/PrecompiledHeaders/ScriptPCH.h | 1 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_dk.cpp | 239 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_druid.cpp | 29 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_generic.cpp | 36 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_mage.cpp | 95 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_paladin.cpp | 77 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_priest.cpp | 110 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_rogue.cpp | 79 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_shaman.cpp | 8 |
18 files changed, 753 insertions, 288 deletions
diff --git a/sql/base/world_database.sql b/sql/base/world_database.sql index afe2a8e2486..33d8b043793 100644 --- a/sql/base/world_database.sql +++ b/sql/base/world_database.sql @@ -26735,6 +26735,8 @@ LOCK TABLES `spell_script_names` WRITE; /*!40000 ALTER TABLE `spell_script_names` DISABLE KEYS */; INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES -- generic +( 39228, 'spell_gen_absorb0_hitlimit1'), +( 60218, 'spell_gen_absorb0_hitlimit1'), ( 6962, 'spell_gen_pet_summoned'), ( 10848, 'spell_gen_shroud_of_death'), ( 24750, 'spell_gen_trick'), @@ -26755,6 +26757,8 @@ INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES ( 72757, 'spell_pvp_trinket_wotf_shared_cd'), ( 46221, 'spell_gen_animal_blood'), -- instances +-- Black Temple +( 41475, 'spell_boss_lady_malande_shield'), -- Forge of Souls ( 68793, 'spell_bronjahm_magic_bane'), ( 69050, 'spell_bronjahm_magic_bane'), @@ -26912,6 +26916,7 @@ INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES -- warrior ( 12975, 'spell_warr_last_stand'), -- paladin +(-31850, 'spell_pal_ardent_defender'), ( 20425, 'spell_pal_judgement_of_command'), ( 63521, 'spell_pal_guarded_by_the_light'), (-20473, 'spell_pal_holy_shock'), @@ -26929,19 +26934,26 @@ INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES ( 55709, 'spell_hun_pet_heart_of_the_phoenix'), ( 54044, 'spell_hun_pet_carrion_feeder'), -- rogue +(-31228, 'spell_rog_cheat_death'), (-31130, 'spell_rog_nerves_of_steel'), ( 5938, 'spell_rog_shiv'), ( 14185, 'spell_rog_preparation'), (-51685, 'spell_rog_prey_on_the_weak'), -- priest +(-47788, 'spell_pri_guardian_spirit'), +( -8129, 'spell_pri_mana_burn'), ( 47948, 'spell_pri_pain_and_suffering_proc'), (-47540, 'spell_pri_penance'), -( -8129, 'spell_pri_mana_burn'), +( -17, 'spell_pri_reflective_shield_trigger'), -- death knight +( 50462, 'spell_dk_anti_magic_shell_raid'), +( 48707, 'spell_dk_anti_magic_shell_self'), +( 50461, 'spell_dk_anti_magic_zone'), (-49158, 'spell_dk_corpse_explosion'), ( 50524, 'spell_dk_runic_power_feed'), (-55090, 'spell_dk_scourge_strike'), (-49145, 'spell_dk_spell_deflection'), +(-52284, 'spell_dk_will_of_the_necropolis'), -- shaman (-51474, 'spell_sha_astral_shift'), ( 39610, 'spell_sha_mana_tide_totem'), @@ -26950,6 +26962,8 @@ INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES -- mage (-11113, 'spell_mage_blast_wave'), ( 11958, 'spell_mage_cold_snap'), +( -543, 'spell_mage_frost_warding_trigger'), +( -6143, 'spell_mage_frost_warding_trigger'), ( 31687, 'spell_mage_summon_water_elemental'), ( 32826, 'spell_mage_polymorph_visual'), -- warlock diff --git a/sql/updates/10885_world_spell_script_names.sql b/sql/updates/10885_world_spell_script_names.sql new file mode 100644 index 00000000000..2dc9a2f4f2b --- /dev/null +++ b/sql/updates/10885_world_spell_script_names.sql @@ -0,0 +1,27 @@ +DELETE FROM `spell_script_names` WHERE `spell_id`=41475 AND `ScriptName`='spell_boss_lady_malande_shield'; +DELETE FROM `spell_script_names` WHERE `spell_id`=-31850 AND `ScriptName`='spell_pal_ardent_defender'; +DELETE FROM `spell_script_names` WHERE `spell_id`=50462 AND `ScriptName`='spell_dk_anti_magic_shell_raid'; +DELETE FROM `spell_script_names` WHERE `spell_id`=48707 AND `ScriptName`='spell_dk_anti_magic_shell_self'; +DELETE FROM `spell_script_names` WHERE `spell_id`=50461 AND `ScriptName`='spell_dk_anti_magic_zone'; +DELETE FROM `spell_script_names` WHERE `spell_id`=-52284 AND `ScriptName`='spell_dk_will_of_the_necropolis'; +DELETE FROM `spell_script_names` WHERE `spell_id`=39228 AND `ScriptName`='spell_gen_absorb0_hitlimit1'; +DELETE FROM `spell_script_names` WHERE `spell_id`=60218 AND `ScriptName`='spell_gen_absorb0_hitlimit1'; +DELETE FROM `spell_script_names` WHERE `spell_id`=-543 AND `ScriptName`='spell_mage_frost_warding_trigger'; +DELETE FROM `spell_script_names` WHERE `spell_id`=-6143 AND `ScriptName`='spell_mage_frost_warding_trigger'; +DELETE FROM `spell_script_names` WHERE `spell_id`=-17 AND `ScriptName`='spell_pri_reflective_shield_trigger'; +DELETE FROM `spell_script_names` WHERE `spell_id`=-47788 AND `ScriptName`='spell_pri_guardian_spirit'; +DELETE FROM `spell_script_names` WHERE `spell_id`=-31228 AND `ScriptName`='spell_rog_cheat_death'; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +( 41475, 'spell_boss_lady_malande_shield'), +(-31850, 'spell_pal_ardent_defender'), +( 50462, 'spell_dk_anti_magic_shell_raid'), +( 48707, 'spell_dk_anti_magic_shell_self'), +( 50461, 'spell_dk_anti_magic_zone'), +(-52284, 'spell_dk_will_of_the_necropolis'), +( 39228, 'spell_gen_absorb0_hitlimit1'), +( 60218, 'spell_gen_absorb0_hitlimit1'), +( -543, 'spell_mage_frost_warding_trigger'), +( -6143, 'spell_mage_frost_warding_trigger'), +( -17, 'spell_pri_reflective_shield_trigger'), +(-47788, 'spell_pri_guardian_spirit'), +(-31228, 'spell_rog_cheat_death'); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 69bec5d20ea..dcaea3186cc 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -1614,10 +1614,6 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff dmgInfo.ResistDamage(damageResisted); } - // Death Prevention Aura - SpellEntry const* preventDeathSpell = NULL; - int32 preventDeathAmount = 0; - // Incanter's Absorption, for converting to spell power int32 incanterAbsorption = 0; @@ -1673,208 +1669,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff bool defaultPrevented = false; absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, absorb, defaultPrevented); - currentAbsorb = absorb; - switch (spellProto->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - // Reflective Shield (Lady Malande boss) - if (spellProto->Id == 41475) - { - int32 bp = std::min(int32(dmgInfo.GetDamage()), currentAbsorb) / 2; - pVictim->CastCustomSpell(this, 33619, &bp, NULL, NULL, true, NULL, *itr); - break; - } - if ((spellProto->Id == 39228) || // Argussian Compass - (spellProto->Id == 60218)) // Essence of Gossamer - { - // Max absorb stored in 1 dummy effect - int32 maxAbsorb = SpellMgr::CalculateSpellEffectAmount(spellProto, EFFECT_1); - if (maxAbsorb < currentAbsorb) - currentAbsorb = maxAbsorb; - break; - } - break; - } - case SPELLFAMILY_MAGE: - { - // possibly create BeforeEffectAbsorb for this? - // Frost ward and Fire Ward - if (spellProto->Category == 56) - { - // 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); - - 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; - } - case SPELLFAMILY_ROGUE: - { - // Cheat Death (make less prio with Guardian Spirit case) - if (spellProto->SpellIconID == 2109) - { - if (!preventDeathSpell && pVictim->ToPlayer()) - if (!pVictim->ToPlayer()->HasSpellCooldown(31231) && roll_chance_i(absorbAurEff->GetAmount())) - preventDeathSpell = absorbAurEff->GetSpellProto(); - continue; - } - break; - } - case SPELLFAMILY_PRIEST: - { - // Guardian Spirit - if (spellProto->SpellIconID == 2873) - { - preventDeathSpell = absorbAurEff->GetSpellProto(); - preventDeathAmount = absorbAurEff->GetAmount(); - continue; - } - // Power Word: Shield - if (spellProto->SpellFamilyFlags.IsEqual(0x1, 0, 0x400)) - { - if (pVictim == this) - break; - - Unit * caster = absorbAurEff->GetCaster(); - if (!caster) - break; - - // Reflective Shield - if (AuraEffect const * aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 566, EFFECT_0)) - switch(aurEff->GetMiscValue()) - { - case 5065: // Rank 1 - case 5064: // Rank 2 - { - int32 bp = CalculatePctN(std::min(int32(dmgInfo.GetDamage()), currentAbsorb), aurEff->GetAmount()); - pVictim->CastCustomSpell(this, 33619, &bp, NULL, NULL, true, NULL, *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) - { - if (!pVictim->ToPlayer()) - continue; - - 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 - dmgInfo.AbsorbDamage(dmgInfo.GetDamage()); - - uint32 defenseSkillValue = pVictim->GetDefenseSkillValue(); - // Max heal when defense skill denies critical hits from raid bosses - // Formula: max defense at level + 140 (raiting from gear) - uint32 reqDefForMaxHeal = pVictim->getLevel() * 5 + 140; - float pctFromDefense = (defenseSkillValue >= reqDefForMaxHeal) - ? 1.0f - : float(defenseSkillValue) / float(reqDefForMaxHeal); - - int32 healAmount = int32(pVictim->CountPctFromMaxHealth(uint32(absorbAurEff->GetAmount() * pctFromDefense))); - pVictim->CastCustomSpell(pVictim, 66235, &healAmount, NULL, NULL, true, NULL, *itr); - pVictim->ToPlayer()->AddSpellCooldown(66235, 0, time(NULL) + 120); - } - else if (remainingHealth < int32(allowedHealth)) - { - // Reduce damage that brings us under 35% (or full damage if we are already under 35%) by x% - uint32 damageToReduce = (pVictim->GetHealth() < allowedHealth) - ? dmgInfo.GetDamage() - : allowedHealth - remainingHealth; - dmgInfo.AbsorbDamage(CalculatePctN(damageToReduce, currentAbsorb)); - } - continue; - } - break; - } - case SPELLFAMILY_DEATHKNIGHT: - { - switch (spellProto->Id) - { - case 51271: // Unbreakable Armor - if (Unit * caster = absorbAurEff->GetCaster()) - { - uint32 absorbed = uint32(currentAbsorb * caster->GetArmor() * 0.01f); - - // Glyph of Unbreakable Armor - if (AuraEffect const * aurEff = caster->GetAuraEffect(58635, 0)) - AddPctN(absorbed, aurEff->GetAmount()); - - dmgInfo.AbsorbDamage(absorbed); - } - continue; - case 52284: // Will of the Necropolis - case 52285: - case 52286: - { - 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); - SpellEntry const * talentProto = sSpellStore.LookupEntry(sSpellMgr->GetSpellWithRank(49189, rank)); - - int32 minHp = int32(pVictim->CountPctFromMaxHealth(SpellMgr::CalculateSpellEffectAmount(talentProto, EFFECT_0, absorbAurEff->GetCaster()))); - // Damage that would take you below [effect0] health or taken while you are at [effect0] - if (remainingHp < minHp) - { - uint32 absorbed = uint32(currentAbsorb * dmgInfo.GetDamage() * 0.01f); - dmgInfo.AbsorbDamage(absorbed); - } - continue; - } - case 48707: // Anti-Magic Shell (on self) - { - // 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(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) - dmgInfo.AbsorbDamage(CalculatePctN(dmgInfo.GetDamage(), currentAbsorb)); - continue; - case 50461: // Anti-Magic Zone - if (Unit * caster = absorbAurEff->GetCaster()) - { - int32 absorbed = CalculatePctN(dmgInfo.GetDamage(), currentAbsorb); - int32 canabsorb = caster->GetHealth(); - if (canabsorb < absorbed) - absorbed = canabsorb; - - dmgInfo.AbsorbDamage(absorbed); - } - continue; - default: - break; - } - break; - } - default: - break; - } if (defaultPrevented) continue; @@ -1892,6 +1687,9 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff if (spellProto->SpellFamilyName == SPELLFAMILY_MAGE && spellProto->SpellFamilyFlags[2] & 0x8) incanterAbsorption += currentAbsorb; + absorb = currentAbsorb; + absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, absorb); + // Check if our aura is using amount to count damage if (absorbAurEff->GetAmount() >= 0) { @@ -1950,7 +1748,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff } // split damage auras - only when not damaging self - if (pVictim != this) + 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 @@ -2021,46 +1819,6 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff } } - // Apply death prevention spells effects - if (auraAbsorbMod < 100) // Do nothing if 100% absorb ignore - if (preventDeathSpell && (dmgInfo.GetDamage() >= int32(pVictim->GetHealth()))) - { - switch(preventDeathSpell->SpellFamilyName) - { - case SPELLFAMILY_ROGUE: - { - // Cheat Death - if (preventDeathSpell->SpellIconID == 2109) - { - pVictim->CastSpell(pVictim, 31231, true); - pVictim->ToPlayer()->AddSpellCooldown(31231, 0, time(NULL) + 60); - - uint32 health10 = pVictim->CountPctFromMaxHealth(10); - - // 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; - } - case SPELLFAMILY_PRIEST: - { - // Guardian Spirit - if (preventDeathSpell->SpellIconID == 2873) - { - int32 healAmount = int32(pVictim->CountPctFromMaxHealth(preventDeathAmount)); - pVictim->RemoveAurasDueToSpell(preventDeathSpell->Id); - pVictim->CastCustomSpell(pVictim, 48153, &healAmount, NULL, NULL, true); - dmgInfo.AbsorbDamage(dmgInfo.GetDamage()); - } - break; - } - } - } - *resist = dmgInfo.GetResist(); *absorb = dmgInfo.GetAbsorb(); diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 5068de484af..4642b15c724 100755 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1785,6 +1785,21 @@ void Aura::CallScriptEffectAbsorbHandlers(AuraEffect * aurEff, AuraApplication c } } +void Aura::CallScriptEffectAfterAbsorbHandlers(AuraEffect * aurEff, AuraApplication const * aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount) +{ + for(std::list<AuraScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB, aurApp); + std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin(); + for(; effItr != effEndItr ; ++effItr) + { + if ((*effItr).IsEffectAffected(m_spellProto, aurEff->GetEffIndex())) + (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount); + } + (*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 ab9a56be7fc..366373f6b53 100755 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -175,6 +175,7 @@ class Aura 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); + void CallScriptEffectAfterAbsorbHandlers(AuraEffect * aurEff, AuraApplication const * aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount); 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 482a185f590..e175e9d688e 100755 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -447,6 +447,10 @@ 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<EffectAbsorbHandler>::iterator itr = AfterEffectAbsorb.begin(); itr != AfterEffectAbsorb.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()); + return _SpellScript::_Validate(entry); } diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 2d5d81e6310..ad231d757f5 100755 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -283,6 +283,7 @@ enum AuraScriptHookType AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC, AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD, AURA_SCRIPT_HOOK_EFFECT_ABSORB, + AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB, /*AURA_SCRIPT_HOOK_APPLY, AURA_SCRIPT_HOOK_REMOVE,*/ }; @@ -447,6 +448,12 @@ class AuraScript : public _SpellScript HookList<EffectAbsorbHandler> OnEffectAbsorb; #define AuraEffectAbsorbFn(F, I) EffectAbsorbFunction(&F, I) + // executed after absorb aura effect to reduced damage to target - absorbAmount is real amount absorbed by aura + // example: OnEffectAbsorb += AuraEffectAbsorbFn(class::function, EffectIndexSpecifier); + // where function is: void function (AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount); + HookList<EffectAbsorbHandler> AfterEffectAbsorb; + #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); diff --git a/src/server/scripts/Examples/example_spell.cpp b/src/server/scripts/Examples/example_spell.cpp index 8d44cb92a4d..2a9d9a605c4 100644 --- a/src/server/scripts/Examples/example_spell.cpp +++ b/src/server/scripts/Examples/example_spell.cpp @@ -285,14 +285,6 @@ class spell_ex_absorb_aura : public SpellScriptLoader SPELL_TRIGGERED = 18282 }; - bool Validate(SpellEntry const * /*spellEntry*/) - { - // check if spellid exists in dbc, we will trigger it later - if (!sSpellStore.LookupEntry(SPELL_TRIGGERED)) - return false; - return true; - } - void HandleOnEffectAbsorb(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) { sLog->outString("Our aura is now absorbing damage done to us!"); @@ -300,6 +292,11 @@ class spell_ex_absorb_aura : public SpellScriptLoader absorbAmount = dmgInfo.GetDamage(); } + void HandleAfterEffectAbsorb(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + sLog->outString("Our aura has absorbed %u damage!", absorbAmount); + } + /*void HandleAfterAbsorb(DamageInfo & dmgInfo) { sLog->outString("Our auras have just absorbed damage done to us!"); @@ -309,6 +306,7 @@ class spell_ex_absorb_aura : public SpellScriptLoader void Register() { OnEffectAbsorb += AuraEffectAbsorbFn(spell_ex_absorb_auraAuraScript::HandleOnEffectAbsorb, EFFECT_0); + AfterEffectAbsorb += AuraEffectAbsorbFn(spell_ex_absorb_auraAuraScript::HandleAfterEffectAbsorb, EFFECT_0); //AfterAbsorb += AuraAbsorbFn(spell_ex_absorb_auraAuraScript::HandleAfterAbsorb); } }; diff --git a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp index efcc8285984..9dc832d3056 100644 --- a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp +++ b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp @@ -89,6 +89,7 @@ static CouncilYells CouncilEnrage[]= #define SPELL_EMPOWERED_SMITE 41471 #define SPELL_CIRCLE_OF_HEALING 41455 #define SPELL_REFLECTIVE_SHIELD 41475 +#define SPELL_REFLECTIVE_SHIELD_T 33619 #define SPELL_DIVINE_WRATH 41472 #define SPELL_HEAL_VISUAL 24171 @@ -878,14 +879,43 @@ public: } } }; - }; +// SPELL_REFLECTIVE_SHIELD +class spell_boss_lady_malande_shield : public SpellScriptLoader +{ +public: + spell_boss_lady_malande_shield() : SpellScriptLoader("spell_boss_lady_malande_shield") { } + class spell_boss_lady_malande_shield_AuraScript : public AuraScript + { + PrepareAuraScript(spell_boss_lady_malande_shield_AuraScript); + bool Validate(SpellEntry const * /*spellEntry*/) + { + return sSpellStore.LookupEntry(SPELL_REFLECTIVE_SHIELD_T); + } + void Trigger(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + Unit * target = GetTarget(); + if (dmgInfo.GetAttacker() == target) + return; + int32 bp = absorbAmount / 2; + target->CastCustomSpell(dmgInfo.GetAttacker(), SPELL_REFLECTIVE_SHIELD_T, &bp, NULL, NULL, true, NULL, aurEff); + } + void Register() + { + AfterEffectAbsorb += AuraEffectAbsorbFn(spell_boss_lady_malande_shield_AuraScript::Trigger, EFFECT_0); + } + }; + AuraScript *GetAuraScript() const + { + return new spell_boss_lady_malande_shield_AuraScript(); + } +}; void AddSC_boss_illidari_council() { @@ -895,4 +925,5 @@ void AddSC_boss_illidari_council() new boss_lady_malande(); new boss_veras_darkshadow(); new boss_high_nethermancer_zerevor(); + new spell_boss_lady_malande_shield(); } diff --git a/src/server/scripts/PrecompiledHeaders/ScriptPCH.h b/src/server/scripts/PrecompiledHeaders/ScriptPCH.h index 2cba3171202..1cd25309055 100644 --- a/src/server/scripts/PrecompiledHeaders/ScriptPCH.h +++ b/src/server/scripts/PrecompiledHeaders/ScriptPCH.h @@ -23,6 +23,7 @@ #include "DBCStores.h" #include "ObjectMgr.h" #include "SpellScript.h" +#include "SpellAuraEffects.h" #ifdef _WIN32 #include <windows.h> diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 706853db0ae..35656dd9af4 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -32,6 +32,165 @@ enum DeathKnightSpells DK_SPELL_SCOURGE_STRIKE_TRIGGERED = 70890, }; +// 50462 - Anti-Magic Shell (on raid member) +class spell_dk_anti_magic_shell_raid : public SpellScriptLoader +{ +public: + spell_dk_anti_magic_shell_raid() : SpellScriptLoader("spell_dk_anti_magic_shell_raid") { } + + class spell_dk_anti_magic_shell_raid_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dk_anti_magic_shell_raid_AuraScript); + + uint32 absorbPct; + + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0, GetCaster()); + return true; + } + + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) + { + // TODO: this should absorb limited amount of damage, but no info on calculation formula + amount = -1; + } + + void Absorb(AuraEffect * /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + absorbAmount = CalculatePctN(dmgInfo.GetDamage(), absorbPct); + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_anti_magic_shell_raid_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_shell_raid_AuraScript::Absorb, EFFECT_0); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_dk_anti_magic_shell_raid_AuraScript(); + } +}; + +// 48707 - Anti-Magic Shell (on self) +class spell_dk_anti_magic_shell_self : public SpellScriptLoader +{ +public: + spell_dk_anti_magic_shell_self() : SpellScriptLoader("spell_dk_anti_magic_shell_self") { } + + class spell_dk_anti_magic_shell_self_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dk_anti_magic_shell_self_AuraScript); + + enum Spells + { + DK_SPELL_RUNIC_POWER_ENERGIZE = 49088, + }; + + uint32 absorbPct, hpPct; + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0, GetCaster()); + hpPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_1, GetCaster()); + return true; + } + + bool Validate(SpellEntry const * /*spellEntry*/) + { + return sSpellStore.LookupEntry(DK_SPELL_RUNIC_POWER_ENERGIZE); + } + + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) + { + // Set absorbtion amount to unlimited + amount = -1; + } + + void Absorb(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + absorbAmount = std::min(CalculatePctN(dmgInfo.GetDamage(), absorbPct), GetTarget()->CountPctFromMaxHealth(hpPct)); + } + + void Trigger(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + Unit * target = GetTarget(); + // damage absorbed by Anti-Magic Shell energizes the DK with additional runic power. + // This, if I'm not mistaken, shows that we get back ~20% of the absorbed damage as runic power. + int32 bp = absorbAmount * 2 / 10; + target->CastCustomSpell(target, DK_SPELL_RUNIC_POWER_ENERGIZE, &bp, NULL, NULL, true, NULL, aurEff); + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_anti_magic_shell_self_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_shell_self_AuraScript::Absorb, EFFECT_0); + AfterEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_shell_self_AuraScript::Trigger, EFFECT_0); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_dk_anti_magic_shell_self_AuraScript(); + } +}; + +// 50461 - Anti-Magic Zone +class spell_dk_anti_magic_zone : public SpellScriptLoader +{ +public: + spell_dk_anti_magic_zone() : SpellScriptLoader("spell_dk_anti_magic_zone") { } + + class spell_dk_anti_magic_zone_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dk_anti_magic_zone_AuraScript); + + enum Spells + { + DK_SPELL_ANTI_MAGIC_SHELL_TALENT = 51052, + }; + + uint32 absorbPct; + + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0, GetCaster()); + return true; + } + + bool Validate(SpellEntry const * /*spellEntry*/) + { + return sSpellStore.LookupEntry(DK_SPELL_ANTI_MAGIC_SHELL_TALENT); + } + + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) + { + SpellEntry const * talentSpell = sSpellStore.LookupEntry(DK_SPELL_ANTI_MAGIC_SHELL_TALENT); + amount = SpellMgr::CalculateSpellEffectAmount(talentSpell, EFFECT_0, GetCaster()); + // assume caster is a player here + if (Unit * caster = GetCaster()) + amount += 2 * caster->ToPlayer()->GetTotalAttackPowerValue(BASE_ATTACK); + } + + void Absorb(AuraEffect * /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + absorbAmount = CalculatePctN(dmgInfo.GetDamage(), absorbPct); + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_anti_magic_zone_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_zone_AuraScript::Absorb, EFFECT_0); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_dk_anti_magic_zone_AuraScript(); + } +}; + // 49158 Corpse Explosion (51325, 51326, 51327, 51328) class spell_dk_corpse_explosion : public SpellScriptLoader { @@ -168,9 +327,15 @@ public: PrepareAuraScript(spell_dk_spell_deflection_AuraScript); uint32 absorbPct; + + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0, GetCaster()); + return true; + } + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) { - absorbPct = amount; // Set absorbtion amount to unlimited amount = -1; } @@ -195,11 +360,83 @@ public: } }; +// 52284 - Will of the Necropolis +class spell_dk_will_of_the_necropolis : public SpellScriptLoader +{ +public: + spell_dk_will_of_the_necropolis() : SpellScriptLoader("spell_dk_will_of_the_necropolis") { } + + class spell_dk_will_of_the_necropolis_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dk_will_of_the_necropolis_AuraScript); + + enum Spells + { + DK_SPELL_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189, + DK_SPELL_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284, + }; + bool Validate(SpellEntry const *spellEntry) + { + // can't use other spell than will of the necropolis due to spell_ranks dependency + if (sSpellMgr->GetFirstSpellInChain(DK_SPELL_WILL_OF_THE_NECROPOLIS_AURA_R1) != sSpellMgr->GetFirstSpellInChain(spellEntry->Id)) + return false; + + uint8 rank = sSpellMgr->GetSpellRank(spellEntry->Id); + if (!sSpellMgr->GetSpellWithRank(DK_SPELL_WILL_OF_THE_NECROPOLIS_TALENT_R1, rank, true)) + return false; + + return true; + } + + uint32 absorbPct; + + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0, GetCaster()); + return true; + } + + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) + { + // Set absorbtion amount to unlimited + amount = -1; + } + + void Absorb(AuraEffect * /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + // min pct of hp is stored in effect 0 of talent spell + uint32 rank = sSpellMgr->GetSpellRank(GetSpellProto()->Id); + SpellEntry const * talentProto = sSpellStore.LookupEntry(sSpellMgr->GetSpellWithRank(DK_SPELL_WILL_OF_THE_NECROPOLIS_TALENT_R1, rank)); + + int32 remainingHp = int32(GetTarget()->GetHealth() - dmgInfo.GetDamage()); + int32 minHp = int32(GetTarget()->CountPctFromMaxHealth(SpellMgr::CalculateSpellEffectAmount(talentProto, EFFECT_0, GetCaster()))); + + // Damage that would take you below [effect0] health or taken while you are at [effect0] + if (remainingHp < minHp) + absorbAmount = CalculatePctN(dmgInfo.GetDamage(), absorbPct); + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_will_of_the_necropolis_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_will_of_the_necropolis_AuraScript::Absorb, EFFECT_0); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_dk_will_of_the_necropolis_AuraScript(); + } +}; void AddSC_deathknight_spell_scripts() { + new spell_dk_anti_magic_shell_raid(); + new spell_dk_anti_magic_shell_self(); + new spell_dk_anti_magic_zone(); new spell_dk_corpse_explosion(); new spell_dk_runic_power_feed(); new spell_dk_scourge_strike(); new spell_dk_spell_deflection(); + new spell_dk_will_of_the_necropolis(); } diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 47e5ad00a87..0e5c1dd95ef 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -94,9 +94,15 @@ public: PrepareAuraScript(spell_dru_moonkin_form_passive_AuraScript); uint32 absorbPct; + + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0, GetCaster()); + return true; + } + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) { - absorbPct = amount; // Set absorbtion amount to unlimited amount = -1; } @@ -132,9 +138,15 @@ public: PrepareAuraScript(spell_dru_primal_tenacity_AuraScript); uint32 absorbPct; + + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_1, GetCaster()); + return true; + } + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) { - absorbPct = amount; // Set absorbtion amount to unlimited amount = -1; } @@ -170,19 +182,22 @@ public: PrepareAuraScript(spell_dru_savage_defense_AuraScript); uint32 absorbPct; + + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0, GetCaster()); + return true; + } + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) { - absorbPct = amount; // Set absorbtion amount to unlimited amount = -1; } void Absorb(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) { - // don't waste charge when no dmg - if (!dmgInfo.GetDamage()) - return; - absorbAmount = CalculatePctN(GetTarget()->GetTotalAttackPowerValue(BASE_ATTACK), absorbPct); + absorbAmount = int32(CalculatePctN(GetTarget()->GetTotalAttackPowerValue(BASE_ATTACK), absorbPct)); aurEff->SetAmount(0); } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index e99d1e44548..0f664c3d829 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -25,6 +25,41 @@ #include "ScriptPCH.h" #include "SpellAuraEffects.h" +class spell_gen_absorb0_hitlimit1 : public SpellScriptLoader +{ +public: + spell_gen_absorb0_hitlimit1() : SpellScriptLoader("spell_gen_absorb0_hitlimit1") { } + + class spell_gen_absorb0_hitlimit1_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_absorb0_hitlimit1_AuraScript); + + uint32 limit; + + bool Load() + { + // Max absorb stored in 1 dummy effect + limit = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_1); + return true; + } + + void Absorb(AuraEffect * /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + absorbAmount = std::min(limit, absorbAmount); + } + + void Register() + { + OnEffectAbsorb += AuraEffectAbsorbFn(spell_gen_absorb0_hitlimit1_AuraScript::Absorb, EFFECT_0); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_gen_absorb0_hitlimit1_AuraScript(); + } +}; + // 41337 Aura of Anger class spell_gen_aura_of_anger : public SpellScriptLoader { @@ -562,6 +597,7 @@ class spell_gen_shroud_of_death : public SpellScriptLoader void AddSC_generic_spell_scripts() { + new spell_gen_absorb0_hitlimit1(); new spell_gen_aura_of_anger(); new spell_gen_burn_brutallus(); new spell_gen_leeching_swarm(); diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index 901f36a3065..d4794e10b68 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -38,6 +38,39 @@ enum MageSpells SPELL_MAGE_GLYPH_OF_BLAST_WAVE = 62126, }; +class spell_mage_blast_wave : public SpellScriptLoader +{ + public: + spell_mage_blast_wave() : SpellScriptLoader("spell_mage_blast_wave") { } + + class spell_mage_blast_wave_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mage_blast_wave_SpellScript) + bool Validate(SpellEntry const * /*spellEntry*/) + { + if (!sSpellStore.LookupEntry(SPELL_MAGE_GLYPH_OF_BLAST_WAVE)) + return false; + return true; + } + + void HandleKnockBack(SpellEffIndex effIndex) + { + if (GetCaster()->HasAura(SPELL_MAGE_GLYPH_OF_BLAST_WAVE)) + PreventHitDefaultEffect(effIndex); + } + + void Register() + { + OnEffect += SpellEffectFn(spell_mage_blast_wave_SpellScript::HandleKnockBack, EFFECT_2, SPELL_EFFECT_KNOCK_BACK); + } + }; + + SpellScript * GetSpellScript() const + { + return new spell_mage_blast_wave_SpellScript(); + } +}; + class spell_mage_cold_snap : public SpellScriptLoader { public: @@ -176,43 +209,61 @@ class spell_mage_summon_water_elemental : public SpellScriptLoader } }; -class spell_mage_blast_wave : public SpellScriptLoader +// Frost Ward and Fire Ward +class spell_mage_frost_warding_trigger : public SpellScriptLoader { - public: - spell_mage_blast_wave() : SpellScriptLoader("spell_mage_blast_wave") { } +public: + spell_mage_frost_warding_trigger() : SpellScriptLoader("spell_mage_frost_warding_trigger") { } - class spell_mage_blast_wave_SpellScript : public SpellScript + class spell_mage_frost_warding_trigger_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mage_frost_warding_trigger_AuraScript); + + enum Spells { - PrepareSpellScript(spell_mage_blast_wave_SpellScript) - bool Validate(SpellEntry const * /*spellEntry*/) - { - if (!sSpellStore.LookupEntry(SPELL_MAGE_GLYPH_OF_BLAST_WAVE)) - return false; - return true; - } + SPELL_MAGE_FROST_WARDING_TRIGGERED = 57776, + SPELL_MAGE_FROST_WARDING_R1 = 28332, + }; - void HandleKnockBack(SpellEffIndex effIndex) - { - if (GetCaster()->HasAura(SPELL_MAGE_GLYPH_OF_BLAST_WAVE)) - PreventHitDefaultEffect(effIndex); - } + bool Validate(SpellEntry const * /*spellEntry*/) + { + return sSpellStore.LookupEntry(SPELL_MAGE_FROST_WARDING_TRIGGERED) + && sSpellStore.LookupEntry(SPELL_MAGE_FROST_WARDING_R1); + } - void Register() + void Absorb(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + Unit * target = GetTarget(); + if (AuraEffect * talentAurEff = target->GetAuraEffectOfRankedSpell(SPELL_MAGE_FROST_WARDING_R1, EFFECT_0)) { - OnEffect += SpellEffectFn(spell_mage_blast_wave_SpellScript::HandleKnockBack, EFFECT_2, SPELL_EFFECT_KNOCK_BACK); + int32 chance = SpellMgr::CalculateSpellEffectAmount(talentAurEff->GetSpellProto(), EFFECT_1); + + if (roll_chance_i(chance)) + { + absorbAmount = dmgInfo.GetDamage(); + int32 bp = absorbAmount; + target->CastCustomSpell(target, SPELL_MAGE_FROST_WARDING_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff); + } } - }; + } - SpellScript * GetSpellScript() const + void Register() { - return new spell_mage_blast_wave_SpellScript(); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_mage_frost_warding_trigger_AuraScript::Absorb, EFFECT_0); } + }; + + AuraScript *GetAuraScript() const + { + return new spell_mage_frost_warding_trigger_AuraScript(); + } }; void AddSC_mage_spell_scripts() { + new spell_mage_blast_wave; new spell_mage_cold_snap; + new spell_mage_frost_warding_trigger(); new spell_mage_polymorph_cast_visual; new spell_mage_summon_water_elemental; - new spell_mage_blast_wave; } diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index b53f172bfdf..828fa5de699 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -39,6 +39,82 @@ enum PaladinSpells SPELL_BLESSING_OF_LOWER_CITY_SHAMAN = 37881, }; +// 31850 - Ardent Defender +class spell_pal_ardent_defender : public SpellScriptLoader +{ +public: + spell_pal_ardent_defender() : SpellScriptLoader("spell_pal_ardent_defender") { } + + class spell_pal_ardent_defender_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pal_ardent_defender_AuraScript); + + uint32 absorbPct, healPct; + + enum Spell + { + PAL_SPELL_ARDENT_DEFENDER_HEAL = 66235, + }; + + bool Load() + { + healPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_1); + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0); + return GetUnitOwner()->ToPlayer(); + } + + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) + { + // Set absorbtion amount to unlimited + amount = -1; + } + + void Absorb(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + Unit * pVictim = GetTarget(); + int32 remainingHealth = pVictim->GetHealth() - dmgInfo.GetDamage(); + uint32 allowedHealth = pVictim->CountPctFromMaxHealth(35); + // If damage kills us + if (remainingHealth <= 0 && !pVictim->ToPlayer()->HasSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL)) + { + // Cast healing spell, completely avoid damage + absorbAmount = dmgInfo.GetDamage(); + + uint32 defenseSkillValue = pVictim->GetDefenseSkillValue(); + // Max heal when defense skill denies critical hits from raid bosses + // Formula: max defense at level + 140 (raiting from gear) + uint32 reqDefForMaxHeal = pVictim->getLevel() * 5 + 140; + float pctFromDefense = (defenseSkillValue >= reqDefForMaxHeal) + ? 1.0f + : float(defenseSkillValue) / float(reqDefForMaxHeal); + + int32 healAmount = int32(pVictim->CountPctFromMaxHealth(uint32(healPct * pctFromDefense))); + pVictim->CastCustomSpell(pVictim, PAL_SPELL_ARDENT_DEFENDER_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff); + pVictim->ToPlayer()->AddSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, time(NULL) + 120); + } + else if (remainingHealth < int32(allowedHealth)) + { + // Reduce damage that brings us under 35% (or full damage if we are already under 35%) by x% + uint32 damageToReduce = (pVictim->GetHealth() < allowedHealth) + ? dmgInfo.GetDamage() + : allowedHealth - remainingHealth; + absorbAmount = CalculatePctN(damageToReduce, absorbPct); + } + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pal_ardent_defender_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_pal_ardent_defender_AuraScript::Absorb, EFFECT_0); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_pal_ardent_defender_AuraScript(); + } +}; + class spell_pal_blessing_of_faith : public SpellScriptLoader { public: @@ -253,6 +329,7 @@ public: void AddSC_paladin_spell_scripts() { + new spell_pal_ardent_defender(); new spell_pal_blessing_of_faith(); new spell_pal_blessing_of_sanctuary(); new spell_pal_guarded_by_the_light(); diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index 6631d840309..b149f182a1d 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -31,6 +31,66 @@ enum PriestSpells PRIEST_SPELL_PENANCE_R1_HEAL = 47757, }; +// Guardian Spirit +class spell_pri_guardian_spirit : public SpellScriptLoader +{ +public: + spell_pri_guardian_spirit() : SpellScriptLoader("spell_pri_guardian_spirit") { } + + class spell_pri_guardian_spirit_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pri_guardian_spirit_AuraScript); + + uint32 healPct; + + enum Spell + { + PRI_SPELL_GUARDIAN_SPIRIT_HEAL = 48153, + }; + + bool Validate(SpellEntry const * /*spellEntry*/) + { + return sSpellStore.LookupEntry(PRI_SPELL_GUARDIAN_SPIRIT_HEAL); + } + + bool Load() + { + healPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_1); + return true; + } + + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) + { + // Set absorbtion amount to unlimited + amount = -1; + } + + void Absorb(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + Unit * target = GetTarget(); + if (dmgInfo.GetDamage() < target->GetHealth()) + return; + + int32 healAmount = int32(target->CountPctFromMaxHealth(healPct)); + // remove the aura now, we don't want 40% healing bonus + Remove(AURA_REMOVE_BY_ENEMY_SPELL); + target->CastCustomSpell(target, PRI_SPELL_GUARDIAN_SPIRIT_HEAL, &healAmount, NULL, NULL, true); + absorbAmount = dmgInfo.GetDamage(); + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pri_guardian_spirit_AuraScript::CalculateAmount, EFFECT_1, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_pri_guardian_spirit_AuraScript::Absorb, EFFECT_1); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_pri_guardian_spirit_AuraScript(); + } +}; + class spell_pri_mana_burn : public SpellScriptLoader { public: @@ -148,9 +208,59 @@ class spell_pri_penance : public SpellScriptLoader } }; +// Reflective Shield +class spell_pri_reflective_shield_trigger : public SpellScriptLoader +{ +public: + spell_pri_reflective_shield_trigger() : SpellScriptLoader("spell_pri_reflective_shield_trigger") { } + + class spell_pri_reflective_shield_trigger_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pri_reflective_shield_trigger_AuraScript); + + enum Spells + { + SPELL_PRI_REFLECTIVE_SHIELD_TRIGGERED = 33619, + SPELL_PRI_REFLECTIVE_SHIELD_R1 = 33201, + }; + + bool Validate(SpellEntry const * /*spellEntry*/) + { + return sSpellStore.LookupEntry(SPELL_PRI_REFLECTIVE_SHIELD_TRIGGERED) && sSpellStore.LookupEntry(SPELL_PRI_REFLECTIVE_SHIELD_R1); + } + + void Trigger(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + Unit * target = GetTarget(); + if (dmgInfo.GetAttacker() == target) + return; + Unit * caster = GetCaster(); + if (!caster) + return; + if (AuraEffect * talentAurEff = target->GetAuraEffectOfRankedSpell(SPELL_PRI_REFLECTIVE_SHIELD_R1, EFFECT_0)) + { + int32 bp = CalculatePctN(absorbAmount, talentAurEff->GetAmount()); + target->CastCustomSpell(dmgInfo.GetAttacker(), SPELL_PRI_REFLECTIVE_SHIELD_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff); + } + } + + void Register() + { + AfterEffectAbsorb += AuraEffectAbsorbFn(spell_pri_reflective_shield_trigger_AuraScript::Trigger, EFFECT_0); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_pri_reflective_shield_trigger_AuraScript(); + } +}; + void AddSC_priest_spell_scripts() { + new spell_pri_guardian_spirit(); new spell_pri_mana_burn; new spell_pri_pain_and_suffering_proc; new spell_pri_penance; + new spell_pri_reflective_shield_trigger(); } diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index ffae231839c..6d1afef3460 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -30,6 +30,76 @@ enum RogueSpells ROGUE_SPELL_PREY_ON_THE_WEAK = 58670, }; +// Cheat Death +class spell_rog_cheat_death : public SpellScriptLoader +{ +public: + spell_rog_cheat_death() : SpellScriptLoader("spell_rog_cheat_death") { } + + class spell_rog_cheat_death_AuraScript : public AuraScript + { + PrepareAuraScript(spell_rog_cheat_death_AuraScript); + + uint32 absorbChance; + + enum Spell + { + ROG_SPELL_CHEAT_DEATH_COOLDOWN = 31231, + }; + + bool Validate(SpellEntry const * /*spellEntry*/) + { + return sSpellStore.LookupEntry(ROG_SPELL_CHEAT_DEATH_COOLDOWN); + } + + bool Load() + { + absorbChance = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0); + return GetUnitOwner()->ToPlayer(); + } + + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) + { + // Set absorbtion amount to unlimited + amount = -1; + } + + void Absorb(AuraEffect * aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + Unit * target = GetTarget(); + if (dmgInfo.GetDamage() < target->GetHealth()) + return; + if (target->ToPlayer()->HasSpellCooldown(ROG_SPELL_CHEAT_DEATH_COOLDOWN)) + return; + if (!roll_chance_i(absorbChance)) + return; + + target->CastSpell(target, ROG_SPELL_CHEAT_DEATH_COOLDOWN, true); + target->ToPlayer()->AddSpellCooldown(ROG_SPELL_CHEAT_DEATH_COOLDOWN, 0, time(NULL) + 60); + + uint32 health10 = target->CountPctFromMaxHealth(10); + + // hp > 10% - absorb hp till 10% + if (target->GetHealth() > health10) + absorbAmount = dmgInfo.GetDamage() - target->GetHealth() + health10; + // hp lower than 10% - absorb everything + else + absorbAmount = dmgInfo.GetDamage(); + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_rog_cheat_death_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_rog_cheat_death_AuraScript::Absorb, EFFECT_0); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_rog_cheat_death_AuraScript(); + } +}; + // 31130 - Nerves of Steel class spell_rog_nerves_of_steel : public SpellScriptLoader { @@ -41,9 +111,15 @@ public: PrepareAuraScript(spell_rog_nerves_of_steel_AuraScript); uint32 absorbPct; + + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0, GetCaster()); + return true; + } + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) { - absorbPct = amount; // Set absorbtion amount to unlimited amount = -1; } @@ -216,6 +292,7 @@ class spell_rog_shiv : public SpellScriptLoader void AddSC_rogue_spell_scripts() { + new spell_rog_cheat_death(); new spell_rog_nerves_of_steel(); new spell_rog_preparation(); new spell_rog_prey_on_the_weak(); diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index bf8e179a438..7c59c5227ca 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -47,9 +47,15 @@ public: PrepareAuraScript(spell_sha_astral_shift_AuraScript); uint32 absorbPct; + + bool Load() + { + absorbPct = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_0, GetCaster()); + return true; + } + void CalculateAmount(AuraEffect const * /*aurEff*/, int32 & amount, bool & canBeRecalculated) { - absorbPct = amount; // Set absorbtion amount to unlimited amount = -1; } |
