diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-08-01 21:31:06 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2023-08-01 21:31:06 +0200 |
commit | 9cdf3530f41e18fc815e7b164e40c01a18c3d757 (patch) | |
tree | caaee9063d1ab16d2ddfdb5fff2f2acf3d3c08b1 /src | |
parent | 197d4369c894e9b088f862c7189f4fe20b4836ca (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')
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 79 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 12 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 30 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.h | 2 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 13 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.h | 1 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 24 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 24 | ||||
-rw-r--r-- | src/server/game/Spells/SpellScript.cpp | 31 | ||||
-rw-r--r-- | src/server/game/Spells/SpellScript.h | 152 |
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); |