aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/Conditions/ConditionMgr.cpp420
-rwxr-xr-xsrc/server/game/Conditions/ConditionMgr.h29
-rwxr-xr-xsrc/server/game/Entities/Object/Object.cpp12
-rwxr-xr-xsrc/server/game/Entities/Object/Object.h6
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp21
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h1
-rw-r--r--src/server/game/Grids/GridDefines.h10
-rwxr-xr-xsrc/server/game/Grids/Notifiers/GridNotifiers.cpp13
-rwxr-xr-xsrc/server/game/Grids/Notifiers/GridNotifiers.h117
-rwxr-xr-xsrc/server/game/Grids/Notifiers/GridNotifiersImpl.h111
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp2490
-rwxr-xr-xsrc/server/game/Spells/Spell.h192
-rw-r--r--src/server/game/Spells/SpellInfo.cpp414
-rw-r--r--src/server/game/Spells/SpellInfo.h31
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.cpp11
-rwxr-xr-xsrc/server/game/Spells/SpellMgr.h12
-rwxr-xr-xsrc/server/game/Spells/SpellScript.cpp5
-rwxr-xr-xsrc/server/game/Spells/SpellScript.h1
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp34
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp2
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp2
22 files changed, 2121 insertions, 1815 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 550814ccf3f..af0c1a07c2b 100755
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -26,6 +26,7 @@
#include "ConditionMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "Spell.h"
// Checks if object meets the condition
// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI)
@@ -94,14 +95,14 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
}
case CONDITION_CLASS:
{
- if (Player* player = object->ToPlayer())
- condMeets = player->getClassMask() & ConditionValue1;
+ if (Unit* unit = object->ToUnit())
+ condMeets = unit->getClassMask() & ConditionValue1;
break;
}
case CONDITION_RACE:
{
- if (Player* player = object->ToPlayer())
- condMeets = player->getRaceMask() & ConditionValue1;
+ if (Unit* unit = object->ToUnit())
+ condMeets = unit->getRaceMask() & ConditionValue1;
break;
}
case CONDITION_SKILL:
@@ -153,9 +154,6 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
condMeets = ((InstanceMap*)map)->GetInstanceScript()->GetData(ConditionValue1) == ConditionValue2;
break;
}
- case CONDITION_SPELL_SCRIPT_TARGET:
- condMeets = true;//spell target condition is handled in spellsystem, here it is always true
- break;
case CONDITION_MAPID:
condMeets = object->GetMapId() == ConditionValue1;
break;
@@ -291,12 +289,153 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
return condMeets && script;
}
+uint32 Condition::GetSearcherTypeMaskForCondition()
+{
+ // build mask of types for which condition can return true
+ // this is used for speeding up gridsearches
+ if (NegativeCondition)
+ return (GRID_MAP_TYPE_MASK_ALL);
+ uint32 mask = 0;
+ switch (ConditionType)
+ {
+ case CONDITION_NONE:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_AURA:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_ITEM:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_ITEM_EQUIPPED:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_ZONEID:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_REPUTATION_RANK:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_ACHIEVEMENT:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_TEAM:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_CLASS:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_RACE:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_SKILL:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_QUESTREWARDED:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_QUESTTAKEN:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_QUEST_COMPLETE:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_QUEST_NONE:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_ACTIVE_EVENT:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_INSTANCE_DATA:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_MAPID:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_AREAID:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_SPELL:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_LEVEL:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_DRUNKENSTATE:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_NEAR_CREATURE:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_NEAR_GAMEOBJECT:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_OBJECT_ENTRY:
+ switch (ConditionValue1)
+ {
+ case TYPEID_UNIT:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE;
+ break;
+ case TYPEID_PLAYER:
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case TYPEID_GAMEOBJECT:
+ mask |= GRID_MAP_TYPE_MASK_GAMEOBJECT;
+ break;
+ case TYPEID_CORPSE:
+ mask |= GRID_MAP_TYPE_MASK_CORPSE;
+ break;
+ default:
+ break;
+ }
+ case CONDITION_TYPE_MASK:
+ if (ConditionValue1 & TYPEMASK_UNIT)
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ if (ConditionValue1 & TYPEMASK_PLAYER)
+ mask |= GRID_MAP_TYPE_MASK_PLAYER;
+ if (ConditionValue1 & TYPEMASK_GAMEOBJECT)
+ mask |= GRID_MAP_TYPE_MASK_GAMEOBJECT;
+ if (ConditionValue1 & TYPEMASK_CORPSE)
+ mask |= GRID_MAP_TYPE_MASK_CORPSE;
+ break;
+ case CONDITION_RELATION_TO:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_REACTION_TO:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_DISTANCE_TO:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_ALIVE:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_HP_VAL:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_HP_PCT:
+ mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
+ break;
+ case CONDITION_WORLD_STATE:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ case CONDITION_PHASEMASK:
+ mask |= GRID_MAP_TYPE_MASK_ALL;
+ break;
+ default:
+ ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
+ break;
+ }
+ return mask;
+}
+
uint32 Condition::GetMaxAvailableConditionTargets()
{
// returns number of targets which are available for given source type
switch(SourceType)
{
case CONDITION_SOURCE_TYPE_SPELL:
+ case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET:
case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE:
case CONDITION_SOURCE_TYPE_VEHICLE_SPELL:
case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT:
@@ -327,8 +466,49 @@ ConditionList ConditionMgr::GetConditionReferences(uint32 refId)
return conditions;
}
+uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionList const& conditions)
+{
+ if (conditions.empty())
+ return GRID_MAP_TYPE_MASK_ALL;
+ // groupId, typeMask
+ std::map<uint32, uint32> ElseGroupStore;
+ for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i)
+ {
+ // no point of having not loaded conditions in list
+ ASSERT((*i)->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list");
+ std::map<uint32, uint32>::const_iterator itr = ElseGroupStore.find((*i)->ElseGroup);
+ // group not filled yet, fill with widest mask possible
+ if (itr == ElseGroupStore.end())
+ ElseGroupStore[(*i)->ElseGroup] = GRID_MAP_TYPE_MASK_ALL;
+ // no point of checking anymore, empty mask
+ else if (!(*itr).second)
+ continue;
+
+ if ((*i)->ReferenceId) // handle reference
+ {
+ ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find((*i)->ReferenceId);
+ ASSERT(ref != ConditionReferenceStore.end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference");
+ ElseGroupStore[(*i)->ElseGroup] &= GetSearcherTypeMaskForConditionList((*ref).second);
+ }
+ else // handle normal condition
+ {
+ // object will match conditions in one ElseGroupStore only when it matches all of them
+ // so, let's find a smallest possible mask which satisfies all conditions
+ ElseGroupStore[(*i)->ElseGroup] &= (*i)->GetSearcherTypeMaskForCondition();
+ }
+ }
+ // object will match condition when one of the checks in ElseGroupStore is matching
+ // so, let's include all possible masks
+ uint32 mask = 0;
+ for (std::map<uint32, uint32>::const_iterator i = ElseGroupStore.begin(); i != ElseGroupStore.end(); ++i)
+ mask |= i->second;
+
+ return mask;
+}
+
bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions)
{
+ // groupId, groupCheckPassed
std::map<uint32, bool> ElseGroupStore;
for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i)
{
@@ -391,6 +571,32 @@ bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, Con
return IsObjectMeetToConditionList(sourceInfo, conditions);
}
+bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const
+{
+ return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU ||
+ sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION ||
+ sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL ||
+ sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET ||
+ sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
+}
+
+bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) const
+{
+ return (sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
+}
+
ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry)
{
ConditionList spellCond;
@@ -487,6 +693,7 @@ void ConditionMgr::LoadConditions(bool isReload)
sLog->outString("Re-Loading `gossip_menu_option` Table for Conditions!");
sObjectMgr->LoadGossipMenuItems();
+ sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists();
}
QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, "
@@ -583,16 +790,23 @@ void ConditionMgr::LoadConditions(bool isReload)
}
//Grouping is only allowed for some types (loot templates, gossip menus, gossip items)
- if (cond->SourceGroup && !isGroupable(cond->SourceType))
+ if (cond->SourceGroup && !CanHaveSourceGroupSet(cond->SourceType))
+ {
+ sLog->outErrorDb("Condition type %u has not allowed value of SourceGroup = %u!", uint32(cond->SourceType), cond->SourceGroup);
+ delete cond;
+ continue;
+ }
+ if (cond->SourceId && !CanHaveSourceIdSet(cond->SourceType))
{
- sLog->outErrorDb("Condition type %u has not allowed grouping %u!", uint32(cond->SourceType), cond->SourceGroup);
+ sLog->outErrorDb("Condition type %u has not allowed value of SourceId = %u!", uint32(cond->SourceType), cond->SourceId);
delete cond;
continue;
}
- else if (cond->SourceGroup)
+
+ if (cond->SourceGroup)
{
bool valid = false;
- //handle grouped conditions
+ // handle grouped conditions
switch (cond->SourceType)
{
case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE:
@@ -637,6 +851,9 @@ void ConditionMgr::LoadConditions(bool isReload)
case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
valid = addToGossipMenuItems(cond);
break;
+ case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET:
+ valid = addToSpellImplicitTargetConditions(cond);
+ break;
case CONDITION_SOURCE_TYPE_VEHICLE_SPELL:
{
//if no list for vehicle create one
@@ -771,6 +988,78 @@ bool ConditionMgr::addToGossipMenuItems(Condition* cond)
return false;
}
+bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond)
+{
+ uint32 conditionEffMask = cond->SourceGroup;
+ SpellInfo* spellInfo = const_cast<SpellInfo*>(sSpellMgr->GetSpellInfo(cond->SourceEntry));
+ ASSERT(spellInfo);
+ std::list<uint32> sharedMasks;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ // check if effect is already a part of some shared mask
+ bool found = false;
+ for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr)
+ {
+ if ((1<<i) & *itr)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ // build new shared mask with found effect
+ uint32 sharedMask = (1<<i);
+ ConditionList* cmp = spellInfo->Effects[i].ImplicitTargetConditions;
+ for (uint8 effIndex = i+1; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
+ {
+ if (spellInfo->Effects[effIndex].ImplicitTargetConditions == cmp)
+ sharedMask |= 1<<effIndex;
+ }
+ sharedMasks.push_back(sharedMask);
+ }
+
+ for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr)
+ {
+ // some effect indexes should have same data
+ if (uint32 commonMask = *itr & conditionEffMask)
+ {
+ uint8 firstEffIndex = 0;
+ for (; firstEffIndex < MAX_SPELL_EFFECTS; ++firstEffIndex)
+ if ((1<<firstEffIndex) & *itr)
+ break;
+
+ // get shared data
+ ConditionList* sharedList = spellInfo->Effects[firstEffIndex].ImplicitTargetConditions;
+
+ // there's already data entry for that sharedMask
+ if (sharedList)
+ {
+ // we have overlapping masks in db
+ if (conditionEffMask != *itr)
+ {
+ sLog->outErrorDb("SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set - "
+ "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring.", cond->SourceEntry, cond->SourceGroup);
+ return false;
+ }
+ }
+ // no data for shared mask, we can create new submask
+ else
+ {
+ // add new list, create new shared mask
+ sharedList = new ConditionList();
+ for (uint8 i = firstEffIndex; i < MAX_SPELL_EFFECTS; ++i)
+ if ((1<<i) & commonMask)
+ spellInfo->Effects[i].ImplicitTargetConditions = sharedList;
+ }
+ sharedList->push_back(cond);
+ break;
+ }
+ }
+ return true;
+}
+
bool ConditionMgr::isSourceTypeValid(Condition* cond)
{
if (cond->SourceType == CONDITION_SOURCE_TYPE_NONE || cond->SourceType >= CONDITION_SOURCE_TYPE_MAX)
@@ -985,64 +1274,48 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
}
break;
}
- case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET:
+ case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET:
{
- if (cond->ConditionType != CONDITION_SPELL_SCRIPT_TARGET)
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry);
+ if (!spellInfo)
{
- sLog->outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_SPELL_SCRIPT_TARGET(18) is valid for CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET(14), ignoring.", cond->SourceEntry, uint32(cond->ConditionType));
+ sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry);
return false;
}
- SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry);
- if (!spellProto)
+ if ((cond->SourceGroup > MAX_EFFECT_MASK) || !cond->SourceGroup)
{
- sLog->outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->SourceEntry);
+ sLog->outErrorDb("SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set , ignoring.", cond->SourceEntry, cond->SourceGroup);
return false;
}
- bool targetfound = false;
+ uint32 origGroup = cond->SourceGroup;
+
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
- if (spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENTRY ||
- spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_SRC_AREA_ENTRY ||
- spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENTRY ||
- spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ENTRY ||
- spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_NEARBY_ENTRY ||
- spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_NEARBY_ENTRY ||
- spellProto->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_NEARBY_ENTRY ||
- spellProto->Effects[i].TargetB.GetTarget() == TARGET_GAMEOBJECT_NEARBY_ENTRY ||
- spellProto->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_SRC_AREA ||
- spellProto->Effects[i].TargetB.GetTarget() == TARGET_GAMEOBJECT_SRC_AREA ||
- spellProto->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_DEST_AREA ||
- spellProto->Effects[i].TargetB.GetTarget() == TARGET_GAMEOBJECT_DEST_AREA ||
- spellProto->Effects[i].TargetA.GetTarget() == TARGET_DEST_NEARBY_ENTRY ||
- spellProto->Effects[i].TargetB.GetTarget() == TARGET_DEST_NEARBY_ENTRY ||
- spellProto->Effects[i].TargetA.GetTarget() == TARGET_UNIT_CONE_ENTRY ||
- spellProto->Effects[i].TargetB.GetTarget() == TARGET_UNIT_CONE_ENTRY)
+ if (!((1<<i) & cond->SourceGroup))
+ continue;
+
+ switch (spellInfo->Effects[i].TargetA.GetSelectionCategory())
{
- targetfound = true;
- //break;
+ case TARGET_SELECT_CATEGORY_NEARBY:
+ case TARGET_SELECT_CATEGORY_CONE:
+ case TARGET_SELECT_CATEGORY_AREA:
+ continue;
}
- else if (cond->ConditionValue3 & (1 << i))
+ switch (spellInfo->Effects[i].TargetB.GetSelectionCategory())
{
- cond->ConditionValue3 &= ~(1 << i);
- sLog->outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DEST_NEARBY_ENTRY (46)"
- ", TARGET_UNIT_SRC_AREA_ENTRY(7), TARGET_UNIT_DEST_AREA_ENTRY(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)"
- "TARGET_GAMEOBJECT_SRC_AREA(51), TARGET_GAMEOBJECT_DEST_AREA(52) in effect %u", cond->SourceEntry, uint32(i));
+ case TARGET_SELECT_CATEGORY_NEARBY:
+ case TARGET_SELECT_CATEGORY_CONE:
+ case TARGET_SELECT_CATEGORY_AREA:
+ continue;
}
+ sLog->outErrorDb("SourceEntry %u SourceGroup %u in `condition` table - spell %u does not have implicit targets of types: _AREA_, _CONE_, _NEARBY_ for effect %u, SourceGroup needs correction, ignoring.", cond->SourceEntry, origGroup, cond->SourceEntry, uint32(i));
+ cond->SourceGroup &= ~(1<<i);
}
- if (!targetfound && !cond->ConditionValue3) // cond->mConditionValue3 already errored up there
- {
- sLog->outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DEST_NEARBY_ENTRY (46)"
- ", TARGET_UNIT_SRC_AREA_ENTRY(7), TARGET_UNIT_DEST_AREA_ENTRY(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)"
- "TARGET_GAMEOBJECT_SRC_AREA(51), TARGET_GAMEOBJECT_DEST_AREA(52)", cond->SourceEntry);
- return false;
- }
- if ((cond->ConditionValue1 == SPELL_TARGET_TYPE_DEAD) && !spellProto->IsAllowingDeadTarget())
- {
- sLog->outErrorDb("SourceEntry %u in `condition` table does have SPELL_TARGET_TYPE_DEAD specified but spell does not have SPELL_ATTR2_CAN_TARGET_DEAD", cond->SourceEntry);
+ // all effects were removed, no need to add the condition at all
+ if (!cond->SourceGroup)
return false;
- }
break;
}
case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE:
@@ -1318,46 +1591,6 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
sLog->outErrorDb("Race condition has useless data in value3 (%u)!", cond->ConditionValue3);
break;
}
- case CONDITION_SPELL_SCRIPT_TARGET:
- {
- if (cond->ConditionValue1 >= MAX_SPELL_TARGET_TYPE)
- {
- sLog->outErrorDb("SpellTarget condition has non existing spell target type (%u), skipped", cond->ConditionValue1);
- return false;
- }
-
- switch (cond->ConditionValue1)
- {
- case SPELL_TARGET_TYPE_GAMEOBJECT:
- {
- if (cond->ConditionValue2 && !sObjectMgr->GetGameObjectTemplate(cond->ConditionValue2))
- {
- sLog->outErrorDb("SpellTarget condition has non existing gameobject (%u) as target, skipped", cond->ConditionValue2);
- return false;
- }
- break;
- }
- case SPELL_TARGET_TYPE_CONTROLLED:
- case SPELL_TARGET_TYPE_CREATURE:
- case SPELL_TARGET_TYPE_DEAD:
- {
- if (cond->ConditionValue2 && !sObjectMgr->GetCreatureTemplate(cond->ConditionValue2))
- {
- sLog->outErrorDb("SpellTarget condition has non existing creature template entry (%u) as target, skipped", cond->ConditionValue2);
- return false;
- }
-
- const CreatureTemplate* cInfo = sObjectMgr->GetCreatureTemplate(cond->ConditionValue2);
- if (cond->SourceEntry == 30427 && !cInfo->SkinLootId)
- {
- sLog->outErrorDb("SpellTarget condition has creature entry %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!, skipped", cond->ConditionValue2);
- return false;
- }
- break;
- }
- }
- break;
- }
case CONDITION_MAPID:
{
MapEntry const* me = sMapStore.LookupEntry(cond->ConditionValue1);
@@ -1598,6 +1831,9 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
sLog->outErrorDb("Phasemask condition has useless data in value3 (%u)!", cond->ConditionValue3);
break;
}
+ case CONDITION_UNUSED_18:
+ sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_18 in `conditions` table - ignoring");
+ return false;
case CONDITION_UNUSED_19:
sLog->outErrorDb("Found ConditionTypeOrReference = CONDITION_UNUSED_19 in `conditions` table - ignoring");
return false;
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index 9911aa2a98a..a1c6146d0cf 100755
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -48,7 +48,7 @@ enum ConditionTypes
CONDITION_CLASS = 15, // class 0 0 true if player's class is equal to class
CONDITION_RACE = 16, // race 0 0 true if player's race is equal to race
CONDITION_ACHIEVEMENT = 17, // achievement_id 0 0 true if achievement is complete
- CONDITION_SPELL_SCRIPT_TARGET = 18, // SpellScriptTargetType, TargetEntry, 0
+ CONDITION_UNUSED_18 = 18, //
CONDITION_UNUSED_19 = 19, //
CONDITION_UNUSED_20 = 20, //
CONDITION_UNUSED_21 = 21, //
@@ -87,7 +87,7 @@ enum ConditionSourceType
CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE = 10,
CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE = 11,
CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE = 12,
- CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET = 13,
+ CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET = 13,
CONDITION_SOURCE_TYPE_GOSSIP_MENU = 14,
CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION = 15,
CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE = 16,
@@ -173,6 +173,7 @@ struct Condition
}
bool Meets(ConditionSourceInfo& sourceInfo);
+ uint32 GetSearcherTypeMaskForCondition();
bool isLoaded() const { return ConditionType > CONDITION_NONE || ReferenceId; }
uint32 GetMaxAvailableConditionTargets();
};
@@ -198,9 +199,12 @@ class ConditionMgr
bool isConditionTypeValid(Condition* cond);
ConditionList GetConditionReferences(uint32 refId);
+ uint32 GetSearcherTypeMaskForConditionList(ConditionList const& conditions);
bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions);
bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions);
bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions);
+ bool CanHaveSourceGroupSet(ConditionSourceType sourceType) const;
+ bool CanHaveSourceIdSet(ConditionSourceType sourceType) const;
ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry);
ConditionList GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId);
ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType);
@@ -211,29 +215,10 @@ class ConditionMgr
bool addToLootTemplate(Condition* cond, LootTemplate* loot);
bool addToGossipMenus(Condition* cond);
bool addToGossipMenuItems(Condition* cond);
+ bool addToSpellImplicitTargetConditions(Condition* cond);
bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions);
- bool isGroupable(ConditionSourceType sourceType) const
- {
- return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE ||
- sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU ||
- sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION ||
sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT ||
- sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL ||
- sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT);
- }
-
void Clean(); // free up resources
std::list<Condition*> AllocatedMemoryStore; // some garbage collection :)
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index aadf9f44b0b..c98364ecb2d 100755
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1085,9 +1085,9 @@ bool Object::PrintIndexError(uint32 index, bool set) const
return false;
}
-bool Position::HasInLine(Unit const* target, float distance, float width) const
+bool Position::HasInLine(WorldObject const* target, float width) const
{
- if (!HasInArc(M_PI, target) || !target->IsWithinDist3d(m_positionX, m_positionY, m_positionZ, distance))
+ if (!HasInArc(M_PI, target))
return false;
width += target->GetObjectSize();
float angle = GetRelativeAngle(target);
@@ -1502,14 +1502,14 @@ bool WorldObject::IsInBetween(const WorldObject* obj1, const WorldObject* obj2,
return (size * size) >= GetExactDist2dSq(obj1->GetPositionX() + cos(angle) * dist, obj1->GetPositionY() + sin(angle) * dist);
}
-bool WorldObject::isInFront(WorldObject const* target, float distance, float arc) const
+bool WorldObject::isInFront(WorldObject const* target, float arc) const
{
- return IsWithinDist(target, distance) && HasInArc(arc, target);
+ return HasInArc(arc, target);
}
-bool WorldObject::isInBack(WorldObject const* target, float distance, float arc) const
+bool WorldObject::isInBack(WorldObject const* target, float arc) const
{
- return IsWithinDist(target, distance) && !HasInArc(2 * M_PI - arc, target);
+ return !HasInArc(2 * M_PI - arc, target);
}
void WorldObject::GetRandomPoint(const Position &pos, float distance, float &rand_x, float &rand_y, float &rand_z) const
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index c14b7599d5f..7b3fcc4a337 100755
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -451,7 +451,7 @@ struct Position
bool IsInDist(const Position* pos, float dist) const
{ return GetExactDistSq(pos) < dist * dist; }
bool HasInArc(float arcangle, const Position* pos) const;
- bool HasInLine(Unit const* target, float distance, float width) const;
+ bool HasInLine(WorldObject const* target, float width) const;
std::string ToString() const;
};
ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer);
@@ -707,8 +707,8 @@ class WorldObject : public Object, public WorldLocation
bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const;
bool IsInRange2d(float x, float y, float minRange, float maxRange) const;
bool IsInRange3d(float x, float y, float z, float minRange, float maxRange) const;
- bool isInFront(WorldObject const* target, float distance, float arc = M_PI) const;
- bool isInBack(WorldObject const* target, float distance, float arc = M_PI) const;
+ bool isInFront(WorldObject const* target, float arc = M_PI) const;
+ bool isInBack(WorldObject const* target, float arc = M_PI) const;
bool IsInBetween(const WorldObject* obj1, const WorldObject* obj2, float size = 0) const;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 47c3c1a9395..0e3e2f593fa 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -10004,6 +10004,7 @@ Unit* Unit::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo)
&& _IsValidAttackTarget(magnet, spellInfo)
&& IsWithinLOSInMap(magnet))
{
+ // TODO: handle this charge drop by proc in cast phase on explicit target
(*itr)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
return magnet;
}
@@ -16178,26 +16179,6 @@ bool Unit::IsInRaidWith(Unit const* unit) const
return false;
}
-bool Unit::IsTargetMatchingCheck(Unit const* target, SpellTargetSelectionCheckTypes check) const
-{
- switch (check)
- {
- case TARGET_SELECT_CHECK_ENEMY:
- if (IsControlledByPlayer())
- return !IsFriendlyTo(target);
- else
- return IsHostileTo(target);
- case TARGET_SELECT_CHECK_ALLY:
- return IsFriendlyTo(target);
- case TARGET_SELECT_CHECK_PARTY:
- return IsInPartyWith(target);
- case TARGET_SELECT_CHECK_RAID:
- return IsInRaidWith(target);
- default:
- return true;
- }
-}
-
void Unit::GetRaidMember(std::list<Unit*> &nearMembers, float radius)
{
Player* owner = GetCharmerOrOwnerPlayerOrPlayerItself();
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 66b0bcbeb54..e55141a3bae 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1394,7 +1394,6 @@ class Unit : public WorldObject
bool IsNeutralToAll() const;
bool IsInPartyWith(Unit const* unit) const;
bool IsInRaidWith(Unit const* unit) const;
- bool IsTargetMatchingCheck(Unit const* target, SpellTargetSelectionCheckTypes check) const;
void GetPartyMemberInDist(std::list<Unit*> &units, float dist);
void GetPartyMembers(std::list<Unit*> &units);
void GetRaidMember(std::list<Unit*> &units, float dist);
diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h
index 8651680cb49..d096bb7ab63 100644
--- a/src/server/game/Grids/GridDefines.h
+++ b/src/server/game/Grids/GridDefines.h
@@ -65,6 +65,16 @@ typedef GridRefManager<DynamicObject> DynamicObjectMapType;
typedef GridRefManager<GameObject> GameObjectMapType;
typedef GridRefManager<Player> PlayerMapType;
+enum GridMapTypeMask
+{
+ GRID_MAP_TYPE_MASK_CORPSE = 0x01,
+ GRID_MAP_TYPE_MASK_CREATURE = 0x02,
+ GRID_MAP_TYPE_MASK_DYNAMICOBJECT = 0x04,
+ GRID_MAP_TYPE_MASK_GAMEOBJECT = 0x08,
+ GRID_MAP_TYPE_MASK_PLAYER = 0x10,
+ GRID_MAP_TYPE_MASK_ALL = 0x1F
+};
+
typedef Grid<Player, AllWorldObjectTypes, AllGridObjectTypes> GridType;
typedef NGrid<MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType;
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
index 2446e9d4276..17d3066e64d 100755
--- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
@@ -343,24 +343,17 @@ bool AnyDeadUnitObjectInRangeCheck::operator()(Creature* u)
bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Player* u)
{
- return AnyDeadUnitObjectInRangeCheck::operator()(u)
- && (i_spellInfo->CheckTarget(i_searchObj, u, true) == SPELL_CAST_OK)
- && i_searchObj->IsTargetMatchingCheck(u, i_check);
+ return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
}
bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Corpse* u)
{
- Player* owner = ObjectAccessor::FindPlayer(u->GetOwnerGUID());
- return owner && AnyDeadUnitObjectInRangeCheck::operator()(u)
- && (i_spellInfo->CheckTarget(i_searchObj, owner, true) == SPELL_CAST_OK)
- && i_searchObj->IsTargetMatchingCheck(owner, i_check);
+ return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
}
bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Creature* u)
{
- return AnyDeadUnitObjectInRangeCheck::operator()(u)
- && (i_spellInfo->CheckTarget(i_searchObj, u, true) == SPELL_CAST_OK)
- && i_searchObj->IsTargetMatchingCheck(u, i_check);
+ return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
}
template void ObjectUpdater::Visit<GameObject>(GameObjectMapType &);
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 12e3fda0484..21f27d6a453 100755
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -30,6 +30,7 @@
#include "Player.h"
#include "Unit.h"
#include "CreatureAI.h"
+#include "Spell.h"
class Player;
//class Map;
@@ -168,12 +169,33 @@ namespace Trinity
template<class Check>
struct WorldObjectSearcher
{
+ uint32 i_mapTypeMask;
uint32 i_phaseMask;
WorldObject* &i_object;
Check &i_check;
- WorldObjectSearcher(WorldObject const* searcher, WorldObject* & result, Check& check)
- : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check) {}
+ WorldObjectSearcher(WorldObject const* searcher, WorldObject* & result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check), i_mapTypeMask(mapTypeMask) {}
+
+ void Visit(GameObjectMapType &m);
+ void Visit(PlayerMapType &m);
+ void Visit(CreatureMapType &m);
+ void Visit(CorpseMapType &m);
+ void Visit(DynamicObjectMapType &m);
+
+ template<class NOT_INTERESTED> void Visit(GridRefManager<NOT_INTERESTED> &) {}
+ };
+
+ template<class Check>
+ struct WorldObjectLastSearcher
+ {
+ uint32 i_mapTypeMask;
+ uint32 i_phaseMask;
+ WorldObject* &i_object;
+ Check &i_check;
+
+ WorldObjectLastSearcher(WorldObject const* searcher, WorldObject* & result, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
+ : i_phaseMask(searcher->GetPhaseMask()), i_object(result), i_check(check), i_mapTypeMask(mapTypeMask) {}
void Visit(GameObjectMapType &m);
void Visit(PlayerMapType &m);
@@ -187,12 +209,13 @@ namespace Trinity
template<class Check>
struct WorldObjectListSearcher
{
+ uint32 i_mapTypeMask;
uint32 i_phaseMask;
std::list<WorldObject*> &i_objects;
Check& i_check;
- WorldObjectListSearcher(WorldObject const* searcher, std::list<WorldObject*> &objects, Check & check)
- : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {}
+ WorldObjectListSearcher(WorldObject const* searcher, std::list<WorldObject*> &objects, Check & check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
+ : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check), i_mapTypeMask(mapTypeMask) {}
void Visit(PlayerMapType &m);
void Visit(CreatureMapType &m);
@@ -206,14 +229,17 @@ namespace Trinity
template<class Do>
struct WorldObjectWorker
{
+ uint32 i_mapTypeMask;
uint32 i_phaseMask;
Do const& i_do;
- WorldObjectWorker(WorldObject const* searcher, Do const& _do)
- : i_phaseMask(searcher->GetPhaseMask()), i_do(_do) {}
+ WorldObjectWorker(WorldObject const* searcher, Do const& _do, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL)
+ : i_phaseMask(searcher->GetPhaseMask()), i_do(_do), i_mapTypeMask(mapTypeMask) {}
void Visit(GameObjectMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT))
+ return;
for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
i_do(itr->getSource());
@@ -221,12 +247,16 @@ namespace Trinity
void Visit(PlayerMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER))
+ return;
for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
i_do(itr->getSource());
}
void Visit(CreatureMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE))
+ return;
for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
i_do(itr->getSource());
@@ -234,6 +264,8 @@ namespace Trinity
void Visit(CorpseMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE))
+ return;
for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
i_do(itr->getSource());
@@ -241,6 +273,8 @@ namespace Trinity
void Visit(DynamicObjectMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT))
+ return;
for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
i_do(itr->getSource());
@@ -527,73 +561,11 @@ namespace Trinity
// CHECKS && DO classes
// WorldObject check classes
- class RaiseDeadObjectCheck
- {
- public:
- RaiseDeadObjectCheck(Unit* source, float range) : _source(source), _range(range) {}
- bool operator()(Creature* u)
- {
- if (_source->GetTypeId() != TYPEID_PLAYER || !((Player*)_source)->isHonorOrXPTarget(u) ||
- u->getDeathState() != CORPSE ||
- (u->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1))) == 0 ||
- (u->GetDisplayId() != u->GetNativeDisplayId()))
- return false;
-
- return _source->IsWithinDistInMap(u, _range);
- }
- bool operator()(Player* u)
- {
- if (_source == u || _source->GetTypeId() != TYPEID_PLAYER || !((Player*)_source)->isHonorOrXPTarget(u) ||
- u->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST) || u->isInFlight() || !u->isDead() ||
- (u->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1))) == 0)
- return false;
- return _source->IsWithinDistInMap(u, _range);
- }
-
- bool operator()(Corpse* u)
- {
- if (_source->GetTypeId() != TYPEID_PLAYER || u->GetType() == CORPSE_BONES)
- return false;
-
- return _source->IsWithinDistInMap(u, _range);
- }
- template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
- private:
- Unit* const _source;
- float _range;
- };
-
- class ExplodeCorpseObjectCheck
- {
- public:
- ExplodeCorpseObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {}
- bool operator()(Player* u)
- {
- if (u->getDeathState() != CORPSE || u->isInFlight() ||
- u->HasAuraType(SPELL_AURA_GHOST) || (u->GetDisplayId() != u->GetNativeDisplayId()))
- return false;
-
- return i_funit->IsWithinDistInMap(u, i_range);
- }
- bool operator()(Creature* u)
- {
- if (u->getDeathState() != CORPSE || u->isInFlight() ||
- (u->GetDisplayId() != u->GetNativeDisplayId()) ||
- (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL) != 0)
- return false;
-
- return i_funit->IsWithinDistInMap(u, i_range);
- }
- template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
- private:
- Unit* const i_funit;
- float i_range;
- };
class AnyDeadUnitObjectInRangeCheck
{
public:
- AnyDeadUnitObjectInRangeCheck(Unit const* searchObj, float range) : i_searchObj(searchObj), i_range(range) {}
+ AnyDeadUnitObjectInRangeCheck(Unit* searchObj, float range) : i_searchObj(searchObj), i_range(range) {}
bool operator()(Player* u);
bool operator()(Corpse* u);
bool operator()(Creature* u);
@@ -606,15 +578,16 @@ namespace Trinity
class AnyDeadUnitSpellTargetInRangeCheck : public AnyDeadUnitObjectInRangeCheck
{
public:
- AnyDeadUnitSpellTargetInRangeCheck(Unit const* searchObj, float range, SpellInfo const* spellInfo, SpellTargetSelectionCheckTypes check)
- : AnyDeadUnitObjectInRangeCheck(searchObj, range), i_spellInfo(spellInfo), i_check(check) {}
+ AnyDeadUnitSpellTargetInRangeCheck(Unit* searchObj, float range, SpellInfo const* spellInfo, SpellTargetCheckTypes check)
+ : AnyDeadUnitObjectInRangeCheck(searchObj, range), i_spellInfo(spellInfo), i_check(searchObj, searchObj, spellInfo, check, NULL)
+ {}
bool operator()(Player* u);
bool operator()(Corpse* u);
bool operator()(Creature* u);
template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
protected:
SpellInfo const* i_spellInfo;
- SpellTargetSelectionCheckTypes i_check;
+ WorldObjectSpellTargetCheck i_check;
};
// WorldObject do classes
diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
index 34fe7757c5f..40b3863679b 100755
--- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
@@ -51,6 +51,9 @@ inline void Trinity::ObjectUpdater::Visit(CreatureMapType &m)
template<class Check>
void Trinity::WorldObjectSearcher<Check>::Visit(GameObjectMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT))
+ return;
+
// already found
if (i_object)
return;
@@ -71,6 +74,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(GameObjectMapType &m)
template<class Check>
void Trinity::WorldObjectSearcher<Check>::Visit(PlayerMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER))
+ return;
+
// already found
if (i_object)
return;
@@ -91,6 +97,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(PlayerMapType &m)
template<class Check>
void Trinity::WorldObjectSearcher<Check>::Visit(CreatureMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE))
+ return;
+
// already found
if (i_object)
return;
@@ -111,6 +120,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(CreatureMapType &m)
template<class Check>
void Trinity::WorldObjectSearcher<Check>::Visit(CorpseMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE))
+ return;
+
// already found
if (i_object)
return;
@@ -131,6 +143,9 @@ void Trinity::WorldObjectSearcher<Check>::Visit(CorpseMapType &m)
template<class Check>
void Trinity::WorldObjectSearcher<Check>::Visit(DynamicObjectMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT))
+ return;
+
// already found
if (i_object)
return;
@@ -148,9 +163,93 @@ void Trinity::WorldObjectSearcher<Check>::Visit(DynamicObjectMapType &m)
}
}
+
+template<class Check>
+void Trinity::WorldObjectLastSearcher<Check>::Visit(GameObjectMapType &m)
+{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT))
+ return;
+
+ for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
+ {
+ if (!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
+ if (i_check(itr->getSource()))
+ i_object = itr->getSource();
+ }
+}
+
+template<class Check>
+void Trinity::WorldObjectLastSearcher<Check>::Visit(PlayerMapType &m)
+{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER))
+ return;
+
+ for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
+ {
+ if (!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
+ if (i_check(itr->getSource()))
+ i_object = itr->getSource();
+ }
+}
+
+template<class Check>
+void Trinity::WorldObjectLastSearcher<Check>::Visit(CreatureMapType &m)
+{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE))
+ return;
+
+ for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
+ {
+ if (!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
+ if (i_check(itr->getSource()))
+ i_object = itr->getSource();
+ }
+}
+
+template<class Check>
+void Trinity::WorldObjectLastSearcher<Check>::Visit(CorpseMapType &m)
+{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE))
+ return;
+
+ for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
+ {
+ if (!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
+ if (i_check(itr->getSource()))
+ i_object = itr->getSource();
+ }
+}
+
+template<class Check>
+void Trinity::WorldObjectLastSearcher<Check>::Visit(DynamicObjectMapType &m)
+{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT))
+ return;
+
+ for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
+ {
+ if (!itr->getSource()->InSamePhase(i_phaseMask))
+ continue;
+
+ if (i_check(itr->getSource()))
+ i_object = itr->getSource();
+ }
+}
+
template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(PlayerMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_PLAYER))
+ return;
+
for (PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
if (i_check(itr->getSource()))
@@ -160,6 +259,9 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(PlayerMapType &m)
template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(CreatureMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CREATURE))
+ return;
+
for (CreatureMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
if (i_check(itr->getSource()))
@@ -169,6 +271,9 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(CreatureMapType &m)
template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(CorpseMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_CORPSE))
+ return;
+
for (CorpseMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
if (i_check(itr->getSource()))
@@ -178,6 +283,9 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(CorpseMapType &m)
template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(GameObjectMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_GAMEOBJECT))
+ return;
+
for (GameObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
if (i_check(itr->getSource()))
@@ -187,6 +295,9 @@ void Trinity::WorldObjectListSearcher<Check>::Visit(GameObjectMapType &m)
template<class Check>
void Trinity::WorldObjectListSearcher<Check>::Visit(DynamicObjectMapType &m)
{
+ if (!(i_mapTypeMask & GRID_MAP_TYPE_MASK_DYNAMICOBJECT))
+ return;
+
for (DynamicObjectMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
if (itr->getSource()->InSamePhase(i_phaseMask))
if (i_check(itr->getSource()))
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 53356772ff6..207ab2b663d 100755
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -592,19 +592,6 @@ Spell::~Spell()
CheckEffectExecuteData();
}
-template<typename T>
-WorldObject* Spell::FindCorpseUsing()
-{
- // non-standard target selection
- float max_range = m_spellInfo->GetMaxRange(false);
-
- WorldObject* result = NULL;
- T u_check(m_caster, max_range);
- Trinity::WorldObjectSearcher<T> searcher(m_caster, result, u_check);
- m_caster->GetMap()->VisitFirstFound(m_caster->GetPositionX(), m_caster->GetPositionY(), max_range, searcher);
- return result;
-}
-
void Spell::InitExplicitTargets(SpellCastTargets const& targets)
{
m_targets = targets;
@@ -707,7 +694,8 @@ void Spell::SelectSpellTargets()
{
// select targets for cast phase
SelectExplicitTargets();
- uint32 processedTargets = 0;
+
+ uint32 processedAreaEffectsMask = 0;
for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
// not call for empty effect.
@@ -715,9 +703,6 @@ void Spell::SelectSpellTargets()
if (!m_spellInfo->Effects[i].IsEffect())
continue;
- if (processedTargets & (1 << i))
- continue;
-
// set expected type of implicit targets to be sent to client
uint32 implicitTargetMask = GetTargetFlagMask(m_spellInfo->Effects[i].TargetA.GetObjectType()) | GetTargetFlagMask(m_spellInfo->Effects[i].TargetB.GetObjectType());
if (implicitTargetMask & TARGET_FLAG_UNIT)
@@ -725,13 +710,8 @@ void Spell::SelectSpellTargets()
if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM))
m_targets.SetTargetFlag(TARGET_FLAG_GAMEOBJECT);
- uint32 targetA = m_spellInfo->Effects[i].TargetA.GetTarget();
- uint32 targetB = m_spellInfo->Effects[i].TargetB.GetTarget();
-
- if (targetA)
- processedTargets |= SelectEffectTargets(i, m_spellInfo->Effects[i].TargetA);
- if (targetB)
- processedTargets |= SelectEffectTargets(i, m_spellInfo->Effects[i].TargetB);
+ SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetA, processedAreaEffectsMask);
+ SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetB, processedAreaEffectsMask);
// Select targets of effect based on effect type
// those are used when no valid target could be added for spell effect based on spell target type
@@ -793,6 +773,920 @@ void Spell::SelectSpellTargets()
}
}
+void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32& processedEffectMask)
+{
+ if (!targetType.GetTarget())
+ return;
+
+ uint32 effectMask = 1 << effIndex;
+ // set the same target list for all effects
+ // some spells appear to need this, however this requires more research
+ switch (targetType.GetSelectionCategory())
+ {
+ case TARGET_SELECT_CATEGORY_NEARBY:
+ case TARGET_SELECT_CATEGORY_CONE:
+ case TARGET_SELECT_CATEGORY_AREA:
+ // targets for effect already selected
+ if (effectMask & processedEffectMask)
+ return;
+ // choose which targets we can select at once
+ for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j)
+ if (GetSpellInfo()->Effects[effIndex].TargetA.GetTarget() == GetSpellInfo()->Effects[j].TargetA.GetTarget() &&
+ GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == GetSpellInfo()->Effects[j].TargetB.GetTarget() &&
+ GetSpellInfo()->Effects[effIndex].ImplicitTargetConditions == GetSpellInfo()->Effects[j].ImplicitTargetConditions &&
+ GetSpellInfo()->Effects[effIndex].CalcRadius(m_caster) == GetSpellInfo()->Effects[j].CalcRadius(m_caster))
+ effectMask |= 1 << j;
+ processedEffectMask |= effectMask;
+ }
+
+ switch(targetType.GetSelectionCategory())
+ {
+ case TARGET_SELECT_CATEGORY_CHANNEL:
+ SelectImplicitChannelTargets(effIndex, targetType);
+ break;
+ case TARGET_SELECT_CATEGORY_NEARBY:
+ SelectImplicitNearbyTargets(effIndex, targetType, effectMask);
+ break;
+ case TARGET_SELECT_CATEGORY_CONE:
+ SelectImplicitConeTargets(effIndex, targetType, effectMask);
+ break;
+ case TARGET_SELECT_CATEGORY_AREA:
+ SelectImplicitAreaTargets(effIndex, targetType, effectMask);
+ break;
+ case TARGET_SELECT_CATEGORY_DEFAULT:
+ switch (targetType.GetObjectType())
+ {
+ case TARGET_OBJECT_TYPE_SRC:
+ switch(targetType.GetReferenceType())
+ {
+ case TARGET_REFERENCE_TYPE_CASTER:
+ m_targets.SetSrc(*m_caster);
+ break;
+ default:
+ ASSERT("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_SRC");
+ break;
+ }
+ break;
+ case TARGET_OBJECT_TYPE_DEST:
+ switch(targetType.GetReferenceType())
+ {
+ case TARGET_REFERENCE_TYPE_CASTER:
+ SelectImplicitCasterDestTargets(effIndex, targetType);
+ break;
+ case TARGET_REFERENCE_TYPE_TARGET:
+ SelectImplicitCasterDestTargets(effIndex, targetType);
+ break;
+ case TARGET_REFERENCE_TYPE_DEST:
+ SelectImplicitDestDestTargets(effIndex, targetType);
+ break;
+ default:
+ ASSERT("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_DEST");
+ break;
+ }
+ break;
+ default:
+ switch(targetType.GetReferenceType())
+ {
+ case TARGET_REFERENCE_TYPE_CASTER:
+ SelectImplicitCasterObjectTargets(effIndex, targetType);
+ break;
+ case TARGET_REFERENCE_TYPE_TARGET:
+ SelectImplicitTargetObjectTargets(effIndex, targetType);
+ break;
+ default:
+ ASSERT("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT");
+ break;
+ }
+ break;
+ }
+ break;
+ case TARGET_SELECT_CATEGORY_NYI:
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: target type %u, found in spellID %u, effect %u is not implemented yet!", m_spellInfo->Id, effIndex, targetType.GetTarget());
+ break;
+ default:
+ ASSERT(false && "Spell::SelectEffectImplicitTargets: received not implemented select target category");
+ break;
+ }
+}
+
+void Spell::SelectImplicitChannelTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
+{
+ if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER)
+ {
+ ASSERT(false && "Spell::SelectImplicitChannelTargets: received not implemented target reference type");
+ return;
+ }
+
+ Spell* channeledSpell = m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
+ if (!channeledSpell)
+ {
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::SelectImplicitChannelTargets: cannot find channel spell for spell ID %u, effect %u", m_spellInfo->Id, effIndex);
+ return;
+ }
+ switch (targetType.GetType())
+ {
+ case TARGET_UNIT_CHANNEL_TARGET:
+ // 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);
+ 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);
+ else
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: cannot find channel spell destination for spell ID %u, effect %u", m_spellInfo->Id, effIndex);
+ break;
+ case TARGET_DEST_CHANNEL_CASTER:
+ m_targets.SetDst(*channeledSpell->GetCaster());
+ break;
+ default:
+ ASSERT(false && "Spell::SelectImplicitChannelTargets: received not implemented target type");
+ break;
+ }
+}
+
+void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask)
+{
+ if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER)
+ {
+ ASSERT(false && "Spell::SelectImplicitNearbyTargets: received not implemented target reference type");
+ return;
+ }
+
+ float range;
+ switch (targetType.GetCheckType())
+ {
+ case TARGET_CHECK_ENEMY:
+ range = m_spellInfo->GetMaxRange(false, m_caster, this);
+ break;
+ case TARGET_CHECK_ALLY:
+ case TARGET_CHECK_PARTY:
+ case TARGET_CHECK_RAID:
+ case TARGET_CHECK_RAID_CLASS:
+ range = m_spellInfo->GetMaxRange(true, m_caster, this);
+ break;
+ case TARGET_CHECK_ENTRY:
+ case TARGET_CHECK_DEFAULT:
+ range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive(), m_caster, this);
+ break;
+ default:
+ ASSERT(false && "Spell::SelectImplicitNearbyTargets: received not implemented selection check type");
+ break;
+ }
+
+ ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
+
+ // handle emergency case - try to use other provided targets if no conditions provided
+ if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && !condList || condList->empty())
+ {
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::SelectImplicitNearbyTargets: no conditions entry for target with TARGET_CHECK_ENTRY of spell ID %u, effect %u - selecting default targets", m_spellInfo->Id, effIndex);
+ switch (targetType.GetObjectType())
+ {
+ case TARGET_OBJECT_TYPE_GOBJ:
+ if (m_spellInfo->RequiresSpellFocus)
+ {
+ if (focusObject)
+ AddGOTarget(focusObject, effMask);
+ return;
+ }
+ break;
+ case TARGET_OBJECT_TYPE_DEST:
+ if (m_spellInfo->RequiresSpellFocus)
+ {
+ if (focusObject)
+ m_targets.SetDst(*focusObject);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ WorldObject* target = SearchNearbyTarget(range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
+ if (!target)
+ {
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::SelectImplicitNearbyTargets: cannot find nearby target for spell ID %u, effect %u", m_spellInfo->Id, effIndex);
+ return;
+ }
+
+ switch (targetType.GetObjectType())
+ {
+ case TARGET_OBJECT_TYPE_UNIT:
+ if (Unit* unitTarget = target->ToUnit())
+ AddUnitTarget(unitTarget, effMask, false);
+ break;
+ case TARGET_OBJECT_TYPE_GOBJ:
+ if (GameObject* gobjTarget = target->ToGameObject())
+ AddGOTarget(gobjTarget, effMask);
+ break;
+ case TARGET_OBJECT_TYPE_DEST:
+ m_targets.SetDst(*target);
+ break;
+ default:
+ ASSERT(false && "Spell::SelectImplicitNearbyTargets: received not implemented target object type");
+ break;
+ }
+
+ SelectImplicitChainTargets(effIndex, targetType, target, effMask);
+}
+
+void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask)
+{
+ if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER)
+ {
+ ASSERT(false && "Spell::SelectImplicitConeTargets: received not implemented target reference type");
+ return;
+ }
+ std::list<WorldObject*> targets;
+ SpellTargetObjectTypes objectType = targetType.GetObjectType();
+ SpellTargetCheckTypes selectionType = targetType.GetCheckType();
+ ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
+ float coneAngle = M_PI/2;
+ float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod;
+
+ if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList))
+ {
+ Trinity::WorldObjectSpellConeTargetCheck check(coneAngle, radius, m_caster, m_spellInfo, selectionType, condList);
+ Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> searcher(m_caster, targets, check, containerTypeMask);
+ SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> > (searcher, containerTypeMask, m_caster, m_caster, radius);
+
+ if (!targets.empty())
+ {
+ // Other special target selection goes here
+ if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
+ {
+ Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
+ for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
+ if ((*j)->IsAffectedOnSpell(m_spellInfo))
+ maxTargets += (*j)->GetAmount();
+
+ Trinity::RandomResizeList(targets, maxTargets);
+ }
+
+ // for compability with older code - add only unit and go targets
+ // TODO: remove this
+ std::list<Unit*> unitTargets;
+ std::list<GameObject*> gObjTargets;
+
+ for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ {
+ if (Unit* unitTarget = (*itr)->ToUnit())
+ unitTargets.push_back(unitTarget);
+ else if (GameObject* gObjTarget = (*itr)->ToGameObject())
+ gObjTargets.push_back(gObjTarget);
+ }
+
+ CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex);
+
+ for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end(); ++itr)
+ AddUnitTarget(*itr, effMask, false);
+
+ for (std::list<GameObject*>::iterator itr = gObjTargets.begin(); itr != gObjTargets.end(); ++itr)
+ AddGOTarget(*itr, effMask);
+ }
+ }
+}
+
+void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask)
+{
+ Unit* referer = NULL;
+ switch (targetType.GetReferenceType())
+ {
+ case TARGET_REFERENCE_TYPE_SRC:
+ case TARGET_REFERENCE_TYPE_DEST:
+ case TARGET_REFERENCE_TYPE_CASTER:
+ referer = m_caster;
+ break;
+ case TARGET_REFERENCE_TYPE_TARGET:
+ referer = m_targets.GetUnitTarget();
+ break;
+ case TARGET_REFERENCE_TYPE_LAST:
+ {
+ // find last added target for this effect
+ for (std::list<TargetInfo>::reverse_iterator ihit = m_UniqueTargetInfo.rbegin(); ihit != m_UniqueTargetInfo.rend(); ++ihit)
+ {
+ if (ihit->effectMask & (1<<effIndex))
+ {
+ referer = ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ ASSERT(false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type");
+ return;
+ }
+ if (!referer)
+ return;
+
+ Position const* center = NULL;
+ switch (targetType.GetReferenceType())
+ {
+ case TARGET_REFERENCE_TYPE_SRC:
+ center = m_targets.GetSrc();
+ break;
+ case TARGET_REFERENCE_TYPE_DEST:
+ center = m_targets.GetDst();
+ break;
+ case TARGET_REFERENCE_TYPE_CASTER:
+ case TARGET_REFERENCE_TYPE_TARGET:
+ case TARGET_REFERENCE_TYPE_LAST:
+ center = referer;
+ break;
+ default:
+ ASSERT(false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type");
+ return;
+ }
+ std::list<WorldObject*> targets;
+ float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod;
+ SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions);
+
+ // Custom entries
+ // TODO: remove those
+ switch (m_spellInfo->Id)
+ {
+ case 46584: // Raise Dead
+ {
+ if (Player* playerCaster = m_caster->ToPlayer())
+ {
+ for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ {
+ switch ((*itr)->GetTypeId())
+ {
+ case TYPEID_UNIT:
+ case TYPEID_PLAYER:
+ {
+ Unit* unitTarget = (*itr)->ToUnit();
+ if (unitTarget->isAlive() || !playerCaster->isHonorOrXPTarget(unitTarget)
+ || ((unitTarget->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1))) == 0)
+ || (unitTarget->GetDisplayId() != unitTarget->GetNativeDisplayId()))
+ break;
+ AddUnitTarget(unitTarget, effMask, false);
+ // no break;
+ }
+ case TYPEID_CORPSE: // wont work until corpses are allowed in target lists, but at least will send dest in packet
+ m_targets.SetDst(*(*itr));
+ return; // nothing more to do here
+ default:
+ break;
+ }
+ }
+ }
+ return; // don't add targets to target map
+ }
+ // Corpse Explosion
+ case 49158:
+ case 51325:
+ case 51326:
+ case 51327:
+ case 51328:
+ // check if our target is not valid (spell can target ghoul or dead unit)
+ if (!(m_targets.GetUnitTarget() && m_targets.GetUnitTarget()->GetDisplayId() == m_targets.GetUnitTarget()->GetNativeDisplayId() &&
+ ((m_targets.GetUnitTarget()->GetEntry() == 26125 && m_targets.GetUnitTarget()->GetOwnerGUID() == m_caster->GetGUID())
+ || m_targets.GetUnitTarget()->isDead())))
+ {
+ // remove existing targets
+ CleanupTargetList();
+
+ for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ {
+ switch ((*itr)->GetTypeId())
+ {
+ case TYPEID_UNIT:
+ case TYPEID_PLAYER:
+ if (!(*itr)->ToUnit()->isDead())
+ break;
+ AddUnitTarget((*itr)->ToUnit(), 1 << effIndex, false);
+ return;
+ default:
+ break;
+ }
+ }
+ if (m_caster->GetTypeId() == TYPEID_PLAYER)
+ m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true);
+ SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW);
+ finish(false);
+ }
+ return;
+ default:
+ break;
+ }
+ std::list<Unit*> unitTargets;
+ std::list<GameObject*> gObjTargets;
+ // for compability with older code - add only unit and go targets
+ // TODO: remove this
+ for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ {
+ if (Unit* unitTarget = (*itr)->ToUnit())
+ unitTargets.push_back(unitTarget);
+ else if (GameObject* gObjTarget = (*itr)->ToGameObject())
+ gObjTargets.push_back(gObjTarget);
+ }
+
+ if (!unitTargets.empty())
+ {
+ // Special target selection for smart heals and energizes
+ uint32 maxSize = 0;
+ int32 power = -1;
+ switch (m_spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
+ switch (m_spellInfo->Id)
+ {
+ case 52759: // Ancestral Awakening
+ case 71610: // Echoes of Light (Althor's Abacus normal version)
+ case 71641: // Echoes of Light (Althor's Abacus heroic version)
+ maxSize = 1;
+ power = POWER_HEALTH;
+ break;
+ case 54968: // Glyph of Holy Light
+ maxSize = m_spellInfo->MaxAffectedTargets;
+ power = POWER_HEALTH;
+ break;
+ case 57669: // Replenishment
+ // In arenas Replenishment may only affect the caster
+ if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->InArena())
+ {
+ unitTargets.clear();
+ unitTargets.push_back(m_caster);
+ break;
+ }
+ maxSize = 10;
+ power = POWER_MANA;
+ break;
+ default:
+ break;
+ }
+ break;
+ case SPELLFAMILY_PRIEST:
+ if (m_spellInfo->SpellFamilyFlags[0] == 0x10000000) // Circle of Healing
+ {
+ maxSize = m_caster->HasAura(55675) ? 6 : 5; // Glyph of Circle of Healing
+ power = POWER_HEALTH;
+ }
+ else if (m_spellInfo->Id == 64844) // Divine Hymn
+ {
+ maxSize = 3;
+ power = POWER_HEALTH;
+ }
+ else if (m_spellInfo->Id == 64904) // Hymn of Hope
+ {
+ maxSize = 3;
+ power = POWER_MANA;
+ }
+ else
+ break;
+
+ // Remove targets outside caster's raid
+ for (std::list<Unit*>::iterator itr = unitTargets.begin() ; itr != unitTargets.end();)
+ {
+ if (!(*itr)->IsInRaidWith(m_caster))
+ itr = unitTargets.erase(itr);
+ else
+ ++itr;
+ }
+ break;
+ case SPELLFAMILY_DRUID:
+ if (m_spellInfo->SpellFamilyFlags[1] == 0x04000000) // Wild Growth
+ {
+ maxSize = m_caster->HasAura(62970) ? 6 : 5; // Glyph of Wild Growth
+ power = POWER_HEALTH;
+ }
+ else if (m_spellInfo->SpellFamilyFlags[2] == 0x0100) // Starfall
+ {
+ // Remove targets not in LoS or in stealth
+ for (std::list<Unit*>::iterator itr = unitTargets.begin() ; itr != unitTargets.end();)
+ {
+ if ((*itr)->HasStealthAura() || (*itr)->HasInvisibilityAura() || !(*itr)->IsWithinLOSInMap(m_caster))
+ itr = unitTargets.erase(itr);
+ else
+ ++itr;
+ }
+ break;
+ }
+ else
+ break;
+
+ // Remove targets outside caster's raid
+ for (std::list<Unit*>::iterator itr = unitTargets.begin() ; itr != unitTargets.end();)
+ if (!(*itr)->IsInRaidWith(m_caster))
+ itr = unitTargets.erase(itr);
+ else
+ ++itr;
+ break;
+ default:
+ break;
+ }
+
+ if (maxSize && power != -1)
+ {
+ if (Powers(power) == POWER_HEALTH)
+ {
+ if (unitTargets.size() > maxSize)
+ {
+ unitTargets.sort(Trinity::HealthPctOrderPred());
+ unitTargets.resize(maxSize);
+ }
+ }
+ else
+ {
+ for (std::list<Unit*>::iterator itr = unitTargets.begin() ; itr != unitTargets.end();)
+ if ((*itr)->getPowerType() != (Powers)power)
+ itr = unitTargets.erase(itr);
+ else
+ ++itr;
+
+ if (unitTargets.size() > maxSize)
+ {
+ unitTargets.sort(Trinity::PowerPctOrderPred((Powers)power));
+ unitTargets.resize(maxSize);
+ }
+ }
+ }
+
+ // Other special target selection goes here
+ if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
+ {
+ Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
+ for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
+ if ((*j)->IsAffectedOnSpell(m_spellInfo))
+ maxTargets += (*j)->GetAmount();
+
+ if (m_spellInfo->Id == 5246) //Intimidating Shout
+ unitTargets.remove(m_targets.GetUnitTarget());
+ Trinity::RandomResizeList(unitTargets, maxTargets);
+ }
+
+ CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex);
+
+ for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end(); ++itr)
+ AddUnitTarget(*itr, effMask, false);
+ }
+
+ if (!gObjTargets.empty())
+ {
+ if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
+ {
+ Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
+ for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
+ if ((*j)->IsAffectedOnSpell(m_spellInfo))
+ maxTargets += (*j)->GetAmount();
+
+ Trinity::RandomResizeList(gObjTargets, maxTargets);
+ }
+ for (std::list<GameObject*>::iterator itr = gObjTargets.begin(); itr != gObjTargets.end(); ++itr)
+ AddGOTarget(*itr, effMask);
+ }
+}
+
+void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
+{
+ switch(targetType.GetType())
+ {
+ case TARGET_DEST_CASTER:
+ m_targets.SetDst(*m_caster);
+ return;
+ case TARGET_DEST_HOME:
+ if (Player* playerCaster = m_caster->ToPlayer())
+ m_targets.SetDst(playerCaster->m_homebindX, playerCaster->m_homebindY, playerCaster->m_homebindZ, playerCaster->GetOrientation(), playerCaster->m_homebindMapId);
+ return;
+ case TARGET_DEST_DB:
+ if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id))
+ {
+ // TODO: fix this check
+ if (m_spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS))
+ m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId);
+ else if (st->target_mapId == m_caster->GetMapId())
+ m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation);
+ }
+ else
+ {
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id);
+ WorldObject* target = m_targets.GetObjectTarget();
+ m_targets.SetDst(target ? *target : *m_caster);
+ }
+ return;
+ case TARGET_DEST_CASTER_FISHING:
+ {
+ float min_dis = m_spellInfo->GetMinRange(true);
+ float max_dis = m_spellInfo->GetMaxRange(true);
+ float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis;
+ float x, y, z, angle;
+ angle = (float)rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
+ m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, angle);
+ m_targets.SetDst(x, y, z, m_caster->GetOrientation());
+ return;
+ }
+ }
+
+ float dist;
+ float angle = targetType.CalcDirectionAngle();
+ float objSize = m_caster->GetObjectSize();
+ if (targetType.GetType() == TARGET_DEST_CASTER_SUMMON)
+ dist = PET_FOLLOW_DIST;
+ else
+ dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
+
+ if (dist < objSize)
+ dist = objSize;
+ else if (targetType.GetType() == TARGET_DEST_CASTER_RANDOM)
+ dist = objSize + (dist - objSize) * (float)rand_norm();
+
+ Position pos;
+ if (targetType.GetType() == TARGET_DEST_CASTER_FRONT_LEAP)
+ m_caster->GetFirstCollisionPosition(pos, dist, angle);
+ else
+ m_caster->GetNearPosition(pos, dist, angle);
+ m_targets.SetDst(*m_caster);
+ m_targets.ModDst(pos);
+}
+
+void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
+{
+ WorldObject* target = m_targets.GetObjectTarget();
+ switch(targetType.GetTarget())
+ {
+ case TARGET_DEST_TARGET_ENEMY:
+ case TARGET_DEST_TARGET_ANY:
+ m_targets.SetDst(*target);
+ return;
+ }
+
+ float angle = targetType.CalcDirectionAngle();
+ float objSize = target->GetObjectSize();
+ float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
+ if (dist < objSize)
+ dist = objSize;
+ else if (targetType.GetType() == TARGET_DEST_TARGET_RANDOM)
+ dist = objSize + (dist - objSize) * (float)rand_norm();
+
+ Position pos;
+ target->GetNearPosition(pos, dist, angle);
+ m_targets.SetDst(*target);
+ m_targets.ModDst(pos);
+}
+
+void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
+{
+ switch(targetType.GetTarget())
+ {
+ case TARGET_DEST_DYNOBJ_ENEMY:
+ case TARGET_DEST_DYNOBJ_ALLY:
+ case TARGET_DEST_DYNOBJ_NONE:
+ case TARGET_DEST_DEST:
+ return;
+ case TARGET_DEST_TRAJ:
+ SelectImplicitTrajTargets();
+ return;
+ }
+
+ float angle = targetType.CalcDirectionAngle();
+ float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
+ if (targetType.GetTarget() == TARGET_DEST_DEST_RANDOM)
+ dist *= (float)rand_norm();
+
+ Position pos = *m_targets.GetDst();
+ m_caster->MovePosition(pos, dist, angle);
+ m_targets.ModDst(pos);
+}
+
+void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
+{
+ switch(targetType.GetTarget())
+ {
+ case TARGET_UNIT_CASTER:
+ AddUnitTarget(m_caster, 1 << effIndex, false);
+ break;
+ case TARGET_UNIT_MASTER:
+ if (Unit* owner = m_caster->GetCharmerOrOwner())
+ AddUnitTarget(owner, 1 << effIndex);
+ break;
+ case TARGET_UNIT_PET:
+ if (Guardian* pet = m_caster->GetGuardianPet())
+ AddUnitTarget(pet, 1 << effIndex);
+ break;
+ case TARGET_UNIT_SUMMONER:
+ if (m_caster->isSummon())
+ if (Unit* unit = m_caster->ToTempSummon()->GetSummoner())
+ AddUnitTarget(unit, 1 << effIndex);
+ break;
+ case TARGET_UNIT_VEHICLE:
+ if (Unit *vehicle = m_caster->GetVehicleBase())
+ AddUnitTarget(vehicle, 1 << effIndex);
+ break;
+ case TARGET_UNIT_PASSENGER_0:
+ case TARGET_UNIT_PASSENGER_1:
+ case TARGET_UNIT_PASSENGER_2:
+ case TARGET_UNIT_PASSENGER_3:
+ case TARGET_UNIT_PASSENGER_4:
+ case TARGET_UNIT_PASSENGER_5:
+ 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);
+ break;
+ }
+}
+
+void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
+{
+ ASSERT(m_targets.GetObjectTarget() && "Spell::SelectImplicitTargetObjectTargets - no explicit object target available!");
+ if (Unit* unit = m_targets.GetUnitTarget())
+ AddUnitTarget(unit, 1 << effIndex);
+ else if (GameObject* gobj = m_targets.GetGOTarget())
+ AddGOTarget(gobj, 1 << effIndex);
+ else
+ AddItemTarget(m_targets.GetItemTarget(), effIndex);
+
+ if (WorldObject* target = m_targets.GetObjectTarget())
+ SelectImplicitChainTargets(effIndex, targetType, target, 1 << effIndex);
+}
+
+void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask)
+{
+ uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTarget;
+ if (Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this);
+
+ if (maxTargets > 1)
+ {
+ // mark damage multipliers as used
+ for (uint32 k = effIndex; k < MAX_SPELL_EFFECTS; ++k)
+ if (effMask & (1 << k))
+ m_damageMultipliers[k] = 1.0f;
+ m_applyMultiplierMask |= effMask;
+
+ std::list<WorldObject*> targets;
+ SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType()
+ , m_spellInfo->Effects[effIndex].ImplicitTargetConditions, targetType.GetType() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY);
+
+ // for backward compability
+ std::list<Unit*> unitTargets;
+ for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ if (Unit* unitTarget = (*itr)->ToUnit())
+ unitTargets.push_back(unitTarget);
+
+ CallScriptAfterUnitTargetSelectHandlers(unitTargets, effIndex);
+
+ for (std::list<Unit*>::iterator itr = unitTargets.begin(); itr != unitTargets.end(); ++itr)
+ AddUnitTarget(*itr, effMask, false);
+ }
+}
+
+float tangent(float x)
+{
+ x = tan(x);
+ //if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x;
+ //if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max();
+ //if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max();
+ if (x < 100000.0f && x > -100000.0f) return x;
+ if (x >= 100000.0f) return 100000.0f;
+ if (x <= 100000.0f) return -100000.0f;
+ return 0.0f;
+}
+
+#define DEBUG_TRAJ(a) //a
+
+void Spell::SelectImplicitTrajTargets()
+{
+ if (!m_targets.HasTraj())
+ return;
+
+ float dist2d = m_targets.GetDist2d();
+ if (!dist2d)
+ return;
+
+ float srcToDestDelta = m_targets.GetDst()->m_positionZ - m_targets.GetSrc()->m_positionZ;
+
+ std::list<WorldObject*> targets;
+ Trinity::WorldObjectSpellTrajTargetCheck check(dist2d, m_targets.GetSrc(), m_caster, m_spellInfo);
+ Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> searcher(m_caster, targets, check, GRID_MAP_TYPE_MASK_ALL);
+ SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, m_targets.GetSrc(), dist2d);
+ if (targets.empty())
+ return;
+
+ targets.sort(Trinity::ObjectDistanceOrderPred(m_caster));
+
+ float b = tangent(m_targets.GetElevation());
+ float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);
+ if (a > -0.0001f)
+ a = 0;
+ DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: a %f b %f", a, b);)
+
+ float bestDist = m_spellInfo->GetMaxRange(false);
+
+ std::list<WorldObject*>::const_iterator itr = targets.begin();
+ for (; itr != targets.end(); ++itr)
+ {
+ if (Unit* unitTarget = (*itr)->ToUnit())
+ if (m_caster == *itr || m_caster->IsOnVehicle(unitTarget) || (unitTarget)->GetVehicle())//(*itr)->IsOnVehicle(m_caster))
+ continue;
+
+ const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3)
+ // TODO: all calculation should be based on src instead of m_caster
+ const float objDist2d = m_targets.GetSrc()->GetExactDist2d(*itr) * cos(m_targets.GetSrc()->GetRelativeAngle(*itr));
+ const float dz = (*itr)->GetPositionZ() - m_targets.GetSrc()->m_positionZ;
+
+ DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: check %u, dist between %f %f, height between %f %f.", (*itr)->GetEntry(), objDist2d - size, objDist2d + size, dz - size, dz + size);)
+
+ float dist = objDist2d - size;
+ float height = dist * (a * dist + b);
+ DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)
+ if (dist < bestDist && height < dz + size && height > dz - size)
+ {
+ bestDist = dist > 0 ? dist : 0;
+ break;
+ }
+
+#define CHECK_DIST {\
+ DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)\
+ if (dist > bestDist)\
+ continue;\
+ if (dist < objDist2d + size && dist > objDist2d - size)\
+ {\
+ bestDist = dist;\
+ break;\
+ }\
+ }
+
+ if (!a)
+ {
+ height = dz - size;
+ dist = height / b;
+ CHECK_DIST;
+
+ height = dz + size;
+ dist = height / b;
+ CHECK_DIST;
+
+ continue;
+ }
+
+ height = dz - size;
+ float sqrt1 = b * b + 4 * a * height;
+ if (sqrt1 > 0)
+ {
+ sqrt1 = sqrt(sqrt1);
+ dist = (sqrt1 - b) / (2 * a);
+ CHECK_DIST;
+ }
+
+ height = dz + size;
+ float sqrt2 = b * b + 4 * a * height;
+ if (sqrt2 > 0)
+ {
+ sqrt2 = sqrt(sqrt2);
+ dist = (sqrt2 - b) / (2 * a);
+ CHECK_DIST;
+
+ dist = (-sqrt2 - b) / (2 * a);
+ CHECK_DIST;
+ }
+
+ if (sqrt1 > 0)
+ {
+ dist = (-sqrt1 - b) / (2 * a);
+ CHECK_DIST;
+ }
+ }
+
+ if (m_targets.GetSrc()->GetExactDist2d(m_targets.GetDst()) > bestDist)
+ {
+ float x = m_targets.GetSrc()->m_positionX + cos(m_caster->GetOrientation()) * bestDist;
+ float y = m_targets.GetSrc()->m_positionY + sin(m_caster->GetOrientation()) * bestDist;
+ float z = m_targets.GetSrc()->m_positionZ + bestDist * (a * bestDist + b);
+
+ if (itr != targets.end())
+ {
+ float distSq = (*itr)->GetExactDistSq(x, y, z);
+ float sizeSq = (*itr)->GetObjectSize();
+ sizeSq *= sizeSq;
+ DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);)
+ if (distSq > sizeSq)
+ {
+ float factor = 1 - sqrt(sizeSq / distSq);
+ x += factor * ((*itr)->GetPositionX() - x);
+ y += factor * ((*itr)->GetPositionY() - y);
+ z += factor * ((*itr)->GetPositionZ() - z);
+
+ distSq = (*itr)->GetExactDistSq(x, y, z);
+ DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);)
+ }
+ }
+
+ Position trajDst;
+ trajDst.Relocate(x, y, z, m_caster->GetOrientation());
+ m_targets.ModDst(trajDst);
+ }
+}
+
void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex)
{
// special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER
@@ -865,6 +1759,190 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex)
}
}
+uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList)
+{
+ // this function selects which containers need to be searched for spell target
+ uint32 retMask = GRID_MAP_TYPE_MASK_ALL;
+
+ // filter searchers based on searched object type
+ switch (objType)
+ {
+ case TARGET_OBJECT_TYPE_UNIT:
+ case TARGET_OBJECT_TYPE_UNIT_AND_DEST:
+ case TARGET_OBJECT_TYPE_CORPSE:
+ case TARGET_OBJECT_TYPE_CORPSE_ENEMY:
+ case TARGET_OBJECT_TYPE_CORPSE_ALLY:
+ retMask &= GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_CREATURE;
+ break;
+ case TARGET_OBJECT_TYPE_GOBJ:
+ case TARGET_OBJECT_TYPE_GOBJ_ITEM:
+ retMask &= GRID_MAP_TYPE_MASK_GAMEOBJECT;
+ break;
+ }
+ if (!(m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD))
+ retMask &= ~GRID_MAP_TYPE_MASK_CORPSE;
+ if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS)
+ retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER;
+ if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS)
+ retMask &= GRID_MAP_TYPE_MASK_PLAYER;
+
+ if (condList)
+ retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList);
+ return retMask;
+}
+
+template<class SEARCHER>
+void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* referer, Position const* pos, float radius)
+{
+ if (!containerMask)
+ return;
+
+ // search world and grid for possible targets
+ bool searchInGrid = containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT);
+ bool searchInWorld = containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE);
+ if (searchInGrid || searchInWorld)
+ {
+ float x,y;
+ x = pos->GetPositionX();
+ y = pos->GetPositionY();
+
+ CellCoord p(Trinity::ComputeCellCoord(x, y));
+ Cell cell(p);
+ cell.SetNoCreate();
+
+ Map& map = *(referer->GetMap());
+
+ if (searchInWorld)
+ {
+ TypeContainerVisitor<SEARCHER, WorldTypeMapContainer> world_object_notifier(searcher);
+ cell.Visit(p, world_object_notifier, map, radius, x, y);
+ }
+ if (searchInGrid)
+ {
+ TypeContainerVisitor<SEARCHER, GridTypeMapContainer > grid_object_notifier(searcher);
+ cell.Visit(p, grid_object_notifier, map, radius, x , y);
+ }
+ }
+}
+
+WorldObject* Spell::SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList)
+{
+ WorldObject* target = NULL;
+ uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
+ if (!containerTypeMask)
+ return NULL;
+ Trinity::WorldObjectSpellNearbyTargetCheck check(range, m_caster, m_spellInfo, selectionType, condList);
+ Trinity::WorldObjectLastSearcher<Trinity::WorldObjectSpellNearbyTargetCheck> searcher(m_caster, target, check, containerTypeMask);
+ SearchTargets<Trinity::WorldObjectLastSearcher<Trinity::WorldObjectSpellNearbyTargetCheck> > (searcher, containerTypeMask, m_caster, m_caster, range);
+ return target;
+}
+
+void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, Unit* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList)
+{
+ uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
+ if (!containerTypeMask)
+ return;
+ Trinity::WorldObjectSpellAreaTargetCheck check(range, position, m_caster, referer, m_spellInfo, selectionType, condList);
+ Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> searcher(m_caster, targets, check, containerTypeMask);
+ SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> > (searcher, containerTypeMask, m_caster, m_caster, range);
+}
+
+void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionList* condList, bool isChainHeal)
+{
+ // max dist for jump target selection
+ float jumpRadius = 0.0f;
+ switch (m_spellInfo->DmgClass)
+ {
+ case SPELL_DAMAGE_CLASS_RANGED:
+ // 7.5y for multi shot
+ jumpRadius = 7.5f;
+ break;
+ case SPELL_DAMAGE_CLASS_MELEE:
+ // 5y for swipe, cleave and similar
+ jumpRadius = 5.0f;
+ break;
+ case SPELL_DAMAGE_CLASS_NONE:
+ case SPELL_DAMAGE_CLASS_MAGIC:
+ // 12.5y for chain heal spell since 3.2 patch
+ if (isChainHeal)
+ jumpRadius = 12.5f;
+ // 10y as default for magic chain spells
+ else
+ jumpRadius = 10.0f;
+ break;
+ }
+
+ // chain lightning/heal spells and similar - allow to jump at larger distance and go out of los
+ bool isBouncingFar = (m_spellInfo->AttributesEx4 & SPELL_ATTR4_AREA_TARGET_CHAIN
+ || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE
+ || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC);
+
+ // max dist which spell can reach
+ float searchRadius = jumpRadius;
+ if (isBouncingFar)
+ searchRadius *= chainTargets;
+
+ std::list<WorldObject*> tempTargets;
+ SearchAreaTargets(tempTargets, searchRadius, target, m_caster, objectType, selectType, condList);
+ tempTargets.remove(target);
+
+ // remove targets which are always invalid for chain spells
+ // for some spells allow only chain targets in front of caster (swipe for example)
+ if (!isBouncingFar)
+ {
+ for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end();)
+ {
+ std::list<WorldObject*>::iterator checkItr = itr++;
+ if (!m_caster->HasInArc(static_cast<float>(M_PI), *checkItr))
+ tempTargets.erase(checkItr);
+ }
+ }
+
+ while (chainTargets)
+ {
+ // try to get unit for next chain jump
+ std::list<WorldObject*>::iterator foundItr = tempTargets.end();
+ // get unit with highest hp deficit in dist
+ if (isChainHeal)
+ {
+ uint32 maxHPDeficit = 0;
+ for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
+ {
+ if (Unit* unitTarget = (*itr)->ToUnit())
+ {
+ uint32 deficit = unitTarget->GetMaxHealth() - unitTarget->GetHealth();
+ if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && target->IsWithinDist(unitTarget, jumpRadius) && target->IsWithinLOSInMap(unitTarget))
+ {
+ foundItr = itr;
+ maxHPDeficit = deficit;
+ }
+ }
+ }
+ }
+ // get closest object
+ else
+ {
+ for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
+ {
+ if (foundItr == tempTargets.end())
+ {
+ if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr))
+ foundItr = itr;
+ }
+ else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr))
+ foundItr = itr;
+ }
+ }
+ // not found any valid target - chain ends
+ if (foundItr == tempTargets.end())
+ break;
+ target = *foundItr;
+ tempTargets.erase(foundItr);
+ targets.push_back(target);
+ --chainTargets;
+ }
+}
+
void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
{
//==========================================================================================
@@ -1791,1077 +2869,6 @@ struct ChainHealingOrder : public std::binary_function<const Unit*, const Unit*,
}
};
-void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uint32 num, SpellTargets TargetType)
-{
- Unit* cur = m_targets.GetUnitTarget();
- if (!cur)
- return;
-
- //FIXME: This very like horrible hack and wrong for most spells
- if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE)
- max_range += num * CHAIN_SPELL_JUMP_RADIUS;
-
- std::list<Unit*> tempUnitMap;
- if (TargetType == SPELL_TARGETS_CHAINHEAL)
- {
- SearchAreaTarget(tempUnitMap, max_range, PUSH_CHAIN, SPELL_TARGETS_ALLY);
- tempUnitMap.sort(ChainHealingOrder(m_caster));
- }
- else
- SearchAreaTarget(tempUnitMap, max_range, PUSH_CHAIN, TargetType);
- tempUnitMap.remove(cur);
-
- while (num)
- {
- TagUnitMap.push_back(cur);
- --num;
-
- if (tempUnitMap.empty())
- break;
-
- std::list<Unit*>::iterator next;
-
- if (TargetType == SPELL_TARGETS_CHAINHEAL)
- {
- next = tempUnitMap.begin();
- while (cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS || !cur->IsWithinLOSInMap(*next))
- {
- ++next;
- if (next == tempUnitMap.end())
- return;
- }
- }
- else
- {
- tempUnitMap.sort(Trinity::ObjectDistanceOrderPred(cur));
- next = tempUnitMap.begin();
-
- if (cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) // Don't search beyond the max jump radius
- break;
-
- // Check if (*next) is a valid chain target. If not, don't add to TagUnitMap, and repeat loop.
- // If you want to add any conditions to exclude a target from TagUnitMap, add condition in this while () loop.
- while ((m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE
- && !m_caster->isInFrontInMap(*next, max_range))
- || !m_caster->canSeeOrDetect(*next)
- || !cur->IsWithinLOSInMap(*next)
- || (*next)->GetCreatureType() == CREATURE_TYPE_CRITTER
- || ((GetSpellInfo()->AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED) && !(*next)->CanFreeMove()))
- {
- ++next;
- if (next == tempUnitMap.end() || cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) // Don't search beyond the max jump radius
- return;
- }
- }
-
- cur = *next;
- tempUnitMap.erase(next);
- }
-}
-
-void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry)
-{
- if (TargetType == SPELL_TARGETS_GO)
- return;
-
- Position const* pos;
- switch (type)
- {
- case PUSH_DST_CENTER:
- CheckDst();
- pos = m_targets.GetDst();
- break;
- case PUSH_SRC_CENTER:
- CheckSrc();
- pos = m_targets.GetSrc();
- break;
- case PUSH_CHAIN:
- {
- Unit* target = m_targets.GetUnitTarget();
- if (!target)
- {
- sLog->outError("SPELL: cannot find unit target for spell ID %u\n", m_spellInfo->Id);
- return;
- }
- pos = target;
- break;
- }
- default:
- pos = m_caster;
- break;
- }
-
- Trinity::SpellNotifierCreatureAndPlayer notifier(m_caster, TagUnitMap, radius, type, TargetType, pos, entry, m_spellInfo);
- if ((m_spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS) || (TargetType == SPELL_TARGETS_ENTRY && !entry))
- m_caster->GetMap()->VisitWorld(pos->m_positionX, pos->m_positionY, radius, notifier);
- else
- m_caster->GetMap()->VisitAll(pos->m_positionX, pos->m_positionY, radius, notifier);
-}
-
-void Spell::SearchGOAreaTarget(std::list<GameObject*> &TagGOMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry)
-{
- if (TargetType != SPELL_TARGETS_GO)
- return;
-
- Position const* pos;
- switch (type)
- {
- case PUSH_DST_CENTER:
- CheckDst();
- pos = m_targets.GetDst();
- break;
- case PUSH_SRC_CENTER:
- CheckSrc();
- pos = m_targets.GetSrc();
- break;
- default:
- pos = m_caster;
- break;
- }
-
- Trinity::GameObjectInRangeCheck check(pos->m_positionX, pos->m_positionY, pos->m_positionZ, radius, entry);
- Trinity::GameObjectListSearcher<Trinity::GameObjectInRangeCheck> searcher(m_caster, TagGOMap, check);
- m_caster->GetMap()->VisitGrid(pos->m_positionX, pos->m_positionY, radius, searcher);
-}
-
-WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType, SpellEffIndex effIndex)
-{
- switch (TargetType)
- {
- case SPELL_TARGETS_ENTRY:
- {
- ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id);
- if (conditions.empty())
- {
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell (ID: %u) (caster Entry: %u) does not have record in `conditions` for spell script target (ConditionSourceType 13)", m_spellInfo->Id, m_caster->GetEntry());
- if (m_spellInfo->IsPositive())
- return SearchNearbyTarget(range, SPELL_TARGETS_ALLY, effIndex);
- else
- return SearchNearbyTarget(range, SPELL_TARGETS_ENEMY, effIndex);
- }
-
- Creature* creatureScriptTarget = NULL;
- GameObject* goScriptTarget = NULL;
-
- for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST)
- {
- if ((*i_spellST)->ConditionType != CONDITION_SPELL_SCRIPT_TARGET)
- continue;
- if ((*i_spellST)->ConditionValue3 && !((*i_spellST)->ConditionValue3 & (1 << uint32(effIndex))))
- continue;
- switch ((*i_spellST)->ConditionValue1)
- {
- case SPELL_TARGET_TYPE_CONTROLLED:
- for (Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr)
- if ((*itr)->GetEntry() == (*i_spellST)->ConditionValue2 && (*itr)->IsWithinDistInMap(m_caster, range))
- {
- goScriptTarget = NULL;
- creatureScriptTarget = (*itr)->ToCreature();
- range = m_caster->GetDistance(creatureScriptTarget);
- }
- break;
- case SPELL_TARGET_TYPE_GAMEOBJECT:
- if ((*i_spellST)->ConditionValue2)
- {
- if (GameObject* go = m_caster->FindNearestGameObject((*i_spellST)->ConditionValue2, range))
- {
- // remember found target and range, next attempt will find more near target with another entry
- goScriptTarget = go;
- creatureScriptTarget = NULL;
- range = m_caster->GetDistance(goScriptTarget);
- }
- }
- else if (focusObject) //Focus Object
- {
- float frange = m_caster->GetDistance(focusObject);
- if (range >= frange)
- {
- creatureScriptTarget = NULL;
- goScriptTarget = focusObject;
- range = frange;
- }
- }
- break;
- case SPELL_TARGET_TYPE_CREATURE:
- if (m_targets.GetUnitTarget() && m_targets.GetUnitTarget()->GetEntry() == (*i_spellST)->ConditionValue2)
- return m_targets.GetUnitTarget();
- case SPELL_TARGET_TYPE_DEAD:
- default:
- if (Creature* cre = m_caster->FindNearestCreature((*i_spellST)->ConditionValue2, range, (*i_spellST)->ConditionValue1 != SPELL_TARGET_TYPE_DEAD))
- {
- creatureScriptTarget = cre;
- goScriptTarget = NULL;
- range = m_caster->GetDistance(creatureScriptTarget);
- }
- break;
- }
- }
-
- if (creatureScriptTarget)
- return creatureScriptTarget;
- else
- return goScriptTarget;
- }
- default:
- case SPELL_TARGETS_ENEMY:
- {
- Unit* target = NULL;
- Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, range);
- Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check);
- m_caster->VisitNearbyObject(range, searcher);
- return target;
- }
- case SPELL_TARGETS_ALLY:
- {
- Unit* target = NULL;
- Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, range);
- Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(m_caster, target, u_check);
- m_caster->VisitNearbyObject(range, searcher);
- return target;
- }
- }
-}
-
-uint32 Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur)
-{
- SpellNotifyPushType pushType = PUSH_NONE;
- Player* modOwner = NULL;
- if (m_originalCaster)
- modOwner = m_originalCaster->GetSpellModOwner();
-
- uint32 effectMask = 1 << i;
- // ENTRY targets may have different selection lists, skip those for now until we can compare lists easily and quickly
- if (GetSpellInfo()->Effects[i].TargetA.GetSelectionCheckType() != TARGET_SELECT_CHECK_ENTRY &&
- GetSpellInfo()->Effects[i].TargetB.GetSelectionCheckType() != TARGET_SELECT_CHECK_ENTRY)
- for (uint32 j = i + 1; j < MAX_SPELL_EFFECTS; ++j)
- if (GetSpellInfo()->Effects[i].TargetA.GetTarget() == GetSpellInfo()->Effects[j].TargetA.GetTarget() &&
- GetSpellInfo()->Effects[i].TargetB.GetTarget() == GetSpellInfo()->Effects[j].TargetB.GetTarget() &&
- GetSpellInfo()->Effects[i].CalcRadius(m_caster) == GetSpellInfo()->Effects[j].CalcRadius(m_caster))
- effectMask |= 1 << j;
-
- switch (cur.GetType())
- {
- case TARGET_TYPE_UNIT_CASTER:
- {
- switch (cur.GetTarget())
- {
- case TARGET_UNIT_CASTER:
- AddUnitTarget(m_caster, effectMask, false);
- break;
- case TARGET_DEST_CASTER_FISHING:
- {
- float min_dis = m_spellInfo->GetMinRange(true);
- float max_dis = m_spellInfo->GetMaxRange(true);
- float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis;
- float x, y, z, angle;
- angle = (float)rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
- m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, angle);
- m_targets.SetDst(x, y, z, m_caster->GetOrientation());
- break;
- }
- case TARGET_UNIT_MASTER:
- if (Unit* owner = m_caster->GetCharmerOrOwner())
- AddUnitTarget(owner, effectMask);
- break;
- case TARGET_UNIT_PET:
- if (Guardian* pet = m_caster->GetGuardianPet())
- AddUnitTarget(pet, effectMask);
- break;
- case TARGET_UNIT_SUMMONER:
- if (m_caster->isSummon())
- if (Unit* unit = m_caster->ToTempSummon()->GetSummoner())
- AddUnitTarget(unit, effectMask);
- break;
- case TARGET_UNIT_CASTER_AREA_PARTY:
- case TARGET_UNIT_CASTER_AREA_RAID:
- pushType = PUSH_CASTER_CENTER;
- break;
- case TARGET_UNIT_VEHICLE:
- if (Unit* vehicle = m_caster->GetVehicleBase())
- AddUnitTarget(vehicle, effectMask);
- break;
- case TARGET_UNIT_PASSENGER_0:
- case TARGET_UNIT_PASSENGER_1:
- case TARGET_UNIT_PASSENGER_2:
- case TARGET_UNIT_PASSENGER_3:
- case TARGET_UNIT_PASSENGER_4:
- case TARGET_UNIT_PASSENGER_5:
- 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(cur.GetTarget() - TARGET_UNIT_PASSENGER_0))
- AddUnitTarget(unit, effectMask);
- break;
- default:
- break;
- }
- break;
- }
-
- case TARGET_TYPE_UNIT_TARGET:
- {
- Unit* target = m_targets.GetUnitTarget();
- if (!target)
- {
- sLog->outError("SPELL: no unit target for spell ID %u", m_spellInfo->Id);
- break;
- }
-
- switch (cur.GetTarget())
- {
- case TARGET_UNIT_TARGET_ENEMY:
- case TARGET_UNIT_TARGET_ANY:
- pushType = PUSH_CHAIN;
- break;
- case TARGET_UNIT_TARGET_CHAINHEAL_ALLY:
- pushType = PUSH_CHAIN;
- break;
- case TARGET_UNIT_TARGET_ALLY:
- AddUnitTarget(target, effectMask, false);
- break;
- case TARGET_UNIT_TARGET_RAID:
- case TARGET_UNIT_TARGET_PARTY:
- case TARGET_UNIT_TARGET_MINIPET:
- AddUnitTarget(target, effectMask, false);
- break;
- case TARGET_UNIT_TARGET_PASSENGER:
- AddUnitTarget(target, effectMask, false);
- break;
- case TARGET_UNIT_LASTTARGET_AREA_PARTY:
- case TARGET_UNIT_TARGET_AREA_RAID_CLASS:
- pushType = PUSH_CASTER_CENTER; // not real
- break;
- default:
- break;
- }
- break;
- }
-
- case TARGET_TYPE_UNIT_NEARBY:
- {
- WorldObject* target = NULL;
- float range;
-
- switch (cur.GetTarget())
- {
- case TARGET_UNIT_NEARBY_ENEMY:
- range = m_spellInfo->GetMaxRange(false);
- if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
- target = SearchNearbyTarget(range, SPELL_TARGETS_ENEMY, SpellEffIndex(i));
- break;
- case TARGET_UNIT_NEARBY_ALLY:
- case TARGET_UNIT_NEARBY_PARTY: // TODO: fix party/raid targets
- case TARGET_UNIT_NEARBY_RAID:
- range = m_spellInfo->GetMaxRange(true);
- if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
- target = SearchNearbyTarget(range, SPELL_TARGETS_ALLY, SpellEffIndex(i));
- break;
- case TARGET_UNIT_NEARBY_ENTRY:
- case TARGET_GAMEOBJECT_NEARBY_ENTRY:
- range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive());
- if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
- target = SearchNearbyTarget(range, SPELL_TARGETS_ENTRY, SpellEffIndex(i));
- break;
- default:
- break;
- }
-
- if (!target)
- return 0;
- else if (target->GetTypeId() == TYPEID_GAMEOBJECT)
- AddGOTarget((GameObject*)target, effectMask);
- else
- {
- pushType = PUSH_CHAIN;
-
- if (m_targets.GetUnitTarget() != target)
- m_targets.SetUnitTarget((Unit*)target);
- }
-
- break;
- }
-
- case TARGET_TYPE_AREA_SRC:
- pushType = PUSH_SRC_CENTER;
- break;
-
- case TARGET_TYPE_AREA_DST:
- pushType = PUSH_DST_CENTER;
- break;
-
- case TARGET_TYPE_AREA_CONE:
- if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_BACK)
- pushType = PUSH_IN_BACK;
- else if (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_LINE)
- pushType = PUSH_IN_LINE;
- else
- pushType = PUSH_IN_FRONT;
- break;
-
- case TARGET_TYPE_DEST_CASTER: //4+8+2
- {
- if (cur.GetTarget() == TARGET_SRC_CASTER)
- {
- m_targets.SetSrc(*m_caster);
- break;
- }
- else if (cur.GetTarget() == TARGET_DEST_CASTER)
- {
- m_targets.SetDst(*m_caster);
- break;
- }
-
- float angle, dist;
-
- float objSize = m_caster->GetObjectSize();
- if (cur.GetTarget() == TARGET_DEST_CASTER_SUMMON)
- dist = 0.0f;
- else
- dist = m_spellInfo->Effects[i].CalcRadius(m_caster);
- if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, dist, this);
- if (dist < objSize)
- dist = objSize;
- else if (cur.GetTarget() == TARGET_DEST_CASTER_RANDOM)
- dist = objSize + (dist - objSize) * (float)rand_norm();
-
- switch (cur.GetTarget())
- {
- case TARGET_DEST_CASTER_FRONT_LEFT: angle = static_cast<float>(-M_PI/4); break;
- case TARGET_DEST_CASTER_BACK_LEFT: angle = static_cast<float>(-3*M_PI/4); break;
- case TARGET_DEST_CASTER_BACK_RIGHT: angle = static_cast<float>(3*M_PI/4); break;
- case TARGET_DEST_CASTER_FRONT_RIGHT:angle = static_cast<float>(M_PI/4); break;
- case TARGET_DEST_CASTER_SUMMON:
- case TARGET_DEST_CASTER_FRONT_LEAP:
- case TARGET_DEST_CASTER_FRONT: angle = 0.0f; break;
- case TARGET_DEST_CASTER_BACK: angle = static_cast<float>(M_PI); break;
- case TARGET_DEST_CASTER_RIGHT: angle = static_cast<float>(-M_PI/2); break;
- case TARGET_DEST_CASTER_LEFT: angle = static_cast<float>(M_PI/2); break;
- default: angle = (float)rand_norm()*static_cast<float>(2*M_PI); break;
- }
-
- Position pos;
- if (cur.GetTarget() == TARGET_DEST_CASTER_FRONT_LEAP)
- m_caster->GetFirstCollisionPosition(pos, dist, angle);
- else
- m_caster->GetNearPosition(pos, dist, angle);
- m_targets.SetDst(*m_caster);
- m_targets.ModDst(pos);
- break;
- }
-
- case TARGET_TYPE_DEST_TARGET: //2+8+2
- {
- Unit* target = m_targets.GetUnitTarget();
- if (!target)
- {
- sLog->outError("SPELL: no unit target for spell ID %u", m_spellInfo->Id);
- break;
- }
-
- if (cur.GetTarget() == TARGET_DEST_TARGET_ENEMY || cur.GetTarget() == TARGET_DEST_TARGET_ANY)
- {
- m_targets.SetDst(*target);
- break;
- }
-
- float angle, dist;
-
- float objSize = target->GetObjectSize();
- dist = m_spellInfo->Effects[i].CalcRadius(m_caster);
- if (dist < objSize)
- dist = objSize;
- else if (cur.GetTarget() == TARGET_DEST_TARGET_RANDOM)
- dist = objSize + (dist - objSize) * (float)rand_norm();
-
- switch (cur.GetTarget())
- {
- case TARGET_DEST_TARGET_FRONT: angle = 0.0f; break;
- case TARGET_DEST_TARGET_BACK: angle = static_cast<float>(M_PI); break;
- case TARGET_DEST_TARGET_RIGHT: angle = static_cast<float>(M_PI/2); break;
- case TARGET_DEST_TARGET_LEFT: angle = static_cast<float>(-M_PI/2); break;
- case TARGET_DEST_TARGET_FRONT_LEFT: angle = static_cast<float>(-M_PI/4); break;
- case TARGET_DEST_TARGET_BACK_LEFT: angle = static_cast<float>(-3*M_PI/4); break;
- case TARGET_DEST_TARGET_BACK_RIGHT: angle = static_cast<float>(3*M_PI/4); break;
- case TARGET_DEST_TARGET_FRONT_RIGHT:angle = static_cast<float>(M_PI/4); break;
- default: angle = (float)rand_norm()*static_cast<float>(2*M_PI); break;
- }
-
- Position pos;
- target->GetNearPosition(pos, dist, angle);
- m_targets.SetDst(*target);
- m_targets.ModDst(pos);
- break;
- }
-
- case TARGET_TYPE_DEST_DEST: //5+8+1
- {
- if (!m_targets.HasDst())
- {
- sLog->outError("SPELL: no destination for spell ID %u", m_spellInfo->Id);
- break;
- }
-
- float angle;
- switch (cur.GetTarget())
- {
- case TARGET_DEST_DYNOBJ_ENEMY:
- case TARGET_DEST_DYNOBJ_ALLY:
- case TARGET_DEST_DYNOBJ_NONE:
- case TARGET_DEST_DEST:
- return effectMask;
- case TARGET_DEST_TRAJ:
- SelectTrajTargets();
- return effectMask;
- case TARGET_DEST_DEST_FRONT: angle = 0.0f; break;
- case TARGET_DEST_DEST_BACK: angle = static_cast<float>(M_PI); break;
- case TARGET_DEST_DEST_RIGHT: angle = static_cast<float>(M_PI/2); break;
- case TARGET_DEST_DEST_LEFT: angle = static_cast<float>(-M_PI/2); break;
- case TARGET_DEST_DEST_FRONT_LEFT: angle = static_cast<float>(-M_PI/4); break;
- case TARGET_DEST_DEST_BACK_LEFT: angle = static_cast<float>(-3*M_PI/4); break;
- case TARGET_DEST_DEST_BACK_RIGHT: angle = static_cast<float>(3*M_PI/4); break;
- case TARGET_DEST_DEST_FRONT_RIGHT:angle = static_cast<float>(M_PI/4); break;
- default: angle = (float)rand_norm()*static_cast<float>(2*M_PI); break;
- }
-
- float dist = m_spellInfo->Effects[i].CalcRadius(m_caster);
- if (cur.GetTarget() == TARGET_DEST_DEST_RANDOM || cur.GetTarget() == TARGET_DEST_DEST_RADIUS)
- dist *= (float)rand_norm();
-
- // must has dst, no need to set flag
- Position pos = *m_targets.GetDst();
- m_caster->MovePosition(pos, dist, angle);
- m_targets.ModDst(pos);
- break;
- }
-
- case TARGET_TYPE_DEST_SPECIAL:
- {
- switch (cur.GetTarget())
- {
- case TARGET_DEST_DB:
- if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id))
- {
- //TODO: fix this check
- if (m_spellInfo->Effects[0].Effect == SPELL_EFFECT_TELEPORT_UNITS || m_spellInfo->Effects[1].Effect == SPELL_EFFECT_TELEPORT_UNITS || m_spellInfo->Effects[2].Effect == SPELL_EFFECT_TELEPORT_UNITS)
- m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId);
- else if (st->target_mapId == m_caster->GetMapId())
- m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation);
- }
- else
- {
- sLog->outError("SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id);
- Unit* target = NULL;
- if (uint64 guid = m_caster->GetUInt64Value(UNIT_FIELD_TARGET))
- target = ObjectAccessor::GetUnit(*m_caster, guid);
- m_targets.SetDst(target ? *target : *m_caster);
- }
- break;
- case TARGET_DEST_HOME:
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_targets.SetDst(m_caster->ToPlayer()->m_homebindX, m_caster->ToPlayer()->m_homebindY, m_caster->ToPlayer()->m_homebindZ, m_caster->ToPlayer()->GetOrientation(), m_caster->ToPlayer()->m_homebindMapId);
- break;
- case TARGET_DEST_NEARBY_ENTRY:
- {
- float range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive());
- if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
-
- if (WorldObject* target = SearchNearbyTarget(range, SPELL_TARGETS_ENTRY, SpellEffIndex(i)))
- m_targets.SetDst(*target);
- break;
- }
- default:
- break;
- }
- break;
- }
-
- case TARGET_TYPE_CHANNEL:
- {
- if (!m_originalCaster || !m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
- {
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: no current channeled spell for spell ID %u - spell triggering this spell was interrupted.", m_spellInfo->Id);
- break;
- }
-
- switch (cur.GetTarget())
- {
- case TARGET_UNIT_CHANNEL_TARGET:
- // unit target may be no longer avalible - teleported out of map for example
- if (Unit* target = Unit::GetUnit(*m_caster, m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->m_targets.GetUnitTargetGUID()))
- AddUnitTarget(target, effectMask);
- else
- sLog->outError("SPELL: cannot find channel spell target for spell ID %u", m_spellInfo->Id);
- break;
- case TARGET_DEST_CHANNEL_TARGET:
- if (m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->m_targets.HasDst())
- m_targets.SetDst(m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->m_targets);
- else if (Unit* target = Unit::GetUnit(*m_caster, m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->m_targets.GetUnitTargetGUID()))
- m_targets.SetDst(*target);
- else
- sLog->outError("SPELL: cannot find channel spell destination for spell ID %u", m_spellInfo->Id);
- break;
- case TARGET_DEST_CHANNEL_CASTER:
- m_targets.SetDst(*m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->GetCaster());
- break;
- default:
- break;
- }
- break;
- }
-
- default:
- {
- switch (cur.GetTarget())
- {
- case TARGET_GAMEOBJECT_TARGET:
- if (m_targets.GetGOTarget())
- AddGOTarget(m_targets.GetGOTarget(), effectMask);
- break;
- case TARGET_GAMEOBJECT_ITEM_TARGET:
- if (m_targets.GetGOTargetGUID())
- AddGOTarget(m_targets.GetGOTarget(), effectMask);
- else if (m_targets.GetItemTarget())
- AddItemTarget(m_targets.GetItemTarget(), effectMask);
- break;
- default:
- sLog->outError("SPELL (caster[type: %u; guidlow: %u], spell: %u): unhandled spell target (%u)",
- m_caster->GetTypeId(), m_caster->GetGUIDLow(), m_spellInfo->Id, cur.GetTarget());
- break;
- }
- break;
- }
- }
-
- if (pushType == PUSH_CHAIN) // Chain
- {
- Unit* target = m_targets.GetUnitTarget();
- if (!target)
- {
- sLog->outError("SPELL: no chain unit target for spell ID %u", m_spellInfo->Id);
- return 0;
- }
-
- //Chain: 2, 6, 22, 25, 45, 77
- uint32 maxTargets = m_spellInfo->Effects[i].ChainTarget;
- if (modOwner)
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this);
-
- if (maxTargets > 1)
- {
- //otherwise, this multiplier is used for something else
- for (uint32 k = i; k < MAX_SPELL_EFFECTS; ++k)
- if (effectMask & (1 << k))
- m_damageMultipliers[k] = 1.0f;
- m_applyMultiplierMask |= effectMask;
-
- float range;
- std::list<Unit*> unitList;
-
- switch (cur.GetTarget())
- {
- case TARGET_UNIT_NEARBY_ENEMY:
- case TARGET_UNIT_TARGET_ENEMY:
- case TARGET_UNIT_NEARBY_ENTRY: // fix me
- range = m_spellInfo->GetMaxRange(false);
- if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
- SearchChainTarget(unitList, range, maxTargets, SPELL_TARGETS_ENEMY);
- break;
- case TARGET_UNIT_TARGET_CHAINHEAL_ALLY:
- case TARGET_UNIT_NEARBY_ALLY: // fix me
- case TARGET_UNIT_NEARBY_PARTY:
- case TARGET_UNIT_NEARBY_RAID:
- range = m_spellInfo->GetMaxRange(true);
- if (modOwner) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
- SearchChainTarget(unitList, range, maxTargets, SPELL_TARGETS_CHAINHEAL);
- break;
- default:
- break;
- }
-
- CallScriptAfterUnitTargetSelectHandlers(unitList, SpellEffIndex(i));
-
- for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
- AddUnitTarget(*itr, effectMask, false);
- }
- else
- AddUnitTarget(target, effectMask, false);
- }
- else if (pushType)
- {
- float radius;
- SpellTargets targetType;
- switch (cur.GetTarget())
- {
- case TARGET_UNIT_SRC_AREA_ENEMY:
- case TARGET_UNIT_DEST_AREA_ENEMY:
- case TARGET_UNIT_CONE_ENEMY_24:
- case TARGET_UNIT_CONE_ENEMY_54:
- case TARGET_UNIT_CONE_ENEMY_104:
- radius = m_spellInfo->Effects[i].CalcRadius();
- targetType = SPELL_TARGETS_ENEMY;
- break;
- case TARGET_UNIT_SRC_AREA_ALLY:
- case TARGET_UNIT_DEST_AREA_ALLY:
- case TARGET_UNIT_CONE_ALLY:
- radius = m_spellInfo->Effects[i].CalcRadius();
- targetType = SPELL_TARGETS_ALLY;
- break;
- case TARGET_UNIT_DEST_AREA_ENTRY:
- case TARGET_UNIT_SRC_AREA_ENTRY:
- case TARGET_UNIT_CONE_ENTRY: // fix me
- radius = m_spellInfo->Effects[i].CalcRadius();
- targetType = SPELL_TARGETS_ENTRY;
- break;
- case TARGET_GAMEOBJECT_SRC_AREA:
- case TARGET_GAMEOBJECT_DEST_AREA:
- case TARGET_GAMEOBJECT_CONE:
- radius = m_spellInfo->Effects[i].CalcRadius();
- targetType = SPELL_TARGETS_GO;
- break;
- default:
- radius = m_spellInfo->Effects[i].CalcRadius();
- targetType = SPELL_TARGETS_NONE;
- break;
- }
-
- if (modOwner)
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius, this);
- radius *= m_spellValue->RadiusMod;
-
- std::list<Unit*> unitList;
- std::list<GameObject*> gobjectList;
- switch (targetType)
- {
- case SPELL_TARGETS_ENTRY:
- {
- ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id);
- if (!conditions.empty())
- {
- for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST)
- {
- if ((*i_spellST)->ConditionType != CONDITION_SPELL_SCRIPT_TARGET)
- continue;
- if ((*i_spellST)->ConditionValue3 && !((*i_spellST)->ConditionValue3 & effectMask))
- continue;
- if ((*i_spellST)->ConditionValue1 == SPELL_TARGET_TYPE_CREATURE)
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, (*i_spellST)->ConditionValue2);
- else if ((*i_spellST)->ConditionValue1 == SPELL_TARGET_TYPE_CONTROLLED)
- {
- for (Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr)
- if ((*itr)->GetEntry() == (*i_spellST)->ConditionValue2 &&
- (*itr)->IsInMap(m_caster)) // For 60243 and 52173 need skip radius check or use range (no radius entry for effect)
- unitList.push_back(*itr);
- }
- }
- }
- else
- {
- // Custom entries
- // TODO: move these to sql
- switch (m_spellInfo->Id)
- {
- case 46584: // Raise Dead
- {
- if (WorldObject* result = FindCorpseUsing<Trinity::RaiseDeadObjectCheck>())
- {
- switch (result->GetTypeId())
- {
- case TYPEID_UNIT:
- case TYPEID_PLAYER:
- unitList.push_back(result->ToUnit());
- // no break;
- case TYPEID_CORPSE: // wont work until corpses are allowed in target lists, but at least will send dest in packet
- m_targets.SetDst(*result);
- break;
- default:
- break;
- }
- }
- break;
- }
- // Corpse Explosion
- case 49158:
- case 51325:
- case 51326:
- case 51327:
- case 51328:
- // Search for ghoul if our ghoul or dead body not valid unit target
- if (!(m_targets.GetUnitTarget() && ((m_targets.GetUnitTarget()->GetEntry() == 26125 && m_targets.GetUnitTarget()->GetOwnerGUID() == m_caster->GetGUID())
- || (m_targets.GetUnitTarget()->getDeathState() == CORPSE
- && m_targets.GetUnitTarget()->GetTypeId() == TYPEID_UNIT
- && !(m_targets.GetUnitTarget()->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL)
- && m_targets.GetUnitTarget()->GetDisplayId() == m_targets.GetUnitTarget()->GetNativeDisplayId()))))
- {
- CleanupTargetList();
-
- WorldObject* result = FindCorpseUsing<Trinity::ExplodeCorpseObjectCheck>();
-
- if (result)
- {
- switch (result->GetTypeId())
- {
- case TYPEID_UNIT:
- case TYPEID_PLAYER:
- m_targets.SetUnitTarget((Unit*)result);
- break;
- default:
- break;
- }
- }
- else
- {
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true);
- SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW);
- finish(false);
- }
- }
- break;
-
- default:
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell (ID: %u) (caster Entry: %u) does not have type CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET record in `conditions` table.", m_spellInfo->Id, m_caster->GetEntry());
-
- if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_TELEPORT_UNITS)
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, 0);
- else if (m_spellInfo->IsPositiveEffect(i))
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY);
- else
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY);
- }
- }
- break;
- }
- case SPELL_TARGETS_GO:
- {
- ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id);
- if (!conditions.empty())
- {
- for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST)
- {
- if ((*i_spellST)->ConditionType != CONDITION_SPELL_SCRIPT_TARGET)
- continue;
- if ((*i_spellST)->ConditionValue3 && !((*i_spellST)->ConditionValue3 & effectMask))
- continue;
- if ((*i_spellST)->ConditionValue1 == SPELL_TARGET_TYPE_GAMEOBJECT)
- SearchGOAreaTarget(gobjectList, radius, pushType, SPELL_TARGETS_GO, (*i_spellST)->ConditionValue2);
- }
- }
- else
- {
- if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_ACTIVATE_OBJECT)
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell (ID: %u) (caster Entry: %u) with SPELL_EFFECT_ACTIVATE_OBJECT does not have type CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET record in `conditions` table.", m_spellInfo->Id, m_caster->GetEntry());
- SearchGOAreaTarget(gobjectList, radius, pushType, SPELL_TARGETS_GO);
- }
- break;
- }
- case SPELL_TARGETS_ALLY:
- case SPELL_TARGETS_ENEMY:
- case SPELL_TARGETS_CHAINHEAL:
- case SPELL_TARGETS_ANY:
- SearchAreaTarget(unitList, radius, pushType, targetType);
- break;
- default:
- switch (cur.GetTarget())
- {
- case TARGET_UNIT_SRC_AREA_PARTY:
- case TARGET_UNIT_DEST_AREA_PARTY:
- m_caster->GetPartyMemberInDist(unitList, radius); //fix me
- break;
- case TARGET_UNIT_LASTTARGET_AREA_PARTY:
- m_targets.GetUnitTarget()->GetPartyMemberInDist(unitList, radius);
- break;
- case TARGET_UNIT_CASTER_AREA_PARTY:
- m_caster->GetPartyMemberInDist(unitList, radius);
- break;
- case TARGET_UNIT_CASTER_AREA_RAID:
- m_caster->GetRaidMember(unitList, radius);
- break;
- case TARGET_UNIT_TARGET_AREA_RAID_CLASS:
- {
- Player* targetPlayer = m_targets.GetUnitTarget() && m_targets.GetUnitTarget()->GetTypeId() == TYPEID_PLAYER
- ? (Player*)m_targets.GetUnitTarget() : NULL;
-
- Group* group = targetPlayer ? targetPlayer->GetGroup() : NULL;
- if (group)
- {
- for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player* Target = itr->getSource();
-
- // IsHostileTo check duel and controlled by enemy
- if (Target && targetPlayer->IsWithinDistInMap(Target, radius) && targetPlayer->getClass() == Target->getClass() && !m_caster->IsHostileTo(Target))
- AddUnitTarget(Target, effectMask);
- }
- }
- else if (m_targets.GetUnitTarget())
- AddUnitTarget(m_targets.GetUnitTarget(), effectMask);
- break;
- }
- default:
- break;
- }
- break;
- }
-
- if (!unitList.empty())
- {
- // Special target selection for smart heals and energizes
- uint32 maxSize = 0;
- int32 power = -1;
- switch (m_spellInfo->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- switch (m_spellInfo->Id)
- {
- case 52759: // Ancestral Awakening
- case 71610: // Echoes of Light (Althor's Abacus normal version)
- case 71641: // Echoes of Light (Althor's Abacus heroic version)
- maxSize = 1;
- power = POWER_HEALTH;
- break;
- case 54968: // Glyph of Holy Light
- maxSize = m_spellInfo->MaxAffectedTargets;
- power = POWER_HEALTH;
- break;
- case 57669: // Replenishment
- // In arenas Replenishment may only affect the caster
- if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->InArena())
- {
- unitList.clear();
- unitList.push_back(m_caster);
- break;
- }
- maxSize = 10;
- power = POWER_MANA;
- break;
- default:
- break;
- }
- break;
- case SPELLFAMILY_PRIEST:
- if (m_spellInfo->SpellFamilyFlags[0] == 0x10000000) // Circle of Healing
- {
- maxSize = m_caster->HasAura(55675) ? 6 : 5; // Glyph of Circle of Healing
- power = POWER_HEALTH;
- }
- else if (m_spellInfo->Id == 64844) // Divine Hymn
- {
- maxSize = 3;
- power = POWER_HEALTH;
- }
- else if (m_spellInfo->Id == 64904) // Hymn of Hope
- {
- maxSize = 3;
- power = POWER_MANA;
- }
- else
- break;
-
- // Remove targets outside caster's raid
- for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();)
- {
- if (!(*itr)->IsInRaidWith(m_caster))
- itr = unitList.erase(itr);
- else
- ++itr;
- }
- break;
- case SPELLFAMILY_DRUID:
- if (m_spellInfo->SpellFamilyFlags[1] == 0x04000000) // Wild Growth
- {
- maxSize = m_caster->HasAura(62970) ? 6 : 5; // Glyph of Wild Growth
- power = POWER_HEALTH;
- }
- else if (m_spellInfo->SpellFamilyFlags[2] == 0x0100) // Starfall
- {
- // Remove targets not in LoS or in stealth
- for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();)
- {
- if ((*itr)->HasStealthAura() || (*itr)->HasInvisibilityAura() || !(*itr)->IsWithinLOSInMap(m_caster))
- itr = unitList.erase(itr);
- else
- ++itr;
- }
- break;
- }
- else
- break;
-
- // Remove targets outside caster's raid
- for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();)
- if (!(*itr)->IsInRaidWith(m_caster))
- itr = unitList.erase(itr);
- else
- ++itr;
- break;
- default:
- break;
- }
-
- if (maxSize && power != -1)
- {
- if (Powers(power) == POWER_HEALTH)
- {
- if (unitList.size() > maxSize)
- {
- unitList.sort(Trinity::HealthPctOrderPred());
- unitList.resize(maxSize);
- }
- }
- else
- {
- for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();)
- if ((*itr)->getPowerType() != (Powers)power)
- itr = unitList.erase(itr);
- else
- ++itr;
-
- if (unitList.size() > maxSize)
- {
- unitList.sort(Trinity::PowerPctOrderPred((Powers)power));
- unitList.resize(maxSize);
- }
- }
- }
-
- // Other special target selection goes here
- if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
- {
- Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
- for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
- if ((*j)->IsAffectedOnSpell(m_spellInfo))
- maxTargets += (*j)->GetAmount();
-
- if (m_spellInfo->Id == 5246) //Intimidating Shout
- unitList.remove(m_targets.GetUnitTarget());
- Trinity::RandomResizeList(unitList, maxTargets);
- }
-
- CallScriptAfterUnitTargetSelectHandlers(unitList, SpellEffIndex(i));
-
- for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
- AddUnitTarget(*itr, effectMask, false);
- }
-
- if (!gobjectList.empty())
- {
- if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
- {
- Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
- for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
- if ((*j)->IsAffectedOnSpell(m_spellInfo))
- maxTargets += (*j)->GetAmount();
-
- Trinity::RandomResizeList(gobjectList, maxTargets);
- }
- for (std::list<GameObject*>::iterator itr = gobjectList.begin(); itr != gobjectList.end(); ++itr)
- AddGOTarget(*itr, effectMask);
- }
- }
-
- return effectMask;
-}
-
void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggeredByAura)
{
if (m_CastItem)
@@ -6847,150 +6854,6 @@ void Spell::SetSpellValue(SpellValueMod mod, int32 value)
}
}
-float tangent(float x)
-{
- x = tan(x);
- //if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x;
- //if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max();
- //if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max();
- if (x < 100000.0f && x > -100000.0f) return x;
- if (x >= 100000.0f) return 100000.0f;
- if (x <= 100000.0f) return -100000.0f;
- return 0.0f;
-}
-
-#define DEBUG_TRAJ(a) //a
-
-void Spell::SelectTrajTargets()
-{
- if (!m_targets.HasTraj())
- return;
-
- float dist2d = m_targets.GetDist2d();
- if (!dist2d)
- return;
-
- float srcToDestDelta = m_targets.GetDst()->m_positionZ - m_targets.GetSrc()->m_positionZ;
-
- UnitList unitList;
- SearchAreaTarget(unitList, dist2d, PUSH_IN_THIN_LINE, SPELL_TARGETS_ANY);
- if (unitList.empty())
- return;
-
- unitList.sort(Trinity::ObjectDistanceOrderPred(m_caster));
-
- float b = tangent(m_targets.GetElevation());
- float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);
- if (a > -0.0001f)
- a = 0;
- DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: a %f b %f", a, b);)
-
- float bestDist = m_spellInfo->GetMaxRange(false);
-
- UnitList::const_iterator itr = unitList.begin();
- for (; itr != unitList.end(); ++itr)
- {
- if (m_caster == *itr || m_caster->IsOnVehicle(*itr) || (*itr)->GetVehicle())//(*itr)->IsOnVehicle(m_caster))
- continue;
-
- const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3)
- // TODO: all calculation should be based on src instead of m_caster
- const float objDist2d = m_targets.GetSrc()->GetExactDist2d(*itr) * cos(m_targets.GetSrc()->GetRelativeAngle(*itr));
- const float dz = (*itr)->GetPositionZ() - m_targets.GetSrc()->m_positionZ;
-
- DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: check %u, dist between %f %f, height between %f %f.", (*itr)->GetEntry(), objDist2d - size, objDist2d + size, dz - size, dz + size);)
-
- float dist = objDist2d - size;
- float height = dist * (a * dist + b);
- DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)
- if (dist < bestDist && height < dz + size && height > dz - size)
- {
- bestDist = dist > 0 ? dist : 0;
- break;
- }
-
-#define CHECK_DIST {\
- DEBUG_TRAJ(sLog->outError("Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)\
- if (dist > bestDist)\
- continue;\
- if (dist < objDist2d + size && dist > objDist2d - size)\
- {\
- bestDist = dist;\
- break;\
- }\
- }
-
- if (!a)
- {
- height = dz - size;
- dist = height / b;
- CHECK_DIST;
-
- height = dz + size;
- dist = height / b;
- CHECK_DIST;
-
- continue;
- }
-
- height = dz - size;
- float sqrt1 = b * b + 4 * a * height;
- if (sqrt1 > 0)
- {
- sqrt1 = sqrt(sqrt1);
- dist = (sqrt1 - b) / (2 * a);
- CHECK_DIST;
- }
-
- height = dz + size;
- float sqrt2 = b * b + 4 * a * height;
- if (sqrt2 > 0)
- {
- sqrt2 = sqrt(sqrt2);
- dist = (sqrt2 - b) / (2 * a);
- CHECK_DIST;
-
- dist = (-sqrt2 - b) / (2 * a);
- CHECK_DIST;
- }
-
- if (sqrt1 > 0)
- {
- dist = (-sqrt1 - b) / (2 * a);
- CHECK_DIST;
- }
- }
-
- if (m_targets.GetSrc()->GetExactDist2d(m_targets.GetDst()) > bestDist)
- {
- float x = m_targets.GetSrc()->m_positionX + cos(m_caster->GetOrientation()) * bestDist;
- float y = m_targets.GetSrc()->m_positionY + sin(m_caster->GetOrientation()) * bestDist;
- float z = m_targets.GetSrc()->m_positionZ + bestDist * (a * bestDist + b);
-
- if (itr != unitList.end())
- {
- float distSq = (*itr)->GetExactDistSq(x, y, z);
- float sizeSq = (*itr)->GetObjectSize();
- sizeSq *= sizeSq;
- DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);)
- if (distSq > sizeSq)
- {
- float factor = 1 - sqrt(sizeSq / distSq);
- x += factor * ((*itr)->GetPositionX() - x);
- y += factor * ((*itr)->GetPositionY() - y);
- z += factor * ((*itr)->GetPositionZ() - z);
-
- distSq = (*itr)->GetExactDistSq(x, y, z);
- DEBUG_TRAJ(sLog->outError("Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);)
- }
- }
-
- Position trajDst;
- trajDst.Relocate(x, y, z, m_caster->GetOrientation());
- m_targets.ModDst(trajDst);
- }
-}
-
void Spell::PrepareTargetProcessing()
{
CheckEffectExecuteData();
@@ -7342,3 +7205,152 @@ void Spell::CancelGlobalCooldown()
else if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo);
}
+
+namespace Trinity
+{
+
+WorldObjectSpellTargetCheck::WorldObjectSpellTargetCheck(Unit* caster, Unit* referer, SpellInfo const* spellInfo,
+ SpellTargetCheckTypes selectionType, ConditionList* condList) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
+ _condList(condList), _targetSelectionType(selectionType)
+{
+ if (condList)
+ _condSrcInfo = new ConditionSourceInfo(NULL, caster);
+ else
+ _condSrcInfo = NULL;
+}
+
+WorldObjectSpellTargetCheck::~WorldObjectSpellTargetCheck()
+{
+ if (_condSrcInfo)
+ delete _condSrcInfo;
+}
+
+bool WorldObjectSpellTargetCheck::operator()(WorldObject* target)
+{
+ if (_spellInfo->CheckTarget(_caster, target, true) != SPELL_CAST_OK)
+ return false;
+ Unit* unitTarget = target->ToUnit();
+ if (Corpse* corpseTarget = target->ToCorpse())
+ {
+ // use ofter for party/assistance checks
+ if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()))
+ unitTarget = owner;
+ else
+ return false;
+ }
+ if (unitTarget)
+ {
+ switch (_targetSelectionType)
+ {
+ case TARGET_CHECK_ENEMY:
+ if (unitTarget->isTotem())
+ return false;
+ if (!_caster->_IsValidAttackTarget(unitTarget, _spellInfo))
+ return false;
+ break;
+ case TARGET_CHECK_ALLY:
+ if (unitTarget->isTotem())
+ return false;
+ if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo))
+ return false;
+ break;
+ case TARGET_CHECK_PARTY:
+ if (unitTarget->isTotem())
+ return false;
+ if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo))
+ return false;
+ if (!_referer->IsInPartyWith(unitTarget))
+ return false;
+ break;
+ case TARGET_CHECK_RAID_CLASS:
+ if (_referer->getClass() != unitTarget->getClass())
+ return false;
+ // nobreak;
+ case TARGET_CHECK_RAID:
+ if (unitTarget->isTotem())
+ return false;
+ if (!_caster->_IsValidAssistTarget(unitTarget, _spellInfo))
+ return false;
+ if (!_referer->IsInRaidWith(unitTarget))
+ return false;
+ break;
+ default:
+ break;
+ }
+ }
+ if (!_condSrcInfo)
+ return true;
+ _condSrcInfo->mConditionTargets[0] = target;
+ return sConditionMgr->IsObjectMeetToConditions(*_condSrcInfo, *_condList);
+}
+
+WorldObjectSpellNearbyTargetCheck::WorldObjectSpellNearbyTargetCheck(float range, Unit* caster, SpellInfo const* spellInfo,
+ SpellTargetCheckTypes selectionType, ConditionList* condList)
+ : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _range(range), _position(caster)
+{
+}
+
+bool WorldObjectSpellNearbyTargetCheck::operator()(WorldObject* target)
+{
+ float dist = target->GetDistance(*_position);
+ if (dist < _range && WorldObjectSpellTargetCheck::operator ()(target))
+ {
+ _range = dist;
+ return true;
+ }
+ return false;
+}
+
+WorldObjectSpellAreaTargetCheck::WorldObjectSpellAreaTargetCheck(float range, Position const* position, Unit* caster,
+ Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList)
+ : WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList), _range(range), _position(position)
+{
+}
+
+bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target)
+{
+ if (!target->IsWithinDist3d(_position, _range))
+ return false;
+ return WorldObjectSpellTargetCheck::operator ()(target);
+}
+
+WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(float coneAngle, float range, Unit* caster,
+ SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList)
+ : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList), _coneAngle(coneAngle)
+{
+}
+
+bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
+{
+ if (_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_BACK)
+ {
+ if (!_caster->isInBack(target, _coneAngle))
+ return false;
+ }
+ else if (_spellInfo->AttributesCu & SPELL_ATTR0_CU_CONE_LINE)
+ {
+ if (!_caster->HasInLine(target, _caster->GetObjectSize()))
+ return false;
+ }
+ else
+ {
+ if (!_caster->isInFront(target, _coneAngle))
+ return false;
+ }
+ return WorldObjectSpellAreaTargetCheck::operator ()(target);
+}
+
+WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, SpellInfo const* spellInfo)
+ : WorldObjectSpellAreaTargetCheck(range, position, caster, caster, spellInfo, TARGET_CHECK_DEFAULT, NULL)
+{
+}
+
+bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target)
+{
+ // return all targets on missile trajectory (0 - size of a missile)
+ if (!_caster->HasInLine(target, 0))
+ return false;
+ return WorldObjectSpellAreaTargetCheck::operator ()(target);
+}
+
+} //namespace Trinity
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 583123eb261..5e7c3a94737 100755
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -79,19 +79,6 @@ enum SpellRangeFlag
SPELL_RANGE_RANGED = 2, //hunter range and ranged weapon
};
-enum SpellNotifyPushType
-{
- PUSH_NONE = 0,
- PUSH_IN_FRONT,
- PUSH_IN_BACK,
- PUSH_IN_LINE,
- PUSH_IN_THIN_LINE,
- PUSH_SRC_CENTER,
- PUSH_DST_CENTER,
- PUSH_CASTER_CENTER, //this is never used in grid search
- PUSH_CHAIN,
-};
-
class SpellCastTargets
{
public:
@@ -210,17 +197,6 @@ enum SpellEffectHandleMode
SPELL_EFFECT_HANDLE_HIT_TARGET,
};
-enum SpellTargets
-{
- SPELL_TARGETS_NONE = 0,
- SPELL_TARGETS_ALLY,
- SPELL_TARGETS_ENEMY,
- SPELL_TARGETS_ENTRY,
- SPELL_TARGETS_CHAINHEAL,
- SPELL_TARGETS_ANY,
- SPELL_TARGETS_GO
-};
-
namespace Trinity
{
struct SpellNotifierCreatureAndPlayer;
@@ -228,7 +204,6 @@ namespace Trinity
class Spell
{
- friend struct Trinity::SpellNotifierCreatureAndPlayer;
friend void Unit::SetCurrentCastedSpell(Spell* pSpell);
friend class SpellScript;
public:
@@ -364,6 +339,32 @@ class Spell
Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, uint64 originalCasterGUID = 0, bool skipCheck = false);
~Spell();
+ void InitExplicitTargets(SpellCastTargets const& targets);
+ void SelectExplicitTargets();
+
+ void SelectSpellTargets();
+ void SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32& processedEffectMask);
+ void SelectImplicitChannelTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
+ void SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask);
+ void SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask);
+ void SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask);
+ void SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
+ void SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
+ void SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
+ void SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
+ void SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType);
+ void SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask);
+ void SelectImplicitTrajTargets();
+
+ void SelectEffectTypeImplicitTargets(uint8 effIndex);
+
+ uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList);
+ template<class SEARCHER> void SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* referer, Position const* pos, float radius);
+
+ WorldObject* SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList = NULL);
+ void SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, Unit* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList);
+ void SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionList* condList, bool isChainHeal);
+
void prepare(SpellCastTargets const* targets, AuraEffect const* triggeredByAura = NULL);
void cancel();
void update(uint32 difftime);
@@ -404,15 +405,6 @@ class Spell
void WriteSpellGoTargets(WorldPacket* data);
void WriteAmmoToPacket(WorldPacket* data);
- void InitExplicitTargets(SpellCastTargets const& targets);
- void SelectExplicitTargets();
- void SelectSpellTargets();
- void SelectEffectTypeImplicitTargets(uint8 effIndex);
- uint32 SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur);
- void SelectTrajTargets();
-
- template<typename T> WorldObject* FindCorpseUsing();
-
bool CheckEffectTarget(Unit const* target, uint32 eff) const;
bool CanAutoCast(Unit* target);
void CheckSrc() { if (!m_targets.HasSrc()) m_targets.SetSrc(*m_caster); }
@@ -607,10 +599,6 @@ class Spell
void DoAllEffectOnTarget(GOTargetInfo* target);
void DoAllEffectOnTarget(ItemTargetInfo* target);
bool UpdateChanneledTargetList();
- void SearchAreaTarget(std::list<Unit*> &unitList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0);
- void SearchGOAreaTarget(std::list<GameObject*> &gobjectList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0);
- void SearchChainTarget(std::list<Unit*> &unitList, float radius, uint32 unMaxTargets, SpellTargets TargetType);
- WorldObject* SearchNearbyTarget(float range, SpellTargets TargetType, SpellEffIndex effIndex);
bool IsValidDeadOrAliveTarget(Unit const* target) const;
void HandleLaunchPhase();
void DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier);
@@ -676,98 +664,52 @@ class Spell
namespace Trinity
{
- struct SpellNotifierCreatureAndPlayer
+ struct WorldObjectSpellTargetCheck
{
- std::list<Unit*> *i_data;
- SpellNotifyPushType i_push_type;
- float i_radius;
- SpellTargets i_TargetType;
- const Unit* const i_source;
- uint32 i_entry;
- const Position* const i_pos;
- SpellInfo const* i_spellProto;
-
- SpellNotifierCreatureAndPlayer(Unit* source, std::list<Unit*> &data, float radius, SpellNotifyPushType type,
- SpellTargets TargetType = SPELL_TARGETS_ENEMY, const Position* pos = NULL, uint32 entry = 0, SpellInfo const* spellProto = NULL)
- : i_data(&data), i_push_type(type), i_radius(radius), i_TargetType(TargetType),
- i_source(source), i_entry(entry), i_pos(pos), i_spellProto(spellProto)
- {
- ASSERT(i_source);
- }
+ Unit* _caster;
+ Unit* _referer;
+ SpellInfo const* _spellInfo;
+ SpellTargetCheckTypes _targetSelectionType;
+ ConditionSourceInfo* _condSrcInfo;
+ ConditionList* _condList;
+
+ WorldObjectSpellTargetCheck(Unit* caster, Unit* referer, SpellInfo const* spellInfo,
+ SpellTargetCheckTypes selectionType, ConditionList* condList);
+ WorldObjectSpellTargetCheck::~WorldObjectSpellTargetCheck();
+ bool operator()(WorldObject* target);
+ };
- template<class T> inline void Visit(GridRefManager<T>& m)
- {
- for (typename GridRefManager<T>::iterator itr = m.begin(); itr != m.end(); ++itr)
- {
- Unit* target = (Unit*)itr->getSource();
-
- if (i_spellProto->CheckTarget(i_source, target, true) != SPELL_CAST_OK)
- continue;
-
- switch (i_TargetType)
- {
- case SPELL_TARGETS_ENEMY:
- if (target->isTotem())
- continue;
- if (!i_source->_IsValidAttackTarget(target, i_spellProto))
- continue;
- break;
- case SPELL_TARGETS_ALLY:
- if (target->isTotem())
- continue;
- if (!i_source->_IsValidAssistTarget(target, i_spellProto))
- continue;
- break;
- case SPELL_TARGETS_ENTRY:
- if (target->GetEntry()!= i_entry)
- continue;
- break;
- case SPELL_TARGETS_ANY:
- default:
- break;
- }
-
- switch (i_push_type)
- {
- case PUSH_SRC_CENTER:
- case PUSH_DST_CENTER:
- case PUSH_CHAIN:
- default:
- if (target->IsWithinDist3d(i_pos, i_radius))
- i_data->push_back(target);
- break;
- case PUSH_IN_FRONT:
- if (i_source->isInFront(target, i_radius, static_cast<float>(M_PI/2)))
- i_data->push_back(target);
- break;
- case PUSH_IN_BACK:
- if (i_source->isInBack(target, i_radius, static_cast<float>(M_PI/2)))
- i_data->push_back(target);
- break;
- case PUSH_IN_LINE:
- if (i_source->HasInLine(target, i_radius, i_source->GetObjectSize()))
- i_data->push_back(target);
- break;
- case PUSH_IN_THIN_LINE: // only traj
- if (i_pos->HasInLine(target, i_radius, 0))
- i_data->push_back(target);
- break;
- }
- }
- }
+ struct WorldObjectSpellNearbyTargetCheck : public WorldObjectSpellTargetCheck
+ {
+ float _range;
+ Position const* _position;
+ WorldObjectSpellNearbyTargetCheck(float range, Unit* caster, SpellInfo const* spellInfo,
+ SpellTargetCheckTypes selectionType, ConditionList* condList);
+ bool operator()(WorldObject* target);
+ };
+
+ struct WorldObjectSpellAreaTargetCheck : public WorldObjectSpellTargetCheck
+ {
+ float _range;
+ Position const* _position;
+ WorldObjectSpellAreaTargetCheck(float range, Position const* position, Unit* caster,
+ Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList);
+ bool operator()(WorldObject* target);
+ };
- #ifdef _WIN32
- template<> inline void Visit(CorpseMapType &) {}
- template<> inline void Visit(GameObjectMapType &) {}
- template<> inline void Visit(DynamicObjectMapType &) {}
- #endif
+ struct WorldObjectSpellConeTargetCheck : public WorldObjectSpellAreaTargetCheck
+ {
+ float _coneAngle;
+ WorldObjectSpellConeTargetCheck(float coneAngle, float range, Unit* caster,
+ SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList);
+ bool operator()(WorldObject* target);
};
- #ifndef _WIN32
- template<> inline void SpellNotifierCreatureAndPlayer::Visit(CorpseMapType&) {}
- template<> inline void SpellNotifierCreatureAndPlayer::Visit(GameObjectMapType&) {}
- template<> inline void SpellNotifierCreatureAndPlayer::Visit(DynamicObjectMapType&) {}
- #endif
+ struct WorldObjectSpellTrajTargetCheck : public WorldObjectSpellAreaTargetCheck
+ {
+ WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, SpellInfo const* spellInfo);
+ bool operator()(WorldObject* target);
+ };
}
typedef void(Spell::*pEffect)(SpellEffIndex effIndex);
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index ad465767ab0..6d5c802e64f 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -20,6 +20,7 @@
#include "SpellMgr.h"
#include "Spell.h"
#include "DBCStores.h"
+#include "ConditionMgr.h"
uint32 GetTargetFlagMask(SpellTargetObjectTypes objType)
{
@@ -80,7 +81,7 @@ SpellTargetObjectTypes SpellImplicitTargetInfo::GetObjectType() const
return _data[_target].ObjectType;
}
-SpellTargetSelectionCheckTypes SpellImplicitTargetInfo::GetSelectionCheckType() const
+SpellTargetCheckTypes SpellImplicitTargetInfo::GetCheckType() const
{
return _data[_target].SelectionCheckType;
}
@@ -158,23 +159,25 @@ uint32 SpellImplicitTargetInfo::GetExplicitTargetMask(bool& srcSet, bool& dstSet
case TARGET_OBJECT_TYPE_UNIT_AND_DEST:
case TARGET_OBJECT_TYPE_UNIT:
case TARGET_OBJECT_TYPE_DEST:
- switch (GetSelectionCheckType())
+ switch (GetCheckType())
{
- case TARGET_SELECT_CHECK_ENEMY:
+ case TARGET_CHECK_ENEMY:
targetMask = TARGET_FLAG_UNIT_ENEMY;
break;
- case TARGET_SELECT_CHECK_ALLY:
+ case TARGET_CHECK_ALLY:
targetMask = TARGET_FLAG_UNIT_ALLY;
break;
- case TARGET_SELECT_CHECK_PARTY:
+ case TARGET_CHECK_PARTY:
targetMask = TARGET_FLAG_UNIT_PARTY;
break;
- case TARGET_SELECT_CHECK_RAID:
+ case TARGET_CHECK_RAID:
targetMask = TARGET_FLAG_UNIT_RAID;
break;
- case TARGET_SELECT_CHECK_PASSENGER:
+ case TARGET_CHECK_PASSENGER:
targetMask = TARGET_FLAG_UNIT_PASSENGER;
break;
+ case TARGET_CHECK_RAID_CLASS:
+ // nobreak;
default:
targetMask = TARGET_FLAG_UNIT;
break;
@@ -344,117 +347,117 @@ SpellSelectTargetTypes SpellImplicitTargetInfo::Type[TOTAL_SPELL_TARGETS];
SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_TARGETS] =
{
- {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, //
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 1 TARGET_UNIT_CASTER
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 2 TARGET_UNIT_NEARBY_ENEMY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 3 TARGET_UNIT_NEARBY_PARTY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 4 TARGET_UNIT_NEARBY_ALLY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 5 TARGET_UNIT_PET
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 6 TARGET_UNIT_TARGET_ENEMY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 7 TARGET_UNIT_SRC_AREA_ENTRY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 8 TARGET_UNIT_DEST_AREA_ENTRY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 9 TARGET_DEST_HOME
- {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 10
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 11 TARGET_UNIT_SRC_AREA_UNK_11
- {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 12
- {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 13
- {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 14
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 15 TARGET_UNIT_SRC_AREA_ENEMY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 16 TARGET_UNIT_DEST_AREA_ENEMY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 17 TARGET_DEST_DB
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 18 TARGET_DEST_CASTER
- {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 19
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 20 TARGET_UNIT_CASTER_AREA_PARTY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 21 TARGET_UNIT_TARGET_ALLY
- {TARGET_OBJECT_TYPE_SRC, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 22 TARGET_SRC_CASTER
- {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 23 TARGET_GAMEOBJECT_TARGET
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_FRONT}, // 24 TARGET_UNIT_CONE_ENEMY_24
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 25 TARGET_UNIT_TARGET_ANY
- {TARGET_OBJECT_TYPE_GOBJ_ITEM, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 26 TARGET_GAMEOBJECT_ITEM_TARGET
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 27 TARGET_UNIT_MASTER
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 28 TARGET_DEST_DYNOBJ_ENEMY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 29 TARGET_DEST_DYNOBJ_ALLY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 30 TARGET_UNIT_SRC_AREA_ALLY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 31 TARGET_UNIT_DEST_AREA_ALLY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 32 TARGET_DEST_CASTER_SUMMON
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 33 TARGET_UNIT_SRC_AREA_PARTY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 34 TARGET_UNIT_DEST_AREA_PARTY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 35 TARGET_UNIT_TARGET_PARTY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 36 TARGET_DEST_CASTER_UNK_36
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_LAST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_PARTY, TARGET_DIR_NONE}, // 37 TARGET_UNIT_LASTTARGET_AREA_PARTY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 38 TARGET_UNIT_NEARBY_ENTRY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 39 TARGET_DEST_CASTER_FISHING
- {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 40 TARGET_GAMEOBJECT_NEARBY_ENTRY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 41 TARGET_DEST_CASTER_FRONT_RIGHT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 42 TARGET_DEST_CASTER_BACK_RIGHT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 43 TARGET_DEST_CASTER_BACK_LEFT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 44 TARGET_DEST_CASTER_FRONT_LEFT
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_NONE}, // 45 TARGET_UNIT_TARGET_CHAINHEAL_ALLY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_NONE}, // 46 TARGET_DEST_NEARBY_ENTRY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 47 TARGET_DEST_CASTER_FRONT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK}, // 48 TARGET_DEST_CASTER_BACK
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 49 TARGET_DEST_CASTER_RIGHT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 50 TARGET_DEST_CASTER_LEFT
- {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 51 TARGET_GAMEOBJECT_SRC_AREA
- {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 52 TARGET_GAMEOBJECT_DEST_AREA
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 53 TARGET_DEST_TARGET_ENEMY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_FRONT}, // 54 TARGET_UNIT_CONE_ENEMY_54
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 55 TARGET_DEST_CASTER_FRONT_LEAP
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_RAID, TARGET_DIR_NONE}, // 56 TARGET_UNIT_CASTER_AREA_RAID
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_RAID, TARGET_DIR_NONE}, // 57 TARGET_UNIT_TARGET_RAID
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CHECK_RAID, TARGET_DIR_NONE}, // 58 TARGET_UNIT_NEARBY_RAID
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ALLY, TARGET_DIR_FRONT}, // 59 TARGET_UNIT_CONE_ALLY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ENTRY, TARGET_DIR_FRONT}, // 60 TARGET_UNIT_CONE_ENTRY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_AREA, TARGET_SELECT_CHECK_RAID, TARGET_DIR_NONE}, // 61 TARGET_UNIT_TARGET_AREA_RAID_CLASS
- {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 62 TARGET_UNK_62
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 63 TARGET_DEST_TARGET_ANY
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 64 TARGET_DEST_TARGET_FRONT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK}, // 65 TARGET_DEST_TARGET_BACK
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 66 TARGET_DEST_TARGET_RIGHT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 67 TARGET_DEST_TARGET_LEFT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 68 TARGET_DEST_TARGET_FRONT_RIGHT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 69 TARGET_DEST_TARGET_BACK_RIGHT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 70 TARGET_DEST_TARGET_BACK_LEFT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 71 TARGET_DEST_TARGET_FRONT_LEFT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 72 TARGET_DEST_CASTER_RANDOM
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 73 TARGET_DEST_CASTER_RADIUS
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 74 TARGET_DEST_TARGET_RANDOM
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 75 TARGET_DEST_TARGET_RADIUS
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 76 TARGET_DEST_CHANNEL_TARGET
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 77 TARGET_UNIT_CHANNEL_TARGET
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 78 TARGET_DEST_DEST_FRONT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK}, // 79 TARGET_DEST_DEST_BACK
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 80 TARGET_DEST_DEST_RIGHT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 81 TARGET_DEST_DEST_LEFT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 82 TARGET_DEST_DEST_FRONT_RIGHT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 83 TARGET_DEST_DEST_BACK_RIGHT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 84 TARGET_DEST_DEST_BACK_LEFT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 85 TARGET_DEST_DEST_FRONT_LEFT
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 86 TARGET_DEST_DEST_RANDOM
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 87 TARGET_DEST_DEST
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 88 TARGET_DEST_DYNOBJ_NONE
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 89 TARGET_DEST_TRAJ
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 90 TARGET_UNIT_TARGET_MINIPET
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 91 TARGET_DEST_DEST_RADIUS
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 92 TARGET_UNIT_SUMMONER
- {TARGET_OBJECT_TYPE_CORPSE, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_NONE}, // 93 TARGET_CORPSE_SRC_AREA_ENEMY
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 94 TARGET_UNIT_VEHICLE
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_PASSENGER, TARGET_DIR_NONE}, // 95 TARGET_UNIT_TARGET_PASSENGER
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 96 TARGET_UNIT_PASSENGER_0
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 97 TARGET_UNIT_PASSENGER_1
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 98 TARGET_UNIT_PASSENGER_2
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 99 TARGET_UNIT_PASSENGER_3
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 100 TARGET_UNIT_PASSENGER_4
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 101 TARGET_UNIT_PASSENGER_5
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 102 TARGET_UNIT_PASSENGER_6
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 103 TARGET_UNIT_PASSENGER_7
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_ENEMY, TARGET_DIR_FRONT}, // 104 TARGET_UNIT_CONE_ENEMY_104
- {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 105 TARGET_UNIT_UNK_105
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 106 TARGET_DEST_CHANNEL_CASTER
- {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 107 TARGET_UNK_DEST_AREA_UNK_107
- {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 108 TARGET_GAMEOBJECT_CONE
- {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 109
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_SELECT_CHECK_DEFAULT, TARGET_DIR_NONE}, // 110 TARGET_DEST_UNK_110
+ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, //
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 1 TARGET_UNIT_CASTER
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 2 TARGET_UNIT_NEARBY_ENEMY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 3 TARGET_UNIT_NEARBY_PARTY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 4 TARGET_UNIT_NEARBY_ALLY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 5 TARGET_UNIT_PET
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 6 TARGET_UNIT_TARGET_ENEMY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 7 TARGET_UNIT_SRC_AREA_ENTRY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 8 TARGET_UNIT_DEST_AREA_ENTRY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 9 TARGET_DEST_HOME
+ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 10
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 11 TARGET_UNIT_SRC_AREA_UNK_11
+ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 12
+ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 13
+ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 14
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 15 TARGET_UNIT_SRC_AREA_ENEMY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 16 TARGET_UNIT_DEST_AREA_ENEMY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 17 TARGET_DEST_DB
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 18 TARGET_DEST_CASTER
+ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 19
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 20 TARGET_UNIT_CASTER_AREA_PARTY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 21 TARGET_UNIT_TARGET_ALLY
+ {TARGET_OBJECT_TYPE_SRC, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 22 TARGET_SRC_CASTER
+ {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 23 TARGET_GAMEOBJECT_TARGET
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENEMY, TARGET_DIR_FRONT}, // 24 TARGET_UNIT_CONE_ENEMY_24
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 25 TARGET_UNIT_TARGET_ANY
+ {TARGET_OBJECT_TYPE_GOBJ_ITEM, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 26 TARGET_GAMEOBJECT_ITEM_TARGET
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 27 TARGET_UNIT_MASTER
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 28 TARGET_DEST_DYNOBJ_ENEMY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 29 TARGET_DEST_DYNOBJ_ALLY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 30 TARGET_UNIT_SRC_AREA_ALLY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 31 TARGET_UNIT_DEST_AREA_ALLY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 32 TARGET_DEST_CASTER_SUMMON
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 33 TARGET_UNIT_SRC_AREA_PARTY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 34 TARGET_UNIT_DEST_AREA_PARTY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 35 TARGET_UNIT_TARGET_PARTY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 36 TARGET_DEST_CASTER_UNK_36
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_LAST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_PARTY, TARGET_DIR_NONE}, // 37 TARGET_UNIT_LASTTARGET_AREA_PARTY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 38 TARGET_UNIT_NEARBY_ENTRY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 39 TARGET_DEST_CASTER_FISHING
+ {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 40 TARGET_GAMEOBJECT_NEARBY_ENTRY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 41 TARGET_DEST_CASTER_FRONT_RIGHT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 42 TARGET_DEST_CASTER_BACK_RIGHT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 43 TARGET_DEST_CASTER_BACK_LEFT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 44 TARGET_DEST_CASTER_FRONT_LEFT
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 45 TARGET_UNIT_TARGET_CHAINHEAL_ALLY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 46 TARGET_DEST_NEARBY_ENTRY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 47 TARGET_DEST_CASTER_FRONT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK}, // 48 TARGET_DEST_CASTER_BACK
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 49 TARGET_DEST_CASTER_RIGHT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 50 TARGET_DEST_CASTER_LEFT
+ {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 51 TARGET_GAMEOBJECT_SRC_AREA
+ {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 52 TARGET_GAMEOBJECT_DEST_AREA
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 53 TARGET_DEST_TARGET_ENEMY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENEMY, TARGET_DIR_FRONT}, // 54 TARGET_UNIT_CONE_ENEMY_54
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 55 TARGET_DEST_CASTER_FRONT_LEAP
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_RAID, TARGET_DIR_NONE}, // 56 TARGET_UNIT_CASTER_AREA_RAID
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_RAID, TARGET_DIR_NONE}, // 57 TARGET_UNIT_TARGET_RAID
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_RAID, TARGET_DIR_NONE}, // 58 TARGET_UNIT_NEARBY_RAID
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ALLY, TARGET_DIR_FRONT}, // 59 TARGET_UNIT_CONE_ALLY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENTRY, TARGET_DIR_FRONT}, // 60 TARGET_UNIT_CONE_ENTRY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_RAID_CLASS,TARGET_DIR_NONE}, // 61 TARGET_UNIT_TARGET_AREA_RAID_CLASS
+ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 62 TARGET_UNK_62
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 63 TARGET_DEST_TARGET_ANY
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 64 TARGET_DEST_TARGET_FRONT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK}, // 65 TARGET_DEST_TARGET_BACK
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 66 TARGET_DEST_TARGET_RIGHT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 67 TARGET_DEST_TARGET_LEFT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 68 TARGET_DEST_TARGET_FRONT_RIGHT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 69 TARGET_DEST_TARGET_BACK_RIGHT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 70 TARGET_DEST_TARGET_BACK_LEFT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 71 TARGET_DEST_TARGET_FRONT_LEFT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 72 TARGET_DEST_CASTER_RANDOM
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 73 TARGET_DEST_CASTER_RADIUS
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 74 TARGET_DEST_TARGET_RANDOM
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 75 TARGET_DEST_TARGET_RADIUS
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 76 TARGET_DEST_CHANNEL_TARGET
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 77 TARGET_UNIT_CHANNEL_TARGET
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 78 TARGET_DEST_DEST_FRONT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK}, // 79 TARGET_DEST_DEST_BACK
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RIGHT}, // 80 TARGET_DEST_DEST_RIGHT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_LEFT}, // 81 TARGET_DEST_DEST_LEFT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_RIGHT}, // 82 TARGET_DEST_DEST_FRONT_RIGHT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_RIGHT}, // 83 TARGET_DEST_DEST_BACK_RIGHT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_BACK_LEFT}, // 84 TARGET_DEST_DEST_BACK_LEFT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT_LEFT}, // 85 TARGET_DEST_DEST_FRONT_LEFT
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 86 TARGET_DEST_DEST_RANDOM
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 87 TARGET_DEST_DEST
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 88 TARGET_DEST_DYNOBJ_NONE
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 89 TARGET_DEST_TRAJ
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 90 TARGET_UNIT_TARGET_MINIPET
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 91 TARGET_DEST_DEST_RADIUS
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 92 TARGET_UNIT_SUMMONER
+ {TARGET_OBJECT_TYPE_CORPSE, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 93 TARGET_CORPSE_SRC_AREA_ENEMY
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 94 TARGET_UNIT_VEHICLE
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_PASSENGER, TARGET_DIR_NONE}, // 95 TARGET_UNIT_TARGET_PASSENGER
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 96 TARGET_UNIT_PASSENGER_0
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 97 TARGET_UNIT_PASSENGER_1
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 98 TARGET_UNIT_PASSENGER_2
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 99 TARGET_UNIT_PASSENGER_3
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 100 TARGET_UNIT_PASSENGER_4
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 101 TARGET_UNIT_PASSENGER_5
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 102 TARGET_UNIT_PASSENGER_6
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 103 TARGET_UNIT_PASSENGER_7
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENEMY, TARGET_DIR_FRONT}, // 104 TARGET_UNIT_CONE_ENEMY_104
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 105 TARGET_UNIT_UNK_105
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 106 TARGET_DEST_CHANNEL_CASTER
+ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 107 TARGET_UNK_DEST_AREA_UNK_107
+ {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 108 TARGET_GAMEOBJECT_CONE
+ {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 109
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 110 TARGET_DEST_UNK_110
};
SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex)
@@ -481,6 +484,7 @@ SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const*
ItemType = spellEntry->EffectItemType[effIndex];
TriggerSpell = spellEntry->EffectTriggerSpell[effIndex];
SpellClassMask = spellEntry->EffectSpellClassMask[effIndex];
+ ImplicitTargetConditions = NULL;
}
bool SpellEffectInfo::IsEffect() const
@@ -938,6 +942,11 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry)
ChainEntry = NULL;
}
+SpellInfo::~SpellInfo()
+{
+ _UnloadImplicitTargetConditionLists();
+}
+
bool SpellInfo::HasEffect(SpellEffects effect) const
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
@@ -1563,38 +1572,99 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
return SPELL_CAST_OK;
}
-SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, bool implicit) const
+SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* target, bool implicit) const
{
if (AttributesEx & SPELL_ATTR1_CANT_TARGET_SELF && caster == target)
return SPELL_FAILED_BAD_TARGETS;
- if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT && target->isInCombat())
- return SPELL_FAILED_TARGET_AFFECTING_COMBAT;
+ // check visibility - ignore stealth for implicit (area) targets
+ if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !caster->canSeeOrDetect(target, implicit))
+ return SPELL_FAILED_BAD_TARGETS;
+
+ Unit const* unitTarget;
+
+ // creature/player specific target checks
+ if (unitTarget = target->ToUnit())
+ {
+ if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT && unitTarget->isInCombat())
+ return SPELL_FAILED_TARGET_AFFECTING_COMBAT;
+
+ // only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts
+ if (((AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) != 0) != unitTarget->HasAuraType(SPELL_AURA_GHOST))
+ {
+ if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS)
+ return SPELL_FAILED_TARGET_NOT_GHOST;
+ else
+ return SPELL_FAILED_BAD_TARGETS;
+ }
+
+ if (caster != unitTarget)
+ {
+ if (caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ // Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
+ if (AttributesEx2 & SPELL_ATTR2_CANT_TARGET_TAPPED)
+ if (Creature const* targetCreature = unitTarget->ToCreature())
+ if (targetCreature->hasLootRecipient() && !targetCreature->isTappedBy(caster->ToPlayer()))
+ return SPELL_FAILED_CANT_CAST_ON_TAPPED;
+
+ if (AttributesCu & SPELL_ATTR0_CU_PICKPOCKET)
+ {
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER)
+ return SPELL_FAILED_BAD_TARGETS;
+ else if ((unitTarget->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) == 0)
+ return SPELL_FAILED_TARGET_NO_POCKETS;
+ }
+
+ // Not allow disarm unarmed player
+ if (Mechanic == MECHANIC_DISARM)
+ {
+ if (unitTarget->GetTypeId() == TYPEID_PLAYER)
+ {
+ Player const* player = unitTarget->ToPlayer();
+ if (!player->GetWeaponForAttack(BASE_ATTACK) || !player->IsUseEquipedWeapon(true))
+ return SPELL_FAILED_TARGET_NO_WEAPONS;
+ }
+ else if (!unitTarget->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID))
+ return SPELL_FAILED_TARGET_NO_WEAPONS;
+ }
+ }
+ }
+ }
+ // corpse specific target checks
+ else if (Corpse const* corpseTarget = target->ToCorpse())
+ {
+ // cannot target bare bones
+ if (corpseTarget->GetType() == CORPSE_BONES)
+ return SPELL_FAILED_BAD_TARGETS;
+ // we have to use owner for some checks (aura preventing resurrection for example)
+ if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()))
+ unitTarget = owner;
+ // we're not interested in corpses without owner
+ else
+ return SPELL_FAILED_BAD_TARGETS;
+ }
+ // other types of objects - always valid
+ else return SPELL_CAST_OK;
- if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS && !target->ToPlayer())
+ // corpseOwner and unit specific target checks
+ if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS && !unitTarget->ToPlayer())
return SPELL_FAILED_TARGET_NOT_PLAYER;
- if (!IsAllowingDeadTarget() && !target->isAlive())
+ if (!IsAllowingDeadTarget() && !unitTarget->isAlive())
return SPELL_FAILED_TARGETS_DEAD;
- if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS && !(!target->isAlive() && target->HasAuraType(SPELL_AURA_GHOST)))
- return SPELL_FAILED_TARGET_NOT_GHOST;
-
// check this flag only for implicit targets (chain and area), allow to explicitly target units for spells like Shield of Righteousness
- if (implicit && AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED && !target->CanFreeMove())
+ if (implicit && AttributesEx6 & SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED && !unitTarget->CanFreeMove())
return SPELL_FAILED_BAD_TARGETS;
- // check visibility - ignore stealth for implicit (area) targets
- if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_INVISIBLE) && !caster->canSeeOrDetect(target, implicit))
- return SPELL_FAILED_BAD_TARGETS;
-
// checked in Unit::IsValidAttack/AssistTarget, shouldn't be checked for ENTRY targets
//if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_UNTARGETABLE) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
// return SPELL_FAILED_BAD_TARGETS;
//if (!(AttributesEx6 & SPELL_ATTR6_CAN_TARGET_POSSESSED_FRIENDS)
- if (!CheckTargetCreatureType(target))
+ if (!CheckTargetCreatureType(unitTarget))
{
if (target->GetTypeId() == TYPEID_PLAYER)
return SPELL_FAILED_TARGET_IS_PLAYER;
@@ -1603,65 +1673,32 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, b
}
// check GM mode and GM invisibility - only for player casts (npc casts are controlled by AI) and negative spells
- if (target != caster && (caster->IsControlledByPlayer() || !IsPositive()) && target->GetTypeId() == TYPEID_PLAYER)
+ if (unitTarget != caster && (caster->IsControlledByPlayer() || !IsPositive()) && unitTarget->GetTypeId() == TYPEID_PLAYER)
{
- if (!target->ToPlayer()->IsVisible())
+ if (!unitTarget->ToPlayer()->IsVisible())
return SPELL_FAILED_BM_OR_INVISGOD;
- if (target->ToPlayer()->isGameMaster())
+ if (unitTarget->ToPlayer()->isGameMaster())
return SPELL_FAILED_BM_OR_INVISGOD;
}
// not allow casting on flying player
- if (target->HasUnitState(UNIT_STATE_IN_FLIGHT))
+ if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT))
return SPELL_FAILED_BAD_TARGETS;
- if (TargetAuraState && !target->HasAuraState(AuraStateType(TargetAuraState), this, caster))
+ if (TargetAuraState && !unitTarget->HasAuraState(AuraStateType(TargetAuraState), this, caster))
return SPELL_FAILED_TARGET_AURASTATE;
- if (TargetAuraStateNot && target->HasAuraState(AuraStateType(TargetAuraStateNot), this, caster))
+ if (TargetAuraStateNot && unitTarget->HasAuraState(AuraStateType(TargetAuraStateNot), this, caster))
return SPELL_FAILED_TARGET_AURASTATE;
- if (TargetAuraSpell && !target->HasAura(sSpellMgr->GetSpellIdForDifficulty(TargetAuraSpell, caster)))
+ if (TargetAuraSpell && !unitTarget->HasAura(sSpellMgr->GetSpellIdForDifficulty(TargetAuraSpell, caster)))
return SPELL_FAILED_TARGET_AURASTATE;
- if (ExcludeTargetAuraSpell && target->HasAura(sSpellMgr->GetSpellIdForDifficulty(ExcludeTargetAuraSpell, caster)))
+ if (ExcludeTargetAuraSpell && unitTarget->HasAura(sSpellMgr->GetSpellIdForDifficulty(ExcludeTargetAuraSpell, caster)))
return SPELL_FAILED_TARGET_AURASTATE;
- if (caster != target)
- {
- if (caster->GetTypeId() == TYPEID_PLAYER)
- {
- // Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
- if (AttributesEx2 & SPELL_ATTR2_CANT_TARGET_TAPPED)
- if (Creature const* targetCreature = target->ToCreature())
- if (targetCreature->hasLootRecipient() && !targetCreature->isTappedBy(caster->ToPlayer()))
- return SPELL_FAILED_CANT_CAST_ON_TAPPED;
-
- if (AttributesCu & SPELL_ATTR0_CU_PICKPOCKET)
- {
- if (target->GetTypeId() == TYPEID_PLAYER)
- return SPELL_FAILED_BAD_TARGETS;
- else if ((target->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) == 0)
- return SPELL_FAILED_TARGET_NO_POCKETS;
- }
-
- // Not allow disarm unarmed player
- if (Mechanic == MECHANIC_DISARM)
- {
- if (target->GetTypeId() == TYPEID_PLAYER)
- {
- Player const* player = target->ToPlayer();
- if (!player->GetWeaponForAttack(BASE_ATTACK) || !player->IsUseEquipedWeapon(true))
- return SPELL_FAILED_TARGET_NO_WEAPONS;
- }
- else if (!target->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID))
- return SPELL_FAILED_TARGET_NO_WEAPONS;
- }
- }
- }
-
- if (target->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION))
+ if (unitTarget->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION))
if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT_NEW))
return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED;
@@ -2035,13 +2072,19 @@ float SpellInfo::GetMinRange(bool positive) const
return RangeEntry->minRangeHostile;
}
-float SpellInfo::GetMaxRange(bool positive) const
+float SpellInfo::GetMaxRange(bool positive, Unit* caster, Spell* spell) const
{
if (!RangeEntry)
return 0.0f;
+ float range;
if (positive)
- return RangeEntry->maxRangeFriend;
- return RangeEntry->maxRangeHostile;
+ range = RangeEntry->maxRangeFriend;
+ else
+ range = RangeEntry->maxRangeHostile;
+ if (caster)
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(Id, SPELLMOD_RANGE, range, spell);
+ return range;
}
int32 SpellInfo::GetDuration() const
@@ -2552,3 +2595,20 @@ bool SpellInfo::_IsPositiveTarget(uint32 targetA, uint32 targetB)
return _IsPositiveTarget(targetB, 0);
return true;
}
+
+void SpellInfo::_UnloadImplicitTargetConditionLists()
+{
+ // find the same instances of ConditionList and delete them.
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ ConditionList* cur = Effects[i].ImplicitTargetConditions;
+ if (!cur)
+ continue;
+ for (uint8 j = i; j < MAX_SPELL_EFFECTS; ++j)
+ {
+ if (Effects[j].ImplicitTargetConditions == cur)
+ Effects[j].ImplicitTargetConditions = NULL;
+ }
+ delete cur;
+ }
+}
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 65be5981c64..69ea07f7563 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -36,6 +36,7 @@ struct SpellRangeEntry;
struct SpellRadiusEntry;
struct SpellEntry;
struct SpellCastTimesEntry;
+struct Condition;
enum SpellCastTargetFlags
{
@@ -105,15 +106,16 @@ enum SpellTargetObjectTypes
TARGET_OBJECT_TYPE_CORPSE_ALLY,
};
-enum SpellTargetSelectionCheckTypes
+enum SpellTargetCheckTypes
{
- TARGET_SELECT_CHECK_DEFAULT,
- TARGET_SELECT_CHECK_ENTRY,
- TARGET_SELECT_CHECK_ENEMY,
- TARGET_SELECT_CHECK_ALLY,
- TARGET_SELECT_CHECK_PARTY,
- TARGET_SELECT_CHECK_RAID,
- TARGET_SELECT_CHECK_PASSENGER,
+ TARGET_CHECK_DEFAULT,
+ TARGET_CHECK_ENTRY,
+ TARGET_CHECK_ENEMY,
+ TARGET_CHECK_ALLY,
+ TARGET_CHECK_PARTY,
+ TARGET_CHECK_RAID,
+ TARGET_CHECK_RAID_CLASS,
+ TARGET_CHECK_PASSENGER,
};
enum SpellTargetDirectionTypes
@@ -220,7 +222,7 @@ public:
SpellTargetSelectionCategories GetSelectionCategory() const;
SpellTargetReferenceTypes GetReferenceType() const;
SpellTargetObjectTypes GetObjectType() const;
- SpellTargetSelectionCheckTypes GetSelectionCheckType() const;
+ SpellTargetCheckTypes GetCheckType() const;
SpellTargetDirectionTypes GetDirectionType() const;
float CalcDirectionAngle() const;
@@ -240,7 +242,7 @@ private:
SpellTargetObjectTypes ObjectType; // type of object returned by target type
SpellTargetReferenceTypes ReferenceType; // defines which object is used as a reference when selecting target
SpellTargetSelectionCategories SelectionCategory;
- SpellTargetSelectionCheckTypes SelectionCheckType; // defines selection criteria
+ SpellTargetCheckTypes SelectionCheckType; // defines selection criteria
SpellTargetDirectionTypes DirectionType; // direction for cone and dest targets
};
static StaticData _data[TOTAL_SPELL_TARGETS];
@@ -271,6 +273,7 @@ public:
uint32 ItemType;
uint32 TriggerSpell;
flag96 SpellClassMask;
+ std::list<Condition*>* ImplicitTargetConditions;
SpellEffectInfo() {}
SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex);
@@ -388,6 +391,7 @@ public:
SpellChainNode const* ChainEntry;
SpellInfo(SpellEntry const* spellEntry);
+ ~SpellInfo();
bool HasEffect(SpellEffects effect) const;
bool HasAura(AuraType aura) const;
@@ -438,7 +442,7 @@ public:
SpellCastResult CheckShapeshift(uint32 form) const;
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const;
- SpellCastResult CheckTarget(Unit const* caster, Unit const* target, bool implicit = true) const;
+ SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = NULL) const;
bool CheckTargetCreatureType(Unit const* target) const;
@@ -456,7 +460,7 @@ public:
SpellSpecificType GetSpellSpecific() const;
float GetMinRange(bool positive = false) const;
- float GetMaxRange(bool positive = false) const;
+ float GetMaxRange(bool positive = false, Unit* caster = NULL, Spell* spell = NULL) const;
int32 GetDuration() const;
int32 GetMaxDuration() const;
@@ -482,6 +486,9 @@ public:
bool _IsPositiveEffect(uint8 effIndex, bool deep) const;
bool _IsPositiveSpell() const;
static bool _IsPositiveTarget(uint32 targetA, uint32 targetB);
+
+ // unloading helpers
+ void _UnloadImplicitTargetConditionLists();
};
#endif // _SPELLINFO_H
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index ff4eaae42f2..c1b267d9fac 100755
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2644,11 +2644,20 @@ void SpellMgr::UnloadSpellInfoStore()
for (uint32 i = 0; i < mSpellInfoMap.size(); ++i)
{
if (mSpellInfoMap[i])
- delete mSpellInfoMap[i];
+ delete mSpellInfoMap[i];
}
mSpellInfoMap.clear();
}
+void SpellMgr::UnloadSpellInfoImplicitTargetConditionLists()
+{
+ for (uint32 i = 0; i < mSpellInfoMap.size(); ++i)
+ {
+ if (mSpellInfoMap[i])
+ mSpellInfoMap[i]->_UnloadImplicitTargetConditionLists();
+ }
+}
+
void SpellMgr::LoadSpellCustomAttr()
{
uint32 oldMSTime = getMSTime();
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 14137b6a91b..9fffd474651 100755
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -360,17 +360,6 @@ struct SpellThreatEntry
typedef std::map<uint32, SpellThreatEntry> SpellThreatMap;
-// Spell script target related declarations (accessed using SpellMgr functions)
-enum SpellScriptTargetType
-{
- SPELL_TARGET_TYPE_GAMEOBJECT = 0,
- SPELL_TARGET_TYPE_CREATURE = 1,
- SPELL_TARGET_TYPE_DEAD = 2,
- SPELL_TARGET_TYPE_CONTROLLED = 3,
-};
-
-#define MAX_SPELL_TARGET_TYPE 4
-
// coordinates for spells (accessed using SpellMgr functions)
struct SpellTargetPosition
{
@@ -726,6 +715,7 @@ class SpellMgr
void LoadSpellAreas();
void LoadSpellInfoStore();
void UnloadSpellInfoStore();
+ void UnloadSpellInfoImplicitTargetConditionLists();
void LoadSpellCustomAttr();
void LoadDbcDataCorrections();
diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp
index 14dd32a71b6..03fea614c0d 100755
--- a/src/server/game/Spells/SpellScript.cpp
+++ b/src/server/game/Spells/SpellScript.cpp
@@ -473,11 +473,6 @@ void SpellScript::GetSummonPosition(uint32 i, Position &pos, float radius = 0.0f
m_spell->GetSummonPosition(i, pos, radius, count);
}
-void SpellScript::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry)
-{
- m_spell->SearchAreaTarget(TagUnitMap, radius, type, TargetType, entry);
-}
-
void SpellScript::PreventHitEffect(SpellEffIndex effIndex)
{
if (!IsInHitPhase() && !IsInEffectHook())
diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h
index 09b9eaebd62..1bf8d25adef 100755
--- a/src/server/game/Spells/SpellScript.h
+++ b/src/server/game/Spells/SpellScript.h
@@ -336,7 +336,6 @@ class SpellScript : public _SpellScript
void PreventHitHeal() { SetHitHeal(0); }
Spell* GetSpell() { return m_spell; }
void GetSummonPosition(uint32 i, Position &pos, float radius, uint32 count);
- void SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry);
// returns current spell hit target aura
Aura* GetHitAura();
// prevents applying aura on current spell hit target
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp
index d5695a0f39d..19ed96e8885 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp
@@ -62,7 +62,7 @@ class OrientationCheck : public std::unary_function<Unit*, bool>
explicit OrientationCheck(Unit* _caster) : caster(_caster) { }
bool operator() (Unit* unit)
{
- return !unit->isInFront(caster, 40.0f, 2.5f);
+ return !unit->isInFront(caster, 2.5f) || !unit->IsWithinDist(caster, 40.0f);
}
private:
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
index da46d016e91..c4f973726bc 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
@@ -1736,25 +1736,29 @@ class spell_vehicle_throw_passenger : public SpellScriptLoader
if (Vehicle* vehicle = GetCaster()->GetVehicleKit())
if (Unit* passenger = vehicle->GetPassenger(damage - 1))
{
- std::list<Unit*> unitList;
// use 99 because it is 3d search
- SearchAreaTarget(unitList, 99, PUSH_DST_CENTER, SPELL_TARGETS_ENTRY, NPC_SEAT);
+ std::list<WorldObject*> targetList;
+ Trinity::WorldObjectSpellAreaTargetCheck check(99, GetTargetDest(), GetCaster(), GetCaster(), GetSpellInfo(), TARGET_CHECK_DEFAULT, NULL);
+ Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> searcher(GetCaster(), targetList, check);
+ GetCaster()->GetMap()->VisitAll(GetCaster()->m_positionX, GetCaster()->m_positionY, 99, searcher);
float minDist = 99 * 99;
Unit* target = NULL;
- for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
+ for (std::list<WorldObject*>::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
{
- if (Vehicle* seat = (*itr)->GetVehicleKit())
- if (!seat->GetPassenger(0))
- if (Unit* device = seat->GetPassenger(2))
- if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
- {
- float dist = (*itr)->GetExactDistSq(targets.GetDst());
- if (dist < minDist)
- {
- minDist = dist;
- target = (*itr);
- }
- }
+ if (Unit* unit = (*itr)->ToUnit())
+ if (unit->GetEntry() == NPC_SEAT)
+ if (Vehicle* seat = unit->GetVehicleKit())
+ if (!seat->GetPassenger(0))
+ if (Unit* device = seat->GetPassenger(2))
+ if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
+ {
+ float dist = unit->GetExactDistSq(targets.GetDst());
+ if (dist < minDist)
+ {
+ minDist = dist;
+ target = unit;
+ }
+ }
}
if (target && target->IsWithinDist2d(targets.GetDst(), GetSpellInfo()->Effects[effIndex].CalcRadius() * 2)) // now we use *2 because the location of the seat is not correct
passenger->EnterVehicle(target, 0);
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 638a17bc4f9..3835cb8ca0f 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -196,7 +196,7 @@ class spell_gen_cannibalize : public SpellScriptLoader
float max_range = GetSpellInfo()->GetMaxRange(false);
WorldObject* result = NULL;
// search for nearby enemy corpse in range
- Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_SELECT_CHECK_ENEMY);
+ Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_CHECK_ENEMY);
Trinity::WorldObjectSearcher<Trinity::AnyDeadUnitSpellTargetInRangeCheck> searcher(caster, result, check);
caster->GetMap()->VisitFirstFound(caster->m_positionX, caster->m_positionY, max_range, searcher);
if (!result)
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index dd9bfd90a0b..855af75cd83 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -532,7 +532,7 @@ class spell_hun_pet_carrion_feeder : public SpellScriptLoader
float max_range = GetSpellInfo()->GetMaxRange(false);
WorldObject* result = NULL;
// search for nearby enemy corpse in range
- Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_SELECT_CHECK_ENEMY);
+ Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_CHECK_ENEMY);
Trinity::WorldObjectSearcher<Trinity::AnyDeadUnitSpellTargetInRangeCheck> searcher(caster, result, check);
caster->GetMap()->VisitFirstFound(caster->m_positionX, caster->m_positionY, max_range, searcher);
if (!result)