diff options
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 97 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 6 | ||||
-rw-r--r-- | src/server/game/Spells/SpellScript.h | 21 | ||||
-rw-r--r-- | src/server/scripts/Examples/example_spell.cpp | 21 |
4 files changed, 123 insertions, 22 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 0972c84b3e5..988c55794e1 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1279,6 +1279,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) break; } } + CallScriptOnHitHandlers(); + // All calculated do it! // Do healing and triggers if (m_healing > 0) @@ -1392,6 +1394,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) m_caster->ToPlayer()->UpdatePvP(true); } + CallScriptAfterHitHandlers(); } } @@ -1404,7 +1407,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool if (m_spellInfo->speed && (unit->IsImmunedToDamage(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo))) return SPELL_MISS_IMMUNE; - PrepareTargetHitForScripts(); + PrepareScriptHitHandlers(); + CallScriptBeforeHitHandlers(); if (unit->GetTypeId() == TYPEID_PLAYER) { @@ -1497,7 +1501,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool if (scaleAura) { aurSpellInfo = sSpellMgr.SelectAuraRankForPlayerLevel(m_spellInfo,unitTarget->getLevel()); - ASSERT (aurSpellInfo); + ASSERT(aurSpellInfo); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { basePoints[i] = aurSpellInfo->EffectBasePoints[i]; @@ -1641,12 +1645,15 @@ void Spell::DoAllEffectOnTarget(GOTargetInfo *target) if (!go) return; - PrepareTargetHitForScripts(); + PrepareScriptHitHandlers(); + CallScriptBeforeHitHandlers(); for (uint32 effectNumber = 0; effectNumber < 3; ++effectNumber) if (effectMask & (1 << effectNumber)) HandleEffects(NULL, NULL, go, effectNumber); + CallScriptOnHitHandlers(); + // cast at creature (or GO) quest objectives update at successful cast finished (+channel finished) // ignore autorepeat/melee casts for speed (not exist quest for spells (hm...) if (m_originalCaster && m_originalCaster->IsControlledByPlayer() && !IsAutoRepeat() && !IsNextMeleeSwingSpell() && !IsChannelActive()) @@ -1654,6 +1661,7 @@ void Spell::DoAllEffectOnTarget(GOTargetInfo *target) if (Player* p = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself()) p->CastedCreatureOrGO(go->GetEntry(),go->GetGUID(),m_spellInfo->Id); } + CallScriptAfterHitHandlers(); } void Spell::DoAllEffectOnTarget(ItemTargetInfo *target) @@ -1662,11 +1670,16 @@ void Spell::DoAllEffectOnTarget(ItemTargetInfo *target) if (!target->item || !effectMask) return; - PrepareTargetHitForScripts(); + PrepareScriptHitHandlers(); + CallScriptBeforeHitHandlers(); for (uint32 effectNumber = 0; effectNumber < 3; ++effectNumber) if (effectMask & (1 << effectNumber)) HandleEffects(NULL, target->item, NULL, effectNumber); + + CallScriptOnHitHandlers(); + + CallScriptAfterHitHandlers(); } bool Spell::UpdateChanneledTargetList() @@ -3261,7 +3274,7 @@ void Spell::cast(bool skipCheck) // CAST SPELL SendSpellCooldown(); - PrepareTargetHitForScripts(); + PrepareScriptHitHandlers(); for (uint32 i = 0; i < 3; ++i) { @@ -3427,7 +3440,7 @@ void Spell::_handle_immediate_phase() // handle some immediate features of the spell here HandleThreatSpells(m_spellInfo->Id); - PrepareTargetHitForScripts(); + PrepareScriptHitHandlers(); m_needSpellLog = IsNeedSendToClient(); for (uint32 j = 0; j < 3; ++j) @@ -4677,20 +4690,7 @@ void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTar //we do not need DamageMultiplier here. damage = CalculateDamage(i, NULL); - // execute script effect handler hooks and check if effects was prevented - bool preventDefault = false; - for(std::list<SpellScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) - { - std::list<SpellScript::EffectHandler>::iterator effEndItr = (*scritr)->EffectHandlers.end(), effItr = (*scritr)->EffectHandlers.begin(); - for(; effItr != effEndItr ; ++effItr) - { - // effect execution can be prevented - if (!(*scritr)->_IsEffectPrevented((SpellEffIndex)i) && (*effItr).IsEffectAffected(m_spellInfo, i)) - (*effItr).Call(*scritr, (SpellEffIndex)i); - } - if (!preventDefault) - preventDefault = (*scritr)->_IsDefaultEffectPrevented((SpellEffIndex)i); - } + bool preventDefault = CallScriptEffectHandlers((SpellEffIndex)i); if (!preventDefault && eff < TOTAL_SPELL_EFFECTS) { @@ -7306,10 +7306,65 @@ void Spell::LoadScripts() } } -void Spell::PrepareTargetHitForScripts() +void Spell::PrepareScriptHitHandlers() { for(std::list<SpellScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) { (*scritr)->_InitHit(); } } + +bool Spell::CallScriptEffectHandlers(SpellEffIndex effIndex) +{ + // execute script effect handler hooks and check if effects was prevented + bool preventDefault = false; + for(std::list<SpellScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + std::list<SpellScript::EffectHandler>::iterator effEndItr = (*scritr)->EffectHandlers.end(), effItr = (*scritr)->EffectHandlers.begin(); + for(; effItr != effEndItr ; ++effItr) + { + // effect execution can be prevented + if (!(*scritr)->_IsEffectPrevented(effIndex) && (*effItr).IsEffectAffected(m_spellInfo, effIndex)) + (*effItr).Call(*scritr, effIndex); + } + if (!preventDefault) + preventDefault = (*scritr)->_IsDefaultEffectPrevented(effIndex); + } + return preventDefault; +} + +void Spell::CallScriptBeforeHitHandlers() +{ + for(std::list<SpellScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + std::list<SpellScript::HitHandler>::iterator hookItrEnd = (*scritr)->BeforeHit.end(), hookItr = (*scritr)->BeforeHit.begin(); + for(; hookItr != hookItrEnd ; ++hookItr) + { + ((*scritr)->*(*hookItr))(); + } + } +} + +void Spell::CallScriptOnHitHandlers() +{ + for(std::list<SpellScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + std::list<SpellScript::HitHandler>::iterator hookItrEnd = (*scritr)->OnHit.end(), hookItr = (*scritr)->OnHit.begin(); + for(; hookItr != hookItrEnd ; ++hookItr) + { + ((*scritr)->*(*hookItr))(); + } + } +} + +void Spell::CallScriptAfterHitHandlers() +{ + for(std::list<SpellScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr) + { + std::list<SpellScript::HitHandler>::iterator hookItrEnd = (*scritr)->AfterHit.end(), hookItr = (*scritr)->AfterHit.begin(); + for(; hookItr != hookItrEnd ; ++hookItr) + { + ((*scritr)->*(*hookItr))(); + } + } +} diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 7dd1ae3a9cd..67ce56ea9b2 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -672,7 +672,11 @@ class Spell // Scripting system void LoadScripts(); - void PrepareTargetHitForScripts(); + void PrepareScriptHitHandlers(); + bool CallScriptEffectHandlers(SpellEffIndex effIndex); + void CallScriptBeforeHitHandlers(); + void CallScriptOnHitHandlers(); + void CallScriptAfterHitHandlers(); std::list<SpellScript *> m_loadedScripts; // effect helpers diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index fae3dfcbd58..081b8035ca1 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -34,6 +34,7 @@ class Item; class WorldLocation; typedef void(SpellScript::*EffectHandlerFnType)(SpellEffIndex); +typedef void(SpellScript::*HitHandlerFnType)(); #define SPELL_EFFECT_ANY (uint16)-1 #define SPELL_AURA_ANY (uint16)-1 @@ -108,6 +109,7 @@ class SpellScript : public _SpellScript private: EffectHandlerFnType pEffectHandlerScript; }; + typedef HitHandlerFnType HitHandler; public: bool _Validate(SpellEntry const * entry, const char * scriptname); bool _Load(Spell * spell); @@ -127,6 +129,20 @@ class SpellScript : public _SpellScript // allows more than one hook // example EffectHandlers += EffectHandlerFn(class::function, EffectIndexSpecifier, EffectNameSpecifier); HookList<EffectHandler> EffectHandlers; + // List of functions registered by HitHandlerFn + // allows more than one hook + // example: BeforeHit += HitHandlerFn(class::function); + HookList<HitHandler> BeforeHit; + // example: OnHit += HitHandlerFn(class::function); + HookList<HitHandler> OnHit; + // example: AfterHit += HitHandlerFn(class::function); + HookList<HitHandler> AfterHit; + + // hooks are executed in following order, at specified event of spell: + // 1. BeforeHit - executed just before spell hits a target + // 2. EffectHandlers - executed just before specified effect handler call + // 3. OnHit - executed just before spell deals damage and procs auras + // 4. AfterHit - executed just after spell finishes all it's jobs for target // // methods allowing interaction with Spell object @@ -196,6 +212,11 @@ class SpellScript : public _SpellScript // parameters: function to call, EffectIndexSpecifier, EffectNameSpecifier #define EffectHandlerFn(F, I, N) EffectHandler((EffectHandlerFnType)&F, I, N) +// HitHandlerFn +// called at: Spell hit on unit, before or after effect handlers, depends if bound to OnHit or AfterHit +// parameters: function to call +#define HitHandlerFn(F) (HitHandlerFnType)&F + // // definitions: // diff --git a/src/server/scripts/Examples/example_spell.cpp b/src/server/scripts/Examples/example_spell.cpp index 3063f6f6d8b..d5ba5b4a5ba 100644 --- a/src/server/scripts/Examples/example_spell.cpp +++ b/src/server/scripts/Examples/example_spell.cpp @@ -45,6 +45,21 @@ class spell_ex_49375 : public SpellHandlerScript GetCaster()->CastSpell(target, 70522, true); }; + void HandleBeforeHit() + { + sLog.outError("Spell is about to hit target!"); + } + + void HandleOnHit() + { + sLog.outError("Spell just hit target!"); + } + + void HandleAfterHit() + { + sLog.outError("Spell just finished hitting target!"); + } + void Register() { // we're registering our function here @@ -56,6 +71,12 @@ class spell_ex_49375 : public SpellHandlerScript //EffectHandlers += EffectHandlerFn(spell_gen_49375SpellScript::HandleDummy, EFFECT_FIRST_FOUND, SPELL_EFFECT_ANY); // this will make HandleDummy function to be called on all != 0 effect of spell 49375 //EffectHandlers += EffectHandlerFn(spell_gen_49375SpellScript::HandleDummy, EFFECT_ALL, SPELL_EFFECT_ANY); + // bind handler to BeforeHit event of the spell + BeforeHit += HitHandlerFn(spell_ex_49375SpellScript::HandleBeforeHit); + // bind handler to OnHit event of the spell + OnHit += HitHandlerFn(spell_ex_49375SpellScript::HandleOnHit); + // bind handler to AfterHit event of the spell + AfterHit += HitHandlerFn(spell_ex_49375SpellScript::HandleAfterHit); }; // function called on server startup |