Core/Spells: Fixed npcs channeling spells with SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL being prevented from casting other spells during that time

This commit is contained in:
Shauren
2026-07-22 20:52:14 +02:00
parent 1952511f3f
commit e1cdd3c7d4
4 changed files with 22 additions and 27 deletions
+18 -22
View File
@@ -2192,11 +2192,7 @@ void Unit::DoMeleeAttackIfReady()
return;
if (HasUnitState(UNIT_STATE_CASTING))
{
Spell* channeledSpell = GetCurrentSpell(CURRENT_CHANNELED_SPELL);
if (!channeledSpell || !channeledSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL))
return;
}
return;
Unit* victim = GetVictim();
if (!victim)
@@ -3127,7 +3123,9 @@ void Unit::SetCurrentCastSpell(Spell* pSpell)
if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
AddUnitState(UNIT_STATE_CASTING);
if (!pSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL))
AddUnitState(UNIT_STATE_CASTING);
break;
}
@@ -3204,7 +3202,8 @@ void Unit::FinishSpell(CurrentSpellTypes spellType, SpellCastResult result /*= S
spell->finish(result);
}
bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAutorepeat, bool isAutoshoot, bool skipInstant) const
bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled /*= false*/, bool skipAutorepeat /*= false*/, bool isAutoshoot /*= false*/,
bool skipInstant /*= true*/, bool skipChanneledAllowingActions /*= false*/) const
{
// We don't do loop here to explicitly show that melee spell is excluded.
// Maybe later some special spells will be excluded too.
@@ -3216,7 +3215,7 @@ bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAu
{
if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
{
if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
if (!isAutoshoot || !m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS))
return true;
}
}
@@ -3224,7 +3223,8 @@ bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAu
if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
(m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED))
{
if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
if ((!isAutoshoot || !m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)) &&
(!skipChanneledAllowingActions || !m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL)))
return true;
}
// autorepeat spells may be finished or delayed, but they are still considered cast
@@ -3266,23 +3266,19 @@ int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
bool Unit::IsMovementPreventedByCasting() const
{
// can always move when not casting
if (!HasUnitState(UNIT_STATE_CASTING))
return false;
if (Spell* spell = m_currentSpells[CURRENT_GENERIC_SPELL])
if (CanCastSpellWhileMoving(spell->GetSpellInfo()) || spell->getState() == SPELL_STATE_FINISHED ||
!spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement))
return false;
if (!CanCastSpellWhileMoving(spell->GetSpellInfo())
&& spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement))
return true;
// channeled spells during channel stage (after the initial cast timer) allow movement with a specific spell attribute
// channeled spells during channel stage (after the initial cast timer) allow movement without Moving channel interrupt flag
if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
if (spell->GetSpellInfo()->IsMoveAllowedChannel() || CanCastSpellWhileMoving(spell->GetSpellInfo()))
return false;
if (!CanCastSpellWhileMoving(spell->GetSpellInfo())
&& ((spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement))
|| spell->getState() == SPELL_STATE_CHANNELING && !spell->GetSpellInfo()->IsMoveAllowedChannel()))
return true;
// prohibit movement for all other spell casts
return true;
return false;
}
bool Unit::CanCastSpellWhileMoving(SpellInfo const* spellInfo) const
+2 -1
View File
@@ -1471,7 +1471,8 @@ class TC_GAME_API Unit : public WorldObject
// set withDelayed to true to account delayed spells as cast
// delayed+channeled spells are always accounted as cast
// we can skip channeled or delayed checks using flags
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled = false, bool skipAutorepeat = false, bool isAutoshoot = false, bool skipInstant = true) const;
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled = false, bool skipAutorepeat = false, bool isAutoshoot = false,
bool skipInstant = true, bool skipChanneledAllowingActions = false) const;
// set withDelayed to true to interrupt delayed spells too
// delayed+channeled spells are always interrupted
+2 -2
View File
@@ -3932,7 +3932,7 @@ void Spell::_cast(bool skipCheck)
SetDelayStart(0);
if (Unit* unitCaster = m_caster->ToUnit())
if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true, false, true, true))
unitCaster->ClearUnitState(UNIT_STATE_CASTING);
}
else
@@ -4376,7 +4376,7 @@ void Spell::finish(SpellCastResult result)
if (m_spellInfo->IsChanneled())
unitCaster->UpdateInterruptMask();
if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true, false, true, true))
unitCaster->ClearUnitState(UNIT_STATE_CASTING);
// Unsummon summon as possessed creatures on spell cancel
@@ -20,7 +20,6 @@
* Combat timers requires to be revisited, mainly player class abilities, half of timers are guessed
* Move spell script of spell 43421 to this file
* Currently we generate random companions after every wipe, doubt it is correct
* We interrupt Siphon Soul instantly to allow casting player class abilities, that's a hack
*/
#include "ScriptMgr.h"
@@ -359,7 +358,6 @@ struct boss_hexlord_malacrass : public BossAI
break;
case SPELL_SIPHON_SOUL:
Talk(SAY_CHARM);
me->InterruptNonMeleeSpells(false);
break;
case SPELL_DRAIN_POWER:
Talk(SAY_DRAIN_POWER);