/* * Copyright (C) 2008-2011 TrinityCore * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "SpellAuraDefines.h" #include "SpellInfo.h" #include "SpellMgr.h" #include "Spell.h" #include "DBCStores.h" uint32 GetTargetFlagMask(SpellTargetObjectTypes objType) { switch (objType) { case TARGET_OBJECT_TYPE_DEST: return TARGET_FLAG_DEST_LOCATION; case TARGET_OBJECT_TYPE_UNIT_AND_DEST: return TARGET_FLAG_DEST_LOCATION | TARGET_FLAG_UNIT; case TARGET_OBJECT_TYPE_CORPSE: case TARGET_OBJECT_TYPE_UNIT: return TARGET_FLAG_UNIT; case TARGET_OBJECT_TYPE_GOBJ: return TARGET_FLAG_GAMEOBJECT; case TARGET_OBJECT_TYPE_GOBJ_ITEM: return TARGET_FLAG_GAMEOBJECT_ITEM; case TARGET_OBJECT_TYPE_ITEM: return TARGET_FLAG_ITEM; case TARGET_OBJECT_TYPE_SRC: return TARGET_FLAG_SOURCE_LOCATION; default: return TARGET_FLAG_NONE; } } SpellImplicitTargetInfo::SpellImplicitTargetInfo(uint32 target) { _target = Targets(target); } bool SpellImplicitTargetInfo::IsArea() const { return GetSelectionCategory() == TARGET_SELECT_CATEGORY_AREA || GetSelectionCategory() == TARGET_SELECT_CATEGORY_CONE; } SpellSelectTargetTypes SpellImplicitTargetInfo::GetType() const { return Type[_target]; } SpellTargetSelectionCategories SpellImplicitTargetInfo::GetSelectionCategory() const { return _data[_target].SelectionCategory; } SpellTargetReferenceTypes SpellImplicitTargetInfo::GetReferenceType() const { return _data[_target].ReferenceType; } SpellTargetObjectTypes SpellImplicitTargetInfo::GetObjectType() const { return _data[_target].ObjectType; } SpellTargetSelectionCheckTypes SpellImplicitTargetInfo::GetSelectionCheckType() const { return _data[_target].SelectionCheckType; } SpellTargetDirectionTypes SpellImplicitTargetInfo::GetDirectionType() const { return _data[_target].DirectionType; } float SpellImplicitTargetInfo::CalcDirectionAngle() const { switch (GetDirectionType()) { case TARGET_DIR_FRONT: return 0.0f; case TARGET_DIR_BACK: return static_cast(M_PI); case TARGET_DIR_RIGHT: return static_cast(-M_PI/2); case TARGET_DIR_LEFT: return static_cast(M_PI/2); case TARGET_DIR_FRONT_RIGHT: return static_cast(M_PI/4); case TARGET_DIR_BACK_RIGHT: return static_cast(-3*M_PI/4); case TARGET_DIR_BACK_LEFT: return static_cast(3*M_PI/4); case TARGET_DIR_FRONT_LEFT: return static_cast(M_PI/4); case TARGET_DIR_RANDOM: return float(rand_norm())*static_cast(2*M_PI); default: return 0.0f; } } Targets SpellImplicitTargetInfo::GetTarget() const { return _target; } uint32 SpellImplicitTargetInfo::GetExplicitTargetMask(bool& srcSet, bool& dstSet) const { uint32 targetMask = 0; if (GetTarget() == TARGET_DEST_TRAJ) { if (!srcSet) targetMask = TARGET_FLAG_SOURCE_LOCATION; if (!dstSet) targetMask |= TARGET_FLAG_DEST_LOCATION; } else { switch (GetReferenceType()) { case TARGET_REFERENCE_TYPE_SRC: if (srcSet) break; targetMask = TARGET_FLAG_SOURCE_LOCATION; break; case TARGET_REFERENCE_TYPE_DEST: if (dstSet) break; targetMask = TARGET_FLAG_DEST_LOCATION; break; case TARGET_REFERENCE_TYPE_TARGET: switch (GetObjectType()) { case TARGET_OBJECT_TYPE_GOBJ: targetMask = TARGET_FLAG_GAMEOBJECT; break; case TARGET_OBJECT_TYPE_GOBJ_ITEM: targetMask = TARGET_FLAG_GAMEOBJECT_ITEM; break; case TARGET_OBJECT_TYPE_UNIT_AND_DEST: case TARGET_OBJECT_TYPE_UNIT: case TARGET_OBJECT_TYPE_DEST: switch (GetSelectionCheckType()) { case TARGET_SELECT_CHECK_ENEMY: targetMask = TARGET_FLAG_UNIT_ENEMY; break; case TARGET_SELECT_CHECK_ALLY: targetMask = TARGET_FLAG_UNIT_ALLY; break; case TARGET_SELECT_CHECK_PARTY: targetMask = TARGET_FLAG_UNIT_PARTY; break; case TARGET_SELECT_CHECK_RAID: targetMask = TARGET_FLAG_UNIT_RAID; break; case TARGET_SELECT_CHECK_PASSENGER: targetMask = TARGET_FLAG_UNIT_PASSENGER; break; default: targetMask = TARGET_FLAG_UNIT; break; } break; default: break; } break; default: break; } } switch (GetObjectType()) { case TARGET_OBJECT_TYPE_SRC: srcSet = true; break; case TARGET_OBJECT_TYPE_DEST: case TARGET_OBJECT_TYPE_UNIT_AND_DEST: dstSet = true; break; default: break; } return targetMask; } bool SpellImplicitTargetInfo::IsPosition(uint32 targetType) { switch (SpellImplicitTargetInfo::Type[targetType]) { case TARGET_TYPE_DEST_CASTER: case TARGET_TYPE_DEST_TARGET: case TARGET_TYPE_DEST_DEST: return true; default: break; } return false; } bool SpellImplicitTargetInfo::InitStaticData() { InitTypeData(); return true; } void SpellImplicitTargetInfo::InitTypeData() { for (uint8 i = 0; i < TOTAL_SPELL_TARGETS; ++i) { switch (i) { case TARGET_UNIT_CASTER: case TARGET_DEST_CASTER_FISHING: case TARGET_UNIT_MASTER: case TARGET_UNIT_PET: case TARGET_UNIT_CASTER_AREA_PARTY: case TARGET_UNIT_CASTER_AREA_RAID: case TARGET_UNIT_VEHICLE: 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: case TARGET_UNIT_SUMMONER: Type[i] = TARGET_TYPE_UNIT_CASTER; break; case TARGET_UNIT_TARGET_MINIPET: case TARGET_UNIT_TARGET_ALLY: case TARGET_UNIT_TARGET_RAID: case TARGET_UNIT_TARGET_ANY: case TARGET_UNIT_TARGET_ENEMY: case TARGET_UNIT_TARGET_PARTY: case TARGET_UNIT_TARGET_PASSENGER: case TARGET_UNIT_LASTTARGET_AREA_PARTY: case TARGET_UNIT_TARGET_AREA_RAID_CLASS: case TARGET_UNIT_TARGET_CHAINHEAL_ALLY: Type[i] = TARGET_TYPE_UNIT_TARGET; break; case TARGET_UNIT_NEARBY_ENEMY: case TARGET_UNIT_NEARBY_ALLY: case TARGET_UNIT_NEARBY_ENTRY: case TARGET_UNIT_NEARBY_PARTY: case TARGET_UNIT_NEARBY_RAID: case TARGET_GAMEOBJECT_NEARBY_ENTRY: Type[i] = TARGET_TYPE_UNIT_NEARBY; break; case TARGET_UNIT_SRC_AREA_ENEMY: case TARGET_UNIT_SRC_AREA_ALLY: case TARGET_UNIT_SRC_AREA_ENTRY: case TARGET_UNIT_SRC_AREA_PARTY: case TARGET_GAMEOBJECT_SRC_AREA: Type[i] = TARGET_TYPE_AREA_SRC; break; case TARGET_UNIT_DEST_AREA_ENEMY: case TARGET_UNIT_DEST_AREA_ALLY: case TARGET_UNIT_DEST_AREA_ENTRY: case TARGET_UNIT_DEST_AREA_PARTY: case TARGET_GAMEOBJECT_DEST_AREA: Type[i] = TARGET_TYPE_AREA_DST; break; case TARGET_UNIT_CONE_ENEMY_24: case TARGET_UNIT_CONE_ALLY: case TARGET_UNIT_CONE_ENTRY: case TARGET_UNIT_CONE_ENEMY_54: case TARGET_UNIT_CONE_ENEMY_104: case TARGET_GAMEOBJECT_CONE: Type[i] = TARGET_TYPE_AREA_CONE; break; case TARGET_DEST_CASTER: case TARGET_SRC_CASTER: case TARGET_DEST_CASTER_SUMMON: case TARGET_DEST_CASTER_FRONT_LEAP: case TARGET_DEST_CASTER_FRONT: case TARGET_DEST_CASTER_BACK: case TARGET_DEST_CASTER_RIGHT: case TARGET_DEST_CASTER_LEFT: case TARGET_DEST_CASTER_FRONT_LEFT: case TARGET_DEST_CASTER_BACK_LEFT: case TARGET_DEST_CASTER_BACK_RIGHT: case TARGET_DEST_CASTER_FRONT_RIGHT: case TARGET_DEST_CASTER_RANDOM: case TARGET_DEST_CASTER_RADIUS: Type[i] = TARGET_TYPE_DEST_CASTER; break; case TARGET_DEST_TARGET_ENEMY: case TARGET_DEST_TARGET_ANY: case TARGET_DEST_TARGET_FRONT: case TARGET_DEST_TARGET_BACK: case TARGET_DEST_TARGET_RIGHT: case TARGET_DEST_TARGET_LEFT: case TARGET_DEST_TARGET_FRONT_LEFT: case TARGET_DEST_TARGET_BACK_LEFT: case TARGET_DEST_TARGET_BACK_RIGHT: case TARGET_DEST_TARGET_FRONT_RIGHT: case TARGET_DEST_TARGET_RANDOM: case TARGET_DEST_TARGET_RADIUS: Type[i] = TARGET_TYPE_DEST_TARGET; break; case TARGET_DEST_DYNOBJ_ENEMY: case TARGET_DEST_DYNOBJ_ALLY: case TARGET_DEST_DYNOBJ_NONE: case TARGET_DEST_DEST: case TARGET_DEST_TRAJ: case TARGET_DEST_DEST_FRONT_LEFT: case TARGET_DEST_DEST_BACK_LEFT: case TARGET_DEST_DEST_BACK_RIGHT: case TARGET_DEST_DEST_FRONT_RIGHT: case TARGET_DEST_DEST_FRONT: case TARGET_DEST_DEST_BACK: case TARGET_DEST_DEST_RIGHT: case TARGET_DEST_DEST_LEFT: case TARGET_DEST_DEST_RANDOM: case TARGET_DEST_DEST_RADIUS: Type[i] = TARGET_TYPE_DEST_DEST; break; case TARGET_DEST_DB: case TARGET_DEST_HOME: case TARGET_DEST_NEARBY_ENTRY: Type[i] = TARGET_TYPE_DEST_SPECIAL; break; case TARGET_UNIT_CHANNEL_TARGET: case TARGET_DEST_CHANNEL_TARGET: case TARGET_DEST_CHANNEL_CASTER: Type[i] = TARGET_TYPE_CHANNEL; break; default: Type[i] = TARGET_TYPE_DEFAULT; } } } bool SpellImplicitTargetInfo::Init = SpellImplicitTargetInfo::InitStaticData(); 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 }; SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex) { _spellInfo = spellInfo; _effIndex = effIndex; Effect = spellEntry->Effect[effIndex]; ApplyAuraName = spellEntry->EffectApplyAuraName[effIndex]; Amplitude = spellEntry->EffectAmplitude[effIndex]; DieSides = spellEntry->EffectDieSides[effIndex]; RealPointsPerLevel = spellEntry->EffectRealPointsPerLevel[effIndex]; BasePoints = spellEntry->EffectBasePoints[effIndex]; PointsPerComboPoint = spellEntry->EffectPointsPerComboPoint[effIndex]; ValueMultiplier = spellEntry->EffectValueMultiplier[effIndex]; DamageMultiplier = spellEntry->EffectDamageMultiplier[effIndex]; BonusMultiplier = spellEntry->EffectBonusMultiplier[effIndex]; MiscValue = spellEntry->EffectMiscValue[effIndex]; MiscValueB = spellEntry->EffectMiscValueB[effIndex]; Mechanic = Mechanics(spellEntry->EffectMechanic[effIndex]); TargetA = SpellImplicitTargetInfo(spellEntry->EffectImplicitTargetA[effIndex]); TargetB = SpellImplicitTargetInfo(spellEntry->EffectImplicitTargetB[effIndex]); RadiusEntry = spellEntry->EffectRadiusIndex[effIndex] ? sSpellRadiusStore.LookupEntry(spellEntry->EffectRadiusIndex[effIndex]) : NULL; ChainTarget = spellEntry->EffectChainTarget[effIndex]; ItemType = spellEntry->EffectItemType[effIndex]; TriggerSpell = spellEntry->EffectTriggerSpell[effIndex]; SpellClassMask = spellEntry->EffectSpellClassMask[effIndex]; } bool SpellEffectInfo::IsEffect() const { return Effect != 0; } bool SpellEffectInfo::IsEffect(SpellEffects effectName) const { return Effect == effectName; } bool SpellEffectInfo::IsAura() const { return (IsUnitOwnedAuraEffect() || Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) && ApplyAuraName != 0; } bool SpellEffectInfo::IsAura(AuraType aura) const { return IsAura() && ApplyAuraName == aura; } bool SpellEffectInfo::IsArea() const { return TargetA.IsArea() || TargetB.IsArea(); } bool SpellEffectInfo::IsAreaAuraEffect() const { if (Effect == SPELL_EFFECT_APPLY_AREA_AURA_PARTY || Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID || Effect == SPELL_EFFECT_APPLY_AREA_AURA_FRIEND || Effect == SPELL_EFFECT_APPLY_AREA_AURA_ENEMY || Effect == SPELL_EFFECT_APPLY_AREA_AURA_PET || Effect == SPELL_EFFECT_APPLY_AREA_AURA_OWNER) return true; return false; } bool SpellEffectInfo::IsFarUnitTargetEffect() const { return Effect == SPELL_EFFECT_SUMMON_PLAYER; } bool SpellEffectInfo::IsFarDestTargetEffect() const { return Effect == SPELL_EFFECT_TELEPORT_UNITS; } bool SpellEffectInfo::IsUnitOwnedAuraEffect() const { return IsAreaAuraEffect() || Effect == SPELL_EFFECT_APPLY_AURA; } int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const* /*target*/) const { float basePointsPerLevel = RealPointsPerLevel; int32 basePoints = bp ? *bp : BasePoints; int32 randomPoints = int32(DieSides); // base amount modification based on spell lvl vs caster lvl if (caster) { int32 level = int32(caster->getLevel()); if (level > int32(_spellInfo->MaxLevel) && _spellInfo->MaxLevel > 0) level = int32(_spellInfo->MaxLevel); else if (level < int32(_spellInfo->BaseLevel)) level = int32(_spellInfo->BaseLevel); level -= int32(_spellInfo->SpellLevel); basePoints += int32(level * basePointsPerLevel); } // roll in a range <1;EffectDieSides> as of patch 3.3.3 switch (randomPoints) { case 0: break; case 1: basePoints += 1; break; // range 1..1 default: // range can have positive (1..rand) and negative (rand..1) values, so order its for irand int32 randvalue = (randomPoints >= 1) ? irand(1, randomPoints) : irand(randomPoints, 1); basePoints += randvalue; break; } float value = float(basePoints); // random damage if (caster) { // bonus amount from combo points if (caster->m_movedPlayer) if (uint8 comboPoints = caster->m_movedPlayer->GetComboPoints()) if (float comboDamage = PointsPerComboPoint) value += comboDamage * comboPoints; value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value); // amount multiplication based on caster's level if (!basePointsPerLevel && (_spellInfo->Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION && _spellInfo->SpellLevel) && Effect != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE && Effect != SPELL_EFFECT_KNOCK_BACK && ApplyAuraName != SPELL_AURA_MOD_SPEED_ALWAYS && ApplyAuraName != SPELL_AURA_MOD_SPEED_NOT_STACK && ApplyAuraName != SPELL_AURA_MOD_INCREASE_SPEED && ApplyAuraName != SPELL_AURA_MOD_DECREASE_SPEED) //there are many more: slow speed, -healing pct value *= 0.25f * exp(caster->getLevel() * (70 - _spellInfo->SpellLevel) / 1000.0f); //value = int32(value * (int32)getLevel() / (int32)(_spellInfo->spellLevel ? _spellInfo->spellLevel : 1)); } return int32(value); } int32 SpellEffectInfo::CalcBaseValue(int32 value) const { if (DieSides == 0) return value; else return value - 1; } float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const { float multiplier = ValueMultiplier; if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL)) modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_VALUE_MULTIPLIER, multiplier, spell); return multiplier; } float SpellEffectInfo::CalcDamageMultiplier(Unit* caster, Spell* spell) const { float multiplier = DamageMultiplier; if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL)) modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_DAMAGE_MULTIPLIER, multiplier, spell); return multiplier; } bool SpellEffectInfo::HasRadius() const { return RadiusEntry != NULL; } float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const { if (!HasRadius()) return 0.0f; float radius = RadiusEntry->radiusMax; if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL)) modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell); return radius; } SpellEffectTargetTypes SpellEffectInfo::GetRequiredTargetType() const { return RequiredTargetType[Effect]; } SpellTargetObjectTypes SpellEffectInfo::GetImplicitTargetObjectType() const { return _data[Effect].ImplicitObjectType; } SpellTargetObjectTypes SpellEffectInfo::GetRequiredTargetObjectType() const { return _data[Effect].RequiredObjectType; } bool SpellEffectInfo::InitStaticData() { InitRequiredTargetTypeData(); return true; } void SpellEffectInfo::InitRequiredTargetTypeData() { for (uint8 i = 0; i < TOTAL_SPELL_EFFECTS; ++i) { switch (i) { case SPELL_EFFECT_PERSISTENT_AREA_AURA: //27 case SPELL_EFFECT_SUMMON: //28 case SPELL_EFFECT_TRIGGER_MISSILE: //32 case SPELL_EFFECT_TRANS_DOOR: //50 summon object case SPELL_EFFECT_SUMMON_PET: //56 case SPELL_EFFECT_ADD_FARSIGHT: //72 case SPELL_EFFECT_SUMMON_OBJECT_WILD: //76 //case SPELL_EFFECT_SUMMON_CRITTER: //97 not 303 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: //104 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: //105 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: //106 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: //107 case SPELL_EFFECT_SUMMON_DEAD_PET: //109 case SPELL_EFFECT_TRIGGER_SPELL_2: //151 ritual of summon RequiredTargetType[i] = SPELL_REQUIRE_DEST; break; case SPELL_EFFECT_PARRY: // 0 case SPELL_EFFECT_BLOCK: // 0 case SPELL_EFFECT_SKILL: // always with dummy 3 as A //case SPELL_EFFECT_LEARN_SPELL: // 0 may be 5 pet case SPELL_EFFECT_TRADE_SKILL: // 0 or 1 case SPELL_EFFECT_PROFICIENCY: // 0 RequiredTargetType[i] = SPELL_REQUIRE_NONE; break; case SPELL_EFFECT_ENCHANT_ITEM: case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY: case SPELL_EFFECT_DISENCHANT: //in 243 this is 0, in 309 it is 1 //so both item target and unit target is pushed, and cause crash //case SPELL_EFFECT_FEED_PET: case SPELL_EFFECT_PROSPECTING: case SPELL_EFFECT_MILLING: case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC: RequiredTargetType[i] = SPELL_REQUIRE_ITEM; break; //caster must be pushed otherwise no sound case SPELL_EFFECT_APPLY_AREA_AURA_PARTY: case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND: case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY: case SPELL_EFFECT_APPLY_AREA_AURA_PET: case SPELL_EFFECT_APPLY_AREA_AURA_OWNER: case SPELL_EFFECT_APPLY_AREA_AURA_RAID: case SPELL_EFFECT_CHARGE: case SPELL_EFFECT_CHARGE_DEST: case SPELL_EFFECT_JUMP: case SPELL_EFFECT_JUMP_DEST: case SPELL_EFFECT_LEAP_BACK: RequiredTargetType[i] = SPELL_REQUIRE_CASTER; break; //case SPELL_EFFECT_WMO_DAMAGE: //case SPELL_EFFECT_WMO_REPAIR: //case SPELL_EFFECT_WMO_CHANGE: // RequiredTargetType[i] = SPELL_REQUIRE_GOBJECT; // break; default: RequiredTargetType[i] = SPELL_REQUIRE_UNIT; break; } } } bool SpellEffectInfo::Init = SpellEffectInfo::InitStaticData(); SpellEffectTargetTypes SpellEffectInfo::RequiredTargetType[TOTAL_SPELL_EFFECTS]; SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = { // implicit target required target {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 0 {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 1 SPELL_EFFECT_INSTAKILL {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 2 SPELL_EFFECT_SCHOOL_DAMAGE {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 3 SPELL_EFFECT_DUMMY {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 4 SPELL_EFFECT_PORTAL_TELEPORT {TARGET_OBJECT_TYPE_UNIT_AND_DEST,TARGET_OBJECT_TYPE_UNIT_AND_DEST},// 5 SPELL_EFFECT_TELEPORT_UNITS {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 6 SPELL_EFFECT_APPLY_AURA {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 8 SPELL_EFFECT_POWER_DRAIN {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 9 SPELL_EFFECT_HEALTH_LEECH {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 10 SPELL_EFFECT_HEAL {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 11 SPELL_EFFECT_BIND {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 12 SPELL_EFFECT_PORTAL {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 13 SPELL_EFFECT_RITUAL_BASE {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 16 SPELL_EFFECT_QUEST_COMPLETE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL {TARGET_OBJECT_TYPE_CORPSE, TARGET_OBJECT_TYPE_CORPSE}, // 18 SPELL_EFFECT_RESURRECT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 20 SPELL_EFFECT_DODGE {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 21 SPELL_EFFECT_EVADE {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 22 SPELL_EFFECT_PARRY {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 23 SPELL_EFFECT_BLOCK {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 24 SPELL_EFFECT_CREATE_ITEM {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 25 SPELL_EFFECT_WEAPON {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 26 SPELL_EFFECT_DEFENSE {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 28 SPELL_EFFECT_SUMMON {TARGET_OBJECT_TYPE_UNIT_AND_DEST, TARGET_OBJECT_TYPE_UNIT_AND_DEST},// 29 SPELL_EFFECT_LEAP {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 30 SPELL_EFFECT_ENERGIZE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 32 SPELL_EFFECT_TRIGGER_MISSILE {TARGET_OBJECT_TYPE_GOBJ_ITEM, TARGET_OBJECT_TYPE_GOBJ_ITEM}, // 33 SPELL_EFFECT_OPEN_LOCK {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 36 SPELL_EFFECT_LEARN_SPELL {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 37 SPELL_EFFECT_SPELL_DEFENSE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 38 SPELL_EFFECT_DISPEL {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 39 SPELL_EFFECT_LANGUAGE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 40 SPELL_EFFECT_DUAL_WIELD {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 41 SPELL_EFFECT_JUMP {TARGET_OBJECT_TYPE_UNIT_AND_DEST,TARGET_OBJECT_TYPE_UNIT_AND_DEST},// 42 SPELL_EFFECT_JUMP_DEST {TARGET_OBJECT_TYPE_UNIT_AND_DEST,TARGET_OBJECT_TYPE_UNIT_AND_DEST},// 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 44 SPELL_EFFECT_SKILL_STEP {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 45 SPELL_EFFECT_ADD_HONOR {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 46 SPELL_EFFECT_SPAWN {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 47 SPELL_EFFECT_TRADE_SKILL {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 48 SPELL_EFFECT_STEALTH {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 49 SPELL_EFFECT_DETECT {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 50 SPELL_EFFECT_TRANS_DOOR {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 52 SPELL_EFFECT_GUARANTEE_HIT {TARGET_OBJECT_TYPE_ITEM, TARGET_OBJECT_TYPE_ITEM}, // 53 SPELL_EFFECT_ENCHANT_ITEM {TARGET_OBJECT_TYPE_ITEM, TARGET_OBJECT_TYPE_ITEM}, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 55 SPELL_EFFECT_TAMECREATURE {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 56 SPELL_EFFECT_SUMMON_PET {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 57 SPELL_EFFECT_LEARN_PET_SPELL {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 58 SPELL_EFFECT_WEAPON_DAMAGE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 60 SPELL_EFFECT_PROFICIENCY {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 61 SPELL_EFFECT_SEND_EVENT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 62 SPELL_EFFECT_POWER_BURN {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 63 SPELL_EFFECT_THREAT {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 64 SPELL_EFFECT_TRIGGER_SPELL {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 66 SPELL_EFFECT_CREATE_MANA_GEM {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 68 SPELL_EFFECT_INTERRUPT_CAST {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 69 SPELL_EFFECT_DISTRACT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 70 SPELL_EFFECT_PULL {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 71 SPELL_EFFECT_PICKPOCKET {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 72 SPELL_EFFECT_ADD_FARSIGHT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 73 SPELL_EFFECT_UNTRAIN_TALENTS {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 74 SPELL_EFFECT_APPLY_GLYPH {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 75 SPELL_EFFECT_HEAL_MECHANICAL {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 77 SPELL_EFFECT_SCRIPT_EFFECT {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 78 SPELL_EFFECT_ATTACK {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 79 SPELL_EFFECT_SANCTUARY {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 80 SPELL_EFFECT_ADD_COMBO_POINTS {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 81 SPELL_EFFECT_CREATE_HOUSE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 82 SPELL_EFFECT_BIND_SIGHT {TARGET_OBJECT_TYPE_UNIT_AND_DEST,TARGET_OBJECT_TYPE_UNIT_AND_DEST},// 83 SPELL_EFFECT_DUEL {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 84 SPELL_EFFECT_STUCK {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 85 SPELL_EFFECT_SUMMON_PLAYER {TARGET_OBJECT_TYPE_GOBJ, TARGET_OBJECT_TYPE_GOBJ}, // 86 SPELL_EFFECT_ACTIVATE_OBJECT {TARGET_OBJECT_TYPE_GOBJ, TARGET_OBJECT_TYPE_GOBJ}, // 87 SPELL_EFFECT_GAMEOBJECT_DAMAGE {TARGET_OBJECT_TYPE_GOBJ, TARGET_OBJECT_TYPE_GOBJ}, // 88 SPELL_EFFECT_GAMEOBJECT_REPAIR {TARGET_OBJECT_TYPE_GOBJ, TARGET_OBJECT_TYPE_GOBJ}, // 89 SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 90 SPELL_EFFECT_KILL_CREDIT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 91 SPELL_EFFECT_THREAT_ALL {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 93 SPELL_EFFECT_FORCE_DESELECT {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 94 SPELL_EFFECT_SELF_RESURRECT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 95 SPELL_EFFECT_SKINNING {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 96 SPELL_EFFECT_CHARGE {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 97 SPELL_EFFECT_CAST_BUTTON {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 98 SPELL_EFFECT_KNOCK_BACK {TARGET_OBJECT_TYPE_ITEM, TARGET_OBJECT_TYPE_ITEM}, // 99 SPELL_EFFECT_DISENCHANT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 100 SPELL_EFFECT_INEBRIATE {TARGET_OBJECT_TYPE_ITEM, TARGET_OBJECT_TYPE_ITEM}, // 101 SPELL_EFFECT_FEED_PET {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 102 SPELL_EFFECT_DISMISS_PET {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 103 SPELL_EFFECT_REPUTATION {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1 {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2 {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3 {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4 {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 108 SPELL_EFFECT_DISPEL_MECHANIC {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 109 SPELL_EFFECT_SUMMON_DEAD_PET {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 110 SPELL_EFFECT_DESTROY_ALL_TOTEMS {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 111 SPELL_EFFECT_DURABILITY_DAMAGE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 112 SPELL_EFFECT_112 {TARGET_OBJECT_TYPE_CORPSE, TARGET_OBJECT_TYPE_CORPSE}, // 113 SPELL_EFFECT_RESURRECT_NEW {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 114 SPELL_EFFECT_ATTACK_ME {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT {TARGET_OBJECT_TYPE_CORPSE, TARGET_OBJECT_TYPE_CORPSE}, // 116 SPELL_EFFECT_SKIN_PLAYER_CORPSE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 117 SPELL_EFFECT_SPIRIT_HEAL {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 118 SPELL_EFFECT_SKILL {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 119 SPELL_EFFECT_APPLY_AREA_AURA_PET {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 120 SPELL_EFFECT_TELEPORT_GRAVEYARD {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 122 SPELL_EFFECT_122 {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 123 SPELL_EFFECT_SEND_TAXI {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 124 SPELL_EFFECT_PULL_TOWARDS {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 125 SPELL_EFFECT_MODIFY_THREAT_PERCENT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF {TARGET_OBJECT_TYPE_ITEM, TARGET_OBJECT_TYPE_ITEM}, // 127 SPELL_EFFECT_PROSPECTING {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 130 SPELL_EFFECT_REDIRECT_THREAT {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 131 SPELL_EFFECT_131 {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 132 SPELL_EFFECT_PLAY_MUSIC {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 133 SPELL_EFFECT_UNLEARN_SPECIALIZATION {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 134 SPELL_EFFECT_KILL_CREDIT2 {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 135 SPELL_EFFECT_CALL_PET {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 136 SPELL_EFFECT_HEAL_PCT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 137 SPELL_EFFECT_ENERGIZE_PCT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 138 SPELL_EFFECT_LEAP_BACK {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 139 SPELL_EFFECT_CLEAR_QUEST {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 140 SPELL_EFFECT_FORCE_CAST {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 141 SPELL_EFFECT_FORCE_CAST_WITH_VALUE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER {TARGET_OBJECT_TYPE_UNIT_AND_DEST,TARGET_OBJECT_TYPE_UNIT_AND_DEST},// 144 SPELL_EFFECT_KNOCK_BACK_DEST {TARGET_OBJECT_TYPE_UNIT_AND_DEST,TARGET_OBJECT_TYPE_UNIT_AND_DEST},// 145 SPELL_EFFECT_PULL_TOWARDS_DEST {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 146 SPELL_EFFECT_ACTIVATE_RUNE {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 147 SPELL_EFFECT_QUEST_FAIL {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 148 SPELL_EFFECT_148 {TARGET_OBJECT_TYPE_DEST, TARGET_OBJECT_TYPE_DEST}, // 149 SPELL_EFFECT_CHARGE_DEST {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 150 SPELL_EFFECT_QUEST_START {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 151 SPELL_EFFECT_TRIGGER_SPELL_2 {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_NONE}, // 152 SPELL_EFFECT_SUMMON_RAF_FRIEND {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 153 SPELL_EFFECT_CREATE_TAMED_PET {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 154 SPELL_EFFECT_DISCOVER_TAXI {TARGET_OBJECT_TYPE_NONE, TARGET_OBJECT_TYPE_UNIT}, // 155 SPELL_EFFECT_TITAN_GRIP {TARGET_OBJECT_TYPE_ITEM, TARGET_OBJECT_TYPE_ITEM}, // 156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 157 SPELL_EFFECT_CREATE_ITEM_2 {TARGET_OBJECT_TYPE_ITEM, TARGET_OBJECT_TYPE_ITEM}, // 158 SPELL_EFFECT_MILLING {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 159 SPELL_EFFECT_ALLOW_RENAME_PET {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 160 SPELL_EFFECT_160 {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 161 SPELL_EFFECT_TALENT_SPEC_COUNT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 162 SPELL_EFFECT_TALENT_SPEC_SELECT {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 163 SPELL_EFFECT_163 {TARGET_OBJECT_TYPE_UNIT, TARGET_OBJECT_TYPE_UNIT}, // 164 SPELL_EFFECT_REMOVE_AURA }; SpellInfo::SpellInfo(SpellEntry const* spellEntry) { Id = spellEntry->Id; Category = spellEntry->Category; Dispel = spellEntry->Dispel; Mechanic = spellEntry->Mechanic; Attributes = spellEntry->Attributes; AttributesEx = spellEntry->AttributesEx; AttributesEx2 = spellEntry->AttributesEx2; AttributesEx3 = spellEntry->AttributesEx3; AttributesEx4 = spellEntry->AttributesEx4; AttributesEx5 = spellEntry->AttributesEx5; AttributesEx6 = spellEntry->AttributesEx6; AttributesEx7 = spellEntry->AttributesEx7; AttributesCu = 0; Stances = spellEntry->Stances; StancesNot = spellEntry->StancesNot; Targets = spellEntry->Targets; TargetCreatureType = spellEntry->TargetCreatureType; RequiresSpellFocus = spellEntry->RequiresSpellFocus; FacingCasterFlags = spellEntry->FacingCasterFlags; CasterAuraState = spellEntry->CasterAuraState; TargetAuraState = spellEntry->TargetAuraState; CasterAuraStateNot = spellEntry->CasterAuraStateNot; TargetAuraStateNot = spellEntry->TargetAuraStateNot; CasterAuraSpell = spellEntry->casterAuraSpell; TargetAuraSpell = spellEntry->targetAuraSpell; ExcludeCasterAuraSpell = spellEntry->excludeCasterAuraSpell; ExcludeTargetAuraSpell = spellEntry->excludeTargetAuraSpell; CastTimeEntry = spellEntry->CastingTimeIndex ? sSpellCastTimesStore.LookupEntry(spellEntry->CastingTimeIndex) : NULL; RecoveryTime = spellEntry->RecoveryTime; CategoryRecoveryTime = spellEntry->CategoryRecoveryTime; StartRecoveryCategory = spellEntry->StartRecoveryCategory; StartRecoveryTime = spellEntry->StartRecoveryTime; InterruptFlags = spellEntry->InterruptFlags; AuraInterruptFlags = spellEntry->AuraInterruptFlags; ChannelInterruptFlags = spellEntry->ChannelInterruptFlags; ProcFlags = spellEntry->procFlags; ProcChance = spellEntry->procChance; ProcCharges = spellEntry->procCharges; MaxLevel = spellEntry->maxLevel; BaseLevel = spellEntry->baseLevel; SpellLevel = spellEntry->spellLevel; DurationEntry = spellEntry->DurationIndex ? sSpellDurationStore.LookupEntry(spellEntry->DurationIndex) : NULL; PowerType = spellEntry->powerType; ManaCost = spellEntry->manaCost; ManaCostPerlevel = spellEntry->manaCostPerlevel; ManaPerSecond = spellEntry->manaPerSecond; ManaPerSecondPerLevel = spellEntry->manaPerSecondPerLevel; ManaCostPercentage = spellEntry->ManaCostPercentage; RuneCostID = spellEntry->runeCostID; RangeEntry = spellEntry->rangeIndex ? sSpellRangeStore.LookupEntry(spellEntry->rangeIndex) : NULL; Speed = spellEntry->speed; StackAmount = spellEntry->StackAmount; for (uint8 i = 0; i < 2; ++i) Totem[i] = spellEntry->Totem[i]; for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i) Reagent[i] = spellEntry->Reagent[i]; for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i) ReagentCount[i] = spellEntry->ReagentCount[i]; EquippedItemClass = spellEntry->EquippedItemClass; EquippedItemSubClassMask = spellEntry->EquippedItemSubClassMask; EquippedItemInventoryTypeMask = spellEntry->EquippedItemInventoryTypeMask; for (uint8 i = 0; i < 2; ++i) TotemCategory[i] = spellEntry->TotemCategory[i]; for (uint8 i = 0; i < 2; ++i) SpellVisual[i] = spellEntry->SpellVisual[i]; SpellIconID = spellEntry->SpellIconID; ActiveIconID = spellEntry->activeIconID; for (uint8 i = 0; i < 16; ++i) SpellName[i] = spellEntry->SpellName[i]; for (uint8 i = 0; i < 16; ++i) Rank[i] = spellEntry->Rank[i]; MaxTargetLevel = spellEntry->MaxTargetLevel; MaxAffectedTargets = spellEntry->MaxAffectedTargets; SpellFamilyName = spellEntry->SpellFamilyName; SpellFamilyFlags = spellEntry->SpellFamilyFlags; DmgClass = spellEntry->DmgClass; PreventionType = spellEntry->PreventionType; AreaGroupId = spellEntry->AreaGroupId; SchoolMask = spellEntry->SchoolMask; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) Effects[i] = SpellEffectInfo(spellEntry, this, i); ExplicitTargetMask = _GetExplicitTargetMask(); ChainEntry = NULL; } bool SpellInfo::HasEffect(SpellEffects effect) const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (Effects[i].IsEffect(effect)) return true; return false; } bool SpellInfo::HasAura(AuraType aura) const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (Effects[i].IsAura(aura)) return true; return false; } bool SpellInfo::HasAreaAuraEffect() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (Effects[i].IsAreaAuraEffect()) return true; return false; } bool SpellInfo::IsExplicitDiscovery() const { return ((Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM || Effects[0].Effect == SPELL_EFFECT_CREATE_ITEM_2) && Effects[1].Effect == SPELL_EFFECT_SCRIPT_EFFECT) || Id == 64323; } bool SpellInfo::IsLootCrafting() const { return (Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM || // different random cards from Inscription (121==Virtuoso Inking Set category) r without explicit item (Effects[0].Effect == SPELL_EFFECT_CREATE_ITEM_2 && (TotemCategory[0] != 0 || Effects[0].ItemType == 0))); } bool SpellInfo::IsQuestTame() const { return Effects[0].Effect == SPELL_EFFECT_THREAT && Effects[1].Effect == SPELL_EFFECT_APPLY_AURA && Effects[1].ApplyAuraName == SPELL_AURA_DUMMY; } bool SpellInfo::IsProfessionOrRiding() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (Effects[i].Effect == SPELL_EFFECT_SKILL) { uint32 skill = Effects[i].MiscValue; if (IsProfessionOrRidingSkill(skill)) return true; } } return false; } bool SpellInfo::IsProfession() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (Effects[i].Effect == SPELL_EFFECT_SKILL) { uint32 skill = Effects[i].MiscValue; if (IsProfessionSkill(skill)) return true; } } return false; } bool SpellInfo::IsPrimaryProfession() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (Effects[i].Effect == SPELL_EFFECT_SKILL) { uint32 skill = Effects[i].MiscValue; if (IsPrimaryProfessionSkill(skill)) return true; } } return false; } bool SpellInfo::IsPrimaryProfessionFirstRank() const { return IsPrimaryProfession() && GetRank() == 1; } bool SpellInfo::IsAbilityLearnedWithProfession() const { SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id); for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx) { SkillLineAbilityEntry const* pAbility = _spell_idx->second; if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL) continue; if (pAbility->req_skill_value > 0) return true; } return false; } bool SpellInfo::IsAbilityOfSkillType(uint32 skillType) const { SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id); for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx) if (_spell_idx->second->skillId == uint32(skillType)) return true; return false; } bool SpellInfo::IsAOE() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (Effects[i].IsArea()) return true; return false; } bool SpellInfo::NeedsExplicitUnitTarget() const { return GetExplicitTargetMask() & TARGET_FLAG_UNIT_MASK; } bool SpellInfo::NeedsToBeTriggeredByCaster() const { if (NeedsExplicitUnitTarget()) return true; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (Effects[i].IsEffect()) { if (Effects[i].TargetA.GetSelectionCategory() == TARGET_SELECT_CATEGORY_CHANNEL || Effects[i].TargetB.GetSelectionCategory() == TARGET_SELECT_CATEGORY_CHANNEL) return true; } } return false; } bool SpellInfo::IsPassive() const { return Attributes & SPELL_ATTR0_PASSIVE; } bool SpellInfo::IsAutocastable() const { if (Attributes & SPELL_ATTR0_PASSIVE) return false; if (AttributesEx & SPELL_ATTR1_UNAUTOCASTABLE_BY_PET) return false; return true; } bool SpellInfo::IsStackableWithRanks() const { if (IsPassive()) return false; if (PowerType != POWER_MANA && PowerType != POWER_HEALTH) return false; if (IsProfessionOrRiding()) return false; if (IsAbilityLearnedWithProfession()) return false; // All stance spells. if any better way, change it. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { switch (SpellFamilyName) { case SPELLFAMILY_PALADIN: // Paladin aura Spell if (Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID) return false; break; case SPELLFAMILY_DRUID: // Druid form Spell if (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA && Effects[i].ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT) return false; break; } } return true; } bool SpellInfo::IsPassiveStackableWithRanks() const { return IsPassive() && !HasEffect(SPELL_EFFECT_APPLY_AURA); } bool SpellInfo::IsMultiSlotAura() const { return IsPassive() || Id == 44413; } bool SpellInfo::IsDeathPersistent() const { return AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT; } bool SpellInfo::IsRequiringDeadTarget() const { return AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS; } bool SpellInfo::IsAllowingDeadTarget() const { return AttributesEx2 & SPELL_ATTR2_CAN_TARGET_DEAD || Targets & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_DEAD); } bool SpellInfo::CanBeUsedInCombat() const { return !(Attributes & SPELL_ATTR0_CANT_USED_IN_COMBAT); } bool SpellInfo::IsPositive() const { return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE); } bool SpellInfo::IsPositiveEffect(uint8 effIndex) const { switch (effIndex) { default: case 0: return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF0); case 1: return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF1); case 2: return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF2); } } bool SpellInfo::IsChanneled() const { return (AttributesEx & (SPELL_ATTR1_CHANNELED_1 | SPELL_ATTR1_CHANNELED_2)); } bool SpellInfo::NeedsComboPoints() const { return (AttributesEx & (SPELL_ATTR1_REQ_COMBO_POINTS1 | SPELL_ATTR1_REQ_COMBO_POINTS2)); } bool SpellInfo::IsBreakingStealth() const { return !(AttributesEx & SPELL_ATTR1_NOT_BREAK_STEALTH); } bool SpellInfo::IsRangedWeaponSpell() const { return (SpellFamilyName == SPELLFAMILY_HUNTER && !(SpellFamilyFlags[1] & 0x10000000)) // for 53352, cannot find better way || (EquippedItemSubClassMask & ITEM_SUBCLASS_MASK_WEAPON_RANGED); } bool SpellInfo::IsAutoRepeatRangedSpell() const { return AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG; } bool SpellInfo::IsAffectedBySpellMods() const { return !(AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS); } bool SpellInfo::IsAffectedBySpellMod(SpellModifier* mod) const { if (!IsAffectedBySpellMods()) return false; SpellInfo const* affectSpell = sSpellMgr->GetSpellInfo(mod->spellId); // False if affect_spell == NULL or spellFamily not equal if (!affectSpell || affectSpell->SpellFamilyName != SpellFamilyName) return false; // true if (mod->mask & SpellFamilyFlags) return true; return false; } bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const { // these spells pierce all avalible spells (Resurrection Sickness for example) if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) return true; // these spells (Cyclone for example) can pierce all... if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) // ...but not these (Divine shield for example) && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY))) return true; return false; } bool SpellInfo::CanDispelAura(SpellInfo const* aura) const { // These auras (like ressurection sickness) can't be dispelled if (aura->Attributes & SPELL_ATTR0_NEGATIVE_1) return false; // These spells (like Mass Dispel) can dispell all auras if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) return true; // These auras (like Divine Shield) can't be dispelled if (aura->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) return false; // These auras (Cyclone for example) are not dispelable if (aura->AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) return false; return true; } bool SpellInfo::IsSingleTarget() const { // all other single target spells have if it has AttributesEx5 if (AttributesEx5 & SPELL_ATTR5_SINGLE_TARGET_SPELL) return true; switch (GetSpellSpecific()) { case SPELL_SPECIFIC_JUDGEMENT: return true; default: break; } return false; } bool SpellInfo::IsSingleTargetWith(SpellInfo const* spellInfo) const { // TODO - need better check // Equal icon and spellfamily if (SpellFamilyName == spellInfo->SpellFamilyName && SpellIconID == spellInfo->SpellIconID) return true; SpellSpecificType spec = GetSpellSpecific(); // spell with single target specific types switch (spec) { case SPELL_SPECIFIC_JUDGEMENT: case SPELL_SPECIFIC_MAGE_POLYMORPH: if (spellInfo->GetSpellSpecific() == spec) return true; break; default: break; } return false; } bool SpellInfo::IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const { SpellSpecificType spellSpec1 = GetSpellSpecific(); SpellSpecificType spellSpec2 = spellInfo->GetSpellSpecific(); switch (spellSpec1) { case SPELL_SPECIFIC_PHASE: case SPELL_SPECIFIC_TRACKER: case SPELL_SPECIFIC_WARLOCK_ARMOR: case SPELL_SPECIFIC_MAGE_ARMOR: case SPELL_SPECIFIC_ELEMENTAL_SHIELD: case SPELL_SPECIFIC_MAGE_POLYMORPH: case SPELL_SPECIFIC_PRESENCE: case SPELL_SPECIFIC_CHARM: case SPELL_SPECIFIC_SCROLL: case SPELL_SPECIFIC_WARRIOR_ENRAGE: case SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE: case SPELL_SPECIFIC_PRIEST_DIVINE_SPIRIT: return spellSpec1 == spellSpec2; case SPELL_SPECIFIC_FOOD: return spellSpec2 == SPELL_SPECIFIC_FOOD || spellSpec2 == SPELL_SPECIFIC_FOOD_AND_DRINK; case SPELL_SPECIFIC_DRINK: return spellSpec2 == SPELL_SPECIFIC_DRINK || spellSpec2 == SPELL_SPECIFIC_FOOD_AND_DRINK; case SPELL_SPECIFIC_FOOD_AND_DRINK: return spellSpec2 == SPELL_SPECIFIC_FOOD || spellSpec2 == SPELL_SPECIFIC_DRINK || spellSpec2 == SPELL_SPECIFIC_FOOD_AND_DRINK; default: return false; } } bool SpellInfo::IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const { SpellSpecificType spellSpec = GetSpellSpecific(); switch (spellSpec) { case SPELL_SPECIFIC_SEAL: case SPELL_SPECIFIC_HAND: case SPELL_SPECIFIC_AURA: case SPELL_SPECIFIC_STING: case SPELL_SPECIFIC_CURSE: case SPELL_SPECIFIC_ASPECT: case SPELL_SPECIFIC_JUDGEMENT: case SPELL_SPECIFIC_WARLOCK_CORRUPTION: return spellSpec == spellInfo->GetSpellSpecific(); default: return false; } } SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const { // talents that learn spells can have stance requirements that need ignore // (this requirement only for client-side stance show in talent description) if (GetTalentSpellCost(Id) > 0 && (Effects[0].Effect == SPELL_EFFECT_LEARN_SPELL || Effects[1].Effect == SPELL_EFFECT_LEARN_SPELL || Effects[2].Effect == SPELL_EFFECT_LEARN_SPELL)) return SPELL_CAST_OK; uint32 stanceMask = (form ? 1 << (form - 1) : 0); if (stanceMask & StancesNot) // can explicitly not be casted in this stance return SPELL_FAILED_NOT_SHAPESHIFT; if (stanceMask & Stances) // can explicitly be casted in this stance return SPELL_CAST_OK; bool actAsShifted = false; SpellShapeshiftEntry const* shapeInfo = NULL; if (form > 0) { shapeInfo = sSpellShapeshiftStore.LookupEntry(form); if (!shapeInfo) { sLog->outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form); return SPELL_CAST_OK; } actAsShifted = !(shapeInfo->flags1 & 1); // shapeshift acts as normal form for spells } if (actAsShifted) { if (Attributes & SPELL_ATTR0_NOT_SHAPESHIFT) // not while shapeshifted return SPELL_FAILED_NOT_SHAPESHIFT; else if (Stances != 0) // needs other shapeshift return SPELL_FAILED_ONLY_SHAPESHIFT; } else { // needs shapeshift if (!(AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT) && Stances != 0) return SPELL_FAILED_ONLY_SHAPESHIFT; } // Check if stance disables cast of not-stance spells // Example: cannot cast any other spells in zombie or ghoul form // TODO: Find a way to disable use of these spells clientside if (shapeInfo && shapeInfo->flags1 & 0x400) { if (!(stanceMask & Stances)) return SPELL_FAILED_ONLY_SHAPESHIFT; } return SPELL_CAST_OK; } SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player) const { // normal case if (AreaGroupId > 0) { bool found = false; AreaGroupEntry const* groupEntry = sAreaGroupStore.LookupEntry(AreaGroupId); while (groupEntry) { for (uint8 i = 0; i < MAX_GROUP_AREA_IDS; ++i) if (groupEntry->AreaId[i] == zone_id || groupEntry->AreaId[i] == area_id) found = true; if (found || !groupEntry->nextGroup) break; // Try search in next group groupEntry = sAreaGroupStore.LookupEntry(groupEntry->nextGroup); } if (!found) return SPELL_FAILED_INCORRECT_AREA; } // continent limitation (virtual continent) if (AttributesEx4 & SPELL_ATTR4_CAST_ONLY_IN_OUTLAND) { uint32 v_map = GetVirtualMapForMapAndZone(map_id, zone_id); MapEntry const* mapEntry = sMapStore.LookupEntry(v_map); if (!mapEntry || mapEntry->addon < 1 || !mapEntry->IsContinent()) return SPELL_FAILED_INCORRECT_AREA; } // raid instance limitation if (AttributesEx6 & SPELL_ATTR6_NOT_IN_RAID_INSTANCE) { MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); if (!mapEntry || mapEntry->IsRaid()) return SPELL_FAILED_NOT_IN_RAID_INSTANCE; } // DB base check (if non empty then must fit at least single for allow) SpellAreaMapBounds saBounds = sSpellMgr->GetSpellAreaMapBounds(Id); if (saBounds.first != saBounds.second) { for (SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) { if (itr->second.IsFitToRequirements(player, zone_id, area_id)) return SPELL_CAST_OK; } return SPELL_FAILED_INCORRECT_AREA; } // bg spell checks switch (Id) { case 23333: // Warsong Flag case 23335: // Silverwing Flag return map_id == 489 && player && player->InBattleground() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; case 34976: // Netherstorm Flag return map_id == 566 && player && player->InBattleground() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; case 2584: // Waiting to Resurrect case 22011: // Spirit Heal Channel case 22012: // Spirit Heal case 24171: // Resurrection Impact Visual case 42792: // Recently Dropped Flag case 43681: // Inactive case 44535: // Spirit Heal (mana) { MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); if (!mapEntry) return SPELL_FAILED_INCORRECT_AREA; return zone_id == 4197 || (mapEntry->IsBattleground() && player && player->InBattleground()) ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 44521: // Preparation { if (!player) return SPELL_FAILED_REQUIRES_AREA; MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); if (!mapEntry) return SPELL_FAILED_INCORRECT_AREA; if (!mapEntry->IsBattleground()) return SPELL_FAILED_REQUIRES_AREA; Battleground* bg = player->GetBattleground(); return bg && bg->GetStatus() == STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 32724: // Gold Team (Alliance) case 32725: // Green Team (Alliance) case 35774: // Gold Team (Horde) case 35775: // Green Team (Horde) { MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); if (!mapEntry) return SPELL_FAILED_INCORRECT_AREA; return mapEntry->IsBattleArena() && player && player->InBattleground() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 32727: // Arena Preparation { if (!player) return SPELL_FAILED_REQUIRES_AREA; MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); if (!mapEntry) return SPELL_FAILED_INCORRECT_AREA; if (!mapEntry->IsBattleArena()) return SPELL_FAILED_REQUIRES_AREA; Battleground* bg = player->GetBattleground(); return bg && bg->GetStatus() == STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } } // aura limitations for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { switch (Effects[i].ApplyAuraName) { case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED: case SPELL_AURA_FLY: { if (player && !player->IsKnowHowFlyIn(map_id, zone_id)) return SPELL_FAILED_INCORRECT_AREA; } } } return SPELL_CAST_OK; } SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit 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; if (AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS && !target->ToPlayer()) return SPELL_FAILED_TARGET_NOT_PLAYER; if (!IsAllowingDeadTarget() && !target->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()) 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; 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 (target->GetTypeId() == TYPEID_PLAYER) return SPELL_FAILED_TARGET_IS_PLAYER; else return SPELL_FAILED_BAD_TARGETS; } // check UNIT_FLAG_NON_ATTACKABLE flag - a player can cast spells on his pet (or other controlled unit) though in any state if (!IsPositive() && target != caster && target->GetCharmerOrOwnerGUID() != caster->GetGUID()) { // any unattackable target skipped if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return SPELL_FAILED_BAD_TARGETS; } // 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 (!target->ToPlayer()->IsVisible()) return SPELL_FAILED_BAD_TARGETS; if (target->ToPlayer()->isGameMaster()) return SPELL_FAILED_BAD_TARGETS; } // not allow casting on flying player if (target->HasUnitState(UNIT_STAT_IN_FLIGHT)) return SPELL_FAILED_BAD_TARGETS; if (TargetAuraState && !target->HasAuraState(AuraStateType(TargetAuraState), this, caster)) return SPELL_FAILED_TARGET_AURASTATE; if (TargetAuraStateNot && target->HasAuraState(AuraStateType(TargetAuraStateNot), this, caster)) return SPELL_FAILED_TARGET_AURASTATE; if (TargetAuraSpell && !target->HasAura(sSpellMgr->GetSpellIdForDifficulty(TargetAuraSpell, caster))) return SPELL_FAILED_TARGET_AURASTATE; if (ExcludeTargetAuraSpell && target->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_RESSURECTION)) if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT_NEW)) return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED; return SPELL_CAST_OK; } SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget) const { uint32 neededTargets = GetExplicitTargetMask(); if (!target) { if (neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT_MASK | TARGET_FLAG_CORPSE_MASK)) if (!(neededTargets & TARGET_FLAG_GAMEOBJECT_ITEM) || !itemTarget) return SPELL_FAILED_BAD_TARGETS; return SPELL_CAST_OK; } if (Unit const* unitTarget = target->ToUnit()) { if (neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT_ALLY | TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_UNIT_PASSENGER)) { if (neededTargets & TARGET_FLAG_UNIT_ENEMY) if (!caster->IsFriendlyTo(unitTarget)) return SPELL_CAST_OK; if (neededTargets & TARGET_FLAG_UNIT_ALLY) if (caster->IsFriendlyTo(unitTarget)) return SPELL_CAST_OK; if (neededTargets & TARGET_FLAG_UNIT_PARTY) if (caster->IsInPartyWith(unitTarget)) return SPELL_CAST_OK; if (neededTargets & TARGET_FLAG_UNIT_RAID) if (caster->IsInRaidWith(unitTarget)) return SPELL_CAST_OK; if (neededTargets & TARGET_FLAG_UNIT_MINIPET) if (unitTarget->GetGUID() == caster->GetCritterGUID()) return SPELL_CAST_OK; if (neededTargets & TARGET_FLAG_UNIT_PASSENGER) if (unitTarget->IsOnVehicle(caster)) return SPELL_CAST_OK; return SPELL_FAILED_BAD_TARGETS; } } return SPELL_CAST_OK; } bool SpellInfo::CheckTargetCreatureType(Unit const* target) const { // Curse of Doom & Exorcism: not find another way to fix spell target check :/ if (SpellFamilyName == SPELLFAMILY_WARLOCK && Category == 1179) { // not allow cast at player if (target->GetTypeId() == TYPEID_PLAYER) return false; else return true; } uint32 creatureType = target->GetCreatureTypeMask(); return !TargetCreatureType || !creatureType || (creatureType & TargetCreatureType); } SpellSchoolMask SpellInfo::GetSchoolMask() const { return SpellSchoolMask(SchoolMask); } uint32 SpellInfo::GetAllEffectsMechanicMask() const { uint32 mask = 0; if (Mechanic) mask |= 1 << Mechanic; for (int i = 0; i < MAX_SPELL_EFFECTS; ++i) if (Effects[i].Mechanic) mask |= 1 << Effects[i].Mechanic; return mask; } uint32 SpellInfo::GetEffectMechanicMask(uint8 effIndex) const { uint32 mask = 0; if (Mechanic) mask |= 1<< Mechanic; if (Effects[effIndex].Mechanic) mask |= 1<< Effects[effIndex].Mechanic; return mask; } Mechanics SpellInfo::GetEffectMechanic(uint8 effIndex) const { if (Effects[effIndex].Mechanic) return Mechanics(Effects[effIndex].Mechanic); if (Mechanic) return Mechanics(Mechanic); return MECHANIC_NONE; } uint32 SpellInfo::GetDispelMask() const { return GetDispelMask(DispelType(Dispel)); } uint32 SpellInfo::GetDispelMask(DispelType type) { // If dispel all if (type == DISPEL_ALL) return DISPEL_ALL_MASK; else return uint32(1 << type); } uint32 SpellInfo::GetExplicitTargetMask() const { return ExplicitTargetMask; } AuraStateType SpellInfo::GetAuraState() const { // Seals if (GetSpellSpecific() == SPELL_SPECIFIC_SEAL) return AURA_STATE_JUDGEMENT; // Conflagrate aura state on Immolate and Shadowflame if (SpellFamilyName == SPELLFAMILY_WARLOCK && // Immolate ((SpellFamilyFlags[0] & 4) || // Shadowflame (SpellFamilyFlags[2] & 2))) return AURA_STATE_CONFLAGRATE; // Faerie Fire (druid versions) if (SpellFamilyName == SPELLFAMILY_DRUID && SpellFamilyFlags[0] & 0x400) return AURA_STATE_FAERIE_FIRE; // Sting (hunter's pet ability) if (Category == 1133) return AURA_STATE_FAERIE_FIRE; // Victorious if (SpellFamilyName == SPELLFAMILY_WARRIOR && SpellFamilyFlags[1] & 0x00040000) return AURA_STATE_WARRIOR_VICTORY_RUSH; // Swiftmend state on Regrowth & Rejuvenation if (SpellFamilyName == SPELLFAMILY_DRUID && SpellFamilyFlags[0] & 0x50) return AURA_STATE_SWIFTMEND; // Deadly poison aura state if (SpellFamilyName == SPELLFAMILY_ROGUE && SpellFamilyFlags[0] & 0x10000) return AURA_STATE_DEADLY_POISON; // Enrage aura state if (Dispel == DISPEL_ENRAGE) return AURA_STATE_ENRAGE; // Bleeding aura state if (GetAllEffectsMechanicMask() & 1<Id) { case 8118: // Strength case 8099: // Stamina case 8112: // Spirit case 8096: // Intellect case 8115: // Agility case 8091: // Armor return SPELL_SPECIFIC_SCROLL; case 12880: // Enrage (Enrage) case 57518: // Enrage (Wrecking Crew) return SPELL_SPECIFIC_WARRIOR_ENRAGE; } } break; } case SPELLFAMILY_MAGE: { // family flags 18(Molten), 25(Frost/Ice), 28(Mage) if (SpellFamilyFlags[0] & 0x12040000) return SPELL_SPECIFIC_MAGE_ARMOR; // Arcane brillance and Arcane intelect (normal check fails because of flags difference) if (SpellFamilyFlags[0] & 0x400) return SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE; if ((SpellFamilyFlags[0] & 0x1000000) && Effects[0].ApplyAuraName == SPELL_AURA_MOD_CONFUSE) return SPELL_SPECIFIC_MAGE_POLYMORPH; break; } case SPELLFAMILY_WARRIOR: { if (Id == 12292) // Death Wish return SPELL_SPECIFIC_WARRIOR_ENRAGE; break; } case SPELLFAMILY_WARLOCK: { // only warlock curses have this if (Dispel == DISPEL_CURSE) return SPELL_SPECIFIC_CURSE; // Warlock (Demon Armor | Demon Skin | Fel Armor) if (SpellFamilyFlags[1] & 0x20000020 || SpellFamilyFlags[2] & 0x00000010) return SPELL_SPECIFIC_WARLOCK_ARMOR; //seed of corruption and corruption if (SpellFamilyFlags[1] & 0x10 || SpellFamilyFlags[0] & 0x2) return SPELL_SPECIFIC_WARLOCK_CORRUPTION; break; } case SPELLFAMILY_PRIEST: { // Divine Spirit and Prayer of Spirit if (SpellFamilyFlags[0] & 0x20) return SPELL_SPECIFIC_PRIEST_DIVINE_SPIRIT; break; } case SPELLFAMILY_HUNTER: { // only hunter stings have this if (Dispel == DISPEL_POISON) return SPELL_SPECIFIC_STING; // only hunter aspects have this (but not all aspects in hunter family) if (SpellFamilyFlags.HasFlag(0x00380000, 0x00440000, 0x00001010)) return SPELL_SPECIFIC_ASPECT; break; } case SPELLFAMILY_PALADIN: { // Collection of all the seal family flags. No other paladin spell has any of those. if (SpellFamilyFlags[1] & 0x26000C00 || SpellFamilyFlags[0] & 0x0A000000) return SPELL_SPECIFIC_SEAL; if (SpellFamilyFlags[0] & 0x00002190) return SPELL_SPECIFIC_HAND; // Judgement of Wisdom, Judgement of Light, Judgement of Justice if (Id == 20184 || Id == 20185 || Id == 20186) return SPELL_SPECIFIC_JUDGEMENT; // only paladin auras have this (for palaldin class family) if (SpellFamilyFlags[2] & 0x00000020) return SPELL_SPECIFIC_AURA; break; } case SPELLFAMILY_SHAMAN: { // family flags 10 (Lightning), 42 (Earth), 37 (Water), proc shield from T2 8 pieces bonus if (SpellFamilyFlags[1] & 0x420 || SpellFamilyFlags[0] & 0x00000400 || Id == 23552) return SPELL_SPECIFIC_ELEMENTAL_SHIELD; break; } case SPELLFAMILY_DEATHKNIGHT: if (Id == 48266 || Id == 48263 || Id == 48265) return SPELL_SPECIFIC_PRESENCE; break; } for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) { switch (Effects[i].ApplyAuraName) { case SPELL_AURA_MOD_CHARM: case SPELL_AURA_MOD_POSSESS_PET: case SPELL_AURA_MOD_POSSESS: case SPELL_AURA_AOE_CHARM: return SPELL_SPECIFIC_CHARM; case SPELL_AURA_TRACK_CREATURES: case SPELL_AURA_TRACK_RESOURCES: case SPELL_AURA_TRACK_STEALTHED: return SPELL_SPECIFIC_TRACKER; case SPELL_AURA_PHASE: return SPELL_SPECIFIC_PHASE; } } } return SPELL_SPECIFIC_NORMAL; } float SpellInfo::GetMinRange(bool positive) const { if (!RangeEntry) return 0.0f; if (positive) return RangeEntry->minRangeFriend; return RangeEntry->minRangeHostile; } float SpellInfo::GetMaxRange(bool positive) const { if (!RangeEntry) return 0.0f; if (positive) return RangeEntry->maxRangeFriend; return RangeEntry->maxRangeHostile; } int32 SpellInfo::GetDuration() const { if (!DurationEntry) return 0; return (DurationEntry->Duration[0] == -1) ? -1 : abs(DurationEntry->Duration[0]); } int32 SpellInfo::GetMaxDuration() const { if (!DurationEntry) return 0; return (DurationEntry->Duration[2] == -1) ? -1 : abs(DurationEntry->Duration[2]); } uint32 SpellInfo::CalcCastTime(Unit* caster, Spell* spell) const { // not all spells have cast time index and this is all is pasiive abilities if (!CastTimeEntry) return 0; int32 castTime = CastTimeEntry->CastTime; if (caster) caster->ModSpellCastTime(this, castTime, spell); if (Attributes & SPELL_ATTR0_REQ_AMMO && (!IsAutoRepeatRangedSpell())) castTime += 500; return (castTime > 0) ? uint32(castTime) : 0; } uint32 SpellInfo::GetRecoveryTime() const { return RecoveryTime > CategoryRecoveryTime ? RecoveryTime : CategoryRecoveryTime; } uint32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const { // Spell drain all exist power on cast (Only paladin lay of Hands) if (AttributesEx & SPELL_ATTR1_DRAIN_ALL_POWER) { // If power type - health drain all if (PowerType == POWER_HEALTH) return caster->GetHealth(); // Else drain all power if (PowerType < MAX_POWERS) return caster->GetPower(Powers(PowerType)); sLog->outError("SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d", PowerType, Id); return 0; } // Base powerCost int32 powerCost = ManaCost; // PCT cost from total amount if (ManaCostPercentage) { switch (PowerType) { // health as power used case POWER_HEALTH: powerCost += int32(CalculatePctU(caster->GetCreateHealth(), ManaCostPercentage)); break; case POWER_MANA: powerCost += int32(CalculatePctU(caster->GetCreateMana(), ManaCostPercentage)); break; case POWER_RAGE: case POWER_FOCUS: case POWER_ENERGY: case POWER_HAPPINESS: powerCost += int32(CalculatePctU(caster->GetMaxPower(Powers(PowerType)), ManaCostPercentage)); break; case POWER_RUNE: case POWER_RUNIC_POWER: sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "CalculateManaCost: Not implemented yet!"); break; default: sLog->outError("CalculateManaCost: Unknown power type '%d' in spell %d", PowerType, Id); return 0; } } SpellSchools school = GetFirstSchoolInMask(schoolMask); // Flat mod from caster auras by spell school powerCost += caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school); // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) if (AttributesEx4 & SPELL_ATTR4_SPELL_VS_EXTEND_COST) powerCost += caster->GetAttackTime(OFF_ATTACK) / 100; // Apply cost mod by spell if (Player* modOwner = caster->GetSpellModOwner()) modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost); if (Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION) powerCost = int32(powerCost / (1.117f * SpellLevel / caster->getLevel() -0.1327f)); // PCT mod from user auras by school powerCost = int32(powerCost * (1.0f + caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + school))); if (powerCost < 0) powerCost = 0; return powerCost; } bool SpellInfo::IsRanked() const { return ChainEntry != NULL; } uint8 SpellInfo::GetRank() const { if (!ChainEntry) return 1; return ChainEntry->rank; } SpellInfo const* SpellInfo::GetFirstRankSpell() const { if (!ChainEntry) return this; return ChainEntry->first; } SpellInfo const* SpellInfo::GetLastRankSpell() const { if (!ChainEntry) return NULL; return ChainEntry->last; } SpellInfo const* SpellInfo::GetNextRankSpell() const { if (!ChainEntry) return NULL; return ChainEntry->next; } SpellInfo const* SpellInfo::GetPrevRankSpell() const { if (!ChainEntry) return NULL; return ChainEntry->prev; } SpellInfo const* SpellInfo::GetAuraRankForLevel(uint8 level) const { // ignore passive spells if (IsPassive()) return this; bool needRankSelection = false; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (IsPositiveEffect(i) && (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA || Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_PARTY || Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID)) { needRankSelection = true; break; } } // not required if (!needRankSelection) return this; for (SpellInfo const* nextSpellInfo = this; nextSpellInfo != NULL; nextSpellInfo = nextSpellInfo->GetPrevRankSpell()) { // if found appropriate level if (uint32(level + 10) >= nextSpellInfo->SpellLevel) return nextSpellInfo; // one rank less then } // not found return NULL; } bool SpellInfo::IsRankOf(SpellInfo const* spellInfo) const { return GetFirstRankSpell() == spellInfo->GetFirstRankSpell(); } bool SpellInfo::IsDifferentRankOf(SpellInfo const* spellInfo) const { if (Id == spellInfo->Id) return false; return IsRankOf(spellInfo); } bool SpellInfo::IsHighRankOf(SpellInfo const* spellInfo) const { if (ChainEntry && spellInfo->ChainEntry) { if (ChainEntry->first == spellInfo->ChainEntry->first) if (ChainEntry->rank > spellInfo->ChainEntry->rank) return true; } return false; } uint32 SpellInfo::_GetExplicitTargetMask() const { bool srcSet = false; bool dstSet = false; uint32 targetMask = Targets; // prepare target mask using effect target entries for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (!Effects[i].IsEffect()) continue; targetMask |= Effects[i].TargetA.GetExplicitTargetMask(srcSet, dstSet); targetMask |= Effects[i].TargetB.GetExplicitTargetMask(srcSet, dstSet); } // spells with range may need explicit targets, even if target entries not set // for example many SPELL_EFFECT_LEARN_SPELL spells need to have unit target if (GetMaxRange(true) > 0.0f || GetMaxRange(false) > 0.0f) { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (!Effects[i].IsEffect()) continue; uint32 effImplicitTargetMask = GetTargetFlagMask(Effects[i].GetImplicitTargetObjectType()); uint32 providedTargetMask = GetTargetFlagMask(Effects[i].TargetA.GetObjectType()) | GetTargetFlagMask(Effects[i].TargetB.GetObjectType()) | targetMask; // check if valid targets already present, prevent adding redundant flags switch (Effects[i].GetImplicitTargetObjectType()) { case TARGET_OBJECT_TYPE_UNIT_AND_DEST: if (providedTargetMask & TARGET_FLAG_UNIT_MASK) effImplicitTargetMask &= ~(TARGET_FLAG_UNIT_MASK); if (dstSet || providedTargetMask & TARGET_FLAG_DEST_LOCATION) effImplicitTargetMask &= ~(TARGET_FLAG_DEST_LOCATION); if (!effImplicitTargetMask) continue; break; case TARGET_OBJECT_TYPE_SRC: if (srcSet || providedTargetMask & TARGET_FLAG_SOURCE_LOCATION) continue; break; case TARGET_OBJECT_TYPE_DEST: if (dstSet || providedTargetMask & TARGET_FLAG_DEST_LOCATION) continue; break; case TARGET_OBJECT_TYPE_UNIT: if (providedTargetMask & TARGET_FLAG_UNIT_MASK) continue; break; case TARGET_OBJECT_TYPE_CORPSE: if (providedTargetMask & (TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_UNIT_MASK)) continue; break; case TARGET_OBJECT_TYPE_ITEM: if (providedTargetMask & (TARGET_FLAG_GAMEOBJECT_ITEM | TARGET_FLAG_ITEM)) continue; break; case TARGET_OBJECT_TYPE_GOBJ: if (providedTargetMask & TARGET_FLAG_GAMEOBJECT_MASK) continue; break; case TARGET_OBJECT_TYPE_GOBJ_ITEM: if (providedTargetMask & (TARGET_FLAG_GAMEOBJECT_ITEM | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_ITEM)) continue; break; default: continue; } // extend explicit target mask only if valid targets for effect could not be provided by target types targetMask |= effImplicitTargetMask &~(providedTargetMask); } } return targetMask; } bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const { // not found a single positive spell with this attribute if (Attributes & SPELL_ATTR0_NEGATIVE_1) return false; switch (SpellFamilyName) { case SPELLFAMILY_GENERIC: switch (Id) { case 34700: // Allergic Reaction case 61716: // Rabbit Costume case 61734: // Noblegarden Bunny case 61987: // Avenging Wrath Marker case 61988: // Divine Shield exclude aura case 62532: // Conservator's Grip return false; case 30877: // Tag Murloc case 62344: // Fists of Stone return true; default: break; } break; case SPELLFAMILY_MAGE: // Amplify Magic, Dampen Magic if (SpellFamilyFlags[0] == 0x00002000) return true; // Ignite if (SpellIconID == 45) return true; break; case SPELLFAMILY_PRIEST: switch (Id) { case 64844: // Divine Hymn case 64904: // Hymn of Hope case 47585: // Dispersion return true; default: break; } break; case SPELLFAMILY_HUNTER: // Aspect of the Viper if (Id == 34074) return true; break; case SPELLFAMILY_SHAMAN: if (Id == 30708) return false; break; default: break; } switch (Mechanic) { case MECHANIC_IMMUNE_SHIELD: return true; default: break; } // Special case: effects which determine positivity of whole spell for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (Effects[i].ApplyAuraName == SPELL_AURA_MOD_STEALTH) return true; } switch (Effects[effIndex].Effect) { case SPELL_EFFECT_DUMMY: // some explicitly required dummy effect sets switch (Id) { case 28441: return false; // AB Effect 000 default: break; } break; // always positive effects (check before target checks that provided non-positive result in some case for positive effects) case SPELL_EFFECT_HEAL: case SPELL_EFFECT_LEARN_SPELL: case SPELL_EFFECT_SKILL_STEP: case SPELL_EFFECT_HEAL_PCT: case SPELL_EFFECT_ENERGIZE_PCT: return true; // non-positive aura use case SPELL_EFFECT_APPLY_AURA: case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND: { switch (Effects[effIndex].ApplyAuraName) { case SPELL_AURA_MOD_DAMAGE_DONE: // dependent from bas point sign (negative -> negative) case SPELL_AURA_MOD_STAT: case SPELL_AURA_MOD_SKILL: case SPELL_AURA_MOD_DODGE_PERCENT: case SPELL_AURA_MOD_HEALING_PCT: case SPELL_AURA_MOD_HEALING_DONE: case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE: if (Effects[effIndex].CalcValue() < 0) return false; break; case SPELL_AURA_MOD_DAMAGE_TAKEN: // dependent from bas point sign (positive -> negative) if (Effects[effIndex].CalcValue() > 0) return false; break; case SPELL_AURA_MOD_CRIT_PCT: case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: if (Effects[effIndex].CalcValue() > 0) return true; // some expected positive spells have SPELL_ATTR1_NEGATIVE break; case SPELL_AURA_ADD_TARGET_TRIGGER: return true; case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: case SPELL_AURA_PERIODIC_TRIGGER_SPELL: if (!deep) { if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(Effects[effIndex].TriggerSpell)) { // negative targets of main spell return early for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (!spellTriggeredProto->Effects[i].Effect) continue; // if non-positive trigger cast targeted to positive target this main cast is non-positive // this will place this spell auras as debuffs if (_IsPositiveTarget(spellTriggeredProto->Effects[i].TargetA.GetTarget(), spellTriggeredProto->Effects[effIndex].TargetB.GetTarget()) && !spellTriggeredProto->_IsPositiveEffect(i, true)) return false; } } } case SPELL_AURA_PROC_TRIGGER_SPELL: // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example) break; case SPELL_AURA_MOD_STUN: //have positive and negative spells, we can't sort its correctly at this moment. if (effIndex == 0 && Effects[1].Effect == 0 && Effects[2].Effect == 0) return false; // but all single stun aura spells is negative break; case SPELL_AURA_MOD_PACIFY_SILENCE: if (Id == 24740) // Wisp Costume return true; return false; case SPELL_AURA_MOD_ROOT: case SPELL_AURA_MOD_SILENCE: case SPELL_AURA_GHOST: case SPELL_AURA_PERIODIC_LEECH: case SPELL_AURA_MOD_STALKED: case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: case SPELL_AURA_PREVENT_RESSURECTION: return false; case SPELL_AURA_PERIODIC_DAMAGE: // used in positive spells also. // part of negative spell if casted at self (prevent cancel) if (Effects[effIndex].TargetA.GetTarget() == TARGET_UNIT_CASTER) return false; break; case SPELL_AURA_MOD_DECREASE_SPEED: // used in positive spells also // part of positive spell if casted at self if (Effects[effIndex].TargetA.GetTarget() != TARGET_UNIT_CASTER) return false; // but not this if this first effect (didn't find better check) if (Attributes & SPELL_ATTR0_NEGATIVE_1 && effIndex == 0) return false; break; case SPELL_AURA_MECHANIC_IMMUNITY: { // non-positive immunities switch (Effects[effIndex].MiscValue) { case MECHANIC_BANDAGE: case MECHANIC_SHIELD: case MECHANIC_MOUNT: case MECHANIC_INVULNERABILITY: return false; default: break; } break; } case SPELL_AURA_ADD_FLAT_MODIFIER: // mods case SPELL_AURA_ADD_PCT_MODIFIER: { // non-positive mods switch (Effects[effIndex].MiscValue) { case SPELLMOD_COST: // dependent from bas point sign (negative -> positive) if (Effects[effIndex].CalcValue() > 0) { if (!deep) { bool negative = true; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (i != effIndex) if (_IsPositiveEffect(i, true)) { negative = false; break; } } if (negative) return false; } } break; default: break; } break; } default: break; } break; } default: break; } // non-positive targets if (!_IsPositiveTarget(Effects[effIndex].TargetA.GetTarget(), Effects[effIndex].TargetB.GetTarget())) return false; // negative spell if triggered spell is negative if (!deep && !Effects[effIndex].ApplyAuraName && Effects[effIndex].TriggerSpell) { if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(Effects[effIndex].TriggerSpell)) if (!spellTriggeredProto->_IsPositiveSpell()) return false; } // ok, positive return true; } bool SpellInfo::_IsPositiveSpell() const { // spells with at least one negative effect are considered negative // some self-applied spells have negative effects but in self casting case negative check ignored. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (!_IsPositiveEffect(i, true)) return false; return true; } bool SpellInfo::_IsPositiveTarget(uint32 targetA, uint32 targetB) { // non-positive targets switch (targetA) { case TARGET_UNIT_NEARBY_ENEMY: case TARGET_UNIT_TARGET_ENEMY: case TARGET_UNIT_SRC_AREA_ENEMY: case TARGET_UNIT_DEST_AREA_ENEMY: case TARGET_UNIT_CONE_ENEMY_24: case TARGET_UNIT_CONE_ENEMY_104: case TARGET_DEST_DYNOBJ_ENEMY: case TARGET_DEST_TARGET_ENEMY: return false; default: break; } if (targetB) return _IsPositiveTarget(targetB, 0); return true; }