diff options
author | Shauren <shauren.trinity@gmail.com> | 2012-07-03 12:35:06 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2012-07-03 12:35:06 +0200 |
commit | 537caf33e9ee8d88b1c4f4835ee93ee0dd557d2a (patch) | |
tree | 0cefe56b35905ca84ccb0abb7c0d03fa1091eee4 | |
parent | 96014a70cba0d333d7e76cc90cf36468a8b3b247 (diff) |
Core/SpellScript: Implemented OnObjectTargetSelect hook for use with spell target that selects a single object
-rwxr-xr-x | src/server/game/Spells/Spell.cpp | 115 | ||||
-rwxr-xr-x | src/server/game/Spells/Spell.h | 1 | ||||
-rwxr-xr-x | src/server/game/Spells/SpellScript.cpp | 15 | ||||
-rwxr-xr-x | src/server/game/Spells/SpellScript.h | 18 |
4 files changed, 115 insertions, 34 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 2c1cff0c74a..590f880a931 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -914,17 +914,25 @@ void Spell::SelectImplicitChannelTargets(SpellEffIndex effIndex, SpellImplicitTa switch (targetType.GetTarget()) { case TARGET_UNIT_CHANNEL_TARGET: + { + WorldObject* target = ObjectAccessor::GetUnit(*m_caster, channeledSpell->m_targets.GetUnitTargetGUID()); + CallScriptObjectTargetSelectHandlers(target, effIndex); // unit target may be no longer avalible - teleported out of map for example - if (Unit* target = Unit::GetUnit(*m_caster, channeledSpell->m_targets.GetUnitTargetGUID())) - AddUnitTarget(target, 1 << effIndex); + if (target && target->ToUnit()) + AddUnitTarget(target->ToUnit(), 1 << effIndex); else sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: cannot find channel spell target for spell ID %u, effect %u", m_spellInfo->Id, effIndex); break; + } case TARGET_DEST_CHANNEL_TARGET: if (channeledSpell->m_targets.HasDst()) m_targets.SetDst(channeledSpell->m_targets); else if (WorldObject* target = ObjectAccessor::GetWorldObject(*m_caster, channeledSpell->m_targets.GetObjectTargetGUID())) - m_targets.SetDst(*target); + { + CallScriptObjectTargetSelectHandlers(target, effIndex); + if (target) + m_targets.SetDst(*target); + } else sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: cannot find channel spell destination for spell ID %u, effect %u", m_spellInfo->Id, effIndex); break; @@ -1002,6 +1010,8 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar return; } + CallScriptObjectTargetSelectHandlers(target, effIndex); + switch (targetType.GetObjectType()) { case TARGET_OBJECT_TYPE_UNIT: @@ -1492,27 +1502,27 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) { + WorldObject* target = NULL; + bool checkIfValid = true; + switch (targetType.GetTarget()) { case TARGET_UNIT_CASTER: - AddUnitTarget(m_caster, 1 << effIndex, false); + target = m_caster; + checkIfValid = false; break; case TARGET_UNIT_MASTER: - if (Unit* owner = m_caster->GetCharmerOrOwner()) - AddUnitTarget(owner, 1 << effIndex); + target = m_caster->GetCharmerOrOwner(); break; case TARGET_UNIT_PET: - if (Guardian* pet = m_caster->GetGuardianPet()) - AddUnitTarget(pet, 1 << effIndex); + target = m_caster->GetGuardianPet(); break; case TARGET_UNIT_SUMMONER: if (m_caster->isSummon()) - if (Unit* unit = m_caster->ToTempSummon()->GetSummoner()) - AddUnitTarget(unit, 1 << effIndex); + target = m_caster->ToTempSummon()->GetSummoner(); break; case TARGET_UNIT_VEHICLE: - if (Unit *vehicle = m_caster->GetVehicleBase()) - AddUnitTarget(vehicle, 1 << effIndex); + target = m_caster->GetVehicleBase(); break; case TARGET_UNIT_PASSENGER_0: case TARGET_UNIT_PASSENGER_1: @@ -1523,26 +1533,38 @@ void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImpli case TARGET_UNIT_PASSENGER_6: case TARGET_UNIT_PASSENGER_7: if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsVehicle()) - if (Unit *unit = m_caster->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0)) - AddUnitTarget(unit, 1 << effIndex); + target = m_caster->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0); break; default: break; } + + CallScriptObjectTargetSelectHandlers(target, effIndex); + + if (target && target->ToUnit()) + AddUnitTarget(target->ToUnit(), 1 << effIndex, checkIfValid); } void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) { ASSERT((m_targets.GetObjectTarget() || m_targets.GetItemTarget()) && "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!"); - if (Unit* unit = m_targets.GetUnitTarget()) - AddUnitTarget(unit, 1 << effIndex, true, false); - else if (GameObject* gobj = m_targets.GetGOTarget()) - AddGOTarget(gobj, 1 << effIndex); - else - AddItemTarget(m_targets.GetItemTarget(), 1 << effIndex); - if (WorldObject* target = m_targets.GetObjectTarget()) + WorldObject* target = m_targets.GetObjectTarget(); + + CallScriptObjectTargetSelectHandlers(target, effIndex); + + if (target) + { + if (Unit* unit = target->ToUnit()) + AddUnitTarget(unit, 1 << effIndex, true, false); + else if (GameObject* gobj = target->ToGameObject()) + AddGOTarget(gobj, 1 << effIndex); + SelectImplicitChainTargets(effIndex, targetType, target, 1 << effIndex); + } + // Script hook can remove object target and we would wrongly land here + else if (Item* item = m_targets.GetItemTarget()) + AddItemTarget(item, 1 << effIndex); } void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask) @@ -1734,9 +1756,12 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) case SPELL_EFFECT_SUMMON_PLAYER: if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->GetSelection()) { - Player* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection()); - if (target) - AddUnitTarget(target, 1 << effIndex, false); + WorldObject* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection()); + + CallScriptObjectTargetSelectHandlers(target, SpellEffIndex(effIndex)); + + if (target && target->ToPlayer()) + AddUnitTarget(target->ToUnit(), 1 << effIndex, false); } return; default: @@ -1752,6 +1777,8 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) if (!targetMask) return; + WorldObject* target = NULL; + switch (m_spellInfo->Effects[effIndex].GetImplicitTargetType()) { // add explicit object target or self to the target map @@ -1760,40 +1787,46 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) if (targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK)) { if (Unit* unitTarget = m_targets.GetUnitTarget()) - AddUnitTarget(unitTarget, 1 << effIndex, false); + target = unitTarget; else if (targetMask & TARGET_FLAG_CORPSE_MASK) { if (Corpse* corpseTarget = m_targets.GetCorpseTarget()) { // TODO: this is a workaround - corpses should be added to spell target map too, but we can't do that so we add owner instead if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID())) - AddUnitTarget(owner, 1 << effIndex, false); + target = owner; } } else //if (targetMask & TARGET_FLAG_UNIT_MASK) - { - AddUnitTarget(m_caster, 1 << effIndex, false); - } + target = m_caster; } if (targetMask & TARGET_FLAG_ITEM_MASK) { if (Item* itemTarget = m_targets.GetItemTarget()) AddItemTarget(itemTarget, 1 << effIndex); + return; } if (targetMask & TARGET_FLAG_GAMEOBJECT_MASK) - { - if (GameObject* gObjTarget = m_targets.GetGOTarget()) - AddGOTarget(gObjTarget, 1 << effIndex); - } + target = m_targets.GetGOTarget(); break; // add self to the target map case EFFECT_IMPLICIT_TARGET_CASTER: if (targetMask & TARGET_FLAG_UNIT_MASK) - AddUnitTarget(m_caster, 1 << effIndex, false); + target = m_caster; break; default: break; } + + CallScriptObjectTargetSelectHandlers(target, SpellEffIndex(effIndex)); + + if (target) + { + if (target->ToUnit()) + AddUnitTarget(target->ToUnit(), 1 << effIndex, false); + else if (target->ToGameObject()) + AddGOTarget(target->ToGameObject(), 1 << effIndex); + } } uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList) @@ -7053,6 +7086,20 @@ void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& ta } } +void Spell::CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex) +{ + for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT); + std::list<SpellScript::ObjectTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnObjectTargetSelect.end(), hookItr = (*scritr)->OnObjectTargetSelect.begin(); + for (; hookItr != hookItrEnd; ++hookItr) + if ((*hookItr).IsEffectAffected(m_spellInfo, effIndex)) + (*hookItr).Call(*scritr, target); + + (*scritr)->_FinishScriptCall(); + } +} + bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura) const { bool only_on_caster = (triggeredByAura && (triggeredByAura->AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_CASTER)); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 98455904cf5..1376b0fbd40 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -631,6 +631,7 @@ class Spell void CallScriptOnHitHandlers(); void CallScriptAfterHitHandlers(); void CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex); + void CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex); std::list<SpellScript*> m_loadedScripts; struct HitTriggerSpell diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index a19c356b9ed..d0ae6fe3098 100755 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -267,6 +267,17 @@ void SpellScript::ObjectAreaTargetSelectHandler::Call(SpellScript* spellScript, (spellScript->*pObjectAreaTargetSelectHandlerScript)(targets); } +SpellScript::ObjectTargetSelectHandler::ObjectTargetSelectHandler(SpellObjectTargetSelectFnType _pObjectTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) + : TargetHook(_effIndex, _targetType, false) +{ + pObjectTargetSelectHandlerScript = _pObjectTargetSelectHandlerScript; +} + +void SpellScript::ObjectTargetSelectHandler::Call(SpellScript* spellScript, WorldObject*& target) +{ + (spellScript->*pObjectTargetSelectHandlerScript)(target); +} + bool SpellScript::_Validate(SpellInfo const* entry) { for (std::list<EffectHandler>::iterator itr = OnEffectLaunch.begin(); itr != OnEffectLaunch.end(); ++itr) @@ -289,6 +300,10 @@ bool SpellScript::_Validate(SpellInfo const* entry) if (!(*itr).GetAffectedEffectsMask(entry)) sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnObjectAreaTargetSelect` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); + for (std::list<ObjectTargetSelectHandler>::iterator itr = OnObjectTargetSelect.begin(); itr != OnObjectTargetSelect.end(); ++itr) + if (!(*itr).GetAffectedEffectsMask(entry)) + sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnObjectTargetSelect` of SpellScript 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 51631bb8ffe..376e7f18edc 100755 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -132,6 +132,7 @@ enum SpellScriptHookType SPELL_SCRIPT_HOOK_HIT, SPELL_SCRIPT_HOOK_AFTER_HIT, SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT, + SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT, SPELL_SCRIPT_HOOK_CHECK_CAST, SPELL_SCRIPT_HOOK_BEFORE_CAST, SPELL_SCRIPT_HOOK_ON_CAST, @@ -155,6 +156,7 @@ class SpellScript : public _SpellScript typedef void(CLASSNAME::*SpellHitFnType)(); \ typedef void(CLASSNAME::*SpellCastFnType)(); \ typedef void(CLASSNAME::*SpellObjectAreaTargetSelectFnType)(std::list<WorldObject*>&); \ + typedef void(CLASSNAME::*SpellObjectTargetSelectFnType)(WorldObject*&); SPELLSCRIPT_FUNCTION_TYPE_DEFINES(SpellScript) @@ -216,12 +218,22 @@ class SpellScript : public _SpellScript SpellObjectAreaTargetSelectFnType pObjectAreaTargetSelectHandlerScript; }; + class ObjectTargetSelectHandler : public TargetHook + { + public: + ObjectTargetSelectHandler(SpellObjectTargetSelectFnType _pObjectTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType); + void Call(SpellScript* spellScript, WorldObject*& targets); + private: + SpellObjectTargetSelectFnType pObjectTargetSelectHandlerScript; + }; + #define SPELLSCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) \ class CastHandlerFunction : public SpellScript::CastHandler { public: CastHandlerFunction(SpellCastFnType _pCastHandlerScript) : SpellScript::CastHandler((SpellScript::SpellCastFnType)_pCastHandlerScript) {} }; \ class CheckCastHandlerFunction : public SpellScript::CheckCastHandler { public: CheckCastHandlerFunction(SpellCheckCastFnType _checkCastHandlerScript) : SpellScript::CheckCastHandler((SpellScript::SpellCheckCastFnType)_checkCastHandlerScript) {} }; \ 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 ObjectAreaTargetSelectHandlerFunction : public SpellScript::ObjectAreaTargetSelectHandler { public: ObjectAreaTargetSelectHandlerFunction(SpellObjectAreaTargetSelectFnType _pObjectAreaTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::ObjectAreaTargetSelectHandler((SpellScript::SpellObjectAreaTargetSelectFnType)_pObjectAreaTargetSelectHandlerScript, _effIndex, _targetType) {} }; \ + class ObjectTargetSelectHandlerFunction : public SpellScript::ObjectTargetSelectHandler { public: ObjectTargetSelectHandlerFunction(SpellObjectTargetSelectFnType _pObjectTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::ObjectTargetSelectHandler((SpellScript::SpellObjectTargetSelectFnType)_pObjectTargetSelectHandlerScript, _effIndex, _targetType) {} }; #define PrepareSpellScript(CLASSNAME) SPELLSCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) SPELLSCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) public: @@ -280,10 +292,16 @@ class SpellScript : public _SpellScript HookList<ObjectAreaTargetSelectHandler> OnObjectAreaTargetSelect; #define SpellObjectAreaTargetSelectFn(F, I, N) ObjectAreaTargetSelectHandlerFunction(&F, I, N) + // example: OnObjectTargetSelect += SpellObjectTargetSelectFn(class::function, EffectIndexSpecifier, TargetsNameSpecifier); + // where function is void function(WorldObject*& target) + HookList<ObjectTargetSelectHandler> OnObjectTargetSelect; + #define SpellObjectTargetSelectFn(F, I, N) ObjectTargetSelectHandlerFunction(&F, I, N) + // hooks are executed in following order, at specified event of spell: // 1. BeforeCast - executed when spell preparation is finished (when cast bar becomes full) before cast is handled // 2. OnCheckCast - allows to override result of CheckCast function // 3a. OnObjectAreaTargetSelect - executed just before adding selected targets to final target list (for area targets) + // 3b. OnObjectTargetSelect - executed just before adding selected target to final target list (for single unit targets) // 4. OnCast - executed just before spell is launched (creates missile) or executed // 5. AfterCast - executed after spell missile is launched and immediate spell actions are done // 6. OnEffectLaunch - executed just before specified effect handler call - when spell missile is launched |