aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2023-08-01 21:31:06 +0200
committerShauren <shauren.trinity@gmail.com>2023-08-01 21:31:06 +0200
commit9cdf3530f41e18fc815e7b164e40c01a18c3d757 (patch)
treecaaee9063d1ab16d2ddfdb5fff2f2acf3d3c08b1 /src/server
parent197d4369c894e9b088f862c7189f4fe20b4836ca (diff)
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
Diffstat (limited to 'src/server')
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp79
-rw-r--r--src/server/game/Entities/Unit/Unit.h12
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp30
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h2
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp13
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h1
-rw-r--r--src/server/game/Spells/Spell.cpp24
-rw-r--r--src/server/game/Spells/Spell.h2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp24
-rw-r--r--src/server/game/Spells/SpellScript.cpp31
-rw-r--r--src/server/game/Spells/SpellScript.h152
11 files changed, 296 insertions, 74 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 0b053207feb..3207980d1d1 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -1302,7 +1302,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, Weapon
uint32 damage = 0;
damage += CalculateDamage(damageInfo->AttackType, false, true);
// Add melee damage bonus
- damage = MeleeDamageBonusDone(damageInfo->Target, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, nullptr, SpellSchoolMask(damageInfo->DamageSchoolMask));
+ damage = MeleeDamageBonusDone(damageInfo->Target, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, MECHANIC_NONE, SpellSchoolMask(damageInfo->DamageSchoolMask));
damage = damageInfo->Target->MeleeDamageBonusTaken(this, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, SpellSchoolMask(damageInfo->DamageSchoolMask));
// Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
@@ -6488,22 +6488,35 @@ void Unit::EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damag
SendEnergizeSpellLog(victim, spellInfo->Id, gain, overEnergize, powerType);
}
-uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack /*= 1*/) const
+int32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, int32 pdamage, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack /*= 1*/, Spell* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/) const
{
- if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
+ if (!spellProto || !victim)
return pdamage;
+ int32 DoneTotal = 0;
+ float DoneTotalMod = 1.0f;
+
+ auto callDamageScript = [&](int32& dmg, int32& flatMod, float& pctMod)
+ {
+ if (spell)
+ spell->CallScriptCalcDamageHandlers(victim, dmg, flatMod, pctMod);
+ else if (aurEff)
+ aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, dmg, flatMod, pctMod);
+ };
+
// Some spells don't benefit from done mods
- if (spellProto->HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
- return pdamage;
+ if (damagetype == DIRECT_DAMAGE || spellProto->HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
+ {
+ callDamageScript(pdamage, DoneTotal, DoneTotalMod);
+ return int32(std::max(float(pdamage + DoneTotal) * DoneTotalMod, 0.0f));
+ }
// For totems get damage bonus from owner
if (GetTypeId() == TYPEID_UNIT && IsTotem())
if (Unit* owner = GetOwner())
- return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, stack);
+ return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, stack, spell, aurEff);
- int32 DoneTotal = 0;
- float DoneTotalMod = SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
+ DoneTotalMod = SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
// Done fixed damage bonus auras
int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask());
@@ -6561,13 +6574,15 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack);
}
- float tmpDamage = float(int32(pdamage) + DoneTotal) * DoneTotalMod;
+ callDamageScript(pdamage, DoneTotal, DoneTotalMod);
+
+ float tmpDamage = float(pdamage + DoneTotal) * DoneTotalMod;
// apply spellmod to Done damage (flat and pct)
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, tmpDamage);
- return uint32(std::max(tmpDamage, 0.0f));
+ return int32(std::max(tmpDamage, 0.0f));
}
float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo) const
@@ -6662,7 +6677,7 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage
return DoneTotalMod;
}
-uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype) const
+int32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 pdamage, DamageEffectType damagetype) const
{
if (!spellProto || damagetype == DIRECT_DAMAGE)
return pdamage;
@@ -6744,7 +6759,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
}
float tmpDamage = pdamage * TakenTotalMod;
- return uint32(std::max(tmpDamage, 0.0f));
+ return int32(std::max(tmpDamage, 0.0f));
}
int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
@@ -6980,12 +6995,12 @@ float Unit::SpellCritChanceTaken(Unit const* caster, Spell* spell, AuraEffect co
return damage;
}
-uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack /*= 1*/) const
+int32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack /*= 1*/, Spell* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/) const
{
// For totems get healing bonus from owner (statue isn't totem in fact)
if (GetTypeId() == TYPEID_UNIT && IsTotem())
if (Unit* owner = GetOwner())
- 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
if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
@@ -7068,13 +7083,18 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
DoneTotal = 0;
}
- float heal = float(int32(healamount) + DoneTotal) * DoneTotalMod;
+ if (spell)
+ spell->CallScriptCalcHealingHandlers(victim, healamount, DoneTotal, DoneTotalMod);
+ else if (aurEff)
+ aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, healamount, DoneTotal, DoneTotalMod);
+
+ float heal = float(healamount + DoneTotal) * DoneTotalMod;
// apply spellmod to Done amount
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, heal);
- return uint32(std::max(heal, 0.0f));
+ return int32(std::max(heal, 0.0f));
}
float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
@@ -7128,7 +7148,7 @@ float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
return DoneTotalMod;
}
-uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype) const
+int32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype) const
{
float TakenTotalMod = 1.0f;
@@ -7178,7 +7198,7 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u
}
float heal = healamount * TakenTotalMod;
- return uint32(std::max(heal, 0.0f));
+ return int32(std::max(heal, 0.0f));
}
int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const
@@ -7451,7 +7471,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo co
return false;
}
-uint32 Unit::MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, SpellEffectInfo const* spellEffectInfo /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
+int32 Unit::MeleeDamageBonusDone(Unit* pVictim, int32 damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, Mechanics mechanic /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/, Spell* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/)
{
if (!pVictim || damage == 0)
return 0;
@@ -7542,25 +7562,28 @@ uint32 Unit::MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType
});
// Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
- if (spellEffectInfo && spellEffectInfo->Mechanic)
- AddPct(DoneTotalMod, GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC, spellEffectInfo->Mechanic));
+ if (mechanic != MECHANIC_NONE)
+ AddPct(DoneTotalMod, GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC, mechanic));
else if (spellProto && spellProto->Mechanic)
AddPct(DoneTotalMod, GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC, spellProto->Mechanic));
- float damageF = damage;
+ if (spell)
+ spell->CallScriptCalcDamageHandlers(pVictim, damage, DoneFlatBenefit, DoneTotalMod);
+ else if (aurEff)
+ aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(pVictim->GetGUID()), pVictim, damage, DoneFlatBenefit, DoneTotalMod);
+
+ float damageF = float(damage + DoneFlatBenefit) * DoneTotalMod;
// apply spellmod to Done damage
if (spellProto)
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, damageF);
- damageF = (damageF + DoneFlatBenefit) * DoneTotalMod;
-
// bonus result can be negative
- return uint32(std::max(damageF, 0.0f));
+ return int32(std::max(damageF, 0.0f));
}
-uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
+int32 Unit::MeleeDamageBonusTaken(Unit* attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
{
if (pdamage == 0)
return 0;
@@ -7575,7 +7598,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
else
TakenFlatBenefit += GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN);
- if ((TakenFlatBenefit < 0) && (pdamage < static_cast<uint32>(-TakenFlatBenefit)))
+ if ((TakenFlatBenefit < 0) && (pdamage < -TakenFlatBenefit))
return 0;
// Taken total percent damage auras
@@ -7666,7 +7689,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
}
float tmpDamage = float(pdamage + TakenFlatBenefit) * TakenTotalMod;
- return uint32(std::max(tmpDamage, 0.0f));
+ return int32(std::max(tmpDamage, 0.0f));
}
void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index aa2bfee5b6c..1296f001c22 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1709,16 +1709,16 @@ class TC_GAME_API Unit : public WorldObject
Unit* GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo = nullptr);
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const;
- uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack = 1) const;
+ int32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, int32 pdamage, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack = 1, Spell* spell = nullptr, AuraEffect const* aurEff = nullptr) const;
float SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo) const;
- uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype) const;
+ int32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 pdamage, DamageEffectType damagetype) const;
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const;
- uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack = 1) const;
+ int32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, uint32 stack = 1, Spell* spell = nullptr, AuraEffect const* aurEff = nullptr) const;
float SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const;
- uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype) const;
+ int32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype) const;
- uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto = nullptr, SpellEffectInfo const* spellEffectInfo = nullptr, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL);
- uint32 MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto = nullptr, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL);
+ int32 MeleeDamageBonusDone(Unit* pVictim, int32 damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto = nullptr, Mechanics mechanic = MECHANIC_NONE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, Spell* spell = nullptr, AuraEffect const* aurEff = nullptr);
+ int32 MeleeDamageBonusTaken(Unit* attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto = nullptr, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL);
bool IsBlockCritical();
float SpellCritChanceDone(Spell* spell, AuraEffect const* aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const;
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 665e6fca4de..03ee64aeeb0 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -721,7 +721,7 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
}
Optional<float> AuraEffect::CalculateEstimatedAmount(Unit const* caster, Unit* target, SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo,
- int32 amount, uint8 stack)
+ int32 amount, uint8 stack, AuraEffect const* aurEff)
{
uint32 stackAmountForBonuses = !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::NoScaleWithStack) ? stack : 1;
@@ -729,9 +729,9 @@ Optional<float> AuraEffect::CalculateEstimatedAmount(Unit const* caster, Unit* t
{
case SPELL_AURA_PERIODIC_DAMAGE:
case SPELL_AURA_PERIODIC_LEECH:
- return caster->SpellDamageBonusDone(target, spellInfo, amount, DOT, spellEffectInfo, stackAmountForBonuses);
+ return caster->SpellDamageBonusDone(target, spellInfo, amount, DOT, spellEffectInfo, stackAmountForBonuses, nullptr, aurEff);
case SPELL_AURA_PERIODIC_HEAL:
- return caster->SpellHealingBonusDone(target, spellInfo, amount, DOT, spellEffectInfo, stackAmountForBonuses);
+ return caster->SpellHealingBonusDone(target, spellInfo, amount, DOT, spellEffectInfo, stackAmountForBonuses, nullptr, aurEff);
default:
break;
}
@@ -744,7 +744,7 @@ Optional<float> AuraEffect::CalculateEstimatedAmount(Unit const* caster, int32 a
if (!caster || GetBase()->GetType() != UNIT_AURA_TYPE)
return {};
- return CalculateEstimatedAmount(caster, GetBase()->GetUnitOwner(), GetSpellInfo(), GetSpellEffectInfo(), amount, GetBase()->GetStackAmount());
+ return CalculateEstimatedAmount(caster, GetBase()->GetUnitOwner(), GetSpellInfo(), GetSpellEffectInfo(), amount, GetBase()->GetStackAmount(), this);
}
float AuraEffect::CalculateEstimatedfTotalPeriodicAmount(Unit* caster, Unit* target, SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo,
@@ -774,7 +774,7 @@ float AuraEffect::CalculateEstimatedfTotalPeriodicAmount(Unit* caster, Unit* tar
if (spellInfo->HasAttribute(SPELL_ATTR5_EXTRA_INITIAL_PERIOD))
totalTicks += 1.0f;
- return totalTicks * CalculateEstimatedAmount(caster, target, spellInfo, spellEffectInfo, amount, stack).value_or(amount);
+ return totalTicks * CalculateEstimatedAmount(caster, target, spellInfo, spellEffectInfo, amount, stack, nullptr).value_or(amount);
}
uint32 AuraEffect::GetTotalTicks() const
@@ -5404,16 +5404,10 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
case SPELL_AURA_PERIODIC_DAMAGE:
{
if (caster)
- damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), stackAmountForBonuses);
+ damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), stackAmountForBonuses, nullptr, this);
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT);
- // There is a Chance to make a Soul Shard when Drain soul does damage
- if (caster && GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellInfo()->SpellFamilyFlags[0] & 0x00004000))
- {
- if (caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->isHonorOrXPTarget(target))
- caster->CastSpell(caster, 95810, this);
- }
- else if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_GENERIC)
+ if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_GENERIC)
{
switch (GetId())
{
@@ -5437,7 +5431,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
// Add melee damage bonuses (also check for negative)
if (caster)
- damage = caster->MeleeDamageBonusDone(target, damage, attackType, DOT, GetSpellInfo());
+ damage = caster->MeleeDamageBonusDone(target, damage, attackType, DOT, GetSpellInfo(), GetSpellEffectInfo().Mechanic, GetSpellInfo()->GetSchoolMask(), nullptr, this);
damage = target->MeleeDamageBonusTaken(caster, damage, attackType, DOT, GetSpellInfo());
break;
@@ -5537,7 +5531,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
uint32 damage = std::max(GetAmount(), 0);
if (caster)
- damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), stackAmountForBonuses);
+ damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), stackAmountForBonuses, nullptr, this);
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT);
bool crit = roll_chance_f(GetCritChanceFor(caster, target));
@@ -5600,7 +5594,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster);
- uint32 heal = caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetSpellEffectInfo(), stackAmountForBonuses);
+ uint32 heal = caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetSpellEffectInfo(), stackAmountForBonuses, nullptr, this);
heal = caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT);
HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
@@ -5665,7 +5659,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
if (GetAuraType() == SPELL_AURA_OBS_MOD_HEALTH)
damage = uint32(target->CountPctFromMaxHealth(damage));
else if (caster)
- damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), stackAmountForBonuses);
+ damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), stackAmountForBonuses, nullptr, this);
damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT);
@@ -5960,7 +5954,7 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv
}
SpellNonMeleeDamage damageInfo(target, triggerTarget, GetSpellInfo(), GetBase()->GetSpellVisual(), GetSpellInfo()->SchoolMask, GetBase()->GetCastId());
- uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE, GetSpellEffectInfo());
+ uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE, GetSpellEffectInfo(), 1, nullptr, this);
damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE);
target->CalculateSpellDamageTaken(&damageInfo, damage, GetSpellInfo());
Unit::DealDamageMods(damageInfo.attacker, damageInfo.target, damageInfo.damage, &damageInfo.absorb);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index c90bccead32..ba5e771f456 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -65,7 +65,7 @@ class TC_GAME_API AuraEffect
void SetPeriodicTimer(int32 periodicTimer) { _periodicTimer = periodicTimer; }
int32 CalculateAmount(Unit* caster);
- static Optional<float> CalculateEstimatedAmount(Unit const* caster, Unit* target, SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, int32 amount, uint8 stack);
+ static Optional<float> CalculateEstimatedAmount(Unit const* caster, Unit* target, SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, int32 amount, uint8 stack, AuraEffect const* aurEff);
Optional<float> CalculateEstimatedAmount(Unit const* caster, int32 amount) const;
static float CalculateEstimatedfTotalPeriodicAmount(Unit* caster, Unit* target, SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, float amount, uint8 stack);
void CalculatePeriodic(Unit* caster, bool resetPeriodicTimer = true, bool load = false);
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 7021f4a0367..d6e11cb6521 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -2185,6 +2185,19 @@ void Aura::CallScriptEffectCalcCritChanceHandlers(AuraEffect const* aurEff, Aura
}
}
+void Aura::CallScriptCalcDamageAndHealingHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod)
+{
+ for (AuraScript* script : m_loadedScripts)
+ {
+ script->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_DAMAGE_AND_HEALING, aurApp);
+ for (AuraScript::EffectCalcDamageAndHealingHandler const& effectCalcDamageAndHealing : script->DoEffectCalcDamageAndHealing)
+ if (effectCalcDamageAndHealing.IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effectCalcDamageAndHealing.Call(script, aurEff, victim, damageOrHealing, flatMod, pctMod);
+
+ script->_FinishScriptCall();
+ }
+}
+
void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo& dmgInfo, uint32& absorbAmount, bool& defaultPrevented)
{
for (AuraScript* script : m_loadedScripts)
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index b57958d003e..195f5a2fda6 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -272,6 +272,7 @@ class TC_GAME_API Aura
void CallScriptEffectCalcPeriodicHandlers(AuraEffect const* aurEff, bool& isPeriodic, int32& amplitude);
void CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellModifier*& spellMod);
void CallScriptEffectCalcCritChanceHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, Unit const* victim, float& critChance);
+ void CallScriptCalcDamageAndHealingHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod);
void CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo& dmgInfo, uint32& absorbAmount, bool & defaultPrevented);
void CallScriptEffectAfterAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo& dmgInfo, uint32& absorbAmount);
void CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, HealInfo& healInfo, uint32& absorbAmount, bool& defaultPrevented);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index d525cde3a66..e9a20585c6b 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -8632,6 +8632,30 @@ void Spell::CallScriptCalcCritChanceHandlers(Unit const* victim, float& critChan
}
}
+void Spell::CallScriptCalcDamageHandlers(Unit* victim, int32& damage, int32& flatMod, float& pctMod)
+{
+ for (SpellScript* script : m_loadedScripts)
+ {
+ script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_DAMAGE);
+ for (SpellScript::DamageAndHealingCalcHandler const& calcDamage : script->CalcDamage)
+ calcDamage.Call(script, victim, damage, flatMod, pctMod);
+
+ script->_FinishScriptCall();
+ }
+}
+
+void Spell::CallScriptCalcHealingHandlers(Unit* victim, int32& healing, int32& flatMod, float& pctMod)
+{
+ for (SpellScript* script : m_loadedScripts)
+ {
+ script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_DAMAGE);
+ for (SpellScript::DamageAndHealingCalcHandler const& calcHealing : script->CalcHealing)
+ calcHealing.Call(script, victim, healing, flatMod, pctMod);
+
+ script->_FinishScriptCall();
+ }
+}
+
void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
{
for (SpellScript* script : m_loadedScripts)
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 61c283cb82c..e173a978391 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -852,6 +852,8 @@ class TC_GAME_API Spell
void CallScriptAfterHitHandlers();
public:
void CallScriptCalcCritChanceHandlers(Unit const* victim, float& chance);
+ void CallScriptCalcDamageHandlers(Unit* victim, int32& damage, int32& flatMod, float& pctMod);
+ void CallScriptCalcHealingHandlers(Unit* victim, int32& healing, int32& flatMod, float& pctMod);
protected:
void CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
void CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 402dc90f9ec..22a1bcaf147 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -543,7 +543,7 @@ void Spell::EffectSchoolDMG()
if (unitCaster && apply_direct_bonus)
{
- uint32 bonus = unitCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, *effectInfo);
+ uint32 bonus = unitCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, *effectInfo, 1, this);
damage = bonus + uint32(bonus * variance);
damage = unitTarget->SpellDamageBonusTaken(unitCaster, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
}
@@ -1062,7 +1062,7 @@ void Spell::EffectPowerDrain()
// add spell damage bonus
if (unitCaster)
{
- uint32 bonus = unitCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, *effectInfo);
+ uint32 bonus = unitCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, *effectInfo, 1, this);
damage = bonus + uint32(bonus * variance);
damage = unitTarget->SpellDamageBonusTaken(unitCaster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
}
@@ -1176,10 +1176,10 @@ void Spell::EffectHeal()
}
// Death Pact - return pct of max health to caster
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000)
- addhealth = unitCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(unitCaster->CountPctFromMaxHealth(damage)), HEAL, *effectInfo);
+ addhealth = unitCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(unitCaster->CountPctFromMaxHealth(damage)), HEAL, *effectInfo, 1, this);
else
{
- uint32 bonus = unitCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, *effectInfo);
+ uint32 bonus = unitCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, *effectInfo, 1, this);
addhealth = bonus + uint32(bonus * variance);
}
@@ -1203,7 +1203,7 @@ void Spell::EffectHealPct()
uint32 heal = unitTarget->CountPctFromMaxHealth(damage);
if (Unit* unitCaster = GetUnitCasterForEffectHandlers())
{
- heal = unitCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, heal, HEAL, *effectInfo);
+ heal = unitCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, heal, HEAL, *effectInfo, 1, this);
heal = unitTarget->SpellHealingBonusTaken(unitCaster, m_spellInfo, heal, HEAL);
}
@@ -1221,7 +1221,7 @@ void Spell::EffectHealMechanical()
Unit* unitCaster = GetUnitCasterForEffectHandlers();
uint32 heal = damage;
if (unitCaster)
- heal = unitCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, heal, HEAL, *effectInfo);
+ heal = unitCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, heal, HEAL, *effectInfo, 1, this);
heal += uint32(heal * variance);
if (unitCaster)
@@ -1241,7 +1241,7 @@ void Spell::EffectHealthLeech()
Unit* unitCaster = GetUnitCasterForEffectHandlers();
uint32 bonus = 0;
if (unitCaster)
- bonus = unitCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, *effectInfo);
+ bonus = unitCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, *effectInfo, 1, this);
damage = bonus + uint32(bonus * variance);
@@ -1264,7 +1264,7 @@ void Spell::EffectHealthLeech()
if (unitCaster && unitCaster->IsAlive())
{
- healthGain = unitCaster->SpellHealingBonusDone(unitCaster, m_spellInfo, healthGain, HEAL, *effectInfo);
+ healthGain = unitCaster->SpellHealingBonusDone(unitCaster, m_spellInfo, healthGain, HEAL, *effectInfo, 1, this);
healthGain = unitCaster->SpellHealingBonusTaken(unitCaster, m_spellInfo, healthGain, HEAL);
HealInfo healInfo(unitCaster, unitCaster, healthGain, m_spellInfo, m_spellSchoolMask);
@@ -2801,6 +2801,7 @@ void Spell::EffectWeaponDmg()
}
int32 weaponDamage = unitCaster->CalculateDamage(m_attackType, normalized, addPctMods);
+ Mechanics mechanic = MECHANIC_NONE;
// Sequence is important
for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
@@ -2818,8 +2819,11 @@ void Spell::EffectWeaponDmg()
weaponDamage = int32(weaponDamage * weaponDamagePercentMod);
break;
default:
- break; // not weapon damage effect, just skip
+ continue; // not weapon damage effect, just skip
}
+
+ if (spellEffectInfo.Mechanic != MECHANIC_NONE && mechanic == MECHANIC_NONE)
+ mechanic = spellEffectInfo.Mechanic;
}
weaponDamage += spell_bonus;
@@ -2829,7 +2833,7 @@ void Spell::EffectWeaponDmg()
weaponDamage = std::max(weaponDamage, 0);
// Add melee damage bonuses (also check for negative)
- weaponDamage = unitCaster->MeleeDamageBonusDone(unitTarget, weaponDamage, m_attackType, SPELL_DIRECT_DAMAGE, m_spellInfo, effectInfo);
+ weaponDamage = unitCaster->MeleeDamageBonusDone(unitTarget, weaponDamage, m_attackType, SPELL_DIRECT_DAMAGE, m_spellInfo, mechanic, m_spellSchoolMask, this);
m_damage += unitTarget->MeleeDamageBonusTaken(unitCaster, weaponDamage, m_attackType, SPELL_DIRECT_DAMAGE, m_spellInfo);
}
diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp
index 9435d52ac42..1542ff14c55 100644
--- a/src/server/game/Spells/SpellScript.cpp
+++ b/src/server/game/Spells/SpellScript.cpp
@@ -288,6 +288,27 @@ bool SpellScript::_Validate(SpellInfo const* entry)
if (!hook.GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `{}` Effect `{}` of script `{}` did not match dbc effect data - handler bound to hook `OnDestinationTargetSelect` of SpellScript won't be executed", entry->Id, hook.ToString(), m_scriptName);
+ if (CalcDamage.size())
+ {
+ if (!entry->HasEffect(SPELL_EFFECT_SCHOOL_DAMAGE)
+ && !entry->HasEffect(SPELL_EFFECT_POWER_DRAIN)
+ && !entry->HasEffect(SPELL_EFFECT_HEALTH_LEECH)
+ && !entry->HasEffect(SPELL_EFFECT_WEAPON_DAMAGE)
+ && !entry->HasEffect(SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL)
+ && !entry->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG)
+ && !entry->HasEffect(SPELL_EFFECT_WEAPON_PERCENT_DAMAGE))
+ TC_LOG_ERROR("scripts", "Spell `{}` script `{}` does not have a damage effect - handler bound to hook `CalcDamage` of SpellScript won't be executed", entry->Id, m_scriptName);
+ }
+
+ if (CalcHealing.size())
+ {
+ if (!entry->HasEffect(SPELL_EFFECT_HEAL)
+ && !entry->HasEffect(SPELL_EFFECT_HEAL_PCT)
+ && !entry->HasEffect(SPELL_EFFECT_HEAL_MECHANICAL)
+ && !entry->HasEffect(SPELL_EFFECT_HEALTH_LEECH))
+ TC_LOG_ERROR("scripts", "Spell `{}` script `{}` does not have a damage effect - handler bound to hook `CalcHealing` of SpellScript won't be executed", entry->Id, m_scriptName);
+ }
+
return SpellScriptBase::_Validate(entry);
}
@@ -327,7 +348,9 @@ bool SpellScript::IsAfterTargetSelectionPhase() const
|| IsInEffectHook()
|| m_currentScriptState == SPELL_SCRIPT_HOOK_ON_CAST
|| m_currentScriptState == SPELL_SCRIPT_HOOK_AFTER_CAST
- || m_currentScriptState == SPELL_SCRIPT_HOOK_CALC_CRIT_CHANCE;
+ || m_currentScriptState == SPELL_SCRIPT_HOOK_CALC_CRIT_CHANCE
+ || m_currentScriptState == SPELL_SCRIPT_HOOK_CALC_DAMAGE
+ || m_currentScriptState == SPELL_SCRIPT_HOOK_CALC_HEALING;
}
bool SpellScript::IsInTargetHook() const
@@ -804,6 +827,10 @@ bool AuraScript::_Validate(SpellInfo const* entry)
if (!itr->GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `{}` Effect `{}` of script `{}` did not match dbc effect data - handler bound to hook `DoEffectCalcCritChance` of AuraScript won't be executed", entry->Id, itr->ToString(), m_scriptName);
+ for (EffectCalcDamageAndHealingHandler const& hook : DoEffectCalcDamageAndHealing)
+ if (!hook.GetAffectedEffectsMask(entry))
+ TC_LOG_ERROR("scripts", "Spell `{}` Effect `{}` of script `{}` did not match dbc effect data - handler bound to hook `DoEffectCalcDamageAndHealing` of AuraScript won't be executed", entry->Id, hook.ToString(), m_scriptName);
+
for (auto itr = OnEffectAbsorb.begin(); itr != OnEffectAbsorb.end(); ++itr)
if (!itr->GetAffectedEffectsMask(entry))
TC_LOG_ERROR("scripts", "Spell `{}` Effect `{}` of script `{}` did not match dbc effect data - handler bound to hook `OnEffectAbsorb` of AuraScript won't be executed", entry->Id, itr->ToString(), m_scriptName);
@@ -1139,6 +1166,8 @@ Unit* AuraScript::GetTarget() const
case AURA_SCRIPT_HOOK_EFFECT_AFTER_APPLY:
case AURA_SCRIPT_HOOK_EFFECT_AFTER_REMOVE:
case AURA_SCRIPT_HOOK_EFFECT_PERIODIC:
+ case AURA_SCRIPT_HOOK_EFFECT_CALC_CRIT_CHANCE:
+ case AURA_SCRIPT_HOOK_EFFECT_CALC_DAMAGE_AND_HEALING:
case AURA_SCRIPT_HOOK_EFFECT_ABSORB:
case AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB:
case AURA_SCRIPT_HOOK_EFFECT_MANASHIELD:
diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h
index 651906e4e50..1d13f4f2441 100644
--- a/src/server/game/Spells/SpellScript.h
+++ b/src/server/game/Spells/SpellScript.h
@@ -234,6 +234,8 @@ enum SpellScriptHookType
SPELL_SCRIPT_HOOK_ON_RESIST_ABSORB_CALCULATION,
SPELL_SCRIPT_HOOK_AFTER_CAST,
SPELL_SCRIPT_HOOK_CALC_CRIT_CHANCE,
+ SPELL_SCRIPT_HOOK_CALC_DAMAGE,
+ SPELL_SCRIPT_HOOK_CALC_HEALING,
SPELL_SCRIPT_HOOK_ON_PRECAST,
SPELL_SCRIPT_HOOK_CALC_CAST_TIME,
};
@@ -693,6 +695,60 @@ public:
SafeWrapperType _safeWrapper;
};
+ class DamageAndHealingCalcHandler final
+ {
+ public:
+ union DamageAndHealingCalcFnType
+ {
+ void(SpellScript::* Member)(Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod);
+ void(*Static)(Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod);
+ };
+
+ using SafeWrapperType = void(*)(SpellScript* spellScript, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod, DamageAndHealingCalcFnType callImpl);
+
+ template<typename ScriptFunc>
+ explicit DamageAndHealingCalcHandler(ScriptFunc handler)
+ {
+ using ScriptClass = GetScriptClass_t<ScriptFunc>;
+
+ static_assert(sizeof(DamageAndHealingCalcFnType) >= sizeof(ScriptFunc));
+ static_assert(alignof(DamageAndHealingCalcFnType) >= alignof(ScriptFunc));
+
+ if constexpr (!std::is_void_v<ScriptClass>)
+ {
+ static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, Unit*, int32&, int32&, float&>
+ && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, Unit*, int32&, int32&, float&>, void>,
+ "DamageAndHealingCalcHandler signature must be \"void CalcDamage(Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod)\"");
+
+ _callImpl = { .Member = reinterpret_cast<decltype(DamageAndHealingCalcFnType::Member)>(handler) };
+ _safeWrapper = [](SpellScript* spellScript, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod, DamageAndHealingCalcFnType callImpl)
+ {
+ return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(victim, damageOrHealing, flatMod, pctMod);
+ };
+ }
+ else
+ {
+ static_assert(std::is_invocable_v<ScriptFunc, Unit*, int32&, int32&, float&>
+ && std::is_same_v<std::invoke_result_t<ScriptFunc, Unit*, int32&, int32&, float&>, void>,
+ "DamageAndHealingCalcHandler signature must be \"static void CalcDamage(Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod)\"");
+
+ _callImpl = { .Static = reinterpret_cast<decltype(DamageAndHealingCalcFnType::Static)>(handler) };
+ _safeWrapper = [](SpellScript* /*spellScript*/, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod, DamageAndHealingCalcFnType callImpl)
+ {
+ return reinterpret_cast<ScriptFunc>(callImpl.Static)(victim, damageOrHealing, flatMod, pctMod);
+ };
+ }
+ }
+
+ void Call(SpellScript* spellScript, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod) const
+ {
+ return _safeWrapper(spellScript, victim, damageOrHealing, flatMod, pctMod, _callImpl);
+ }
+ private:
+ DamageAndHealingCalcFnType _callImpl;
+ SafeWrapperType _safeWrapper;
+ };
+
class OnCalculateResistAbsorbHandler final
{
public:
@@ -835,6 +891,16 @@ public:
HookList<DestinationTargetSelectHandler> OnDestinationTargetSelect;
#define SpellDestinationTargetSelectFn(F, I, N) DestinationTargetSelectHandler(&F, I, N)
+ // example: CalcDamage += SpellCalcDamageFn(class::function);
+ // where function is void function(Unit* victim, int32& damage, int32& flatMod, float& pctMod)
+ HookList<DamageAndHealingCalcHandler> CalcDamage;
+ #define SpellCalcDamageFn(F) DamageAndHealingCalcHandler(&F)
+
+ // example: CalcHealing += SpellCalcHealingFn(class::function);
+ // where function is void function(Unit* victim, int32& healing, int32& flatMod, float& pctMod)
+ HookList<DamageAndHealingCalcHandler> CalcHealing;
+ #define SpellCalcHealingFn(F) DamageAndHealingCalcHandler(&F)
+
// example: OnCalculateResistAbsorb += SpellOnResistAbsorbCalculateFn(class::function);
// where function is void function(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount)
HookList<OnCalculateResistAbsorbHandler> OnCalculateResistAbsorb;
@@ -850,14 +916,16 @@ public:
// 5. OnCast - executed just before spell is launched (creates missile) or executed
// 6. AfterCast - executed after spell missile is launched and immediate spell actions are done
// 7. OnEffectLaunch - executed just before specified effect handler call - when spell missile is launched
- // 8. OnEffectLaunchTarget - executed just before specified effect handler call - when spell missile is launched - called for each target from spell target map
- // 9. OnCalcCritChance - executed just after specified effect handler call - when spell missile is launched - called for each target from spell target map
- // 10. OnCalculateResistAbsorb - executed when damage resist/absorbs is calculated - before spell hit target
- // 11. OnEffectHit - executed just before specified effect handler call - when spell missile hits dest
- // 12. BeforeHit - executed just before spell hits a target - called for each target from spell target map
- // 13. OnEffectHitTarget - executed just before specified effect handler call - called for each target from spell target map
- // 14. OnHit - executed just before spell deals damage and procs auras - when spell hits target - called for each target from spell target map
- // 15. AfterHit - executed just after spell finishes all it's jobs for 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
+ // 9. OnEffectLaunchTarget - executed just before specified effect handler call - when spell missile is launched - 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
+ // 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
// this hook is only executed after a successful dispel of any aura
// OnEffectSuccessfulDispel - executed just after effect successfully dispelled aura(s)
@@ -989,6 +1057,7 @@ enum AuraScriptHookType
AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC,
AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD,
AURA_SCRIPT_HOOK_EFFECT_CALC_CRIT_CHANCE,
+ AURA_SCRIPT_HOOK_EFFECT_CALC_DAMAGE_AND_HEALING,
AURA_SCRIPT_HOOK_EFFECT_ABSORB,
AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB,
AURA_SCRIPT_HOOK_EFFECT_MANASHIELD,
@@ -1441,7 +1510,7 @@ public:
{
static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, Unit const*, float&>
&& std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, Unit const*, float&>, void>,
- "EffectCalcSpellModHandler signature must be \"void CalcCritChance(AuraEffect const* aurEff, Unit const* victim, float& critChance)\"");
+ "EffectCalcCritChanceHandler signature must be \"void CalcCritChance(AuraEffect const* aurEff, Unit const* victim, float& critChance)\"");
_callImpl = { .Member = reinterpret_cast<decltype(AuraEffectCalcCritChanceFnType::Member)>(handler) };
_safeWrapper = [](AuraScript* auraScript, AuraEffect const* aurEff, Unit const* victim, float& critChance, AuraEffectCalcCritChanceFnType callImpl)
@@ -1453,7 +1522,7 @@ public:
{
static_assert(std::is_invocable_v<ScriptFunc, AuraEffect const*, Unit const*, float&>
&& std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect const*, Unit const*, float&>, void>,
- "EffectCalcSpellModHandler signature must be \"static void CalcCritChance(AuraEffect const* aurEff, Unit const* victim, float& critChance)\"");
+ "EffectCalcCritChanceHandler signature must be \"static void CalcCritChance(AuraEffect const* aurEff, Unit const* victim, float& critChance)\"");
_callImpl = { .Static = reinterpret_cast<decltype(AuraEffectCalcCritChanceFnType::Static)>(handler) };
_safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect const* aurEff, Unit const* victim, float& critChance, AuraEffectCalcCritChanceFnType callImpl)
@@ -1472,6 +1541,61 @@ public:
SafeWrapperType _safeWrapper;
};
+ class EffectCalcDamageAndHealingHandler final : public EffectBase
+ {
+ public:
+ union AuraEffectDamageAndHealingCalcFnType
+ {
+ void(AuraScript::* Member)(AuraEffect const* aurEff, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod);
+ void(*Static)(AuraEffect const* aurEff, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod);
+ };
+
+ using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect const* aurEff, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod, AuraEffectDamageAndHealingCalcFnType callImpl);
+
+ template<typename ScriptFunc>
+ explicit EffectCalcDamageAndHealingHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType)
+ : EffectBase(effIndex, auraType)
+ {
+ using ScriptClass = GetScriptClass_t<ScriptFunc>;
+
+ static_assert(sizeof(AuraEffectDamageAndHealingCalcFnType) >= sizeof(ScriptFunc));
+ static_assert(alignof(AuraEffectDamageAndHealingCalcFnType) >= alignof(ScriptFunc));
+
+ if constexpr (!std::is_void_v<ScriptClass>)
+ {
+ static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, Unit*, int32&, int32&, float&>
+ && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, Unit*, int32&, int32&, float&>, void>,
+ "EffectCalcDamageAndHealingHandler signature must be \"void CalcDamageAndHealing(AuraEffect const* aurEff, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod)\"");
+
+ _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectDamageAndHealingCalcFnType::Member)>(handler) };
+ _safeWrapper = [](AuraScript* auraScript, AuraEffect const* aurEff, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod, AuraEffectDamageAndHealingCalcFnType callImpl)
+ {
+ return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, victim, damageOrHealing, flatMod, pctMod);
+ };
+ }
+ else
+ {
+ static_assert(std::is_invocable_v<ScriptFunc, AuraEffect const*, Unit*, int32&, int32&, float&>
+ && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect const*, Unit*, int32&, int32&, float&>, void>,
+ "EffectCalcDamageAndHealingHandler signature must be \"static void CalcDamageAndHealing(AuraEffect const* aurEff, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod)\"");
+
+ _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectDamageAndHealingCalcFnType::Static)>(handler) };
+ _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect const* aurEff, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod, AuraEffectDamageAndHealingCalcFnType callImpl)
+ {
+ return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, victim, damageOrHealing, flatMod, pctMod);
+ };
+ }
+ }
+
+ void Call(AuraScript* auraScript, AuraEffect const* aurEff, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod) const
+ {
+ return _safeWrapper(auraScript, aurEff, victim, damageOrHealing, flatMod, pctMod, _callImpl);
+ }
+ private:
+ AuraEffectDamageAndHealingCalcFnType _callImpl;
+ SafeWrapperType _safeWrapper;
+ };
+
class EffectApplyHandler final : public EffectBase
{
public:
@@ -2002,6 +2126,14 @@ public:
HookList<EffectCalcCritChanceHandler> DoEffectCalcCritChance;
#define AuraEffectCalcCritChanceFn(F, I, N) EffectCalcCritChanceHandler(&F, I, N)
+ // 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 function (AuraEffect const* aurEff, Unit* victim, int32& damageOrHealing, int32& flatMod, float& pctMod);
+ HookList<EffectCalcDamageAndHealingHandler> DoEffectCalcDamageAndHealing;
+ #define AuraEffectCalcDamageFn(F, I, N) EffectCalcDamageAndHealingHandler(&F, I, N)
+ #define AuraEffectCalcHealingFn(F, I, N) EffectCalcDamageAndHealingHandler(&F, I, N)
+
// executed when absorb aura effect is going to reduce damage
// example: OnEffectAbsorb += AuraEffectAbsorbFn(class::function, EffectIndexSpecifier);
// where function is: void function (AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount);