Core/Scripts: Added damage and healing calculation hook to spell and aura scripts allowing to override base damage amount, flat value mod and percent value mod separately

Port From (https://github.com/TrinityCore/TrinityCore/commit/9cdf3530f41e18fc815e7b164e40c01a18c3d757)
This commit is contained in:
hondacrx
2023-09-13 18:18:29 -04:00
parent 44e79ec8ea
commit d7c2fa52f4
10 changed files with 248 additions and 107 deletions
@@ -31,6 +31,8 @@ namespace Framework.Constants
OnResistAbsorbCalculation, OnResistAbsorbCalculation,
AfterCast, AfterCast,
CalcCritChance, CalcCritChance,
CalcDamage,
CalcHealing,
OnPrecast, OnPrecast,
CalcCastTime CalcCastTime
} }
@@ -48,6 +50,7 @@ namespace Framework.Constants
EffectCalcPeriodic, EffectCalcPeriodic,
EffectCalcSpellmod, EffectCalcSpellmod,
EffectCalcCritChance, EffectCalcCritChance,
EffectCalcDamageAndHealing,
EffectAbsorb, EffectAbsorb,
EffectAfterAbsorb, EffectAfterAbsorb,
EffectManaShield, EffectManaShield,
+2 -2
View File
@@ -1103,8 +1103,8 @@ namespace Game.Entities
uint damage = 0; uint damage = 0;
damage += CalculateDamage(damageInfo.AttackType, false, true); damage += CalculateDamage(damageInfo.AttackType, false, true);
// Add melee damage bonus // Add melee damage bonus
damage = MeleeDamageBonusDone(damageInfo.Target, damage, damageInfo.AttackType, DamageEffectType.Direct, null, null, (SpellSchoolMask)damageInfo.DamageSchoolMask); damage = (uint)MeleeDamageBonusDone(damageInfo.Target, (int)damage, damageInfo.AttackType, DamageEffectType.Direct, null, default, (SpellSchoolMask)damageInfo.DamageSchoolMask);
damage = damageInfo.Target.MeleeDamageBonusTaken(this, damage, damageInfo.AttackType, DamageEffectType.Direct, null, (SpellSchoolMask)damageInfo.DamageSchoolMask); damage = (uint)damageInfo.Target.MeleeDamageBonusTaken(this, (int)damage, damageInfo.AttackType, DamageEffectType.Direct, null, (SpellSchoolMask)damageInfo.DamageSchoolMask);
// Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
Global.ScriptMgr.ModifyMeleeDamage(damageInfo.Target, damageInfo.Attacker, ref damage); Global.ScriptMgr.ModifyMeleeDamage(damageInfo.Target, damageInfo.Attacker, ref damage);
+44 -23
View File
@@ -57,25 +57,38 @@ namespace Game.Entities
return DoneAdvertisedBenefit; return DoneAdvertisedBenefit;
} }
public uint SpellDamageBonusDone(Unit victim, SpellInfo spellProto, uint pdamage, DamageEffectType damagetype, SpellEffectInfo spellEffectInfo, uint stack = 1) public int SpellDamageBonusDone(Unit victim, SpellInfo spellProto, int pdamage, DamageEffectType damagetype, SpellEffectInfo spellEffectInfo, uint stack = 1, Spell spell = null, AuraEffect aurEff = null)
{ {
if (spellProto == null || victim == null || damagetype == DamageEffectType.Direct) if (spellProto == null || victim == null)
return pdamage; return pdamage;
int DoneTotal = 0;
float DoneTotalMod = 1.0f;
void callDamageScript(ref int dmg, ref int flatMod, ref float pctMod)
{
if (spell != null)
spell.CallScriptCalcDamageHandlers(victim, ref dmg, ref flatMod, ref pctMod);
else if (aurEff != null)
aurEff.GetBase().CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff.GetBase().GetApplicationOfTarget(victim.GetGUID()), victim, ref dmg, ref flatMod, ref pctMod);
}
// Some spells don't benefit from done mods // Some spells don't benefit from done mods
if (spellProto.HasAttribute(SpellAttr3.IgnoreCasterModifiers)) if (damagetype == DamageEffectType.Direct || spellProto.HasAttribute(SpellAttr3.IgnoreCasterModifiers))
return pdamage; {
callDamageScript(ref pdamage, ref DoneTotal, ref DoneTotalMod);
return (int)Math.Max((float)(pdamage + DoneTotal) * DoneTotalMod, 0.0f);
}
// For totems get damage bonus from owner // For totems get damage bonus from owner
if (IsTypeId(TypeId.Unit) && IsTotem()) if (IsTypeId(TypeId.Unit) && IsTotem())
{ {
Unit owner = GetOwner(); Unit owner = GetOwner();
if (owner != null) if (owner != null)
return owner.SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, stack); return owner.SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, stack, spell, aurEff);
} }
int DoneTotal = 0; DoneTotalMod = SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
float DoneTotalMod = SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
// Done fixed damage bonus auras // Done fixed damage bonus auras
int DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto.GetSchoolMask()); int DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto.GetSchoolMask());
@@ -114,7 +127,7 @@ namespace Game.Entities
{ {
// No bonus damage for SPELL_DAMAGE_CLASS_NONE class spells by default // No bonus damage for SPELL_DAMAGE_CLASS_NONE class spells by default
if (spellProto.DmgClass == SpellDmgClass.None) if (spellProto.DmgClass == SpellDmgClass.None)
return (uint)Math.Max(pdamage * DoneTotalMod, 0.0f); return (int)Math.Max(pdamage * DoneTotalMod, 0.0f);
} }
// Default calculation // Default calculation
@@ -131,13 +144,16 @@ namespace Game.Entities
DoneTotal += (int)(DoneAdvertisedBenefit * coeff * stack); DoneTotal += (int)(DoneAdvertisedBenefit * coeff * stack);
} }
float tmpDamage = (float)((int)pdamage + DoneTotal) * DoneTotalMod; callDamageScript(ref pdamage, ref DoneTotal, ref DoneTotalMod);
float tmpDamage = (float)(pdamage + DoneTotal) * DoneTotalMod;
// apply spellmod to Done damage (flat and pct) // apply spellmod to Done damage (flat and pct)
Player _modOwner = GetSpellModOwner(); Player _modOwner = GetSpellModOwner();
if (_modOwner != null) if (_modOwner != null)
_modOwner.ApplySpellMod(spellProto, damagetype == DamageEffectType.DOT ? SpellModOp.PeriodicHealingAndDamage : SpellModOp.HealingAndDamage, ref tmpDamage); _modOwner.ApplySpellMod(spellProto, damagetype == DamageEffectType.DOT ? SpellModOp.PeriodicHealingAndDamage : SpellModOp.HealingAndDamage, ref tmpDamage);
return (uint)Math.Max(tmpDamage, 0.0f); return (int)Math.Max(tmpDamage, 0.0f);
} }
public float SpellDamagePctDone(Unit victim, SpellInfo spellProto, DamageEffectType damagetype, SpellEffectInfo spellEffectInfo) public float SpellDamagePctDone(Unit victim, SpellInfo spellProto, DamageEffectType damagetype, SpellEffectInfo spellEffectInfo)
@@ -243,7 +259,7 @@ namespace Game.Entities
return DoneTotalMod; return DoneTotalMod;
} }
public uint SpellDamageBonusTaken(Unit caster, SpellInfo spellProto, uint pdamage, DamageEffectType damagetype) public int SpellDamageBonusTaken(Unit caster, SpellInfo spellProto, int pdamage, DamageEffectType damagetype)
{ {
if (spellProto == null || damagetype == DamageEffectType.Direct) if (spellProto == null || damagetype == DamageEffectType.Direct)
return pdamage; return pdamage;
@@ -323,7 +339,7 @@ namespace Game.Entities
} }
float tmpDamage = pdamage * TakenTotalMod; float tmpDamage = pdamage * TakenTotalMod;
return (uint)Math.Max(tmpDamage, 0.0f); return (int)Math.Max(tmpDamage, 0.0f);
} }
public uint SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) public uint SpellBaseHealingBonusDone(SpellSchoolMask schoolMask)
@@ -386,14 +402,14 @@ namespace Game.Entities
return damage; return damage;
} }
public uint SpellHealingBonusDone(Unit victim, SpellInfo spellProto, uint healamount, DamageEffectType damagetype, SpellEffectInfo spellEffectInfo, uint stack = 1) public int SpellHealingBonusDone(Unit victim, SpellInfo spellProto, int healamount, DamageEffectType damagetype, SpellEffectInfo spellEffectInfo, uint stack = 1, Spell spell = null, AuraEffect aurEff = null)
{ {
// For totems get healing bonus from owner (statue isn't totem in fact) // For totems get healing bonus from owner (statue isn't totem in fact)
if (IsTypeId(TypeId.Unit) && IsTotem()) if (IsTypeId(TypeId.Unit) && IsTotem())
{ {
Unit owner = GetOwner(); Unit owner = GetOwner();
if (owner) if (owner)
return owner.SpellHealingBonusDone(victim, spellProto, healamount, damagetype, spellEffectInfo, stack); return owner.SpellHealingBonusDone(victim, spellProto, healamount, damagetype, spellEffectInfo, stack, spell, aurEff);
} }
// No bonus healing for potion spells // No bonus healing for potion spells
@@ -406,15 +422,15 @@ namespace Game.Entities
// done scripted mod (take it from owner) // done scripted mod (take it from owner)
Unit owner1 = GetOwner() ?? this; Unit owner1 = GetOwner() ?? this;
var mOverrideClassScript = owner1.GetAuraEffectsByType(AuraType.OverrideClassScripts); var mOverrideClassScript = owner1.GetAuraEffectsByType(AuraType.OverrideClassScripts);
foreach (var aurEff in mOverrideClassScript) foreach (var effect in mOverrideClassScript)
{ {
if (!aurEff.IsAffectingSpell(spellProto)) if (!effect.IsAffectingSpell(spellProto))
continue; continue;
switch (aurEff.GetMiscValue()) switch (effect.GetMiscValue())
{ {
case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind
DoneTotal += aurEff.GetAmount(); DoneTotal += effect.GetAmount();
break; break;
default: default:
break; break;
@@ -445,7 +461,7 @@ namespace Game.Entities
{ {
// No bonus healing for SPELL_DAMAGE_CLASS_NONE class spells by default // No bonus healing for SPELL_DAMAGE_CLASS_NONE class spells by default
if (spellProto.DmgClass == SpellDmgClass.None) if (spellProto.DmgClass == SpellDmgClass.None)
return (uint)Math.Max(healamount * DoneTotalMod, 0.0f); return (int)Math.Max(healamount * DoneTotalMod, 0.0f);
} }
// Default calculation // Default calculation
@@ -476,14 +492,19 @@ namespace Game.Entities
DoneTotal = 0; DoneTotal = 0;
} }
float heal = (float)((int)healamount + DoneTotal) * DoneTotalMod; if (spell != null)
spell.CallScriptCalcHealingHandlers(victim, ref healamount, ref DoneTotal, ref DoneTotalMod);
else if (aurEff != null)
aurEff.GetBase().CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff.GetBase().GetApplicationOfTarget(victim.GetGUID()), victim, ref healamount, ref DoneTotal, ref DoneTotalMod);
float heal = (float)(healamount + DoneTotal) * DoneTotalMod;
// apply spellmod to Done amount // apply spellmod to Done amount
Player _modOwner = GetSpellModOwner(); Player _modOwner = GetSpellModOwner();
if (_modOwner) if (_modOwner)
_modOwner.ApplySpellMod(spellProto, damagetype == DamageEffectType.DOT ? SpellModOp.PeriodicHealingAndDamage : SpellModOp.HealingAndDamage, ref heal); _modOwner.ApplySpellMod(spellProto, damagetype == DamageEffectType.DOT ? SpellModOp.PeriodicHealingAndDamage : SpellModOp.HealingAndDamage, ref heal);
return (uint)Math.Max(heal, 0.0f); return (int)Math.Max(heal, 0.0f);
} }
public float SpellHealingPctDone(Unit victim, SpellInfo spellProto) public float SpellHealingPctDone(Unit victim, SpellInfo spellProto)
@@ -539,7 +560,7 @@ namespace Game.Entities
return DoneTotalMod; return DoneTotalMod;
} }
public uint SpellHealingBonusTaken(Unit caster, SpellInfo spellProto, uint healamount, DamageEffectType damagetype) public int SpellHealingBonusTaken(Unit caster, SpellInfo spellProto, int healamount, DamageEffectType damagetype)
{ {
float TakenTotalMod = 1.0f; float TakenTotalMod = 1.0f;
@@ -589,7 +610,7 @@ namespace Game.Entities
} }
float heal = healamount * TakenTotalMod; float heal = healamount * TakenTotalMod;
return (uint)Math.Max(heal, 0.0f); return (int)Math.Max(heal, 0.0f);
} }
public float SpellCritChanceDone(Spell spell, AuraEffect aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType = WeaponAttackType.BaseAttack) public float SpellCritChanceDone(Spell spell, AuraEffect aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType = WeaponAttackType.BaseAttack)
+14 -11
View File
@@ -3023,8 +3023,8 @@ namespace Game.Entities
Unit caster = dmgShield.GetCaster(); Unit caster = dmgShield.GetCaster();
if (caster) if (caster)
{ {
damage = caster.SpellDamageBonusDone(this, spellInfo, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo()); damage = (uint)caster.SpellDamageBonusDone(this, spellInfo, (int)damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo());
damage = SpellDamageBonusTaken(caster, spellInfo, damage, DamageEffectType.SpellDirect); damage = (uint)SpellDamageBonusTaken(caster, spellInfo, (int)damage, DamageEffectType.SpellDirect);
} }
DamageInfo damageInfo1 = new(this, victim, damage, spellInfo, spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack); DamageInfo damageInfo1 = new(this, victim, damage, spellInfo, spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack);
@@ -3850,7 +3850,7 @@ namespace Game.Entities
return (uint)Math.Max(damage * (1.0f - mitigation), 0.0f); return (uint)Math.Max(damage * (1.0f - mitigation), 0.0f);
} }
public uint MeleeDamageBonusDone(Unit victim, uint damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo spellProto = null, SpellEffectInfo spellEffectInfo = null, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal) public int MeleeDamageBonusDone(Unit victim, int damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo spellProto = null, Mechanics mechanic = default, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal, Spell spell = null, AuraEffect aurEff = null)
{ {
if (victim == null || damage == 0) if (victim == null || damage == 0)
return 0; return 0;
@@ -3944,12 +3944,17 @@ namespace Game.Entities
}); });
// Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
if (spellEffectInfo != null && spellEffectInfo.Mechanic != 0) if (mechanic != Mechanics.None)
MathFunctions.AddPct(ref DoneTotalMod, GetTotalAuraModifierByMiscValue(AuraType.ModDamageDoneForMechanic, (int)spellEffectInfo.Mechanic)); MathFunctions.AddPct(ref DoneTotalMod, GetTotalAuraModifierByMiscValue(AuraType.ModDamageDoneForMechanic, (int)mechanic));
else if (spellProto != null && spellProto.Mechanic != 0) else if (spellProto != null && spellProto.Mechanic != 0)
MathFunctions.AddPct(ref DoneTotalMod, GetTotalAuraModifierByMiscValue(AuraType.ModDamageDoneForMechanic, (int)spellProto.Mechanic)); MathFunctions.AddPct(ref DoneTotalMod, GetTotalAuraModifierByMiscValue(AuraType.ModDamageDoneForMechanic, (int)spellProto.Mechanic));
float damageF = damage; if (spell != null)
spell.CallScriptCalcDamageHandlers(victim, ref damage, ref DoneFlatBenefit, ref DoneTotalMod);
else if (aurEff != null)
aurEff.GetBase().CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff.GetBase().GetApplicationOfTarget(victim.GetGUID()), victim, ref damage, ref DoneFlatBenefit, ref DoneTotalMod);
float damageF = (float)(damage + DoneFlatBenefit) * DoneTotalMod;
// apply spellmod to Done damage // apply spellmod to Done damage
if (spellProto != null) if (spellProto != null)
@@ -3959,13 +3964,11 @@ namespace Game.Entities
modOwner.ApplySpellMod(spellProto, damagetype == DamageEffectType.DOT ? SpellModOp.PeriodicHealingAndDamage : SpellModOp.HealingAndDamage, ref damageF); modOwner.ApplySpellMod(spellProto, damagetype == DamageEffectType.DOT ? SpellModOp.PeriodicHealingAndDamage : SpellModOp.HealingAndDamage, ref damageF);
} }
damageF = (damageF + DoneFlatBenefit) * DoneTotalMod;
// bonus result can be negative // bonus result can be negative
return (uint)Math.Max(damageF, 0.0f); return (int)Math.Max(damageF, 0.0f);
} }
public uint MeleeDamageBonusTaken(Unit attacker, uint pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo spellProto = null, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal) public int MeleeDamageBonusTaken(Unit attacker, int pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo spellProto = null, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal)
{ {
if (pdamage == 0) if (pdamage == 0)
return 0; return 0;
@@ -4068,7 +4071,7 @@ namespace Game.Entities
} }
float tmpDamage = (float)(pdamage + TakenFlatBenefit) * TakenTotalMod; float tmpDamage = (float)(pdamage + TakenFlatBenefit) * TakenTotalMod;
return (uint)Math.Max(tmpDamage, 0.0f); return (int)Math.Max(tmpDamage, 0.0f);
} }
bool IsBlockCritical() bool IsBlockCritical()
+93 -14
View File
@@ -164,6 +164,7 @@ namespace Game.Scripting
// internal use classes & functions // internal use classes & functions
// DO NOT OVERRIDE THESE IN SCRIPTS // DO NOT OVERRIDE THESE IN SCRIPTS
public delegate SpellCastResult SpellCheckCastFnType(); public delegate SpellCastResult SpellCheckCastFnType();
public delegate void DamageAndHealingCalcFnType(Unit victim, ref int damageOrHealing, ref int flatMod, ref float pctMod);
public delegate void SpellOnResistAbsorbCalculateFnType(DamageInfo damageInfo, ref uint resistAmount, ref int absorbAmount); public delegate void SpellOnResistAbsorbCalculateFnType(DamageInfo damageInfo, ref uint resistAmount, ref int absorbAmount);
public delegate void SpellEffectFnType(uint index); public delegate void SpellEffectFnType(uint index);
public delegate void SpellBeforeHitFnType(SpellMissInfo missInfo); public delegate void SpellBeforeHitFnType(SpellMissInfo missInfo);
@@ -201,6 +202,21 @@ namespace Game.Scripting
} }
} }
public class DamageAndHealingCalcHandler
{
DamageAndHealingCalcFnType _callImpl;
public DamageAndHealingCalcHandler(DamageAndHealingCalcFnType handler)
{
_callImpl = handler;
}
public void Call(Unit victim, ref int damageOrHealing, ref int flatMod, ref float pctMod)
{
_callImpl(victim, ref damageOrHealing, ref flatMod, ref pctMod);
}
}
public class OnCalculateResistAbsorbHandler public class OnCalculateResistAbsorbHandler
{ {
SpellOnResistAbsorbCalculateFnType _callImpl; SpellOnResistAbsorbCalculateFnType _callImpl;
@@ -435,6 +451,27 @@ namespace Game.Scripting
if (eff.GetAffectedEffectsMask(entry) == 0) if (eff.GetAffectedEffectsMask(entry) == 0)
Log.outError(LogFilter.Scripts, "Spell `{0}` Effect `{1}` of script `{2}` did not match dbc effect data - handler bound to hook `OnObjectTargetSelect` of SpellScript won't be executed", entry.Id, eff.ToString(), m_scriptName); Log.outError(LogFilter.Scripts, "Spell `{0}` Effect `{1}` of script `{2}` did not match dbc effect data - handler bound to hook `OnObjectTargetSelect` of SpellScript won't be executed", entry.Id, eff.ToString(), m_scriptName);
if (!CalcDamage.Empty())
{
if (!entry.HasEffect(SpellEffectName.SchoolDamage)
&& !entry.HasEffect(SpellEffectName.PowerDrain)
&& !entry.HasEffect(SpellEffectName.HealthLeech)
&& !entry.HasEffect(SpellEffectName.WeaponDamage)
&& !entry.HasEffect(SpellEffectName.WeaponDamageNoSchool)
&& !entry.HasEffect(SpellEffectName.NormalizedWeaponDmg)
&& !entry.HasEffect(SpellEffectName.WeaponPercentDamage))
Log.outError(LogFilter.Scripts, $"Spell `{entry.Id}` script `{m_scriptName}` does not have a damage effect - handler bound to hook `CalcDamage` of SpellScript won't be executed");
}
if (!CalcHealing.Empty())
{
if (!entry.HasEffect(SpellEffectName.Heal)
&& !entry.HasEffect(SpellEffectName.HealPct)
&& !entry.HasEffect(SpellEffectName.HealMechanical)
&& !entry.HasEffect(SpellEffectName.HealthLeech))
Log.outError(LogFilter.Scripts, $"Spell `{entry.Id}` script `{m_scriptName}` does not have a damage effect - handler bound to hook `CalcHealing` of SpellScript won't be executed");
}
return base._Validate(entry); return base._Validate(entry);
} }
@@ -478,7 +515,9 @@ namespace Game.Scripting
|| IsInEffectHook() || IsInEffectHook()
|| m_currentScriptState == (byte)SpellScriptHookType.OnCast || m_currentScriptState == (byte)SpellScriptHookType.OnCast
|| m_currentScriptState == (byte)SpellScriptHookType.AfterCast || m_currentScriptState == (byte)SpellScriptHookType.AfterCast
|| m_currentScriptState == (byte)SpellScriptHookType.CalcCritChance; || m_currentScriptState == (byte)SpellScriptHookType.CalcCritChance
|| m_currentScriptState == (byte)SpellScriptHookType.CalcDamage
|| m_currentScriptState == (byte)SpellScriptHookType.CalcHealing;
} }
public bool IsInTargetHook() public bool IsInTargetHook()
@@ -556,20 +595,32 @@ namespace Game.Scripting
// where function is void function(SpellDestination target) // where function is void function(SpellDestination target)
public List<DestinationTargetSelectHandler> OnDestinationTargetSelect = new(); public List<DestinationTargetSelectHandler> OnDestinationTargetSelect = new();
// where function is void function(Unit victim, ref int damage, ref int flatMod, ref float pctMod)
public List<DamageAndHealingCalcHandler> CalcDamage = new();
// where function is void function(Unit victim, ref int healing, ref int flatMod, ref float pctMod)
public List<DamageAndHealingCalcHandler> CalcHealing = new();
// hooks are executed in following order, at specified event of spell: // hooks are executed in following order, at specified event of spell:
// 1. BeforeCast - executed when spell preparation is finished (when cast bar becomes full) before cast is handled // 1. OnPrecast - executed during spell preparation (before cast bar starts)
// 2. OnCheckCast - allows to override result of CheckCast function // 2. BeforeCast - executed when spell preparation is finished (when cast bar becomes full) before cast is handled
// 3a. OnObjectAreaTargetSelect - executed just before adding selected targets to final target list (for area targets) // 3. OnCheckCast - allows to override result of CheckCast function
// 3b. OnObjectTargetSelect - executed just before adding selected target to final target list (for single unit targets) // 4a. OnObjectAreaTargetSelect - executed just before adding selected targets to final target list (for area targets)
// 4. OnCast - executed just before spell is launched (creates missile) or executed // 4b. OnObjectTargetSelect - executed just before adding selected target to final target list (for single unit targets)
// 5. AfterCast - executed after spell missile is launched and immediate spell actions are done // 4c. OnDestinationTargetSelect - executed just before adding selected target to final target list (for destination targets)
// 6. OnEffectLaunch - executed just before specified effect handler call - when spell missile is launched // 5. OnCast - executed just before spell is launched (creates missile) or executed
// 7. OnEffectLaunchTarget - executed just before specified effect handler call - when spell missile is launched - called for each target from spell target map // 6. AfterCast - executed after spell missile is launched and immediate spell actions are done
// 8. OnEffectHit - executed just before specified effect handler call - when spell missile hits dest // 7. OnEffectLaunch - executed just before specified effect handler call - when spell missile is launched
// 9. BeforeHit - executed just before spell hits a target - called for each target from spell target map // 8. OnCalcCritChance - executed just after specified effect handler call - when spell missile is launched - called for each target from spell target map
// 10. OnEffectHitTarget - executed just before specified effect handler call - called for each target from spell target map // 9. OnEffectLaunchTarget - executed just before specified effect handler call - when spell missile is launched - called for each target from spell target map
// 11. OnHit - executed just before spell deals damage and procs auras - when spell hits target - called for each target from spell target map // 10a. CalcDamage - executed during specified effect handler call - when spell missile is launched - called for each target from spell target map
// 12. AfterHit - executed just after spell finishes all it's jobs for target - called for each target from spell target map // 10b. CalcHealing - executed during specified effect handler call - when spell missile is launched - called for each target from spell target map
// 11. OnCalculateResistAbsorb - executed when damage resist/absorbs is calculated - before spell hit target
// 12. OnEffectHit - executed just before specified effect handler call - when spell missile hits dest
// 13. BeforeHit - executed just before spell hits a target - called for each target from spell target map
// 14. OnEffectHitTarget - executed just before specified effect handler call - called for each target from spell target map
// 15. OnHit - executed just before spell deals damage and procs auras - when spell hits target - called for each target from spell target map
// 16. AfterHit - executed just after spell finishes all it's jobs for target - called for each target from spell target map
// //
// methods allowing interaction with Spell object // methods allowing interaction with Spell object
@@ -1041,6 +1092,7 @@ namespace Game.Scripting
// DO NOT OVERRIDE THESE IN SCRIPTS // DO NOT OVERRIDE THESE IN SCRIPTS
public delegate bool AuraCheckAreaTargetDelegate(Unit target); public delegate bool AuraCheckAreaTargetDelegate(Unit target);
public delegate void AuraDispelDelegate(DispelInfo dispelInfo); public delegate void AuraDispelDelegate(DispelInfo dispelInfo);
public delegate void AuraEffectDamageAndHealingCalcFnType(AuraEffect aurEff, Unit victim, ref int damageOrHealing, ref int flatMod, ref float pctMod);
public delegate void AuraEffectApplicationModeDelegate(AuraEffect aura, AuraEffectHandleModes auraMode); public delegate void AuraEffectApplicationModeDelegate(AuraEffect aura, AuraEffectHandleModes auraMode);
public delegate void AuraEffectPeriodicDelegate(AuraEffect aura); public delegate void AuraEffectPeriodicDelegate(AuraEffect aura);
public delegate void AuraEffectUpdatePeriodicDelegate(AuraEffect aura); public delegate void AuraEffectUpdatePeriodicDelegate(AuraEffect aura);
@@ -1196,6 +1248,21 @@ namespace Game.Scripting
} }
} }
public class EffectCalcDamageAndHealingHandler : EffectBase
{
AuraEffectDamageAndHealingCalcFnType _callImpl;
public EffectCalcDamageAndHealingHandler(AuraEffectDamageAndHealingCalcFnType handler, byte effIndex, AuraType auraType) : base(effIndex, auraType)
{
_callImpl = handler;
}
public void Call(AuraEffect aurEff, Unit victim, ref int damageOrHealing, ref int flatMod, ref float pctMod)
{
_callImpl(aurEff, victim, ref damageOrHealing, ref flatMod, ref pctMod);
}
}
public class EffectApplyHandler : EffectBase public class EffectApplyHandler : EffectBase
{ {
AuraEffectApplicationModeDelegate _callImpl; AuraEffectApplicationModeDelegate _callImpl;
@@ -1410,6 +1477,10 @@ namespace Game.Scripting
if (eff.GetAffectedEffectsMask(entry) == 0) if (eff.GetAffectedEffectsMask(entry) == 0)
Log.outError(LogFilter.Scripts, $"Spell `{entry.Id}` Effect `{eff}` of script `{m_scriptName}` did not match dbc effect data - handler bound to hook `DoEffectCalcCritChance` of AuraScript won't be executed"); Log.outError(LogFilter.Scripts, $"Spell `{entry.Id}` Effect `{eff}` of script `{m_scriptName}` did not match dbc effect data - handler bound to hook `DoEffectCalcCritChance` of AuraScript won't be executed");
foreach (var hook in DoEffectCalcDamageAndHealing)
if (hook.GetAffectedEffectsMask(entry) == 0)
Log.outError(LogFilter.Scripts, $"Spell `{entry.Id}` Effect `{hook}` of script `{m_scriptName}` did not match dbc effect data - handler bound to hook `DoEffectCalcDamageAndHealing` of AuraScript won't be executed");
foreach (var eff in OnEffectAbsorb) foreach (var eff in OnEffectAbsorb)
if (eff.GetAffectedEffectsMask(entry) == 0) if (eff.GetAffectedEffectsMask(entry) == 0)
Log.outError(LogFilter.Scripts, "Spell `{0}` Effect `{1}` of script `{2}` did not match dbc effect data - handler bound to hook `OnEffectAbsorb` of AuraScript won't be executed", entry.Id, eff.ToString(), m_scriptName); Log.outError(LogFilter.Scripts, "Spell `{0}` Effect `{1}` of script `{2}` did not match dbc effect data - handler bound to hook `OnEffectAbsorb` of AuraScript won't be executed", entry.Id, eff.ToString(), m_scriptName);
@@ -1580,6 +1651,12 @@ namespace Game.Scripting
// where function is: void function (AuraEffect const* aurEff, Unit* victim, float& critChance); // where function is: void function (AuraEffect const* aurEff, Unit* victim, float& critChance);
public List<EffectCalcCritChanceHandler> DoEffectCalcCritChance = new(); public List<EffectCalcCritChanceHandler> DoEffectCalcCritChance = new();
// executed when aura effect calculates damage or healing for dots and hots
// example: DoEffectCalcDamageAndHealing += AuraEffectCalcDamageFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier);
// example: DoEffectCalcDamageAndHealing += AuraEffectCalcHealingFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier);
// where function is: void(AuraEffect aurEff, Unit victim, ref int damageOrHealing, ref int flatMod, ref float pctMod);
public List<EffectCalcDamageAndHealingHandler> DoEffectCalcDamageAndHealing = new();
// executed when absorb aura effect is going to reduce damage // executed when absorb aura effect is going to reduce damage
// example: OnEffectAbsorb += AuraEffectAbsorbFn(class.function, EffectIndexSpecifier); // example: OnEffectAbsorb += AuraEffectAbsorbFn(class.function, EffectIndexSpecifier);
// where function is: void function (AuraEffect aurEff, DamageInfo& dmgInfo, uint& absorbAmount); // where function is: void function (AuraEffect aurEff, DamageInfo& dmgInfo, uint& absorbAmount);
@@ -1783,6 +1860,8 @@ namespace Game.Scripting
case AuraScriptHookType.EffectAfterApply: case AuraScriptHookType.EffectAfterApply:
case AuraScriptHookType.EffectAfterRemove: case AuraScriptHookType.EffectAfterRemove:
case AuraScriptHookType.EffectPeriodic: case AuraScriptHookType.EffectPeriodic:
case AuraScriptHookType.EffectCalcCritChance:
case AuraScriptHookType.EffectCalcDamageAndHealing:
case AuraScriptHookType.EffectAbsorb: case AuraScriptHookType.EffectAbsorb:
case AuraScriptHookType.EffectAfterAbsorb: case AuraScriptHookType.EffectAfterAbsorb:
case AuraScriptHookType.EffectManaShield: case AuraScriptHookType.EffectManaShield:
+15 -2
View File
@@ -577,7 +577,7 @@ namespace Game.Spells
} }
} }
} }
} }
if (!addUnit) if (!addUnit)
@@ -994,7 +994,7 @@ namespace Game.Spells
&& !m_spellInfo.HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm) && !m_spellInfo.HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm)
&& !m_spellInfo.HasAttribute(SpellAttr0.NotShapeshifted); && !m_spellInfo.HasAttribute(SpellAttr0.NotShapeshifted);
} }
public bool CanBeSaved() public bool CanBeSaved()
{ {
if (IsPassive()) if (IsPassive())
@@ -2115,6 +2115,19 @@ namespace Game.Spells
loadedScript._FinishScriptCall(); loadedScript._FinishScriptCall();
} }
} }
public void CallScriptCalcDamageAndHealingHandlers(AuraEffect aurEff, AuraApplication aurApp, Unit victim, ref int damageOrHealing, ref int flatMod, ref float pctMod)
{
foreach (AuraScript script in m_loadedScripts)
{
script._PrepareScriptCall(AuraScriptHookType.EffectCalcDamageAndHealing, aurApp);
foreach (var effectCalcDamageAndHealing in script.DoEffectCalcDamageAndHealing)
if (effectCalcDamageAndHealing.IsEffectAffected(m_spellInfo, aurEff.GetEffIndex()))
effectCalcDamageAndHealing.Call(aurEff, victim, ref damageOrHealing, ref flatMod, ref pctMod);
script._FinishScriptCall();
}
}
public void CallScriptEffectAbsorbHandlers(AuraEffect aurEff, AuraApplication aurApp, DamageInfo dmgInfo, ref uint absorbAmount, ref bool defaultPrevented) public void CallScriptEffectAbsorbHandlers(AuraEffect aurEff, AuraApplication aurApp, DamageInfo dmgInfo, ref uint absorbAmount, ref bool defaultPrevented)
{ {
+19 -25
View File
@@ -124,7 +124,7 @@ namespace Game.Spells
return amount; return amount;
} }
public static float? CalculateEstimatedAmount(Unit caster, Unit target, SpellInfo spellInfo, SpellEffectInfo spellEffectInfo, int amount, byte stack) public static float? CalculateEstimatedAmount(Unit caster, Unit target, SpellInfo spellInfo, SpellEffectInfo spellEffectInfo, int amount, byte stack, AuraEffect aurEff)
{ {
uint stackAmountForBonuses = !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? stack : 1u; uint stackAmountForBonuses = !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.NoScaleWithStack) ? stack : 1u;
@@ -132,9 +132,9 @@ namespace Game.Spells
{ {
case AuraType.PeriodicDamage: case AuraType.PeriodicDamage:
case AuraType.PeriodicLeech: case AuraType.PeriodicLeech:
return caster.SpellDamageBonusDone(target, spellInfo, (uint)amount, DamageEffectType.DOT, spellEffectInfo, stackAmountForBonuses); return caster.SpellDamageBonusDone(target, spellInfo, amount, DamageEffectType.DOT, spellEffectInfo, stackAmountForBonuses, null, aurEff);
case AuraType.PeriodicHeal: case AuraType.PeriodicHeal:
return caster.SpellHealingBonusDone(target, spellInfo, (uint)amount, DamageEffectType.DOT, spellEffectInfo, stackAmountForBonuses); return caster.SpellHealingBonusDone(target, spellInfo, amount, DamageEffectType.DOT, spellEffectInfo, stackAmountForBonuses, null, aurEff);
default: default:
break; break;
} }
@@ -147,7 +147,7 @@ namespace Game.Spells
if (!caster || GetBase().GetAuraType() != AuraObjectType.Unit) if (!caster || GetBase().GetAuraType() != AuraObjectType.Unit)
return null; return null;
return CalculateEstimatedAmount(caster, GetBase().GetUnitOwner(), GetSpellInfo(), GetSpellEffectInfo(), amount, GetBase().GetStackAmount()); return CalculateEstimatedAmount(caster, GetBase().GetUnitOwner(), GetSpellInfo(), GetSpellEffectInfo(), amount, GetBase().GetStackAmount(), this);
} }
public static float CalculateEstimatedfTotalPeriodicAmount(Unit caster, Unit target, SpellInfo spellInfo, SpellEffectInfo spellEffectInfo, float amount, byte stack) public static float CalculateEstimatedfTotalPeriodicAmount(Unit caster, Unit target, SpellInfo spellInfo, SpellEffectInfo spellEffectInfo, float amount, byte stack)
@@ -177,7 +177,7 @@ namespace Game.Spells
if (spellInfo.HasAttribute(SpellAttr5.ExtraInitialPeriod)) if (spellInfo.HasAttribute(SpellAttr5.ExtraInitialPeriod))
totalTicks += 1.0f; totalTicks += 1.0f;
return totalTicks * CalculateEstimatedAmount(caster, target, spellInfo, spellEffectInfo, (int)amount, stack).GetValueOrDefault(amount); return totalTicks * CalculateEstimatedAmount(caster, target, spellInfo, spellEffectInfo, (int)amount, stack, null).GetValueOrDefault(amount);
} }
public uint GetTotalTicks() public uint GetTotalTicks()
@@ -5070,17 +5070,11 @@ namespace Game.Spells
case AuraType.PeriodicDamage: case AuraType.PeriodicDamage:
{ {
if (caster != null) if (caster != null)
damage = caster.SpellDamageBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses); damage = (uint)caster.SpellDamageBonusDone(target, GetSpellInfo(), (int)damage, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses, null, this);
damage = target.SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT); damage = (uint)target.SpellDamageBonusTaken(caster, GetSpellInfo(), (int)damage, DamageEffectType.DOT);
// There is a Chance to make a Soul Shard when Drain soul does damage if (GetSpellInfo().SpellFamilyName == SpellFamilyNames.Generic)
if (caster != null && GetSpellInfo().SpellFamilyName == SpellFamilyNames.Warlock && GetSpellInfo().SpellFamilyFlags[0].HasAnyFlag(0x00004000u))
{
if (caster.IsTypeId(TypeId.Player) && caster.ToPlayer().IsHonorOrXPTarget(target))
caster.CastSpell(caster, 95810, new CastSpellExtraArgs(this));
}
else if (GetSpellInfo().SpellFamilyName == SpellFamilyNames.Generic)
{ {
switch (GetId()) switch (GetId())
{ {
@@ -5104,15 +5098,15 @@ namespace Game.Spells
// Add melee damage bonuses (also check for negative) // Add melee damage bonuses (also check for negative)
if (caster != null) if (caster != null)
damage = caster.MeleeDamageBonusDone(target, damage, attackType, DamageEffectType.DOT, GetSpellInfo()); damage = (uint)caster.MeleeDamageBonusDone(target, (int)damage, attackType, DamageEffectType.DOT, GetSpellInfo(), GetSpellEffectInfo().Mechanic, GetSpellInfo().GetSchoolMask(), null, this);
damage = target.MeleeDamageBonusTaken(caster, damage, attackType, DamageEffectType.DOT, GetSpellInfo()); damage = (uint)target.MeleeDamageBonusTaken(caster, (int)damage, attackType, DamageEffectType.DOT, GetSpellInfo());
break; break;
} }
case AuraType.PeriodicDamagePercent: case AuraType.PeriodicDamagePercent:
// ceil obtained value, it may happen that 10 ticks for 10% damage may not kill owner // ceil obtained value, it may happen that 10 ticks for 10% damage may not kill owner
damage = (uint)Math.Ceiling(MathFunctions.CalculatePct((float)target.GetMaxHealth(), (float)damage)); damage = (uint)Math.Ceiling(MathFunctions.CalculatePct((float)target.GetMaxHealth(), (float)damage));
damage = target.SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT); damage = (uint)target.SpellDamageBonusTaken(caster, GetSpellInfo(), (int)damage, DamageEffectType.DOT);
break; break;
default: default:
break; break;
@@ -5196,9 +5190,9 @@ namespace Game.Spells
uint damage = (uint)Math.Max(GetAmount(), 0); uint damage = (uint)Math.Max(GetAmount(), 0);
if (caster) if (caster)
damage = caster.SpellDamageBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses); damage = (uint)caster.SpellDamageBonusDone(target, GetSpellInfo(), (int)damage, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses, null, this);
damage = target.SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT); damage = (uint)target.SpellDamageBonusTaken(caster, GetSpellInfo(), (int)damage, DamageEffectType.DOT);
bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target)); bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target));
if (crit) if (crit)
@@ -5260,8 +5254,8 @@ namespace Game.Spells
float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster); float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster);
uint heal = caster.SpellHealingBonusDone(caster, GetSpellInfo(), (uint)(new_damage * gainMultiplier), DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses); uint heal = (uint)caster.SpellHealingBonusDone(caster, GetSpellInfo(), (int)(new_damage * gainMultiplier), DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses, null, this);
heal = caster.SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DamageEffectType.DOT); heal = (uint)caster.SpellHealingBonusTaken(caster, GetSpellInfo(), (int)heal, DamageEffectType.DOT);
HealInfo healInfo = new(caster, caster, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask()); HealInfo healInfo = new(caster, caster, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
caster.HealBySpell(healInfo); caster.HealBySpell(healInfo);
@@ -5325,9 +5319,9 @@ namespace Game.Spells
if (GetAuraType() == AuraType.ObsModHealth) if (GetAuraType() == AuraType.ObsModHealth)
damage = (uint)target.CountPctFromMaxHealth((int)damage); damage = (uint)target.CountPctFromMaxHealth((int)damage);
else if (caster != null) else if (caster != null)
damage = caster.SpellHealingBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses); damage = (uint)caster.SpellHealingBonusDone(target, GetSpellInfo(), (int)damage, DamageEffectType.DOT, GetSpellEffectInfo(), stackAmountForBonuses, null, this);
damage = target.SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT); damage = (uint)target.SpellHealingBonusTaken(caster, GetSpellInfo(), (int)damage, DamageEffectType.DOT);
bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target)); bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target));
if (crit) if (crit)
@@ -5615,8 +5609,8 @@ namespace Game.Spells
} }
SpellNonMeleeDamage damageInfo = new(target, triggerTarget, GetSpellInfo(), GetBase().GetSpellVisual(), GetSpellInfo().SchoolMask, GetBase().GetCastId()); SpellNonMeleeDamage damageInfo = new(target, triggerTarget, GetSpellInfo(), GetBase().GetSpellVisual(), GetSpellInfo().SchoolMask, GetBase().GetCastId());
int damage = (int)target.SpellDamageBonusDone(triggerTarget, GetSpellInfo(), (uint)GetAmount(), DamageEffectType.SpellDirect, GetSpellEffectInfo()); int damage = target.SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), DamageEffectType.SpellDirect, GetSpellEffectInfo(), 1, null, this);
damage = (int)triggerTarget.SpellDamageBonusTaken(target, GetSpellInfo(), (uint)damage, DamageEffectType.SpellDirect); damage = triggerTarget.SpellDamageBonusTaken(target, GetSpellInfo(), damage, DamageEffectType.SpellDirect);
target.CalculateSpellDamageTaken(damageInfo, damage, GetSpellInfo()); target.CalculateSpellDamageTaken(damageInfo, damage, GetSpellInfo());
Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb); Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
target.DealSpellDamage(damageInfo, true); target.DealSpellDamage(damageInfo, true);
+24
View File
@@ -7623,6 +7623,30 @@ namespace Game.Spells
} }
} }
public void CallScriptCalcDamageHandlers(Unit victim, ref int damage, ref int flatMod, ref float pctMod)
{
foreach (SpellScript script in m_loadedScripts)
{
script._PrepareScriptCall(SpellScriptHookType.CalcDamage);
foreach (var calcDamage in script.CalcDamage)
calcDamage.Call(victim, ref damage, ref flatMod, ref pctMod);
script._FinishScriptCall();
}
}
public void CallScriptCalcHealingHandlers(Unit victim, ref int healing, ref int flatMod, ref float pctMod)
{
foreach (SpellScript script in m_loadedScripts)
{
script._PrepareScriptCall(SpellScriptHookType.CalcHealing);
foreach (var calcHealing in script.CalcHealing)
calcHealing.Call(victim, ref healing, ref flatMod, ref pctMod);
script._FinishScriptCall();
}
}
void CallScriptObjectAreaTargetSelectHandlers(List<WorldObject> targets, uint effIndex, SpellImplicitTargetInfo targetType) void CallScriptObjectAreaTargetSelectHandlers(List<WorldObject> targets, uint effIndex, SpellImplicitTargetInfo targetType)
{ {
foreach (var script in m_loadedScripts) foreach (var script in m_loadedScripts)
+28 -24
View File
@@ -152,9 +152,9 @@ namespace Game.Spells
Unit unitCaster = GetUnitCasterForEffectHandlers(); Unit unitCaster = GetUnitCasterForEffectHandlers();
if (unitCaster != null && apply_direct_bonus) if (unitCaster != null && apply_direct_bonus)
{ {
uint bonus = unitCaster.SpellDamageBonusDone(unitTarget, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect, effectInfo); int bonus = unitCaster.SpellDamageBonusDone(unitTarget, m_spellInfo, damage, DamageEffectType.SpellDirect, effectInfo, 1, this);
damage = (int)(bonus + (uint)(bonus * variance)); damage = (int)(bonus + (bonus * variance));
damage = (int)unitTarget.SpellDamageBonusTaken(unitCaster, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect); damage = unitTarget.SpellDamageBonusTaken(unitCaster, m_spellInfo, damage, DamageEffectType.SpellDirect);
} }
m_damage += damage; m_damage += damage;
@@ -684,9 +684,9 @@ namespace Game.Spells
// add spell damage bonus // add spell damage bonus
if (unitCaster != null) if (unitCaster != null)
{ {
uint bonus = unitCaster.SpellDamageBonusDone(unitTarget, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect, effectInfo); int bonus = unitCaster.SpellDamageBonusDone(unitTarget, m_spellInfo, damage, DamageEffectType.SpellDirect, effectInfo, 1, this);
damage = (int)(bonus + (uint)(bonus * variance)); damage = (int)(bonus + (bonus * variance));
damage = (int)unitTarget.SpellDamageBonusTaken(unitCaster, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect); damage = unitTarget.SpellDamageBonusTaken(unitCaster, m_spellInfo, damage, DamageEffectType.SpellDirect);
} }
int newDamage = -(unitTarget.ModifyPower(powerType, -damage)); int newDamage = -(unitTarget.ModifyPower(powerType, -damage));
@@ -803,14 +803,14 @@ namespace Game.Spells
} }
// Death Pact - return pct of max health to caster // Death Pact - return pct of max health to caster
else if (m_spellInfo.SpellFamilyName == SpellFamilyNames.Deathknight && m_spellInfo.SpellFamilyFlags[0].HasAnyFlag(0x00080000u)) else if (m_spellInfo.SpellFamilyName == SpellFamilyNames.Deathknight && m_spellInfo.SpellFamilyFlags[0].HasAnyFlag(0x00080000u))
addhealth = (int)unitCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)unitCaster.CountPctFromMaxHealth(damage), DamageEffectType.Heal, effectInfo); addhealth = unitCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, (int)unitCaster.CountPctFromMaxHealth(damage), DamageEffectType.Heal, effectInfo, 1, this);
else else
{ {
uint bonus = unitCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)addhealth, DamageEffectType.Heal, effectInfo); int bonus = unitCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, DamageEffectType.Heal, effectInfo, 1, this);
addhealth = (int)(bonus + (uint)(bonus * variance)); addhealth = (int)(bonus + (bonus * variance));
} }
addhealth = (int)unitTarget.SpellHealingBonusTaken(unitCaster, m_spellInfo, (uint)addhealth, DamageEffectType.Heal); addhealth = unitTarget.SpellHealingBonusTaken(unitCaster, m_spellInfo, addhealth, DamageEffectType.Heal);
// Remove Grievious bite if fully healed // Remove Grievious bite if fully healed
if (unitTarget.HasAura(48920) && ((uint)(unitTarget.GetHealth() + (ulong)addhealth) >= unitTarget.GetMaxHealth())) if (unitTarget.HasAura(48920) && ((uint)(unitTarget.GetHealth() + (ulong)addhealth) >= unitTarget.GetMaxHealth()))
@@ -828,15 +828,15 @@ namespace Game.Spells
if (unitTarget == null || !unitTarget.IsAlive() || damage < 0) if (unitTarget == null || !unitTarget.IsAlive() || damage < 0)
return; return;
uint heal = (uint)unitTarget.CountPctFromMaxHealth(damage); int heal = (int)unitTarget.CountPctFromMaxHealth(damage);
Unit unitCaster = GetUnitCasterForEffectHandlers(); Unit unitCaster = GetUnitCasterForEffectHandlers();
if (unitCaster) if (unitCaster)
{ {
heal = unitCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, heal, DamageEffectType.Heal, effectInfo); heal = unitCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, heal, DamageEffectType.Heal, effectInfo, 1, this);
heal = unitTarget.SpellHealingBonusTaken(unitCaster, m_spellInfo, heal, DamageEffectType.Heal); heal = unitTarget.SpellHealingBonusTaken(unitCaster, m_spellInfo, heal, DamageEffectType.Heal);
} }
m_healing += (int)heal; m_healing += heal;
} }
[SpellEffectHandler(SpellEffectName.HealMechanical)] [SpellEffectHandler(SpellEffectName.HealMechanical)]
@@ -849,15 +849,15 @@ namespace Game.Spells
return; return;
Unit unitCaster = GetUnitCasterForEffectHandlers(); Unit unitCaster = GetUnitCasterForEffectHandlers();
uint heal = (uint)damage; int heal = damage;
if (unitCaster) if (unitCaster)
heal = unitCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, heal, DamageEffectType.Heal, effectInfo); heal = unitCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, heal, DamageEffectType.Heal, effectInfo, 1, this);
heal += (uint)(heal * variance); heal += (int)(heal * variance);
if (unitCaster) if (unitCaster)
heal = unitTarget.SpellHealingBonusTaken(unitCaster, m_spellInfo, heal, DamageEffectType.Heal); heal = unitTarget.SpellHealingBonusTaken(unitCaster, m_spellInfo, heal, DamageEffectType.Heal);
m_healing += (int)heal; m_healing += heal;
} }
[SpellEffectHandler(SpellEffectName.HealthLeech)] [SpellEffectHandler(SpellEffectName.HealthLeech)]
@@ -872,12 +872,12 @@ namespace Game.Spells
Unit unitCaster = GetUnitCasterForEffectHandlers(); Unit unitCaster = GetUnitCasterForEffectHandlers();
uint bonus = 0; uint bonus = 0;
if (unitCaster != null) if (unitCaster != null)
unitCaster.SpellDamageBonusDone(unitTarget, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect, effectInfo); bonus = (uint)unitCaster.SpellDamageBonusDone(unitTarget, m_spellInfo, damage, DamageEffectType.SpellDirect, effectInfo, 1, this);
damage = (int)(bonus + (uint)(bonus * variance)); damage = (int)(bonus + (uint)(bonus * variance));
if (unitCaster != null) if (unitCaster != null)
damage = (int)unitTarget.SpellDamageBonusTaken(unitCaster, m_spellInfo, (uint)damage, DamageEffectType.SpellDirect); damage = unitTarget.SpellDamageBonusTaken(unitCaster, m_spellInfo, damage, DamageEffectType.SpellDirect);
Log.outDebug(LogFilter.Spells, "HealthLeech :{0}", damage); Log.outDebug(LogFilter.Spells, "HealthLeech :{0}", damage);
@@ -895,8 +895,8 @@ namespace Game.Spells
if (unitCaster != null && unitCaster.IsAlive()) if (unitCaster != null && unitCaster.IsAlive())
{ {
healthGain = unitCaster.SpellHealingBonusDone(unitCaster, m_spellInfo, healthGain, DamageEffectType.Heal, effectInfo); healthGain = (uint)unitCaster.SpellHealingBonusDone(unitCaster, m_spellInfo, (int)healthGain, DamageEffectType.Heal, effectInfo, 1, this);
healthGain = unitCaster.SpellHealingBonusTaken(unitCaster, m_spellInfo, healthGain, DamageEffectType.Heal); healthGain = (uint)unitCaster.SpellHealingBonusTaken(unitCaster, m_spellInfo, (int)healthGain, DamageEffectType.Heal);
HealInfo healInfo = new(unitCaster, unitCaster, healthGain, m_spellInfo, m_spellSchoolMask); HealInfo healInfo = new(unitCaster, unitCaster, healthGain, m_spellInfo, m_spellSchoolMask);
unitCaster.HealBySpell(healInfo); unitCaster.HealBySpell(healInfo);
@@ -2448,6 +2448,7 @@ namespace Game.Spells
} }
uint weaponDamage = unitCaster.CalculateDamage(m_attackType, normalized, addPctMods); uint weaponDamage = unitCaster.CalculateDamage(m_attackType, normalized, addPctMods);
Mechanics mechanic = Mechanics.None;
// Sequence is important // Sequence is important
foreach (var spellEffectInfo in m_spellInfo.GetEffects()) foreach (var spellEffectInfo in m_spellInfo.GetEffects())
@@ -2465,8 +2466,11 @@ namespace Game.Spells
weaponDamage = (uint)(weaponDamage * weaponDamagePercentMod); weaponDamage = (uint)(weaponDamage * weaponDamagePercentMod);
break; break;
default: default:
break; // not weapon damage effect, just skip continue; // not weapon damage effect, just skip
} }
if (spellEffectInfo.Mechanic != Mechanics.None && mechanic == Mechanics.None)
mechanic = spellEffectInfo.Mechanic;
} }
weaponDamage += (uint)spell_bonus; weaponDamage += (uint)spell_bonus;
@@ -2476,8 +2480,8 @@ namespace Game.Spells
weaponDamage = Math.Max(weaponDamage, 0); weaponDamage = Math.Max(weaponDamage, 0);
// Add melee damage bonuses (also check for negative) // Add melee damage bonuses (also check for negative)
weaponDamage = unitCaster.MeleeDamageBonusDone(unitTarget, weaponDamage, m_attackType, DamageEffectType.SpellDirect, m_spellInfo, effectInfo); weaponDamage = (uint)unitCaster.MeleeDamageBonusDone(unitTarget, (int)weaponDamage, m_attackType, DamageEffectType.SpellDirect, m_spellInfo, mechanic, m_spellSchoolMask, this);
m_damage += (int)unitTarget.MeleeDamageBonusTaken(unitCaster, weaponDamage, m_attackType, DamageEffectType.SpellDirect, m_spellInfo); m_damage += unitTarget.MeleeDamageBonusTaken(unitCaster, (int)weaponDamage, m_attackType, DamageEffectType.SpellDirect, m_spellInfo);
} }
[SpellEffectHandler(SpellEffectName.Threat)] [SpellEffectHandler(SpellEffectName.Threat)]
+6 -6
View File
@@ -942,10 +942,10 @@ namespace Scripts.Spells.Priest
{ {
PreventHitDefaultEffect(effIndex); PreventHitDefaultEffect(effIndex);
float damageBonus = GetCaster().SpellDamageBonusDone(GetHitUnit(), GetSpellInfo(), (uint)GetEffectValue(), DamageEffectType.SpellDirect, GetEffectInfo()); float damageBonus = GetCaster().SpellDamageBonusDone(GetHitUnit(), GetSpellInfo(), GetEffectValue(), DamageEffectType.SpellDirect, GetEffectInfo());
float value = damageBonus + damageBonus * GetEffectVariance(); float value = damageBonus + damageBonus * GetEffectVariance();
value *= 1.0f + (powerOfTheDarkSide.GetAmount() / 100.0f); value *= 1.0f + (powerOfTheDarkSide.GetAmount() / 100.0f);
value = GetHitUnit().SpellDamageBonusTaken(GetCaster(), GetSpellInfo(), (uint)value, DamageEffectType.SpellDirect); value = GetHitUnit().SpellDamageBonusTaken(GetCaster(), GetSpellInfo(), (int)value, DamageEffectType.SpellDirect);
SetHitDamage((int)value); SetHitDamage((int)value);
} }
} }
@@ -972,10 +972,10 @@ namespace Scripts.Spells.Priest
{ {
PreventHitDefaultEffect(effIndex); PreventHitDefaultEffect(effIndex);
float healingBonus = GetCaster().SpellHealingBonusDone(GetHitUnit(), GetSpellInfo(), (uint)GetEffectValue(), DamageEffectType.Heal, GetEffectInfo()); float healingBonus = GetCaster().SpellHealingBonusDone(GetHitUnit(), GetSpellInfo(), GetEffectValue(), DamageEffectType.Heal, GetEffectInfo());
float value = healingBonus + healingBonus * GetEffectVariance(); float value = healingBonus + healingBonus * GetEffectVariance();
value *= 1.0f + (powerOfTheDarkSide.GetAmount() / 100.0f); value *= 1.0f + (powerOfTheDarkSide.GetAmount() / 100.0f);
value = GetHitUnit().SpellHealingBonusTaken(GetCaster(), GetSpellInfo(), (uint)value, DamageEffectType.Heal); value = GetHitUnit().SpellHealingBonusTaken(GetCaster(), GetSpellInfo(), (int)value, DamageEffectType.Heal);
SetHitHeal((int)value); SetHitHeal((int)value);
} }
} }
@@ -1212,7 +1212,7 @@ namespace Scripts.Spells.Priest
void HandleEffectDummy(uint effIndex) void HandleEffectDummy(uint effIndex)
{ {
// Note: we need to increase BasePoints by 1 since it's 4 as default. // Note: we need to increase BasePoints by 1 since it's 4 as default.
uint basePoints = GetCaster().SpellHealingBonusDone(GetHitUnit(), _spellInfoHeal, (uint)_healEffectDummy.CalcValue(GetCaster()), DamageEffectType.Heal, _healEffectDummy); uint basePoints = (uint)GetCaster().SpellHealingBonusDone(GetHitUnit(), _spellInfoHeal, _healEffectDummy.CalcValue(GetCaster()), DamageEffectType.Heal, _healEffectDummy);
CastSpellExtraArgs args = new(TriggerCastFlags.FullMask); CastSpellExtraArgs args = new(TriggerCastFlags.FullMask);
args.AddSpellMod(SpellValueMod.AuraStack, GetEffectValue()); args.AddSpellMod(SpellValueMod.AuraStack, GetEffectValue());
args.AddSpellMod(SpellValueMod.BasePoint0, (int)basePoints); args.AddSpellMod(SpellValueMod.BasePoint0, (int)basePoints);
@@ -1338,7 +1338,7 @@ namespace Scripts.Spells.Priest
if (origCaster != null) if (origCaster != null)
{ {
uint basePoints = origCaster.SpellHealingBonusDone(target, _spellInfoHeal, (uint)_healEffectDummy.CalcValue(origCaster), DamageEffectType.Heal, _healEffectDummy); uint basePoints = (uint)origCaster.SpellHealingBonusDone(target, _spellInfoHeal, _healEffectDummy.CalcValue(origCaster), DamageEffectType.Heal, _healEffectDummy);
CastSpellExtraArgs args = new(TriggerCastFlags.FullMask); CastSpellExtraArgs args = new(TriggerCastFlags.FullMask);
args.AddSpellMod(SpellValueMod.AuraStack, GetEffectValue()); args.AddSpellMod(SpellValueMod.AuraStack, GetEffectValue());
args.AddSpellMod(SpellValueMod.BasePoint0, (int)basePoints); args.AddSpellMod(SpellValueMod.BasePoint0, (int)basePoints);