From 0affdfbda02d91af1f9f1327e6420c8f56321daf Mon Sep 17 00:00:00 2001 From: hondacrx Date: Fri, 29 Jul 2022 17:42:49 -0400 Subject: [PATCH] Core/Spells: Implement OnEffectAbsorbHeal and AfterEffectAbsorbHeal hooks Port From (https://github.com/TrinityCore/TrinityCore/commit/44236c70787eae0239fb636e217305dfa043bf71) --- Source/Game/Entities/Unit/Unit.cs | 70 +++++++++++++--------------- Source/Game/Scripting/SpellScript.cs | 26 +++++++++++ Source/Game/Spells/Auras/Aura.cs | 30 +++++++++++- 3 files changed, 87 insertions(+), 39 deletions(-) diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index ea4e7ca3a..035e67661 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -3593,57 +3593,53 @@ namespace Game.Entities if (healInfo.GetHeal() == 0) return; - // Need remove expired auras after - bool existExpired = false; - // absorb without mana cost var vHealAbsorb = healInfo.GetTarget().GetAuraEffectsByType(AuraType.SchoolHealAbsorb); - for (var i = 0; i < vHealAbsorb.Count; ++i) + for (var i = 0; i < vHealAbsorb.Count && healInfo.GetHeal() > 0; ++i) { - var eff = vHealAbsorb[i]; - if (healInfo.GetHeal() <= 0) - break; - - if (!Convert.ToBoolean(eff.GetMiscValue() & (int)healInfo.GetSpellInfo().SchoolMask)) + AuraEffect absorbAurEff = vHealAbsorb[i]; + // Check if aura was removed during iteration - we don't need to work on such auras + AuraApplication aurApp = absorbAurEff.GetBase().GetApplicationOfTarget(healInfo.GetTarget().GetGUID()); + if (aurApp == null) continue; - // Max Amount can be absorbed by this aura - int currentAbsorb = eff.GetAmount(); - - // Found empty aura (impossible but..) - if (currentAbsorb <= 0) - { - existExpired = true; + if ((absorbAurEff.GetMiscValue() & (int)healInfo.GetSchoolMask()) == 0) + continue; + + // get amount which can be still absorbed by the aura + int 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; + + uint tempAbsorb = (uint)currentAbsorb; + + bool defaultPrevented = false; + + absorbAurEff.GetBase().CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, healInfo, ref tempAbsorb, ref defaultPrevented); + currentAbsorb = (int)tempAbsorb; + + if (defaultPrevented) continue; - } // currentAbsorb - damage can be absorbed by shield - // If need absorb less damage currentAbsorb = (int)Math.Min(healInfo.GetHeal(), currentAbsorb); healInfo.AbsorbHeal((uint)currentAbsorb); - // Reduce shield amount - eff.ChangeAmount(eff.GetAmount() - currentAbsorb); - // Need remove it later - if (eff.GetAmount() <= 0) - existExpired = true; - } + tempAbsorb = (uint)currentAbsorb; + absorbAurEff.GetBase().CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, healInfo, ref tempAbsorb); - // Remove all expired absorb auras - if (existExpired) - { - for (var i = 0; i < vHealAbsorb.Count;) + // Reduce shield amount + absorbAurEff.ChangeAmount(absorbAurEff.GetAmount() - currentAbsorb); + // Check if our aura is using amount to count damage + if (absorbAurEff.GetAmount() >= 0) { - AuraEffect auraEff = vHealAbsorb[i]; - ++i; - if (auraEff.GetAmount() <= 0) - { - uint removedAuras = healInfo.GetTarget().m_removedAurasCount; - auraEff.GetBase().Remove(AuraRemoveMode.EnemySpell); - if (removedAuras + 1 < healInfo.GetTarget().m_removedAurasCount) - i = 0; - } + // Reduce shield amount + absorbAurEff.ChangeAmount(absorbAurEff.GetAmount() - currentAbsorb); + // Aura cannot absorb anything more - remove it + if (absorbAurEff.GetAmount() <= 0) + absorbAurEff.GetBase().Remove(AuraRemoveMode.EnemySpell); } } } diff --git a/Source/Game/Scripting/SpellScript.cs b/Source/Game/Scripting/SpellScript.cs index a0322b091..cfeb9b779 100644 --- a/Source/Game/Scripting/SpellScript.cs +++ b/Source/Game/Scripting/SpellScript.cs @@ -1038,6 +1038,7 @@ namespace Game.Scripting public delegate void AuraEffectCalcSpellModDelegate(AuraEffect aura, ref SpellModifier spellMod); public delegate void AuraEffectCalcCritChanceFnType(AuraEffect aura, Unit victim, ref float critChance); public delegate void AuraEffectAbsorbDelegate(AuraEffect aura, DamageInfo damageInfo, ref uint absorbAmount); + public delegate void AuraEffectAbsorbHealDelegate(AuraEffect aura, HealInfo healInfo, ref uint absorbAmount); public delegate void AuraEffectSplitDelegate(AuraEffect aura, DamageInfo damageInfo, uint splitAmount); public delegate bool AuraCheckProcDelegate(ProcEventInfo info); public delegate bool AuraCheckEffectProcDelegate(AuraEffect aura, ProcEventInfo info); @@ -1202,6 +1203,21 @@ namespace Game.Scripting AuraEffectAbsorbDelegate pEffectHandlerScript; } + public class EffectAbsorbHealHandler : EffectBase + { + public EffectAbsorbHealHandler(AuraEffectAbsorbHealDelegate _pEffectHandlerScript, byte _effIndex) + : base(_effIndex, AuraType.SchoolHealAbsorb) + { + pEffectHandlerScript = _pEffectHandlerScript; + } + + public void Call(AuraEffect aurEff, HealInfo healInfo, ref uint absorbAmount) + { + pEffectHandlerScript(aurEff, healInfo, ref absorbAmount); + } + + AuraEffectAbsorbHealDelegate pEffectHandlerScript; + } public class EffectManaShieldHandler : EffectBase { public EffectManaShieldHandler(AuraEffectAbsorbDelegate _pEffectHandlerScript, byte _effIndex) @@ -1543,11 +1559,21 @@ namespace Game.Scripting // where function is: void function (AuraEffect aurEff, DamageInfo& dmgInfo, uint& absorbAmount); public List OnEffectAbsorb = new(); + // executed when absorb aura effect is going to reduce damage + // example: OnEffectAbsorbHeal += AuraEffectAbsorbHealFn(class::function, EffectIndexSpecifier); + // where function is: void function (AuraEffect const* aurEff, HealInfo& healInfo, uint32& absorbAmount); + public List OnEffectAbsorbHeal = new(); + // executed after absorb aura effect reduced damage to target - absorbAmount is real amount absorbed by aura // example: AfterEffectAbsorb += AuraEffectAbsorbFn(class.function, EffectIndexSpecifier); // where function is: void function (AuraEffect aurEff, DamageInfo& dmgInfo, uint& absorbAmount); public List AfterEffectAbsorb = new(); + // executed after absorb aura effect reduced heal to target - absorbAmount is real amount absorbed by aura + // example: AfterEffectAbsorbHeal += AuraEffectAbsorbHealFn(class::function, EffectIndexSpecifier); + // where function is: void function (AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount); + public List AfterEffectAbsorbHeal = new(); + // executed when mana shield aura effect is going to reduce damage // example: OnEffectManaShield += AuraEffectAbsorbFn(class.function, EffectIndexSpecifier); // where function is: void function (AuraEffect aurEff, DamageInfo& dmgInfo, uint& absorbAmount); diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index 2dbfcbba0..bc68c17a6 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -287,7 +287,7 @@ namespace Game.Spells // When sending EstimatedPoints all effects (at least up to the last one that uses GetEstimatedAmount) must have proper value in packet foreach (AuraEffect effect in GetBase().GetAuraEffects()) if (effect != null && HasEffect(effect.GetEffIndex())) // Not all of aura's effects have to be applied on every target - auraData.EstimatedPoints[(int)effect.GetEffIndex()] = effect.GetEstimatedAmount().GetValueOrDefault(effect.GetAmount()); + auraData.EstimatedPoints.Add(effect.GetEstimatedAmount().GetValueOrDefault(effect.GetAmount())); } } } @@ -542,7 +542,6 @@ namespace Game.Spells if (unit.IsImmunedToSpellEffect(GetSpellInfo(), spellEffectInfo, caster)) value &= ~(1u << (int)spellEffectInfo.EffectIndex); } - if (value == 0 || unit.IsImmunedToSpell(GetSpellInfo(), caster) || !CanBeAppliedOn(unit)) addUnit = false; @@ -2142,6 +2141,20 @@ namespace Game.Spells } } + public void CallScriptEffectAbsorbHandlers(AuraEffect aurEff, AuraApplication aurApp, HealInfo healInfo, ref uint absorbAmount, ref bool defaultPrevented) + { + foreach (var auraScript in m_loadedScripts) + { + auraScript._PrepareScriptCall(AuraScriptHookType.EffectAbsorb, aurApp); + foreach (var eff in auraScript.OnEffectAbsorbHeal) + if (eff.IsEffectAffected(m_spellInfo, aurEff.GetEffIndex())) + eff.Call(aurEff, healInfo, ref absorbAmount); + + defaultPrevented = auraScript._IsDefaultActionPrevented(); + auraScript._FinishScriptCall(); + } + } + public void CallScriptEffectAfterAbsorbHandlers(AuraEffect aurEff, AuraApplication aurApp, DamageInfo dmgInfo, ref uint absorbAmount) { foreach (var auraScript in m_loadedScripts) @@ -2156,6 +2169,19 @@ namespace Game.Spells } } + public void CallScriptEffectAfterAbsorbHandlers(AuraEffect aurEff, AuraApplication aurApp, HealInfo healInfo, ref uint absorbAmount) + { + foreach (var auraScript in m_loadedScripts) + { + auraScript._PrepareScriptCall(AuraScriptHookType.EffectAfterAbsorb, aurApp); + foreach (var eff in auraScript.AfterEffectAbsorbHeal) + if (eff.IsEffectAffected(m_spellInfo, aurEff.GetEffIndex())) + eff.Call(aurEff, healInfo, ref absorbAmount); + + auraScript._FinishScriptCall(); + } + } + public void CallScriptEffectManaShieldHandlers(AuraEffect aurEff, AuraApplication aurApp, DamageInfo dmgInfo, ref uint absorbAmount, ref bool defaultPrevented) { foreach (var auraScript in m_loadedScripts)