From 661d9e9d418d3baaf1698e180dbc5d80c15ea7c9 Mon Sep 17 00:00:00 2001 From: Sevi Date: Thu, 19 Mar 2026 20:57:20 +0100 Subject: [PATCH 1/2] Core/Auras: Fix hunter periodic damage critical bonus calculation --- src/server/game/Entities/Unit/Unit.cpp | 30 ++++++++++++------- src/server/game/Entities/Unit/Unit.h | 3 +- .../game/Spells/Auras/SpellAuraEffects.cpp | 16 +++++----- .../game/Spells/Auras/SpellAuraEffects.h | 2 +- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 22634ee9f4..ff3e43cf13 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -7003,24 +7003,34 @@ float Unit::SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, return std::max(crit_chance, 0.0f); } -/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage) +/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, bool isPeriodic /*= false*/) { // Calculate critical bonus int32 crit_bonus = damage; float crit_mod = 0.0f; + int32 extraCritBonus = 0; - switch (spellProto->DmgClass) + if (isPeriodic && IsReducedPeriodicCritDamageSpell(spellProto)) { - case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100% - case SPELL_DAMAGE_CLASS_RANGED: - /// @todo write here full calculation for melee/ranged spells - crit_bonus += damage; - break; - default: - crit_bonus += damage / 2; // for spells is 50% - break; + extraCritBonus = damage / 2; + } + else + { + switch (spellProto->DmgClass) + { + case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100% + case SPELL_DAMAGE_CLASS_RANGED: + /// @todo write here full calculation for melee/ranged spells + extraCritBonus = damage; + break; + default: + extraCritBonus = damage / 2; // for spells is 50% + break; + } } + crit_bonus += extraCritBonus; + if (caster) { crit_mod += (caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index b0aa46ee44..ac5c11a38c 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1458,8 +1458,9 @@ class TC_GAME_API Unit : public WorldObject bool IsBlockCritical() const; float SpellCritChanceDone(SpellInfo const* spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK, bool isPeriodic = false) const; float SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType = BASE_ATTACK, bool isPeriodic = false) const; - static uint32 SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage); + static uint32 SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, bool isPeriodic = false); static uint32 SpellCriticalHealingBonus(Unit const* caster, uint32 damage); + static bool IsReducedPeriodicCritDamageSpell(SpellInfo const* spellInfo); uint32 GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectType damagetype, uint32 CastingTime) const; float CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffectType damagetype) const; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 5cc77a909b..041642b492 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1499,12 +1499,12 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const } } -bool AuraEffect::CanPeriodicTickCrit(Unit const* caster) const +bool AuraEffect::CanPeriodicTickCrit() const { - if (m_spellInfo->HasAttribute(SPELL_ATTR8_PERIODIC_CAN_CRIT)) - return true; + if (m_spellInfo->HasAttribute(SPELL_ATTR2_CANT_CRIT)) + return false; - return caster && caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, m_spellInfo); + return true; } /*********************************************************/ @@ -5833,11 +5833,11 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const bool crit = false; - if (CanPeriodicTickCrit(caster)) + if (CanPeriodicTickCrit()) crit = roll_chance_f(GetCritChanceFor(caster, target)); if (crit) - damage = Unit::SpellCriticalDamageBonus(caster, m_spellInfo, damage); + damage = Unit::SpellCriticalDamageBonus(caster, m_spellInfo, damage, true); uint32 unmitigatedDamage = damage; @@ -5922,7 +5922,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c bool crit = false; - if (CanPeriodicTickCrit(caster)) + if (CanPeriodicTickCrit()) crit = roll_chance_f(GetCritChanceFor(caster, target)); if (crit) @@ -6054,7 +6054,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const bool crit = false; - if (CanPeriodicTickCrit(caster)) + if (CanPeriodicTickCrit()) crit = roll_chance_f(GetCritChanceFor(caster, target)); if (crit) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index df69204607..0a07696430 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -98,7 +98,7 @@ class TC_GAME_API AuraEffect // add/remove SPELL_AURA_MOD_SHAPESHIFT (36) linked auras void HandleShapeshiftBoosts(Unit* target, bool apply) const; - bool CanPeriodicTickCrit(Unit const* caster) const; + bool CanPeriodicTickCrit() const; private: Aura* const m_base; From 9a71b29e2d17594280b5a31fc33e0278767e280e Mon Sep 17 00:00:00 2001 From: Sevi Date: Thu, 19 Mar 2026 21:24:03 +0100 Subject: [PATCH 2/2] Core/Unit: add missing function --- src/server/game/Entities/Unit/Unit.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index ff3e43cf13..55aa40dbd7 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -7064,6 +7064,22 @@ float Unit::SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, return damage; } +/*static*/ bool Unit::IsReducedPeriodicCritDamageSpell(SpellInfo const* spellInfo) +{ + if (!spellInfo) return false; + + switch (spellInfo->Id) + { + case 1978: // Hunter: Serpent Sting + case 3674: // Hunter: Black Arrow + case 53301: // Hunter: Explosive Shot (Not really sure, can not find that spell damage in sniff) + case 13812: // Hunter: Explosive Trap + return true; + default: + return false; + } +} + int32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype, uint8 effIndex, uint32 stack /*= 1*/, Spell* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/) const { // For totems get healing bonus from owner (statue isn't totem in fact)