*Add script hooks for SpellScript class - now you can use BeforeHit, OnHit, AfterHit hook lists.

--HG--
branch : trunk
This commit is contained in:
QAston
2010-08-21 20:18:54 +02:00
parent 3febdd7884
commit 6714feb3ee
4 changed files with 123 additions and 22 deletions

View File

@@ -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))();
}
}
}

View File

@@ -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

View File

@@ -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:
//

View File

@@ -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