diff --git a/src/game/Entities/Unit.h b/src/game/Entities/Unit.h index 71df313a2b..643c344ea2 100644 --- a/src/game/Entities/Unit.h +++ b/src/game/Entities/Unit.h @@ -2227,7 +2227,7 @@ class Unit : public WorldObject SPELL_PROC_TRIGGER_OK = 2, }; - SpellProcEventTriggerCheck IsTriggeredAtSpellProcEvent(ProcExecutionData& data, SpellAuraHolder* holder, SpellProcEventEntry const*& spellProcEvent); + SpellProcEventTriggerCheck IsTriggeredAtSpellProcEvent(ProcExecutionData& data, SpellAuraHolder* holder, SpellProcEventEntry const*& spellProcEvent, bool (&canProc)[MAX_EFFECT_INDEX]); // only to be used in proc handlers - basepoints is expected to be a MAX_EFFECT_INDEX sized array SpellAuraProcResult TriggerProccedSpell(Unit* target, std::array& basepoints, uint32 triggeredSpellId, Item* castItem, Aura* triggeredByAura, uint32 cooldown, ObjectGuid originalCaster); SpellAuraProcResult TriggerProccedSpell(Unit* target, std::array& basepoints, SpellEntry const* spellInfo, Item* castItem, Aura* triggeredByAura, uint32 cooldown, ObjectGuid originalCaster); diff --git a/src/game/Spells/Spell.cpp b/src/game/Spells/Spell.cpp index 28abad40ce..3b15bb1c00 100644 --- a/src/game/Spells/Spell.cpp +++ b/src/game/Spells/Spell.cpp @@ -871,12 +871,6 @@ void Spell::PrepareMasksForProcSystem(uint8 effectMask, uint32& procAttacker, ui procVictim |= PROC_FLAG_TAKE_MELEE_SWING; } - if (m_spellInfo->HasAttribute(SPELL_ATTR_EX3_TREAT_AS_PERIODIC)) - { - procAttacker = PROC_FLAG_DEAL_HARMFUL_PERIODIC; - procVictim = PROC_FLAG_TAKE_HARMFUL_PERIODIC; - } - if (m_spellInfo->HasAttribute(SPELL_ATTR_EX3_SUPPRESS_CASTER_PROCS)) procAttacker = 0; diff --git a/src/game/Spells/UnitAuraProcHandler.cpp b/src/game/Spells/UnitAuraProcHandler.cpp index 3c51572d38..8f5bf759fd 100644 --- a/src/game/Spells/UnitAuraProcHandler.cpp +++ b/src/game/Spells/UnitAuraProcHandler.cpp @@ -302,6 +302,7 @@ struct ProcTriggeredData {} SpellProcEventEntry const* spellProcEvent; SpellAuraHolder* triggeredByHolder; + bool canProc[MAX_EFFECT_INDEX]; }; typedef std::list< ProcTriggeredData > ProcTriggeredList; @@ -503,8 +504,9 @@ void Unit::ProcDamageAndSpellFor(ProcSystemArguments& argData, bool isVictim) if (holder->GetState() != SPELLAURAHOLDER_STATE_READY || holder->IsDeleted()) continue; - SpellProcEventEntry const* spellProcEvent = nullptr; - SpellProcEventTriggerCheck result = IsTriggeredAtSpellProcEvent(execData, holder, spellProcEvent); + ProcTriggeredData procTriggeredData(nullptr, itr->second); + + SpellProcEventTriggerCheck result = IsTriggeredAtSpellProcEvent(execData, holder, procTriggeredData.spellProcEvent, procTriggeredData.canProc); if (holder->GetSpellProto()->HasAttribute(SPELL_ATTR_PROC_FAILURE_BURNS_CHARGE) && result == SpellProcEventTriggerCheck::SPELL_PROC_TRIGGER_ROLL_FAILED && holder->GetAuraCharges() > 0) holdersForDeletion.push_back(holder); @@ -512,8 +514,8 @@ void Unit::ProcDamageAndSpellFor(ProcSystemArguments& argData, bool isVictim) if (holder->GetSpellProto()->HasAttribute(SPELL_ATTR_EX2_PROC_COOLDOWN_ON_FAILURE) && result == SpellProcEventTriggerCheck::SPELL_PROC_TRIGGER_ROLL_FAILED) { uint32 cooldown = 0; - if (spellProcEvent && spellProcEvent->cooldown) - cooldown = spellProcEvent->cooldown; + if (procTriggeredData.spellProcEvent && procTriggeredData.spellProcEvent->cooldown) + cooldown = procTriggeredData.spellProcEvent->cooldown; if (cooldown) holder->SetProcCooldown(std::chrono::seconds(cooldown), GetMap()->GetCurrentClockTime()); } @@ -521,7 +523,7 @@ void Unit::ProcDamageAndSpellFor(ProcSystemArguments& argData, bool isVictim) if (result != SpellProcEventTriggerCheck::SPELL_PROC_TRIGGER_OK) continue; - procTriggered.push_back(ProcTriggeredData(spellProcEvent, itr->second)); + procTriggered.emplace_back(procTriggeredData); } for (SpellAuraHolder* holder : holdersForDeletion) @@ -556,33 +558,8 @@ void Unit::ProcDamageAndSpellFor(ProcSystemArguments& argData, bool isVictim) continue; Modifier* auraModifier = execData.triggeredByAura->GetModifier(); - - if (execData.spellInfo) - { - if (spellProcEvent) - { - if (spellProcEvent->spellFamilyMask[i]) - { - if (!execData.spellInfo->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i])) - continue; - - // don't allow proc from cast end for non modifier spells - // unless they have proc ex defined for that - if (IsCastEndProcModifierAura(triggeredByHolder->GetSpellProto(), SpellEffectIndex(i), execData.spellInfo)) - { - if (useCharges && execData.procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE) - continue; - } - else if (spellProcEvent->procEx == PROC_EX_NONE && execData.procExtra == PROC_EX_CAST_END) - continue; - } - // don't check dbc FamilyFlags if schoolMask exists - else if (!execData.triggeredByAura->CanProcFrom(execData.spellInfo, spellProcEvent->procEx, execData.procExtra, execData.damage != 0, execData.absorb != 0, !spellProcEvent->schoolMask)) - continue; - } - else if (!execData.triggeredByAura->CanProcFrom(execData.spellInfo, PROC_EX_NONE, execData.procExtra, execData.damage != 0, execData.absorb != 0, true)) - continue; - } + if (itr->canProc[i] == false) + continue; execData.triggeredSpellId = 0; execData.basepoints = { 0, 0, 0 }; @@ -619,7 +596,7 @@ void Unit::ProcDamageAndSpellFor(ProcSystemArguments& argData, bool isVictim) } } -Unit::SpellProcEventTriggerCheck Unit::IsTriggeredAtSpellProcEvent(ProcExecutionData& data, SpellAuraHolder* holder, SpellProcEventEntry const*& spellProcEvent) +Unit::SpellProcEventTriggerCheck Unit::IsTriggeredAtSpellProcEvent(ProcExecutionData& data, SpellAuraHolder* holder, SpellProcEventEntry const*& spellProcEvent, bool (&canProc)[MAX_EFFECT_INDEX]) { SpellEntry const* spellProto = holder->GetSpellProto(); @@ -732,13 +709,67 @@ Unit::SpellProcEventTriggerCheck Unit::IsTriggeredAtSpellProcEvent(ProcExecution for (uint8 i = 0; i < MAX_EFFECT_INDEX; ++i) if (Aura* aura = holder->m_auras[i]) if (data.spell->IsAuraProcced(aura)) - return SpellProcEventTriggerCheck::SPELL_PROC_TRIGGER_FAILED; + canProc[i] = false; } for (uint8 i = 0; i < MAX_EFFECT_INDEX; ++i) if (Aura* aura = holder->m_auras[i]) if (!aura->OnCheckProc(data)) - return SpellProcEventTriggerCheck::SPELL_PROC_TRIGGER_FAILED; + canProc[i] = false; + + if (data.spellInfo) + { + bool useCharges = holder->GetAuraCharges() > 0; + for (uint8 i = 0; i < MAX_EFFECT_INDEX; ++i) + { + if (Aura* aura = holder->m_auras[i]) + { + if (spellProcEvent) + { + if (spellProcEvent->spellFamilyMask[i]) + { + if (!data.spellInfo->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i])) + { + canProc[i] = false; + continue; + } + + // don't allow proc from cast end for non modifier spells + // unless they have proc ex defined for that + if (IsCastEndProcModifierAura(holder->GetSpellProto(), SpellEffectIndex(i), data.spellInfo)) + { + if (useCharges && data.procExtra != PROC_EX_CAST_END && spellProcEvent->procEx == PROC_EX_NONE) + { + canProc[i] = false; + continue; + } + } + else if (spellProcEvent->procEx == PROC_EX_NONE && data.procExtra == PROC_EX_CAST_END) + { + canProc[i] = false; + continue; + } + } + // don't check dbc FamilyFlags if schoolMask exists + else if (!aura->CanProcFrom(data.spellInfo, spellProcEvent->procEx, data.procExtra, data.damage != 0, data.absorb != 0, !spellProcEvent->schoolMask)) + { + canProc[i] = false; + continue; + } + } + else if (!aura->CanProcFrom(data.spellInfo, PROC_EX_NONE, data.procExtra, data.damage != 0, data.absorb != 0, true)) + { + canProc[i] = false; + continue; + } + } + else + canProc[i] = false; + } + } + + if (!canProc[EFFECT_INDEX_0] || !canProc[EFFECT_INDEX_1] || !canProc[EFFECT_INDEX_2]) + return SpellProcEventTriggerCheck::SPELL_PROC_TRIGGER_FAILED; if (roll_chance_f(chance)) return SpellProcEventTriggerCheck::SPELL_PROC_TRIGGER_OK;