aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQAston <none@none>2010-08-21 20:18:54 +0200
committerQAston <none@none>2010-08-21 20:18:54 +0200
commit6714feb3ee95fbc2967f7ea11c837d3caac90d3a (patch)
tree6c848ba8bc21472d351a9cde6cfd274f08153417
parent3febdd7884305d5b9ff427a5295f9aae95533782 (diff)
*Add script hooks for SpellScript class - now you can use BeforeHit, OnHit, AfterHit hook lists.
--HG-- branch : trunk
-rw-r--r--src/server/game/Spells/Spell.cpp97
-rw-r--r--src/server/game/Spells/Spell.h6
-rw-r--r--src/server/game/Spells/SpellScript.h21
-rw-r--r--src/server/scripts/Examples/example_spell.cpp21
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