aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2011-01-21 23:42:51 +0100
committerShauren <shauren.trinity@gmail.com>2011-01-21 23:42:51 +0100
commitc2690f748bcc42a1818b90336e81fb586588dd1e (patch)
tree86c513b372d3a75455b442a8bf856ac38570801f /src
parent76e4b6dda48c7ac20b2b6bfc874fd89deea9398b (diff)
Scripts/Spells: Implemented UnitTargetHandler spell script hook, it can be used to filter area targeting spells
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp30
-rwxr-xr-xsrc/server/game/Spells/Spell.h1
-rwxr-xr-xsrc/server/game/Spells/SpellScript.cpp58
-rwxr-xr-xsrc/server/game/Spells/SpellScript.h39
-rw-r--r--src/server/scripts/Examples/example_spell.cpp8
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp10
6 files changed, 110 insertions, 36 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 04da8686a86..906a40b2261 100755
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2422,6 +2422,8 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
break;
}
+ CallScriptAfterUnitTargetSelectHandlers(unitList, SpellEffIndex(i));
+
for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
AddUnitTarget(*itr, i);
}
@@ -2834,17 +2836,6 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
++itr;
}
break;
- case 69782: case 69796: // Ooze Flood
- case 69798: case 69801: // Ooze Flood
- // get 2 targets except 2 nearest
- unitList.sort(Trinity::ObjectDistanceOrderPred(m_caster));
- unitList.resize(4);
- while (unitList.size() > 2)
- unitList.pop_front();
- // crashfix
- if (unitList.empty())
- return;
- break;
case 68921: case 69049: // Soulstorm
for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end();)
{
@@ -2917,6 +2908,9 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
}
}
}
+
+ CallScriptAfterUnitTargetSelectHandlers(unitList, SpellEffIndex(i));
+
for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
AddUnitTarget(*itr, i);
}
@@ -7404,3 +7398,17 @@ void Spell::CallScriptAfterHitHandlers()
(*scritr)->_FinishScriptCall();
}
}
+
+void Spell::CallScriptAfterUnitTargetSelectHandlers(std::list<Unit*>& unitTargets, SpellEffIndex effIndex)
+{
+ for(std::list<SpellScript *>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end() ; ++scritr)
+ {
+ (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_UNIT_TARGET_SELECT);
+ std::list<SpellScript::UnitTargetHandler>::iterator hookItrEnd = (*scritr)->OnUnitTargetSelect.end(), hookItr = (*scritr)->OnUnitTargetSelect.begin();
+ for(; hookItr != hookItrEnd ; ++hookItr)
+ if ((*hookItr).IsEffectAffected(m_spellInfo, effIndex))
+ (*hookItr).Call(*scritr, unitTargets);
+
+ (*scritr)->_FinishScriptCall();
+ }
+}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 0d7f163c0ea..34ddf5c1028 100755
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -689,6 +689,7 @@ class Spell
void CallScriptBeforeHitHandlers();
void CallScriptOnHitHandlers();
void CallScriptAfterHitHandlers();
+ void CallScriptAfterUnitTargetSelectHandlers(std::list<Unit*>& unitTargets, SpellEffIndex effIndex);
std::list<SpellScript *> m_loadedScripts;
// effect helpers
diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp
index 8938c809a27..30674b4f69d 100755
--- a/src/server/game/Spells/SpellScript.cpp
+++ b/src/server/game/Spells/SpellScript.cpp
@@ -177,15 +177,41 @@ void SpellScript::HitHandler::Call(SpellScript * spellScript)
(spellScript->*pHitHandlerScript)();
}
+SpellScript::UnitTargetHandler::UnitTargetHandler(SpellUnitTargetFnType _pUnitTargetHandlerScript, uint8 _effIndex, uint16 _targetType)
+ : _SpellScript::EffectHook(_effIndex), targetType(_targetType)
+{
+ pUnitTargetHandlerScript = _pUnitTargetHandlerScript;
+}
+
+std::string SpellScript::UnitTargetHandler::ToString()
+{
+ std::ostringstream oss;
+ oss << "Index: " << EffIndexToString() << " Target: " << targetType;
+ return oss.str();
+}
+
+bool SpellScript::UnitTargetHandler::CheckEffect(SpellEntry const * spellEntry, uint8 effIndex)
+{
+ if (!targetType)
+ return false;
+ return (effIndex == SPELL_EFFECT_ANY) || (spellEntry->EffectImplicitTargetA[effIndex] == targetType || spellEntry->EffectImplicitTargetB[effIndex] == targetType);
+}
+
+void SpellScript::UnitTargetHandler::Call(SpellScript * spellScript, std::list<Unit*>& unitTargets)
+{
+ (spellScript->*pUnitTargetHandlerScript)(unitTargets);
+}
+
bool SpellScript::_Validate(SpellEntry const * entry)
{
for (std::list<EffectHandler>::iterator itr = OnEffect.begin(); itr != OnEffect.end(); ++itr)
- {
if (!(*itr).GetAffectedEffectsMask(entry))
- {
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
- }
- }
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+
+ for (std::list<UnitTargetHandler>::iterator itr = OnUnitTargetSelect.begin(); itr != OnUnitTargetSelect.end(); ++itr)
+ if (!(*itr).GetAffectedEffectsMask(entry))
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+
return _SpellScript::_Validate(entry);
}
@@ -417,47 +443,47 @@ bool AuraScript::_Validate(SpellEntry const * entry)
{
for (std::list<EffectApplyHandler>::iterator itr = OnEffectApply.begin(); itr != OnEffectApply.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectApplyHandler>::iterator itr = OnEffectRemove.begin(); itr != OnEffectRemove.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectPeriodicHandler>::iterator itr = OnEffectPeriodic.begin(); itr != OnEffectPeriodic.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectUpdatePeriodicHandler>::iterator itr = OnEffectUpdatePeriodic.begin(); itr != OnEffectUpdatePeriodic.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectCalcAmountHandler>::iterator itr = DoEffectCalcAmount.begin(); itr != DoEffectCalcAmount.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectCalcPeriodicHandler>::iterator itr = DoEffectCalcPeriodic.begin(); itr != DoEffectCalcPeriodic.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectCalcSpellModHandler>::iterator itr = DoEffectCalcSpellMod.begin(); itr != DoEffectCalcSpellMod.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectAbsorbHandler>::iterator itr = OnEffectAbsorb.begin(); itr != OnEffectAbsorb.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectAbsorbHandler>::iterator itr = AfterEffectAbsorb.begin(); itr != AfterEffectAbsorb.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectManaShieldHandler>::iterator itr = OnEffectManaShield.begin(); itr != OnEffectManaShield.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
for (std::list<EffectManaShieldHandler>::iterator itr = AfterEffectManaShield.begin(); itr != AfterEffectManaShield.end(); ++itr)
if (!(*itr).GetAffectedEffectsMask(entry))
- sLog->outError("TSCR: Spell `%u` Effect `%s` of script`%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
+ sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - bound handler won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str());
return _SpellScript::_Validate(entry);
}
diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h
index 7244fbda093..5e0c7fdb4d5 100755
--- a/src/server/game/Spells/SpellScript.h
+++ b/src/server/game/Spells/SpellScript.h
@@ -120,11 +120,12 @@ enum SpellScriptHookType
SPELL_SCRIPT_HOOK_BEFORE_HIT,
SPELL_SCRIPT_HOOK_HIT,
SPELL_SCRIPT_HOOK_AFTER_HIT,
+ SPELL_SCRIPT_HOOK_UNIT_TARGET_SELECT,
};
#define HOOK_SPELL_HIT_START SPELL_SCRIPT_HOOK_EFFECT
#define HOOK_SPELL_HIT_END SPELL_SCRIPT_HOOK_AFTER_HIT + 1
#define HOOK_SPELL_START SPELL_SCRIPT_HOOK_EFFECT
-#define HOOK_SPELL_END SPELL_SCRIPT_HOOK_AFTER_HIT + 1
+#define HOOK_SPELL_END SPELL_SCRIPT_HOOK_UNIT_TARGET_SELECT + 1
#define HOOK_SPELL_COUNT HOOK_SPELL_END - HOOK_SPELL_START
class SpellScript : public _SpellScript
@@ -135,6 +136,7 @@ class SpellScript : public _SpellScript
#define SPELLSCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) \
typedef void(CLASSNAME::*SpellEffectFnType)(SpellEffIndex); \
typedef void(CLASSNAME::*SpellHitFnType)(); \
+ typedef void(CLASSNAME::*SpellUnitTargetFnType)(std::list<Unit*>&); \
SPELLSCRIPT_FUNCTION_TYPE_DEFINES(SpellScript)
@@ -158,21 +160,34 @@ class SpellScript : public _SpellScript
SpellHitFnType pHitHandlerScript;
};
+ class UnitTargetHandler : public _SpellScript::EffectHook
+ {
+ public:
+ UnitTargetHandler(SpellUnitTargetFnType _pUnitTargetHandlerScript, uint8 _effIndex, uint16 _targetType);
+ std::string ToString();
+ bool CheckEffect(SpellEntry const * spellEntry, uint8 targetType);
+ void Call(SpellScript * spellScript, std::list<Unit*>& unitTargets);
+ private:
+ SpellUnitTargetFnType pUnitTargetHandlerScript;
+ uint16 targetType;
+ };
+
#define SPELLSCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) \
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) {} }; \
+ class UnitTargetHandlerFunction : public SpellScript::UnitTargetHandler { public: UnitTargetHandlerFunction(SpellUnitTargetFnType _pUnitTargetHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::UnitTargetHandler((SpellScript::SpellUnitTargetFnType)_pUnitTargetHandlerScript, _effIndex, _targetType) {} }; \
#define PrepareSpellScript(CLASSNAME) SPELLSCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) SPELLSCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME)
public:
bool _Validate(SpellEntry const * entry);
bool _Load(Spell * spell);
void _InitHit();
- bool _IsEffectPrevented(SpellEffIndex effIndex) {return m_hitPreventEffectMask & (1<<effIndex);};
- bool _IsDefaultEffectPrevented(SpellEffIndex effIndex) {return m_hitPreventDefaultEffectMask & (1<<effIndex);};
+ bool _IsEffectPrevented(SpellEffIndex effIndex) { return m_hitPreventEffectMask & (1<<effIndex); }
+ bool _IsDefaultEffectPrevented(SpellEffIndex effIndex) { return m_hitPreventDefaultEffectMask & (1<<effIndex); }
void _PrepareScriptCall(SpellScriptHookType hookType);
void _FinishScriptCall();
- bool IsInHitPhase() { return (m_currentScriptState >= HOOK_SPELL_HIT_START && m_currentScriptState < HOOK_SPELL_HIT_END); };
- bool IsInEffectHook() { return (m_currentScriptState == SPELL_SCRIPT_HOOK_EFFECT); };
+ bool IsInHitPhase() { return (m_currentScriptState >= HOOK_SPELL_HIT_START && m_currentScriptState < HOOK_SPELL_HIT_END); }
+ bool IsInEffectHook() { return (m_currentScriptState == SPELL_SCRIPT_HOOK_EFFECT); }
private:
Spell * m_spell;
uint8 m_hitPreventEffectMask;
@@ -196,11 +211,17 @@ class SpellScript : public _SpellScript
// where function is: void function()
#define SpellHitFn(F) HitHandlerFunction(&F)
+ // example: OnUnitTargetSelect += SpellUnitTargetFn(class::function, EffectIndexSpecifier, TargetsNameSpecifier);
+ // where function is void function(std::list<Unit*>& targetList)
+ HookList<UnitTargetHandler> OnUnitTargetSelect;
+ #define SpellUnitTargetFn(F, I, N) UnitTargetHandlerFunction(&F, I, N)
+
// hooks are executed in following order, at specified event of spell:
- // 1. BeforeHit - executed just before spell hits a target
- // 2. OnEffect - 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
+ // 1. OnUnitTargetSelect - executed just before adding selected targets to final target list
+ // 2. BeforeHit - executed just before spell hits a target
+ // 3. OnEffect - executed just before specified effect handler call
+ // 4. OnHit - executed just before spell deals damage and procs auras
+ // 5. AfterHit - executed just after spell finishes all it's jobs for target
//
// 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 028d016330c..2ac16878d13 100644
--- a/src/server/scripts/Examples/example_spell.cpp
+++ b/src/server/scripts/Examples/example_spell.cpp
@@ -99,6 +99,12 @@ class spell_ex_5581 : public SpellScriptLoader
sLog->outString("Spell just finished hitting target!");
}
+ void FilterTargets(std::list<Unit*>& /*targetList*/)
+ {
+ // usually you want this call for Area Target spells
+ sLog->outString("Spell is about to add targets from targetList to final targets!");
+ }
+
// register functions used in spell script - names of these functions do not matter
void Register()
{
@@ -118,6 +124,8 @@ class spell_ex_5581 : public SpellScriptLoader
OnHit += SpellHitFn(spell_ex_5581SpellScript::HandleOnHit);
// bind handler to AfterHit event of the spell
AfterHit += SpellHitFn(spell_ex_5581SpellScript::HandleAfterHit);
+ // bind handler to OnUnitTargetSelect event of the spell
+ //OnUnitTargetSelect += SpellUnitTargetFn(spell_ex_5581SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER);
}
};
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
index 3141961782e..efe33f6bd74 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
@@ -463,9 +463,19 @@ class spell_rotface_ooze_flood : public SpellScriptLoader
GetHitUnit()->CastSpell(list.back(), uint32(GetEffectValue()), false, NULL, NULL, GetOriginalCaster() ? GetOriginalCaster()->GetGUID() : 0);
}
+ void FilterTargets(std::list<Unit*>& targetList)
+ {
+ // get 2 targets except 2 nearest
+ targetList.sort(Trinity::ObjectDistanceOrderPred(GetCaster()));
+ targetList.resize(4);
+ while (targetList.size() > 2)
+ targetList.pop_front();
+ }
+
void Register()
{
OnEffect += SpellEffectFn(spell_rotface_ooze_flood_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ OnUnitTargetSelect += SpellUnitTargetFn(spell_rotface_ooze_flood_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_AREA_ENTRY_SRC);
}
};