diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index 57ea6f7ff..bf5ee28d5 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -29,8 +29,6 @@ class Unit; class Creature; class Player; class SpellInfo; -enum SpellFinishReason : uint8; - typedef std::vector CreatureBoundary; #define TIME_INTERVAL_LOOK 5000 @@ -147,8 +145,17 @@ public: // Called when spell hits a target virtual void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spell*/) {} - // Called when a spell either finishes, interrupts or cancels a spell cast - virtual void OnSpellCastFinished(SpellInfo const* /*spell*/, SpellFinishReason /*reason*/) {} + // Called when the creature begins casting a spell (has cast time or is channeled) + virtual void OnSpellStart(SpellInfo const* /*spell*/) {} + + // Called when the creature successfully executes a spell cast + virtual void OnSpellCast(SpellInfo const* /*spell*/) {} + + // Called when a spell cast is interrupted or cancelled + virtual void OnSpellFailed(SpellInfo const* /*spell*/) {} + + // Called when a channeled spell finishes its full duration + virtual void OnChannelFinished(SpellInfo const* /*spell*/) {} // Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc) virtual void AttackedBy(Unit* /*attacker*/) {} diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 522b17e41..bac61c314 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -756,9 +756,26 @@ void BossAI::UpdateAI(uint32 diff) DoMeleeAttackIfReady(); } -void BossAI::OnSpellCastFinished(SpellInfo const* spellInfo, SpellFinishReason reason) +void BossAI::OnSpellCast(SpellInfo const* spellInfo) +{ + ScriptedAI::OnSpellCast(spellInfo); + _CheckHealthAfterCast(); +} + +void BossAI::OnChannelFinished(SpellInfo const* spellInfo) +{ + ScriptedAI::OnChannelFinished(spellInfo); + _CheckHealthAfterCast(); +} + +void BossAI::OnSpellFailed(SpellInfo const* spellInfo) +{ + ScriptedAI::OnSpellFailed(spellInfo); + _CheckHealthAfterCast(); +} + +void BossAI::_CheckHealthAfterCast() { - ScriptedAI::OnSpellCastFinished(spellInfo, reason); // Check if any health check events are pending (i.e. waiting for the boss to stop casting. if (_nextHealthCheck.IsPending() && me->IsInCombat()) { diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 47f8cf30c..271366c9d 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -490,7 +490,9 @@ public: bool CanRespawn() override; - void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override; + void OnSpellCast(SpellInfo const* spell) override; + void OnChannelFinished(SpellInfo const* spell) override; + void OnSpellFailed(SpellInfo const* spell) override; void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask) override; void JustSummoned(Creature* summon) override; void SummonedCreatureDespawn(Creature* summon) override; @@ -534,6 +536,7 @@ protected: SummonList summons; private: + void _CheckHealthAfterCast(); uint32 const _bossId; std::list _healthCheckEvents; HealthCheckEventData _nextHealthCheck; diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index d28029e49..2b0359c1c 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -1250,10 +1250,10 @@ bool SmartAI::IsMainSpellPrevented(SpellInfo const* spellInfo) const return false; } -void SmartAI::OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) +void SmartAI::OnSpellFailed(SpellInfo const* spell) { - CreatureAI::OnSpellCastFinished(spell, reason); - if (reason == SPELL_FINISHED_CANCELED && _mainSpellId == spell->Id) + CreatureAI::OnSpellFailed(spell); + if (_mainSpellId == spell->Id) if (_currentRangeMode && IsMainSpellPrevented(spell)) SetCurrentRangeMode(false); } diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 466c17020..5165058bb 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -216,7 +216,7 @@ public: bool IsMainSpellPrevented(SpellInfo const* spellInfo) const; - void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override; + void OnSpellFailed(SpellInfo const* spell) override; private: bool mIsCharmed; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 0d70c952b..134aec250 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -4209,8 +4209,6 @@ void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool wi spell->SetReferencedFromCurrent(false); } - if (IsCreature() && IsAIEnabled) - ToCreature()->AI()->OnSpellCastFinished(spell->GetSpellInfo(), SPELL_FINISHED_CANCELED); } } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 364155be2..6e56bf395 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3629,6 +3629,12 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const m_caster->SetCurrentCastedSpell(this); SendSpellStart(); + // Call CreatureAI hook OnSpellStart for spells with cast time or channeled spells + if (m_casttime > 0 || m_spellInfo->IsChanneled()) + if (Creature* caster = m_caster->ToCreature()) + if (caster->IsAIEnabled) + caster->AI()->OnSpellStart(GetSpellInfo()); + // set target for proper facing if ((m_casttime || m_spellInfo->IsChanneled()) && !HasTriggeredCastFlag(TRIGGERED_IGNORE_SET_FACING)) { @@ -3727,6 +3733,11 @@ void Spell::cancel(bool bySelf) sScriptMgr->OnSpellCastCancel(this, m_caster, m_spellInfo, bySelf); + // Call CreatureAI hook OnSpellFailed only for true interrupts/cancels, not prepare-time failures + if (Creature* creatureCaster = m_caster->ToCreature()) + if (creatureCaster->IsAIEnabled) + creatureCaster->AI()->OnSpellFailed(m_spellInfo); + finish(false); } @@ -4052,11 +4063,10 @@ void Spell::_cast(bool skipCheck) SetExecutedCurrently(false); - // Call CreatureAI hook OnSpellCastFinished - if (m_originalCaster) - if (Creature* caster = m_originalCaster->ToCreature()) - if (caster->IsAIEnabled) - caster->AI()->OnSpellCastFinished(GetSpellInfo(), SPELL_FINISHED_SUCCESSFUL_CAST); + // Call CreatureAI hook on successful cast + if (Creature* caster = m_caster->ToCreature()) + if (caster->IsAIEnabled) + caster->AI()->OnSpellCast(GetSpellInfo()); } void Spell::handle_immediate() @@ -4416,7 +4426,7 @@ void Spell::update(uint32 difftime) // We call the hook here instead of in Spell::finish because we only want to call it for completed channeling. Everything else is handled by interrupts if (Creature* creatureCaster = m_caster->ToCreature()) if (creatureCaster->IsAIEnabled) - creatureCaster->AI()->OnSpellCastFinished(m_spellInfo, SPELL_FINISHED_CHANNELING_COMPLETE); + creatureCaster->AI()->OnChannelFinished(m_spellInfo); } // Xinef: Dont update channeled target list on last tick, allow auras to update duration properly // Xinef: Added this strange check because of diffrent update routines for players / creatures @@ -4478,8 +4488,8 @@ void Spell::finish(bool ok) // Xinef: Reset cooldown event in case of fail cast if (m_spellInfo->IsCooldownStartedOnEvent()) m_caster->ToPlayer()->SendCooldownEvent(m_spellInfo, 0, 0, false); - } + return; } diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 603a5c923..700137f17 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -93,13 +93,6 @@ enum SpellRangeFlag SPELL_RANGE_RANGED = 2, //hunter range and ranged weapon }; -enum SpellFinishReason : uint8 -{ - SPELL_FINISHED_SUCCESSFUL_CAST = 0, // spell has sucessfully launched - SPELL_FINISHED_CANCELED = 1, // spell has been canceled (interrupts) - SPELL_FINISHED_CHANNELING_COMPLETE = 2 // spell channeling has been finished -}; - struct SpellDestination { SpellDestination();