mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-03-16 14:05:28 +00:00
fix(Core/Spells): revert CAST proc ordering and add ApplySpellMod recursion guard (#24990)
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
This commit is contained in:
@@ -3951,70 +3951,8 @@ void Spell::_cast(bool skipCheck)
|
||||
}
|
||||
else
|
||||
{
|
||||
// CAST phase procs for immediate spells (including channeled)
|
||||
if (m_originalCaster)
|
||||
{
|
||||
uint32 procAttacker = m_procAttacker;
|
||||
if (!procAttacker)
|
||||
{
|
||||
bool IsPositive = m_spellInfo->IsPositive();
|
||||
if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
|
||||
{
|
||||
procAttacker = IsPositive ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
|
||||
}
|
||||
else
|
||||
{
|
||||
procAttacker = IsPositive ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 hitMask = PROC_HIT_NORMAL;
|
||||
|
||||
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
||||
{
|
||||
if (ihit->missCondition != SPELL_MISS_NONE)
|
||||
continue;
|
||||
|
||||
if (!ihit->crit)
|
||||
continue;
|
||||
|
||||
hitMask |= PROC_HIT_CRITICAL;
|
||||
break;
|
||||
}
|
||||
|
||||
Unit::ProcSkillsAndAuras(m_originalCaster, m_originalCaster, procAttacker, PROC_FLAG_NONE, hitMask, 1, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell.spellInfo,
|
||||
m_triggeredByAuraSpell.effectIndex, this, nullptr, nullptr, PROC_SPELL_PHASE_CAST);
|
||||
}
|
||||
|
||||
// Immediate spell, no big deal
|
||||
handle_immediate();
|
||||
|
||||
// Clean up deferred 0-charge spell modifier auras
|
||||
// Copy to vector first — aura->Remove() can modify m_appliedMods
|
||||
std::vector<Aura*> appliedModsCopy(m_appliedMods.begin(), m_appliedMods.end());
|
||||
for (Aura* aura : appliedModsCopy)
|
||||
{
|
||||
if (!aura->IsRemoved() && aura->IsUsingCharges()
|
||||
&& !aura->GetCharges())
|
||||
aura->Remove();
|
||||
}
|
||||
|
||||
// Also clean up deferred modifier auras not in m_appliedMods
|
||||
if (Unit* caster = m_caster)
|
||||
{
|
||||
std::vector<Aura*> deferred;
|
||||
for (auto const& [id, aura] : caster->GetOwnedAuras())
|
||||
{
|
||||
if (!aura->IsRemoved() && aura->IsUsingCharges()
|
||||
&& !aura->GetCharges()
|
||||
&& (aura->HasEffectType(SPELL_AURA_ADD_FLAT_MODIFIER)
|
||||
|| aura->HasEffectType(SPELL_AURA_ADD_PCT_MODIFIER)))
|
||||
deferred.push_back(aura);
|
||||
}
|
||||
for (Aura* aura : deferred)
|
||||
if (!aura->IsRemoved())
|
||||
aura->Remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (resetAttackTimers)
|
||||
@@ -4042,9 +3980,13 @@ void Spell::_cast(bool skipCheck)
|
||||
if (modOwner)
|
||||
modOwner->SetSpellModTakingSpell(this, false);
|
||||
|
||||
// CAST phase procs for delayed spells
|
||||
if (m_spellState == SPELL_STATE_DELAYED
|
||||
&& m_originalCaster)
|
||||
// Handle procs on cast - only for non-triggered spells
|
||||
// Triggered spells (from auras, items, etc.) should not fire CAST phase procs
|
||||
// as they are not player-initiated casts. This prevents issues like Arcane Potency
|
||||
// charges being consumed by periodic damage effects (e.g., Blizzard ticks).
|
||||
// Must be called AFTER handle_immediate() so spell mods (like Missile Barrage's
|
||||
// duration reduction) are applied before the aura is consumed by the proc.
|
||||
if (m_originalCaster && !IsTriggered())
|
||||
{
|
||||
uint32 procAttacker = m_procAttacker;
|
||||
if (!procAttacker)
|
||||
|
||||
Reference in New Issue
Block a user