From 9a820e2d26b3b5d323dce66e51c71a96d0e4cb9a Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Mon, 2 Aug 2021 01:02:38 +0200 Subject: [PATCH] fix(Core/Spells): Master of Elements (#7102) * Core/Spells: Master of Elements: Proc now also from arcane spells. Properly proc from periodic spells. Fixed #6035. * You shouldn't be there. * Buildfix. * missing sql. --- .../rev_1627305467043107200.sql | 3 ++ src/server/game/Entities/Unit/Unit.cpp | 22 +++++------ src/server/game/Entities/Unit/Unit.h | 9 +++-- .../game/Spells/Auras/SpellAuraEffects.cpp | 8 ++-- src/server/game/Spells/Spell.cpp | 8 ++-- src/server/game/Spells/Spell.h | 1 + src/server/scripts/Spells/spell_mage.cpp | 37 ++++++++++++++++++- 7 files changed, 65 insertions(+), 23 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1627305467043107200.sql diff --git a/data/sql/updates/pending_db_world/rev_1627305467043107200.sql b/data/sql/updates/pending_db_world/rev_1627305467043107200.sql new file mode 100644 index 000000000..2921f7a48 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1627305467043107200.sql @@ -0,0 +1,3 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1627305467043107200'); + +UPDATE `spell_proc_event` SET `SchoolMask`=84 WHERE `entry`=-29074; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index f01a86566..772700d08 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -142,9 +142,9 @@ void DamageInfo::BlockDamage(uint32 amount) m_damage -= amount; } -ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* /*spell*/, DamageInfo* damageInfo, HealInfo* healInfo, SpellInfo const* triggeredByAuraSpell) +ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* /*spell*/, DamageInfo* damageInfo, HealInfo* healInfo, SpellInfo const* triggeredByAuraSpell, int8 procAuraEffectIndex) : _actor(actor), _actionTarget(actionTarget), _procTarget(procTarget), _typeMask(typeMask), _spellTypeMask(spellTypeMask), _spellPhaseMask(spellPhaseMask), - _hitMask(hitMask), _damageInfo(damageInfo), _healInfo(healInfo), _triggeredByAuraSpell(triggeredByAuraSpell) + _hitMask(hitMask), _damageInfo(damageInfo), _healInfo(healInfo), _triggeredByAuraSpell(triggeredByAuraSpell), _procAuraEffectIndex(procAuraEffectIndex) { } @@ -2041,7 +2041,7 @@ void Unit::CalcAbsorbResist(Unit* attacker, Unit* victim, SpellSchoolMask school // create procs createProcFlags(spellInfo, BASE_ATTACK, false, procAttacker, procVictim); - caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted, nullptr); + caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted); if (attacker) attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted + splitted_absorb, schoolMask, splitted_absorb, 0, false, 0, false); @@ -2109,7 +2109,7 @@ void Unit::CalcAbsorbResist(Unit* attacker, Unit* victim, SpellSchoolMask school // create procs createProcFlags(spellInfo, BASE_ATTACK, false, procAttacker, procVictim); - caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted, nullptr); + caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted); if (attacker) attacker->SendSpellNonMeleeDamageLog(caster, splitSpellInfo->Id, splitted + splitted_absorb, splitSchoolMask, splitted_absorb, 0, false, 0, false); @@ -5835,15 +5835,15 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damag SendSpellNonMeleeDamageLog(&log); } -void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpell, SpellInfo const* procAura) +void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpell, SpellInfo const* procAura, int8 procAuraEffectIndex) { // Not much to do if no flags are set. if (procAttacker) - ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpell, amount, procAura); + ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpell, amount, procAura, procAuraEffectIndex); // Now go on with a victim's events'n'auras // Not much to do if no flags are set or there is no victim if (victim && victim->IsAlive() && procVictim) - victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount, procAura); + victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount, procAura, procAuraEffectIndex); } void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo) @@ -15495,7 +15495,7 @@ uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missC return procEx; } -void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpell, uint32 damage, SpellInfo const* procAura) +void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpell, uint32 damage, SpellInfo const* procAura, int8 procAuraEffectIndex) { // Player is loaded now - do not allow passive spell casts to proc if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading()) @@ -15592,7 +15592,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u DamageInfo damageInfo = DamageInfo(actor, actionTarget, damage, procSpell, procSpell ? SpellSchoolMask(procSpell->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL, SPELL_DIRECT_DAMAGE); HealInfo healInfo = HealInfo(actor, actionTarget, damage, procSpell, procSpell ? SpellSchoolMask(procSpell->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL); - ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, 0, procExtra, nullptr, &damageInfo, &healInfo, procAura); + ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, 0, procExtra, nullptr, &damageInfo, &healInfo, procAura, procAuraEffectIndex); ProcTriggeredList procTriggered; // Fill procTriggered list @@ -15977,12 +15977,12 @@ void Unit::TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo) void Unit::TriggerAurasProcOnEvent(std::list* myProcAuras, std::list* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo) { // prepare data for self trigger - ProcEventInfo myProcEventInfo = ProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo, nullptr); + ProcEventInfo myProcEventInfo = ProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); std::list myAurasTriggeringProc; GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo); // prepare data for target trigger - ProcEventInfo targetProcEventInfo = ProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo, nullptr); + ProcEventInfo targetProcEventInfo = ProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); std::list targetAurasTriggeringProc; if (typeMaskActionTarget) GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 17cc31708..e6e60cb92 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -958,8 +958,10 @@ private: DamageInfo* _damageInfo; HealInfo* _healInfo; SpellInfo const* const _triggeredByAuraSpell; + int8 _procAuraEffectIndex; + public: - explicit ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo, SpellInfo const* triggeredByAuraSpell); + explicit ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo, SpellInfo const* triggeredByAuraSpell = nullptr, int8 procAuraEffectIndex = -1); Unit* GetActor() { return _actor; }; [[nodiscard]] Unit* GetActionTarget() const { return _actionTarget; } [[nodiscard]] Unit* GetProcTarget() const { return _procTarget; } @@ -972,6 +974,7 @@ public: [[nodiscard]] DamageInfo* GetDamageInfo() const { return _damageInfo; } [[nodiscard]] HealInfo* GetHealInfo() const { return _healInfo; } [[nodiscard]] SpellInfo const* GetTriggerAuraSpell() const { return _triggeredByAuraSpell; } + [[nodiscard]] int8 GetTriggerAuraEffectIndex() const { return _procAuraEffectIndex; } [[nodiscard]] uint32 GetProcCooldown() const { return _cooldown; } void SetProcCooldown(uint32 cooldown) { _cooldown = cooldown; } }; @@ -1622,8 +1625,8 @@ public: static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr); static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth); - void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpell = nullptr, SpellInfo const* procAura = nullptr); - void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpell, uint32 damage, SpellInfo const* procAura = nullptr); + void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpell = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1); + void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpell, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1); void GetProcAurasTriggeredOnEvent(std::list& aurasTriggeringProc, std::list* procAuras, ProcEventInfo eventInfo); void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 6ecce88a0..b0b3fb6e0 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -6350,7 +6350,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); // allow null caster to call this function - caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo()); + caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex()); } void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const @@ -6423,7 +6423,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false); // allow null caster to call this function - caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo()); + caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex()); if (!caster || !caster->IsAlive()) return; @@ -6603,7 +6603,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const // ignore item heals if (!haveCastItem && GetAuraType() != SPELL_AURA_OBS_MOD_HEALTH) // xinef: dont allow obs_mod_health to proc spells, this is passive regeneration and not hot // xinef: allow null caster to proc - caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo()); + caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex()); } void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const @@ -6789,7 +6789,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con procVictim |= PROC_FLAG_TAKEN_DAMAGE; caster->DealSpellDamage(&damageInfo, true); - caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto); + caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex()); } void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index bf13a79ac..088a781b9 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -626,6 +626,7 @@ Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, m_glyphIndex = 0; m_preCastSpell = 0; m_triggeredByAuraSpell = nullptr; + m_triggeredByAuraEffectIndex = -1; m_spellAura = nullptr; m_pathFinder = nullptr; // pussywizard _scriptsLoaded = false; @@ -2537,7 +2538,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger) - caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell); + caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell, m_triggeredByAuraEffectIndex); } // Do damage and triggers else if (m_damage > 0) @@ -2611,7 +2612,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger) { - caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell); + caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell, m_triggeredByAuraEffectIndex); if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 && m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx); @@ -2628,7 +2629,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger) { - caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell); + caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell, m_triggeredByAuraEffectIndex); // Xinef: eg. rogue poisons can proc off cheap shot, etc. so this block should be here also // Xinef: ofc count only spells that HIT the target, little hack used to fool the system if ((procEx & PROC_EX_NORMAL_HIT || procEx & PROC_EX_CRITICAL_HIT) && caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 && @@ -3198,6 +3199,7 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const if (triggeredByAura) { m_triggeredByAuraSpell = triggeredByAura->GetSpellInfo(); + m_triggeredByAuraEffectIndex = triggeredByAura->GetEffIndex(); } // create and add update event for this spell diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index c7fa13743..d65d23702 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -715,6 +715,7 @@ protected: // we can't store original aura link to prevent access to deleted auras // and in same time need aura data and after aura deleting. SpellInfo const* m_triggeredByAuraSpell; + int8 m_triggeredByAuraEffectIndex; bool m_skipCheck; uint8 m_auraScaleMask; diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index f800b83c8..dd56bc972 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -950,14 +950,43 @@ public: bool CheckProc(ProcEventInfo& eventInfo) { - return eventInfo.GetDamageInfo()->GetSpellInfo(); // eventInfo.GetSpellInfo() + _spellInfo = eventInfo.GetDamageInfo()->GetSpellInfo(); + if (!_spellInfo) + { + return false; + } + + bool selectCaster = false; + // Triggered spells cost no mana so we need triggering spellInfo + if (SpellInfo const* triggeredByAuraSpellInfo = eventInfo.GetTriggerAuraSpell()) + { + _spellInfo = triggeredByAuraSpellInfo; + selectCaster = true; + } + + // If spell is periodic, mana amount is divided by tick number + if (eventInfo.GetTriggerAuraEffectIndex() >= EFFECT_0) + { + if (Unit* caster = GetCaster()) + { + if (Unit* target = (selectCaster ? eventInfo.GetActor() : eventInfo.GetActionTarget())) + { + if (AuraEffect const* aurEff = target->GetAuraEffect(_spellInfo->Id, eventInfo.GetTriggerAuraEffectIndex(), caster->GetGUID())) + { + ticksModifier = aurEff->GetTotalTicks(); + } + } + } + } + + return _spellInfo; // eventInfo.GetSpellInfo() } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - int32 mana = int32(eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask())); + int32 mana = int32(_spellInfo->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask()) / ticksModifier); mana = CalculatePct(mana, aurEff->GetAmount()); if (mana > 0) @@ -969,6 +998,10 @@ public: DoCheckProc += AuraCheckProcFn(spell_mage_master_of_elements_AuraScript::CheckProc); OnEffectProc += AuraEffectProcFn(spell_mage_master_of_elements_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); } + + private: + SpellInfo const* _spellInfo = nullptr; + uint8 ticksModifier = 1; }; AuraScript* GetAuraScript() const override