mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-03-15 21:45:12 +00:00
feat(Core/AI): port OnSpellStart/OnSpellCast/OnSpellFailed/OnChannelF… (#25026)
Co-authored-by: offl <11556157+offl@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -29,8 +29,6 @@ class Unit;
|
||||
class Creature;
|
||||
class Player;
|
||||
class SpellInfo;
|
||||
enum SpellFinishReason : uint8;
|
||||
|
||||
typedef std::vector<AreaBoundary const*> 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*/) {}
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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<HealthCheckEventData> _healthCheckEvents;
|
||||
HealthCheckEventData _nextHealthCheck;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user