diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/server/game/Spells/Auras/SpellAuras.cpp | 2 | ||||
-rwxr-xr-x | src/server/game/Spells/Spell.cpp | 51 | ||||
-rwxr-xr-x | src/server/game/Spells/Spell.h | 3 | ||||
-rwxr-xr-x | src/server/game/Spells/SpellScript.cpp | 15 | ||||
-rwxr-xr-x | src/server/game/Spells/SpellScript.h | 42 | ||||
-rw-r--r-- | src/server/scripts/Examples/example_spell.cpp | 38 |
6 files changed, 138 insertions, 13 deletions
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 91ecc328fd8..b3898c92450 100755 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -2035,7 +2035,6 @@ void Aura::_DeleteRemovedApplications() void Aura::LoadScripts() { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura::LoadScripts"); sScriptMgr->CreateAuraScripts(m_spellInfo->Id, m_loadedScripts); for (std::list<AuraScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end() ;) { @@ -2046,6 +2045,7 @@ void Aura::LoadScripts() m_loadedScripts.erase(bitr); continue; } + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura::LoadScripts: Script `%s` for aura `%u` is loaded now", (*itr)->_GetScriptName()->c_str(), m_spellInfo->Id); (*itr)->Register(); ++itr; } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index de49b2cf579..113842fb967 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3091,6 +3091,8 @@ void Spell::cast(bool skipCheck) m_caster->ToPlayer()->SetSpellModTakingSpell(this, true); } + CallScriptBeforeCastHandlers(); + // skip check if done already (for instant cast spells for example) if (!skipCheck) { @@ -3160,6 +3162,8 @@ void Spell::cast(bool skipCheck) PrepareTriggersExecutedOnHit(); + CallScriptOnCastHandlers(); + // traded items have trade slot instead of guid in m_itemTargetGUID // set to real guid to be sent later to the client m_targets.UpdateTradeSlotItem(); @@ -3219,6 +3223,8 @@ void Spell::cast(bool skipCheck) handle_immediate(); } + CallScriptAfterCastHandlers(); + if (const std::vector<int32> *spell_triggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id)) { for (std::vector<int32>::const_iterator i = spell_triggered->begin(); i != spell_triggered->end(); ++i) @@ -6969,7 +6975,6 @@ void Spell::CheckEffectExecuteData() void Spell::LoadScripts() { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::LoadScripts"); sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts); for (std::list<SpellScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end() ;) { @@ -6980,15 +6985,49 @@ void Spell::LoadScripts() m_loadedScripts.erase(bitr); continue; } + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::LoadScripts: Script `%s` for spell `%u` is loaded now", (*itr)->_GetScriptName()->c_str(), m_spellInfo->Id); (*itr)->Register(); ++itr; } } -void Spell::PrepareScriptHitHandlers() +void Spell::CallScriptBeforeCastHandlers() { for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) - (*scritr)->_InitHit(); + { + (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_CAST); + std::list<SpellScript::CastHandler>::iterator hookItrEnd = (*scritr)->BeforeCast.end(), hookItr = (*scritr)->BeforeCast.begin(); + for (; hookItr != hookItrEnd ; ++hookItr) + (*hookItr).Call(*scritr); + + (*scritr)->_FinishScriptCall(); + } +} + +void Spell::CallScriptOnCastHandlers() +{ + for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_CAST); + std::list<SpellScript::CastHandler>::iterator hookItrEnd = (*scritr)->OnCast.end(), hookItr = (*scritr)->OnCast.begin(); + for (; hookItr != hookItrEnd ; ++hookItr) + (*hookItr).Call(*scritr); + + (*scritr)->_FinishScriptCall(); + } +} + +void Spell::CallScriptAfterCastHandlers() +{ + for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_CAST); + std::list<SpellScript::CastHandler>::iterator hookItrEnd = (*scritr)->AfterCast.end(), hookItr = (*scritr)->AfterCast.begin(); + for (; hookItr != hookItrEnd ; ++hookItr) + (*hookItr).Call(*scritr); + + (*scritr)->_FinishScriptCall(); + } } SpellCastResult Spell::CallScriptCheckCastHandlers() @@ -7010,6 +7049,12 @@ SpellCastResult Spell::CallScriptCheckCastHandlers() return retVal; } +void Spell::PrepareScriptHitHandlers() +{ + for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + (*scritr)->_InitHit(); +} + bool Spell::CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode) { // execute script effect handler hooks and check if effects was prevented diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index f57b3114a70..a79384e12eb 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -624,6 +624,9 @@ class Spell // Scripting system void LoadScripts(); + void CallScriptBeforeCastHandlers(); + void CallScriptOnCastHandlers(); + void CallScriptAfterCastHandlers(); SpellCastResult CallScriptCheckCastHandlers(); void PrepareScriptHitHandlers(); bool CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode); diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 53ec7822623..fc537ce4fb1 100755 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -52,6 +52,11 @@ void _SpellScript::_Init(std::string const* scriptname, uint32 spellId) m_scriptSpellId = spellId; } +std::string const* _SpellScript::_GetScriptName() const +{ + return m_scriptName; +} + _SpellScript::EffectHook::EffectHook(uint8 _effIndex) { // effect index must be in range <0;2>, allow use of special effindexes @@ -147,6 +152,16 @@ std::string _SpellScript::EffectAuraNameCheck::ToString() } } +SpellScript::CastHandler::CastHandler(SpellCastFnType _pCastHandlerScript) +{ + pCastHandlerScript = _pCastHandlerScript; +} + +void SpellScript::CastHandler::Call(SpellScript* spellScript) +{ + (spellScript->*pCastHandlerScript)(); +} + SpellScript::CheckCastHandler::CheckCastHandler(SpellCheckCastFnType checkCastHandlerScript) { _checkCastHandlerScript = checkCastHandlerScript; diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index dab77f6533d..67886becb74 100755 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -64,6 +64,7 @@ class _SpellScript virtual void _Register(); virtual void _Unload(); virtual void _Init(std::string const* scriptname, uint32 spellId); + std::string const* _GetScriptName() const; protected: class EffectHook @@ -131,6 +132,9 @@ enum SpellScriptHookType SPELL_SCRIPT_HOOK_AFTER_HIT, SPELL_SCRIPT_HOOK_UNIT_TARGET_SELECT, SPELL_SCRIPT_HOOK_CHECK_CAST, + SPELL_SCRIPT_HOOK_BEFORE_CAST, + SPELL_SCRIPT_HOOK_ON_CAST, + SPELL_SCRIPT_HOOK_AFTER_CAST, }; #define HOOK_SPELL_HIT_START SPELL_SCRIPT_HOOK_EFFECT_HIT @@ -148,10 +152,20 @@ class SpellScript : public _SpellScript typedef SpellCastResult(CLASSNAME::*SpellCheckCastFnType)(); \ typedef void(CLASSNAME::*SpellEffectFnType)(SpellEffIndex); \ typedef void(CLASSNAME::*SpellHitFnType)(); \ + typedef void(CLASSNAME::*SpellCastFnType)(); \ typedef void(CLASSNAME::*SpellUnitTargetFnType)(std::list<Unit*>&); \ SPELLSCRIPT_FUNCTION_TYPE_DEFINES(SpellScript) + class CastHandler + { + public: + CastHandler(SpellCastFnType _pCastHandlerScript); + void Call(SpellScript* spellScript); + private: + SpellCastFnType pCastHandlerScript; + }; + class CheckCastHandler { public: @@ -194,6 +208,7 @@ class SpellScript : public _SpellScript }; #define SPELLSCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) \ + class CastHandlerFunction : public SpellScript::CastHandler { public: CastHandlerFunction(SpellCastFnType _pCastHandlerScript) : SpellScript::CastHandler((SpellScript::SpellCastFnType)_pCastHandlerScript) {} }; \ class CheckCastHandlerFunction : public SpellScript::CheckCastHandler { public: CheckCastHandlerFunction(SpellCheckCastFnType _checkCastHandlerScript) : SpellScript::CheckCastHandler((SpellScript::SpellCheckCastFnType)_checkCastHandlerScript) {} }; \ class EffectHandlerFunction : public SpellScript::EffectHandler { public: EffectHandlerFunction(SpellEffectFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName) : SpellScript::EffectHandler((SpellScript::SpellEffectFnType)_pEffectHandlerScript, _effIndex, _effName) {} }; \ class HitHandlerFunction : public SpellScript::HitHandler { public: HitHandlerFunction(SpellHitFnType _pHitHandlerScript) : SpellScript::HitHandler((SpellScript::SpellHitFnType)_pHitHandlerScript) {} }; \ @@ -221,6 +236,13 @@ class SpellScript : public _SpellScript // SpellScript interface // hooks to which you can attach your functions // + // example: BeforeCast += SpellCastFn(class::function); + HookList<CastHandler> BeforeCast; + // example: OnCast += SpellCastFn(class::function); + HookList<CastHandler> OnCast; + // example: AfterCast += SpellCastFn(class::function); + HookList<CastHandler> AfterCast; + #define SpellCastFn(F) CastHandlerFunction(&F) // example: OnCheckCast += SpellCheckCastFn(); // where function is SpellCastResult function() @@ -250,14 +272,18 @@ class SpellScript : public _SpellScript #define SpellUnitTargetFn(F, I, N) UnitTargetHandlerFunction(&F, I, N) // hooks are executed in following order, at specified event of spell: - // 1. OnUnitTargetSelect - executed just before adding selected targets to final target list - // 2. OnEffectLaunch - executed just before specified effect handler call - when spell missile is launched - // 3. OnEffectLaunchTarget - executed just before specified effect handler call - when spell missile is launched - called for each target from spell target map - // 4. OnEffectHit - executed just before specified effect handler call - when spell missile hits dest - // 5. BeforeHit - executed just before spell hits a target - called for each target from spell target map - // 6. OnEffectHitTarget - executed just before specified effect handler call - called for each target from spell target map - // 7. OnHit - executed just before spell deals damage and procs auras - when spell hits target - called for each target from spell target map - // 8. AfterHit - executed just after spell finishes all it's jobs for target - called for each target from spell target map + // 1. BeforeCast - executed when spell preparation is finished (when cast bar becomes full) before cast is handled + // 2. OnCheckCast - allows to override result of CheckCast function + // 3. OnUnitTargetSelect - executed just before adding selected targets to final target list + // 4. OnCast - executed just before spell is launched (creates missile) or executed + // 5. AfterCast - executed after spell missile is launched and immediate spell actions are done + // 6. OnEffectLaunch - executed just before specified effect handler call - when spell missile is launched + // 7. OnEffectLaunchTarget - executed just before specified effect handler call - when spell missile is launched - called for each target from spell target map + // 8. OnEffectHit - executed just before specified effect handler call - when spell missile hits dest + // 9. BeforeHit - executed just before spell hits a target - called for each target from spell target map + // 10. OnEffectHitTarget - executed just before specified effect handler call - called for each target from spell target map + // 11. OnHit - executed just before spell deals damage and procs auras - when spell hits target - called for each target from spell target map + // 12. AfterHit - executed just after spell finishes all it's jobs for target - called for each target from spell target map // // methods allowing interaction with Spell object diff --git a/src/server/scripts/Examples/example_spell.cpp b/src/server/scripts/Examples/example_spell.cpp index 372abc45268..4d2064bf630 100644 --- a/src/server/scripts/Examples/example_spell.cpp +++ b/src/server/scripts/Examples/example_spell.cpp @@ -76,6 +76,38 @@ class spell_ex_5581 : public SpellScriptLoader delete localVariable2; } + void HandleBeforeCast() + { + // this hook is executed before anything about casting the spell is done + // after this hook is executed all the machinery starts + sLog->outString("Caster just finished preparing the spell (cast bar has expired)"); + } + + void HandleOnCast() + { + // cast is validated and spell targets are selected at this moment + // this is a last place when the spell can be safely interrupted + sLog->outString("Spell is about to do take reagents, power, launch missile, do visuals and instant spell effects"); + } + + void HandleAfterCast() + { + sLog->outString("All immediate actions for the spell are finished now"); + // this is a safe for triggering additional effects for a spell without interfering + // with visuals or with other effects of the spell + //GetCaster()->CastSpell(target, SPELL_TRIGGERED, true); + } + + SpellCastResult CheckRequirement() + { + // in this hook you can add additional requirements for spell caster (and throw a client error if reqs're not passed) + // in this case we're disallowing to select non-player as a target of the spell + //if (!GetTargetUnit() || GetTargetUnit()->ToPlayer()) + //return SPELL_FAILED_BAD_TARGETS; + return SPELL_CAST_OK; + } + + void HandleDummyLaunch(SpellEffIndex /*effIndex*/) { sLog->outString("Spell %u with SPELL_EFFECT_DUMMY is just launched!", GetSpellInfo()->Id); @@ -127,7 +159,11 @@ class spell_ex_5581 : public SpellScriptLoader // register functions used in spell script - names of these functions do not matter void Register() { - // we're registering our function here + // we're registering our functions here + BeforeCast += SpellCastFn(spell_ex_5581SpellScript::HandleBeforeCast); + OnCast += SpellCastFn(spell_ex_5581SpellScript::HandleOnCast); + AfterCast += SpellCastFn(spell_ex_5581SpellScript::HandleAfterCast); + OnCheckCast += SpellCheckCastFn(spell_ex_5581SpellScript::CheckRequirement); // function HandleDummy will be called when spell is launched, independant from targets selected for spell, just before default effect 0 launch handler OnEffectLaunch += SpellEffectFn(spell_ex_5581SpellScript::HandleDummyLaunch, EFFECT_0, SPELL_EFFECT_DUMMY); // function HandleDummy will be called when spell is launched at target, just before default effect 0 launch at target handler |