From 306b0cb2273bf754a2713d689dbb7fe7f28160e1 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Mon, 30 May 2022 15:44:21 -0400 Subject: [PATCH] Core/AI: OnSpellCast, OnSpellFailed, OnSpellStart hooks Port From (https://github.com/TrinityCore/TrinityCore/commit/050f55b62fded4cc73b76e42d56d98ea950cc26a) --- Source/Framework/Constants/SmartAIConst.cs | 5 +++- .../Framework/Constants/Spells/SpellConst.cs | 7 ----- Source/Game/AI/CoreAI/CreatureAI.cs | 13 ++++++++-- Source/Game/AI/SmartScripts/SmartAI.cs | 15 +++++++++++ Source/Game/AI/SmartScripts/SmartAIManager.cs | 26 +++++++++++++++++++ Source/Game/AI/SmartScripts/SmartScript.cs | 14 ++++++++++ Source/Game/Entities/Unit/Unit.Spells.cs | 2 +- Source/Game/Spells/Spell.cs | 12 ++++++--- 8 files changed, 80 insertions(+), 14 deletions(-) diff --git a/Source/Framework/Constants/SmartAIConst.cs b/Source/Framework/Constants/SmartAIConst.cs index 729121b6e..863efad12 100644 --- a/Source/Framework/Constants/SmartAIConst.cs +++ b/Source/Framework/Constants/SmartAIConst.cs @@ -237,8 +237,11 @@ namespace Framework.Constants SceneCancel = 80, // none SceneComplete = 81, // none SummonedUnitDies = 82, // CreatureId(0 all), CooldownMin, CooldownMax + OnSpellCast = 83, // SpellID, CooldownMin, CooldownMax + OnSpellFailed = 84, // SpellID, CooldownMin, CooldownMax + OnSpellStart = 85, // SpellID, CooldownMin, CooldownMax - End = 83 + End = 86 } public enum SmartActions diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index 3e4717a4c..4256a73f2 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -98,13 +98,6 @@ namespace Framework.Constants Ranged = 2 //hunter range and ranged weapon } - public enum SpellFinishReason - { - SuccessfulCast = 0, // spell has sucessfully launched - Canceled = 1, // spell has been canceled (interrupts) - ChannelingComplete = 2 // spell channeling has been finished - } - [Flags] public enum SpellInterruptFlags { diff --git a/Source/Game/AI/CoreAI/CreatureAI.cs b/Source/Game/AI/CoreAI/CreatureAI.cs index 0856135d3..4948ba377 100644 --- a/Source/Game/AI/CoreAI/CreatureAI.cs +++ b/Source/Game/AI/CoreAI/CreatureAI.cs @@ -491,8 +491,17 @@ namespace Game.AI // Called when spell hits a target public virtual void SpellHitTarget(WorldObject target, SpellInfo spellInfo) { } - // Called when a spell either finishes, interrupts or cancels a spell cast - public virtual void OnSpellCastFinished(SpellInfo spell, SpellFinishReason reason) { } + // Called when a spell finishes + public virtual void OnSpellCast(SpellInfo spell) { } + + // Called when a spell fails + public virtual void OnSpellFailed(SpellInfo spell) { } + + // Called when a spell starts + public virtual void OnSpellStart(SpellInfo spell) { } + + // Called when a channeled spell finishes + public virtual void OnChannelFinished(SpellInfo spell) { } // Should return true if the NPC is currently being escorted public virtual bool IsEscorted() { return false; } diff --git a/Source/Game/AI/SmartScripts/SmartAI.cs b/Source/Game/AI/SmartScripts/SmartAI.cs index 0f9b67617..15f4c35f6 100644 --- a/Source/Game/AI/SmartScripts/SmartAI.cs +++ b/Source/Game/AI/SmartScripts/SmartAI.cs @@ -670,6 +670,21 @@ namespace Game.AI { GetScript().ProcessEventsFor(SmartEvents.SpellHitTarget, target.ToUnit(), 0, 0, false, spellInfo, target.ToGameObject()); } + + public override void OnSpellCast(SpellInfo spellInfo) + { + GetScript().ProcessEventsFor(SmartEvents.OnSpellCast, null, 0, 0, false, spellInfo); + } + + public override void OnSpellFailed(SpellInfo spellInfo) + { + GetScript().ProcessEventsFor(SmartEvents.OnSpellFailed, null, 0, 0, false, spellInfo); + } + + public override void OnSpellStart(SpellInfo spellInfo) + { + GetScript().ProcessEventsFor(SmartEvents.OnSpellStart, null, 0, 0, false, spellInfo); + } public override void DamageTaken(Unit attacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null) { diff --git a/Source/Game/AI/SmartScripts/SmartAIManager.cs b/Source/Game/AI/SmartScripts/SmartAIManager.cs index c80a2a31f..557d6f79f 100644 --- a/Source/Game/AI/SmartScripts/SmartAIManager.cs +++ b/Source/Game/AI/SmartScripts/SmartAIManager.cs @@ -629,6 +629,9 @@ namespace Game.AI SmartEvents.SceneCancel => 0, SmartEvents.SceneComplete => 0, SmartEvents.SummonedUnitDies => Marshal.SizeOf(typeof(SmartEvent.Summoned)), + SmartEvents.OnSpellCast => Marshal.SizeOf(typeof(SmartEvent.SpellCast)), + SmartEvents.OnSpellFailed => Marshal.SizeOf(typeof(SmartEvent.SpellCast)), + SmartEvents.OnSpellStart => Marshal.SizeOf(typeof(SmartEvent.SpellCast)), _ => Marshal.SizeOf(typeof(SmartEvent.Raw)), }; @@ -987,6 +990,17 @@ namespace Game.AI if (!IsMinMaxValid(e, e.Event.spellHit.cooldownMin, e.Event.spellHit.cooldownMax)) return false; break; + case SmartEvents.OnSpellCast: + case SmartEvents.OnSpellFailed: + case SmartEvents.OnSpellStart: + { + if (!IsSpellValid(e, e.Event.spellCast.spell)) + return false; + + if (!IsMinMaxValid(e, e.Event.spellCast.cooldownMin, e.Event.spellCast.cooldownMax)) + return false; + break; + } case SmartEvents.OocLos: case SmartEvents.IcLos: if (!IsMinMaxValid(e, e.Event.los.cooldownMin, e.Event.los.cooldownMax)) @@ -2406,6 +2420,9 @@ namespace Game.AI SmartEvents.SceneCancel => SmartScriptTypeMaskId.Scene, SmartEvents.SceneComplete => SmartScriptTypeMaskId.Scene, SmartEvents.SummonedUnitDies => SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject, + SmartEvents.OnSpellCast => SmartScriptTypeMaskId.Creature, + SmartEvents.OnSpellFailed => SmartScriptTypeMaskId.Creature, + SmartEvents.OnSpellStart => SmartScriptTypeMaskId.Creature, _ => 0, }; @@ -2589,6 +2606,9 @@ namespace Game.AI [FieldOffset(16)] public Counter counter; + [FieldOffset(16)] + public SpellCast spellCast; + [FieldOffset(16)] public Spell spell; @@ -2782,6 +2802,12 @@ namespace Game.AI public uint cooldownMin; public uint cooldownMax; } + public struct SpellCast + { + public uint spell; + public uint cooldownMin; + public uint cooldownMax; + } public struct Spell { public uint effIndex; diff --git a/Source/Game/AI/SmartScripts/SmartScript.cs b/Source/Game/AI/SmartScripts/SmartScript.cs index b89ec4013..b41a0c963 100644 --- a/Source/Game/AI/SmartScripts/SmartScript.cs +++ b/Source/Game/AI/SmartScripts/SmartScript.cs @@ -3226,6 +3226,20 @@ namespace Game.AI } break; } + case SmartEvents.OnSpellCast: + case SmartEvents.OnSpellFailed: + case SmartEvents.OnSpellStart: + { + if (spell == null) + return; + + if (spell.Id != e.Event.spellCast.spell) + return; + + RecalcTimer(e, e.Event.spellCast.cooldownMin, e.Event.spellCast.cooldownMax); + ProcessAction(e, null, 0, 0, bvar, spell); + break; + } case SmartEvents.OocLos: { if (_me == null || _me.IsEngaged()) diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index d87ccf0cd..676394868 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -2422,7 +2422,7 @@ namespace Game.Entities } if (IsCreature() && IsAIEnabled()) - ToCreature().GetAI().OnSpellCastFinished(spell.GetSpellInfo(), SpellFinishReason.Canceled); + ToCreature().GetAI().OnSpellFailed(spell.GetSpellInfo()); } } public void UpdateInterruptMask() diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 7a8ae94d6..ee031ce94 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2502,6 +2502,12 @@ namespace Game.Spells if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreGCD)) TriggerGlobalCooldown(); + // Call CreatureAI hook OnSpellStart + Creature caster = m_originalCaster.ToCreature(); + if (caster != null) + if (caster.IsAIEnabled()) + caster.GetAI().OnSpellStart(GetSpellInfo()); + if (willCastDirectly) Cast(true); } @@ -2902,11 +2908,11 @@ namespace Game.Spells Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null); - // Call CreatureAI hook OnSuccessfulSpellCast + // Call CreatureAI hook OnSpellCast Creature caster = m_originalCaster.ToCreature(); if (caster) if (caster.IsAIEnabled()) - caster.GetAI().OnSpellCastFinished(GetSpellInfo(), SpellFinishReason.SuccessfulCast); + caster.GetAI().OnSpellCast(GetSpellInfo()); } void DoProcessTargetContainer(List targetContainer) where T : TargetInfoBase @@ -3268,7 +3274,7 @@ namespace Game.Spells Creature creatureCaster = m_caster.ToCreature(); if (creatureCaster != null) if (creatureCaster.IsAIEnabled()) - creatureCaster.GetAI().OnSpellCastFinished(m_spellInfo, SpellFinishReason.ChannelingComplete); + creatureCaster.GetAI().OnChannelFinished(m_spellInfo); } break; }