diff options
author | Shauren <shauren.trinity@gmail.com> | 2011-01-21 23:42:51 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2011-01-21 23:42:51 +0100 |
commit | c2690f748bcc42a1818b90336e81fb586588dd1e (patch) | |
tree | 86c513b372d3a75455b442a8bf856ac38570801f /src | |
parent | 76e4b6dda48c7ac20b2b6bfc874fd89deea9398b (diff) |
Scripts/Spells: Implemented UnitTargetHandler spell script hook, it can be used to filter area targeting spells
Diffstat (limited to 'src')
-rwxr-xr-x | src/server/game/Spells/Spell.cpp | 30 | ||||
-rwxr-xr-x | src/server/game/Spells/Spell.h | 1 | ||||
-rwxr-xr-x | src/server/game/Spells/SpellScript.cpp | 58 | ||||
-rwxr-xr-x | src/server/game/Spells/SpellScript.h | 39 | ||||
-rw-r--r-- | src/server/scripts/Examples/example_spell.cpp | 8 | ||||
-rw-r--r-- | src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp | 10 |
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); } }; |