diff options
15 files changed, 97 insertions, 34 deletions
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index 54b5d8c15af..041b27b6889 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -33,7 +33,6 @@ class PlayerAI; class WorldObject; struct Position; enum class QuestGiverStatus : uint32; -enum SpellFinishReason : uint8; typedef std::vector<AreaBoundary const*> CreatureBoundary; @@ -140,8 +139,17 @@ class TC_GAME_API CreatureAI : public UnitAI // Called when spell hits a target virtual void SpellHitTarget(WorldObject* /*target*/, SpellInfo const* /*spellInfo*/) { } - // Called when a spell either finishes, interrupts or cancels a spell cast - virtual void OnSpellCastFinished(SpellInfo const* /*spell*/, SpellFinishReason /*reason*/) { } + // Called when a spell finishes + virtual void OnSpellCast(SpellInfo const* /*spell*/) { } + + // Called when a spell fails + virtual void OnSpellFailed(SpellInfo const* /*spell*/) { } + + // Called when a spell starts + virtual void OnSpellStart(SpellInfo const* /*spell*/) { } + + // Called when a channeled spell finishes + virtual void OnChannelFinished(SpellInfo const* /*spell*/) { } // Should return true if the NPC is currently being escorted virtual bool IsEscorted() const { return false; } diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index a6ac410475d..61d546ef17d 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -620,6 +620,21 @@ void SmartAI::SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT_TARGET, target->ToUnit(), 0, 0, false, spellInfo, target->ToGameObject()); } +void SmartAI::OnSpellCast(SpellInfo const* spellInfo) +{ + GetScript()->ProcessEventsFor(SMART_EVENT_ON_SPELL_CAST, nullptr, 0, 0, false, spellInfo); +} + +void SmartAI::OnSpellFailed(SpellInfo const* spellInfo) +{ + GetScript()->ProcessEventsFor(SMART_EVENT_ON_SPELL_FAILED, nullptr, 0, 0, false, spellInfo); +} + +void SmartAI::OnSpellStart(SpellInfo const* spellInfo) +{ + GetScript()->ProcessEventsFor(SMART_EVENT_ON_SPELL_START, nullptr, 0, 0, false, spellInfo); +} + void SmartAI::DamageTaken(Unit* doneBy, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) { GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, doneBy, damage); diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index be1ba853c4e..9f12e02af0c 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -123,6 +123,15 @@ class TC_GAME_API SmartAI : public CreatureAI // Called when spell hits a target void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override; + // Called when a spell finishes + void OnSpellCast(SpellInfo const* spellInfo) override; + + // Called when a spell fails + void OnSpellFailed(SpellInfo const* spellInfo) override; + + // Called when a spell starts + void OnSpellStart(SpellInfo const* spellInfo) override; + // Called at any Damage from any attacker (before damage apply) void DamageTaken(Unit* doneBy, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index ea30a829f9a..b7e78371973 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3164,6 +3164,20 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui } break; } + case SMART_EVENT_ON_SPELL_CAST: + case SMART_EVENT_ON_SPELL_FAILED: + case SMART_EVENT_ON_SPELL_START: + { + if (!spell) + return; + + if (spell->Id != e.event.spellCast.spell) + return; + + RecalcTimer(e, e.event.spellCast.cooldownMin, e.event.spellCast.cooldownMax); + ProcessAction(e, nullptr, 0, 0, bvar, spell); + break; + } case SMART_EVENT_OOC_LOS: { if (!me || me->IsEngaged()) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 52e3f79e857..f2b793aff1e 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -841,6 +841,9 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e) case SMART_EVENT_SCENE_CANCEL: return NO_PARAMS; case SMART_EVENT_SCENE_COMPLETE: return NO_PARAMS; case SMART_EVENT_SUMMONED_UNIT_DIES: return sizeof(SmartEvent::summoned); + case SMART_EVENT_ON_SPELL_CAST: return sizeof(SmartEvent::spellCast); + case SMART_EVENT_ON_SPELL_FAILED: return sizeof(SmartEvent::spellCast); + case SMART_EVENT_ON_SPELL_START: return sizeof(SmartEvent::spellCast); default: TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u is using an event with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); @@ -1172,6 +1175,17 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) if (!IsMinMaxValid(e, e.event.spellHit.cooldownMin, e.event.spellHit.cooldownMax)) return false; break; + case SMART_EVENT_ON_SPELL_CAST: + case SMART_EVENT_ON_SPELL_FAILED: + case SMART_EVENT_ON_SPELL_START: + { + if (!IsSpellValid(e, e.event.spellCast.spell)) + return false; + + if (!IsMinMaxValid(e, e.event.spellCast.cooldownMin, e.event.spellCast.cooldownMax)) + return false; + break; + } case SMART_EVENT_OOC_LOS: case SMART_EVENT_IC_LOS: if (!IsMinMaxValid(e, e.event.los.cooldownMin, e.event.los.cooldownMax)) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 69dc73ea5ce..4908ac343e0 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -181,8 +181,11 @@ enum SMART_EVENT SMART_EVENT_SCENE_CANCEL = 80, // none SMART_EVENT_SCENE_COMPLETE = 81, // none SMART_EVENT_SUMMONED_UNIT_DIES = 82, // CreatureId(0 all), CooldownMin, CooldownMax + SMART_EVENT_ON_SPELL_CAST = 83, // SpellID, CooldownMin, CooldownMax + SMART_EVENT_ON_SPELL_FAILED = 84, // SpellID, CooldownMin, CooldownMax + SMART_EVENT_ON_SPELL_START = 85, // SpellID, CooldownMin, CooldownMax - SMART_EVENT_END = 83 + SMART_EVENT_END = 86 }; struct SmartEvent @@ -414,6 +417,13 @@ struct SmartEvent struct { + uint32 spell; + uint32 cooldownMin; + uint32 cooldownMax; + } spellCast; + + struct + { uint32 param1; uint32 param2; uint32 param3; @@ -1543,6 +1553,9 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] = {SMART_EVENT_SCENE_CANCEL, SMART_SCRIPT_TYPE_MASK_SCENE }, {SMART_EVENT_SCENE_COMPLETE, SMART_SCRIPT_TYPE_MASK_SCENE }, {SMART_EVENT_SUMMONED_UNIT_DIES, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, + {SMART_EVENT_ON_SPELL_CAST, SMART_SCRIPT_TYPE_MASK_CREATURE }, + {SMART_EVENT_ON_SPELL_FAILED, SMART_SCRIPT_TYPE_MASK_CREATURE }, + {SMART_EVENT_ON_SPELL_START, SMART_SCRIPT_TYPE_MASK_CREATURE }, }; enum SmartEventFlags diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index f3cbbcf7a42..4a5f8bedba5 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -2922,7 +2922,7 @@ void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool wi } if (GetTypeId() == TYPEID_UNIT && IsAIEnabled()) - ToCreature()->AI()->OnSpellCastFinished(spell->GetSpellInfo(), SPELL_FINISHED_CANCELED); + ToCreature()->AI()->OnSpellFailed(spell->GetSpellInfo()); } } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 53656861b92..3f3b7cc9694 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3341,6 +3341,11 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const if (!(_triggeredCastFlags & TRIGGERED_IGNORE_GCD)) TriggerGlobalCooldown(); + // Call CreatureAI hook OnSpellStart + if (Creature* caster = m_originalCaster->ToCreature()) + if (caster->IsAIEnabled()) + caster->AI()->OnSpellStart(GetSpellInfo()); + if (willCastDirectly) cast(true); } @@ -3707,10 +3712,10 @@ void Spell::_cast(bool skipCheck) Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr); - // Call CreatureAI hook OnSpellCastFinished + // Call CreatureAI hook OnSpellCast if (Creature* caster = m_originalCaster->ToCreature()) if (caster->IsAIEnabled()) - caster->AI()->OnSpellCastFinished(GetSpellInfo(), SPELL_FINISHED_SUCCESSFUL_CAST); + caster->AI()->OnSpellCast(GetSpellInfo()); } template <class Container> @@ -4068,7 +4073,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); } break; } diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index bbe87563654..76cba756fd0 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -152,13 +152,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 SpellLogEffectPowerDrainParams { ObjectGuid Victim; diff --git a/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp b/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp index be8b07d182b..7169440b308 100644 --- a/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp +++ b/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp @@ -24,7 +24,6 @@ #include "ObjectAccessor.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "Spell.h" #include "SpellAuras.h" #include "SpellScript.h" #include "SpellAuraEffects.h" @@ -247,11 +246,8 @@ struct boss_garothi_worldbreaker : public BossAI instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); } - void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override + void OnSpellCast(SpellInfo const* spell) override { - if (reason != SPELL_FINISHED_SUCCESSFUL_CAST) - return; - switch (spell->Id) { case SPELL_APOCALYPSE_DRIVE_FINAL_DAMAGE: diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index be6d571baa2..489800274d5 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -1322,9 +1322,9 @@ struct npc_shambling_horror_icc : public ScriptedAI DoMeleeAttackIfReady(); } - void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override + void OnSpellFailed(SpellInfo const* spell) override { - if (reason == SPELL_FINISHED_CANCELED && spell->Id == ENRAGE) + if (spell->Id == ENRAGE) _events.RescheduleEvent(EVENT_ENRAGE, 1s); } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp index c202169e720..a92c7845153 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp @@ -19,7 +19,6 @@ #include "halls_of_stone.h" #include "InstanceScript.h" #include "ScriptedCreature.h" -#include "Spell.h" #include "SpellInfo.h" #include "SpellMgr.h" @@ -83,9 +82,9 @@ struct boss_maiden_of_grief : public BossAI Talk(SAY_SLAY); } - void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override + void OnSpellCast(SpellInfo const* spell) override { - if (reason == SPELL_FINISHED_SUCCESSFUL_CAST && spell->Id == SPELL_SHOCK_OF_SORROW) + if (spell->Id == SPELL_SHOCK_OF_SORROW) Talk(SAY_STUN); } diff --git a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp index a0a120b46f3..5fecee52b14 100644 --- a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp +++ b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp @@ -20,7 +20,6 @@ #include "ObjectAccessor.h" #include "Player.h" #include "ScriptedCreature.h" -#include "Spell.h" #include "SpellInfo.h" #include "SpellScript.h" @@ -122,9 +121,9 @@ struct boss_exarch_maladaar : public BossAI } } - void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override + void OnSpellCast(SpellInfo const* spell) override { - if (reason == SPELL_FINISHED_SUCCESSFUL_CAST && spell->Id == SPELL_STOLEN_SOUL) + if (spell->Id == SPELL_STOLEN_SOUL) if (roll_chance_i(25)) Talk(SAY_SOUL_CLEAVE); } diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp index ffccab6b686..a637298c64e 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp @@ -17,7 +17,6 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "Spell.h" #include "SpellInfo.h" #include "SpellScript.h" #include "the_botanica.h" @@ -97,9 +96,9 @@ struct boss_commander_sarannis : public BossAI } } - void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override + void OnSpellCast(SpellInfo const* spell) override { - if (reason == SPELL_FINISHED_SUCCESSFUL_CAST && spell->Id == SPELL_SUMMON_REINFORCEMENTS) + if (spell->Id == SPELL_SUMMON_REINFORCEMENTS) Talk(SAY_SUMMON); } diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp index c8c5dd4d2e8..e4672be695a 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp @@ -17,7 +17,6 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "Spell.h" #include "SpellInfo.h" #include "the_botanica.h" @@ -82,9 +81,9 @@ struct boss_warp_splinter : public BossAI Talk(SAY_DEATH); } - void OnSpellCastFinished(SpellInfo const* spell, SpellFinishReason reason) override + void OnSpellCast(SpellInfo const* spell) override { - if (reason == SPELL_FINISHED_SUCCESSFUL_CAST && spell->Id == SPELL_SUMMON_SAPLINGS) + if (spell->Id == SPELL_SUMMON_SAPLINGS) { for (uint32 summonSpells : SummonSaplingsSpells) DoCastSelf(summonSpells, true); |