| 408 | | // TargetA/TargetB dependent from each other, we not switch to full support this dependences |
| 409 | | // but need it support in some know cases |
| 410 | | switch(m_spellInfo->EffectImplicitTargetA[i]) |
| 411 | | { |
| 412 | | case TARGET_ALL_AROUND_CASTER: |
| 413 | | if( m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_PARTY || |
| 414 | | m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER || |
| 415 | | m_spellInfo->EffectImplicitTargetB[i]==TARGET_RANDOM_RAID_MEMBER ) |
| 416 | | { |
| 417 | | SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); |
| 418 | | } |
| 419 | | // Note: this hack with search required until GO casting not implemented |
| 420 | | // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support |
| 421 | | // currently each enemy selected explicitly and self cast damage |
| 422 | | else if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA && m_spellInfo->Effect[i]==SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) |
| 423 | | { |
| 424 | | if(m_targets.getUnitTarget()) |
| 425 | | tmpUnitMap.push_back(m_targets.getUnitTarget()); |
| 426 | | } |
| 427 | | else |
| 428 | | { |
| 429 | | SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); |
| 430 | | SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); |
| 431 | | } |
| 432 | | break; |
| 433 | | case TARGET_TABLE_X_Y_Z_COORDINATES: |
| 434 | | // Only if target A, for target B (used in teleports) dest select in effect |
| 435 | | SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); |
| 436 | | break; |
| 437 | | default: |
| 438 | | switch(m_spellInfo->EffectImplicitTargetB[i]) |
| 439 | | { |
| 440 | | case TARGET_SCRIPT_COORDINATES: // B case filled in canCast but we need fill unit list base at A case |
| 441 | | SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); |
| 442 | | break; |
| 443 | | default: |
| 444 | | SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); |
| 445 | | SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); |
| 446 | | break; |
| 447 | | } |
| 448 | | break; |
| 449 | | } |
| 450 | | |
| 451 | | if( (m_spellInfo->EffectImplicitTargetA[i]==0 || m_spellInfo->EffectImplicitTargetA[i]==TARGET_EFFECT_SELECT) && |
| 452 | | (m_spellInfo->EffectImplicitTargetB[i]==0 || m_spellInfo->EffectImplicitTargetB[i]==TARGET_EFFECT_SELECT) ) |
| 453 | | { |
| | 402 | // Note: this hack with search required until GO casting not implemented |
| | 403 | // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support |
| | 404 | // currently each enemy selected explicitly and self cast damage |
| | 405 | if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_AROUND_CASTER |
| | 406 | && m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA |
| | 407 | && m_spellInfo->Effect[i]==SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) |
| | 408 | { |
| | 409 | tmpUnitMap.push_back(m_targets.getUnitTarget()); |
| | 410 | } |
| | 411 | else |
| | 412 | { |
| | 413 | SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); |
| | 414 | SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); |
| | 415 | } |
| | 416 | |
| | 417 | if(tmpUnitMap.empty()) |
| | 418 | { |
| | 419 | if( m_spellInfo->EffectImplicitTargetA[i]==TARGET_SCRIPT || |
| | 420 | m_spellInfo->EffectImplicitTargetB[i]==TARGET_SCRIPT || |
| | 421 | m_spellInfo->EffectImplicitTargetA[i]==TARGET_SCRIPT_COORDINATES || |
| | 422 | m_spellInfo->EffectImplicitTargetB[i]==TARGET_SCRIPT_COORDINATES ) |
| | 423 | { |
| | 424 | if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) |
| | 425 | continue; |
| | 426 | } |
| | 1142 | void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, Unit* pUnitTarget, float max_range, uint32 unMaxTargets) |
| | 1143 | { |
| | 1144 | if(!pUnitTarget) |
| | 1145 | return; |
| | 1146 | |
| | 1147 | //FIXME: This very like horrible hack and wrong for most spells |
| | 1148 | if(m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE) |
| | 1149 | max_range += unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; |
| | 1150 | |
| | 1151 | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| | 1152 | Cell cell(p); |
| | 1153 | cell.data.Part.reserved = ALL_DISTRICT; |
| | 1154 | cell.SetNoCreate(); |
| | 1155 | |
| | 1156 | std::list<Unit *> tempUnitMap; |
| | 1157 | |
| | 1158 | { |
| | 1159 | Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(pUnitTarget, m_caster, max_range); |
| | 1160 | Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check); |
| | 1161 | |
| | 1162 | TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); |
| | 1163 | TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); |
| | 1164 | |
| | 1165 | CellLock<GridReadGuard> cell_lock(cell, p); |
| | 1166 | cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1167 | cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1168 | } |
| | 1169 | |
| | 1170 | tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); |
| | 1171 | |
| | 1172 | if(tempUnitMap.empty()) |
| | 1173 | return; |
| | 1174 | |
| | 1175 | uint32 t = unMaxTargets; |
| | 1176 | if(pUnitTarget != m_caster) |
| | 1177 | { |
| | 1178 | if(*tempUnitMap.begin() == pUnitTarget) |
| | 1179 | tempUnitMap.erase(tempUnitMap.begin()); |
| | 1180 | TagUnitMap.push_back(pUnitTarget); |
| | 1181 | --t; |
| | 1182 | } |
| | 1183 | Unit *prev = pUnitTarget; |
| | 1184 | |
| | 1185 | std::list<Unit*>::iterator next = tempUnitMap.begin(); |
| | 1186 | |
| | 1187 | while(t && next != tempUnitMap.end()) |
| | 1188 | { |
| | 1189 | if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) |
| | 1190 | break; |
| | 1191 | |
| | 1192 | if(!prev->IsWithinLOSInMap(*next) |
| | 1193 | || m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE && !m_caster->isInFront(*next, max_range)) |
| | 1194 | { |
| | 1195 | ++next; |
| | 1196 | continue; |
| | 1197 | } |
| | 1198 | |
| | 1199 | prev = *next; |
| | 1200 | TagUnitMap.push_back(prev); |
| | 1201 | tempUnitMap.erase(next); |
| | 1202 | tempUnitMap.sort(TargetDistanceOrder(prev)); |
| | 1203 | next = tempUnitMap.begin(); |
| | 1204 | --t; |
| | 1205 | } |
| | 1206 | } |
| | 1207 | |
| | 1208 | void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const uint32 &type, SpellTargets TargetType, uint32 entry) |
| | 1209 | { |
| | 1210 | if(type == PUSH_DEST_CENTER && !m_targets.m_destX && !m_targets.m_destY && !m_targets.m_destZ) |
| | 1211 | { |
| | 1212 | sLog.outError( "SPELL: cannot find destination for spell ID %u\n", m_spellInfo->Id ); |
| | 1213 | return; |
| | 1214 | } |
| | 1215 | |
| | 1216 | CellPair p(Trinity::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); |
| | 1217 | Cell cell(p); |
| | 1218 | cell.data.Part.reserved = ALL_DISTRICT; |
| | 1219 | cell.SetNoCreate(); |
| | 1220 | CellLock<GridReadGuard> cell_lock(cell, p); |
| | 1221 | |
| | 1222 | Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, type, TargetType, entry); |
| | 1223 | |
| | 1224 | if(TargetType != SPELL_TARGETS_ENTRY) |
| | 1225 | { |
| | 1226 | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); |
| | 1227 | cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1228 | } |
| | 1229 | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); |
| | 1230 | cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1231 | } |
| | 1232 | |
| | 1233 | Unit* Spell::SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 entry) |
| | 1234 | { |
| | 1235 | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| | 1236 | Cell cell(p); |
| | 1237 | cell.data.Part.reserved = ALL_DISTRICT; |
| | 1238 | cell.SetNoCreate(); |
| | 1239 | CellLock<GridReadGuard> cell_lock(cell, p); |
| | 1240 | |
| | 1241 | Unit* target = NULL; |
| | 1242 | switch(TargetType) |
| | 1243 | { |
| | 1244 | case SPELL_TARGETS_ENTRY: |
| | 1245 | { |
| | 1246 | Creature* target = NULL; |
| | 1247 | Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster, entry, true, radius); |
| | 1248 | Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(target, u_check); |
| | 1249 | TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); |
| | 1250 | cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1251 | return target; |
| | 1252 | }break; |
| | 1253 | default: |
| | 1254 | case SPELL_TARGETS_AOE_DAMAGE: |
| | 1255 | { |
| | 1256 | Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius); |
| | 1257 | Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, u_check); |
| | 1258 | TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); |
| | 1259 | TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); |
| | 1260 | cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1261 | cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1262 | }break; |
| | 1263 | case SPELL_TARGETS_FRIENDLY: |
| | 1264 | { |
| | 1265 | Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius); |
| | 1266 | Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(target, u_check); |
| | 1267 | TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); |
| | 1268 | TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); |
| | 1269 | cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1270 | cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1271 | }break; |
| | 1272 | } |
| | 1273 | return target; |
| | 1274 | } |
| | 1275 | |
| 1189 | | // destination around caster |
| 1190 | | case TARGET_DEST_CASTER_FRONT_LEFT: |
| 1191 | | case TARGET_DEST_CASTER_BACK_LEFT: |
| 1192 | | case TARGET_DEST_CASTER_BACK_RIGHT: |
| 1193 | | case TARGET_DEST_CASTER_FRONT_RIGHT: |
| 1194 | | case TARGET_DEST_CASTER_FRONT: |
| 1195 | | case TARGET_DEST_CASTER_BACK: |
| 1196 | | case TARGET_DEST_CASTER_RIGHT: |
| 1197 | | case TARGET_DEST_CASTER_LEFT: |
| 1198 | | case TARGET_DEST_CASTER_RANDOM: |
| 1199 | | case TARGET_DEST_CASTER_RADIUS: |
| 1200 | | { |
| 1201 | | float x, y, z, angle, dist; |
| 1202 | | |
| 1203 | | if (m_spellInfo->EffectRadiusIndex[i]) |
| 1204 | | dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); |
| 1205 | | else |
| 1206 | | dist = 3.0f;//do we need this? |
| 1207 | | if (cur == TARGET_DEST_CASTER_RANDOM) |
| 1208 | | dist *= rand_norm(); // This case we need to consider caster size |
| 1209 | | else |
| 1210 | | dist -= m_caster->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it |
| 1211 | | //need a new function to remove this repeated work |
| 1212 | | |
| 1213 | | switch(cur) |
| 1214 | | { |
| 1215 | | case TARGET_DEST_CASTER_FRONT_LEFT: angle = -M_PI/4; break; |
| 1216 | | case TARGET_DEST_CASTER_BACK_LEFT: angle = -3*M_PI/4; break; |
| 1217 | | case TARGET_DEST_CASTER_BACK_RIGHT: angle = 3*M_PI/4; break; |
| 1218 | | case TARGET_DEST_CASTER_FRONT_RIGHT:angle = M_PI/4; break; |
| 1219 | | case TARGET_DEST_CASTER_FRONT: angle = 0.0f; break; |
| 1220 | | case TARGET_DEST_CASTER_BACK: angle = M_PI; break; |
| 1221 | | case TARGET_DEST_CASTER_RIGHT: angle = M_PI/2; break; |
| 1222 | | case TARGET_DEST_CASTER_LEFT: angle = -M_PI/2; break; |
| 1223 | | default: angle = rand_norm()*2*M_PI; break; |
| 1224 | | } |
| 1225 | | |
| 1226 | | m_caster->GetClosePoint(x, y, z, 0, dist, angle); |
| 1227 | | m_targets.setDestination(x, y, z); // do not know if has ground visual |
| 1228 | | TagUnitMap.push_back(m_caster); // may remove this in the future, if unitmap is empty, push m_caster |
| 1229 | | }break; |
| 1230 | | |
| 1231 | | // destination around target |
| 1232 | | case TARGET_DEST_TARGET_FRONT: |
| 1233 | | case TARGET_DEST_TARGET_BACK: |
| 1234 | | case TARGET_DEST_TARGET_RIGHT: |
| 1235 | | case TARGET_DEST_TARGET_LEFT: |
| 1236 | | case TARGET_DEST_TARGET_RANDOM: |
| 1237 | | case TARGET_DEST_TARGET_RADIUS: |
| 1238 | | { |
| 1239 | | Unit *target = m_targets.getUnitTarget(); |
| 1240 | | if(!target) |
| 1241 | | { |
| 1242 | | sLog.outError("SPELL: no unit target for spell ID %u\n", m_spellInfo->Id); |
| 1243 | | break; |
| 1244 | | } |
| 1245 | | |
| 1246 | | float x, y, z, angle, dist; |
| 1247 | | |
| 1248 | | if (m_spellInfo->EffectRadiusIndex[i]) |
| 1249 | | dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); |
| 1250 | | else |
| 1251 | | dist = 3.0f;//do we need this? |
| 1252 | | if (cur == TARGET_DEST_TARGET_RANDOM) |
| 1253 | | dist *= rand_norm(); // This case we need to consider caster size |
| 1254 | | else |
| 1255 | | dist -= target->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it |
| 1256 | | //need a new function to remove this repeated work |
| 1257 | | |
| 1258 | | switch(cur) |
| 1259 | | { |
| 1260 | | case TARGET_DEST_TARGET_FRONT: angle = 0.0f; break; |
| 1261 | | case TARGET_DEST_TARGET_BACK: angle = M_PI; break; |
| 1262 | | case TARGET_DEST_TARGET_RIGHT: angle = M_PI/2; break; |
| 1263 | | case TARGET_DEST_TARGET_LEFT: angle = -M_PI/2; break; |
| 1264 | | default: angle = rand_norm()*2*M_PI; break; |
| 1265 | | } |
| 1266 | | |
| 1267 | | target->GetClosePoint(x, y, z, 0, dist, angle); |
| 1268 | | m_targets.setDestination(x, y, z); // do not know if has ground visual |
| 1269 | | TagUnitMap.push_back(m_caster); // may remove this in the future, if unitmap is empty, push m_caster |
| 1270 | | }break; |
| 1271 | | |
| 1272 | | // destination around destination |
| 1273 | | case TARGET_DEST_DEST_RANDOM: |
| 1274 | | { |
| 1275 | | if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) |
| 1276 | | { |
| 1277 | | sLog.outError("SPELL: no destination for spell ID %u\n", m_spellInfo->Id); |
| 1278 | | break; |
| 1279 | | } |
| 1280 | | float x, y, z, dist, px, py, pz; |
| 1281 | | dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); |
| 1282 | | x = m_targets.m_destX; |
| 1283 | | y = m_targets.m_destY; |
| 1284 | | z = m_targets.m_destZ; |
| 1285 | | m_caster->GetRandomPoint(x, y, z, dist, px, py, pz); |
| 1286 | | m_targets.setDestination(px, py, pz); |
| | 1296 | // specific unit |
| | 1297 | case TARGET_SELF: |
| | 1298 | case TARGET_SELF_FISHING: |
| | 1299 | { |
| 1293 | | |
| 1294 | | case TARGET_SELF: |
| | 1307 | case TARGET_PET: |
| | 1308 | { |
| | 1309 | if(Pet* tmpUnit = m_caster->GetPet()) |
| | 1310 | TagUnitMap.push_back(tmpUnit); |
| | 1311 | }break; |
| | 1312 | case TARGET_NONCOMBAT_PET: |
| | 1313 | { |
| | 1314 | if(Unit* target = m_targets.getUnitTarget()) |
| | 1315 | if( target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && ((Pet*)target)->getPetType() == MINI_PET) |
| | 1316 | TagUnitMap.push_back(target); |
| | 1317 | }break; |
| | 1318 | case TARGET_SINGLE_FRIEND: // ally |
| | 1319 | case TARGET_SINGLE_FRIEND_2: // raid member |
| | 1320 | case TARGET_DUELVSPLAYER: // all (SelectMagnetTarget()?) |
| | 1321 | case TARGET_UNIT_SINGLE_UNKNOWN: |
| | 1322 | { |
| | 1323 | if(m_targets.getUnitTarget()) |
| | 1324 | TagUnitMap.push_back(m_targets.getUnitTarget()); |
| | 1325 | }break; |
| | 1326 | case TARGET_CHAIN_DAMAGE: |
| | 1327 | { |
| | 1328 | if(Unit* pUnitTarget = SelectMagnetTarget()) |
| | 1329 | { |
| | 1330 | if(EffectChainTarget <= 1) |
| | 1331 | TagUnitMap.push_back(pUnitTarget); |
| | 1332 | else //TODO: chain target should also use magnet target |
| | 1333 | SearchChainTarget(TagUnitMap, pUnitTarget, radius, EffectChainTarget); |
| | 1334 | } |
| | 1335 | }break; |
| | 1336 | case TARGET_GAMEOBJECT: |
| | 1337 | { |
| | 1338 | if(m_targets.getGOTarget()) |
| | 1339 | AddGOTarget(m_targets.getGOTarget(), i); |
| | 1340 | }break; |
| | 1341 | case TARGET_GAMEOBJECT_ITEM: |
| | 1342 | { |
| | 1343 | if(m_targets.getGOTargetGUID()) |
| | 1344 | AddGOTarget(m_targets.getGOTarget(), i); |
| | 1345 | else if(m_targets.getItemTarget()) |
| | 1346 | AddItemTarget(m_targets.getItemTarget(), i); |
| | 1347 | }break; |
| | 1348 | |
| | 1349 | // reference dest |
| | 1350 | case TARGET_EFFECT_SELECT: |
| | 1351 | m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; |
| | 1352 | case TARGET_ALL_AROUND_CASTER: |
| | 1353 | { |
| | 1354 | m_caster->GetPosition(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); |
| | 1355 | }break; |
| | 1356 | case TARGET_CURRENT_ENEMY_COORDINATES: |
| | 1357 | m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; |
| | 1358 | case TARGET_DUELVSPLAYER_COORDINATES: // no ground? |
| | 1359 | { |
| | 1360 | if(Unit* currentTarget = m_targets.getUnitTarget()) |
| | 1361 | currentTarget->GetPosition(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); |
| | 1362 | }break; |
| | 1363 | case TARGET_DEST_TABLE_UNKNOWN2: |
| | 1364 | case TARGET_TABLE_X_Y_Z_COORDINATES: |
| | 1365 | { |
| | 1366 | SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); |
| | 1367 | if(st) |
| | 1368 | { |
| | 1369 | if (st->target_mapId == m_caster->GetMapId()) |
| | 1370 | m_targets.setDestination(st->target_X, st->target_Y, st->target_Z); |
| | 1371 | } |
| | 1372 | else |
| | 1373 | sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id ); |
| | 1374 | }break; |
| | 1375 | |
| | 1376 | // area targets |
| | 1377 | case TARGET_ALL_ENEMY_IN_AREA_INSTANT: |
| | 1378 | { |
| | 1379 | if(m_spellInfo->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA) |
| | 1380 | break; |
| | 1381 | m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; |
| | 1382 | } |
| | 1383 | case TARGET_ALL_ENEMY_IN_AREA: |
| | 1384 | { |
| | 1385 | SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_AOE_DAMAGE); |
| | 1386 | }break; |
| | 1387 | case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: |
| | 1388 | m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; |
| | 1389 | case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: |
| | 1390 | { |
| | 1391 | SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_FRIENDLY); |
| | 1392 | }break; |
| | 1394 | m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; |
| | 1395 | case TARGET_UNIT_AREA_ENTRY: |
| | 1396 | { |
| | 1397 | SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); |
| | 1398 | SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); |
| | 1399 | if(lower==upper) |
| | 1400 | { |
| | 1401 | sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT, but does not have record in `spell_script_target`",m_spellInfo->Id); |
| | 1402 | break; |
| | 1403 | } |
| | 1404 | // let it be done in one check? |
| | 1405 | for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST) |
| | 1406 | { |
| | 1407 | if(i_spellST->second.type != SPELL_TARGET_TYPE_CREATURE) |
| | 1408 | { |
| | 1409 | sLog.outError( "SPELL: spell ID %u requires non-creature target\n", m_spellInfo->Id ); |
| | 1410 | continue; |
| | 1411 | } |
| | 1412 | SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry); |
| | 1413 | } |
| | 1414 | }break; |
| | 1415 | case TARGET_IN_FRONT_OF_CASTER: |
| | 1416 | { |
| | 1417 | bool inFront = m_spellInfo->SpellVisual != 3879; |
| | 1418 | SearchAreaTarget(TagUnitMap, radius, inFront ? PUSH_IN_FRONT : PUSH_IN_BACK,SPELL_TARGETS_AOE_DAMAGE); |
| | 1419 | }break; |
| | 1420 | |
| | 1421 | // nearby target |
| | 1422 | case TARGET_UNIT_NEARBY_ALLY: |
| | 1423 | { |
| | 1424 | if(Unit* pUnitTarget = SearchNearbyTarget(radius, SPELL_TARGETS_FRIENDLY)) |
| | 1425 | TagUnitMap.push_back(pUnitTarget); |
| | 1426 | }break; |
| | 1427 | case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA: |
| | 1428 | { |
| | 1429 | if(EffectChainTarget <= 1) |
| | 1430 | { |
| | 1431 | if(Unit* pUnitTarget = SearchNearbyTarget(radius, SPELL_TARGETS_AOE_DAMAGE)) |
| | 1432 | TagUnitMap.push_back(pUnitTarget); |
| | 1433 | } |
| | 1434 | else |
| | 1435 | SearchChainTarget(TagUnitMap, m_caster, radius, EffectChainTarget); |
| | 1436 | }break; |
| | 1437 | case TARGET_SCRIPT: |
| | 1438 | case TARGET_SCRIPT_COORDINATES: |
| | 1439 | { |
| | 1440 | SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); |
| | 1441 | SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); |
| | 1442 | if(lower==upper) |
| | 1443 | sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, but does not have record in `spell_script_target`",m_spellInfo->Id); |
| | 1444 | |
| | 1445 | SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); |
| | 1446 | float range = GetSpellMaxRange(srange); |
| | 1447 | |
| | 1448 | Creature* creatureScriptTarget = NULL; |
| | 1449 | GameObject* goScriptTarget = NULL; |
| | 1450 | |
| | 1451 | for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST) |
| | 1452 | { |
| | 1453 | switch(i_spellST->second.type) |
| | 1454 | { |
| | 1455 | case SPELL_TARGET_TYPE_GAMEOBJECT: |
| | 1456 | { |
| | 1457 | GameObject* p_GameObject = NULL; |
| | 1458 | |
| | 1459 | if(i_spellST->second.targetEntry) |
| | 1460 | { |
| | 1461 | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| | 1462 | Cell cell(p); |
| | 1463 | cell.data.Part.reserved = ALL_DISTRICT; |
| | 1464 | |
| | 1465 | Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range); |
| | 1466 | Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(p_GameObject,go_check); |
| | 1467 | |
| | 1468 | TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker); |
| | 1469 | CellLock<GridReadGuard> cell_lock(cell, p); |
| | 1470 | cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1471 | |
| | 1472 | if(p_GameObject) |
| | 1473 | { |
| | 1474 | // remember found target and range, next attempt will find more near target with another entry |
| | 1475 | creatureScriptTarget = NULL; |
| | 1476 | goScriptTarget = p_GameObject; |
| | 1477 | range = go_check.GetLastRange(); |
| | 1478 | } |
| | 1479 | } |
| | 1480 | else if( focusObject ) //Focus Object |
| | 1481 | { |
| | 1482 | float frange = m_caster->GetDistance(focusObject); |
| | 1483 | if(range >= frange) |
| | 1484 | { |
| | 1485 | creatureScriptTarget = NULL; |
| | 1486 | goScriptTarget = focusObject; |
| | 1487 | range = frange; |
| | 1488 | } |
| | 1489 | } |
| | 1490 | break; |
| | 1491 | } |
| | 1492 | case SPELL_TARGET_TYPE_CREATURE: |
| | 1493 | case SPELL_TARGET_TYPE_DEAD: |
| | 1494 | default: |
| | 1495 | { |
| | 1496 | Creature *p_Creature = NULL; |
| | 1497 | |
| | 1498 | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| | 1499 | Cell cell(p); |
| | 1500 | cell.data.Part.reserved = ALL_DISTRICT; |
| | 1501 | cell.SetNoCreate(); // Really don't know what is that??? |
| | 1502 | |
| | 1503 | Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range); |
| | 1504 | Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check); |
| | 1505 | |
| | 1506 | TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher); |
| | 1507 | |
| | 1508 | CellLock<GridReadGuard> cell_lock(cell, p); |
| | 1509 | cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| | 1510 | |
| | 1511 | if(p_Creature ) |
| | 1512 | { |
| | 1513 | creatureScriptTarget = p_Creature; |
| | 1514 | goScriptTarget = NULL; |
| | 1515 | range = u_check.GetLastRange(); |
| | 1516 | } |
| | 1517 | break; |
| | 1518 | } |
| | 1519 | } |
| | 1520 | } |
| | 1521 | |
| | 1522 | if(cur == TARGET_SCRIPT_COORDINATES) |
| | 1523 | { |
| | 1524 | if(creatureScriptTarget) |
| | 1525 | m_targets.setDestination(creatureScriptTarget->GetPositionX(),creatureScriptTarget->GetPositionY(),creatureScriptTarget->GetPositionZ()); |
| | 1526 | else if(goScriptTarget) |
| | 1527 | m_targets.setDestination(goScriptTarget->GetPositionX(),goScriptTarget->GetPositionY(),goScriptTarget->GetPositionZ()); |
| | 1528 | } |
| | 1529 | }break; |
| | 1530 | |
| | 1531 | |
| | 1532 | // dummy |
| 1301 | | case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA: |
| 1302 | | { |
| 1303 | | m_targets.m_targetMask = 0; |
| 1304 | | unMaxTargets = EffectChainTarget; |
| 1305 | | float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; |
| 1306 | | |
| 1307 | | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| 1308 | | Cell cell(p); |
| 1309 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1310 | | cell.SetNoCreate(); |
| 1311 | | |
| 1312 | | std::list<Unit *> tempUnitMap; |
| 1313 | | |
| 1314 | | { |
| 1315 | | Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(m_caster, m_caster, max_range); |
| 1316 | | Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check); |
| 1317 | | |
| 1318 | | TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); |
| 1319 | | TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); |
| 1320 | | |
| 1321 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1322 | | cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1323 | | cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1324 | | } |
| 1325 | | |
| 1326 | | if(tempUnitMap.empty()) |
| 1327 | | break; |
| 1328 | | |
| 1329 | | tempUnitMap.sort(TargetDistanceOrder(m_caster)); |
| 1330 | | |
| 1331 | | //Now to get us a random target that's in the initial range of the spell |
| 1332 | | uint32 t = 0; |
| 1333 | | std::list<Unit *>::iterator itr = tempUnitMap.begin(); |
| 1334 | | while(itr!= tempUnitMap.end() && (*itr)->GetDistance(m_caster) < radius) |
| 1335 | | ++t, ++itr; |
| 1336 | | |
| 1337 | | if(!t) |
| 1338 | | break; |
| 1339 | | |
| 1340 | | itr = tempUnitMap.begin(); |
| 1341 | | std::advance(itr, rand()%t); |
| 1342 | | Unit *pUnitTarget = *itr; |
| 1343 | | TagUnitMap.push_back(pUnitTarget); |
| 1344 | | |
| 1345 | | tempUnitMap.erase(itr); |
| 1346 | | |
| 1347 | | tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); |
| 1348 | | |
| 1349 | | t = unMaxTargets - 1; |
| 1350 | | Unit *prev = pUnitTarget; |
| 1351 | | std::list<Unit*>::iterator next = tempUnitMap.begin(); |
| 1352 | | |
| 1353 | | while(t && next != tempUnitMap.end() ) |
| 1354 | | { |
| 1355 | | if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) |
| 1356 | | break; |
| 1357 | | |
| 1358 | | if(!prev->IsWithinLOSInMap(*next)) |
| 1359 | | { |
| 1360 | | ++next; |
| 1361 | | continue; |
| 1362 | | } |
| 1363 | | |
| 1364 | | prev = *next; |
| 1365 | | TagUnitMap.push_back(prev); |
| 1366 | | tempUnitMap.erase(next); |
| 1367 | | tempUnitMap.sort(TargetDistanceOrder(prev)); |
| 1368 | | next = tempUnitMap.begin(); |
| 1369 | | |
| 1370 | | --t; |
| 1371 | | } |
| 1372 | | }break; |
| 1373 | | case TARGET_PET: |
| 1374 | | { |
| 1375 | | Pet* tmpUnit = m_caster->GetPet(); |
| 1376 | | if (!tmpUnit) break; |
| 1377 | | TagUnitMap.push_back(tmpUnit); |
| 1378 | | break; |
| 1379 | | } |
| 1380 | | case TARGET_CHAIN_DAMAGE: |
| 1381 | | { |
| 1382 | | if (EffectChainTarget <= 1) |
| 1383 | | { |
| 1384 | | Unit* pUnitTarget = SelectMagnetTarget(); |
| 1385 | | if(pUnitTarget) |
| 1386 | | TagUnitMap.push_back(pUnitTarget); |
| 1387 | | } |
| 1388 | | else |
| 1389 | | { |
| 1390 | | Unit* pUnitTarget = m_targets.getUnitTarget(); |
| 1391 | | if(!pUnitTarget) |
| 1392 | | break; |
| 1393 | | |
| 1394 | | unMaxTargets = EffectChainTarget; |
| 1395 | | |
| 1396 | | float max_range; |
| 1397 | | if(m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE) |
| 1398 | | max_range = radius; // |
| 1399 | | else |
| 1400 | | //FIXME: This very like horrible hack and wrong for most spells |
| 1401 | | max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; |
| 1402 | | |
| 1403 | | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| 1404 | | Cell cell(p); |
| 1405 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1406 | | cell.SetNoCreate(); |
| 1407 | | |
| 1408 | | Unit* originalCaster = GetOriginalCaster(); |
| 1409 | | if(originalCaster) |
| 1410 | | { |
| 1411 | | std::list<Unit *> tempUnitMap; |
| 1412 | | |
| 1413 | | { |
| 1414 | | Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(pUnitTarget, originalCaster, max_range); |
| 1415 | | Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check); |
| 1416 | | |
| 1417 | | TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); |
| 1418 | | TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); |
| 1419 | | |
| 1420 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1421 | | cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1422 | | cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1423 | | } |
| 1424 | | |
| 1425 | | tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); |
| 1426 | | |
| 1427 | | if(tempUnitMap.empty()) |
| 1428 | | break; |
| 1429 | | |
| 1430 | | if(*tempUnitMap.begin() == pUnitTarget) |
| 1431 | | tempUnitMap.erase(tempUnitMap.begin()); |
| 1432 | | |
| 1433 | | TagUnitMap.push_back(pUnitTarget); |
| 1434 | | uint32 t = unMaxTargets - 1; |
| 1435 | | Unit *prev = pUnitTarget; |
| 1436 | | std::list<Unit*>::iterator next = tempUnitMap.begin(); |
| 1437 | | |
| 1438 | | while(t && next != tempUnitMap.end() ) |
| 1439 | | { |
| 1440 | | if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) |
| 1441 | | break; |
| 1442 | | |
| 1443 | | if(!prev->IsWithinLOSInMap(*next)) |
| 1444 | | { |
| 1445 | | ++next; |
| 1446 | | continue; |
| 1447 | | } |
| 1448 | | |
| 1449 | | prev = *next; |
| 1450 | | TagUnitMap.push_back(prev); |
| 1451 | | tempUnitMap.erase(next); |
| 1452 | | tempUnitMap.sort(TargetDistanceOrder(prev)); |
| 1453 | | next = tempUnitMap.begin(); |
| 1454 | | |
| 1455 | | --t; |
| 1456 | | } |
| 1457 | | } |
| 1458 | | } |
| 1459 | | }break; |
| 1460 | | case TARGET_ALL_ENEMY_IN_AREA: |
| 1461 | | { |
| 1462 | | }break; |
| 1463 | | case TARGET_ALL_ENEMY_IN_AREA_INSTANT: |
| 1464 | | { |
| 1465 | | // targets the ground, not the units in the area |
| 1466 | | if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) |
| 1467 | | { |
| 1468 | | CellPair p(Trinity::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); |
| 1469 | | Cell cell(p); |
| 1470 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1471 | | cell.SetNoCreate(); |
| 1472 | | |
| 1473 | | Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_AOE_DAMAGE); |
| 1474 | | |
| 1475 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); |
| 1476 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); |
| 1477 | | |
| 1478 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1479 | | cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1480 | | cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1481 | | |
| 1482 | | // exclude caster (this can be important if this not original caster) |
| 1483 | | TagUnitMap.remove(m_caster); |
| 1484 | | } |
| 1485 | | }break; |
| 1486 | | case TARGET_DUELVSPLAYER_COORDINATES: |
| 1487 | | { |
| 1488 | | if(Unit* currentTarget = m_targets.getUnitTarget()) |
| 1489 | | { |
| 1490 | | m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ()); |
| 1491 | | TagUnitMap.push_back(currentTarget); |
| 1492 | | } |
| 1493 | | }break; |
| | 1538 | |
| 1536 | | }break; |
| 1537 | | case TARGET_SINGLE_FRIEND: |
| 1538 | | case TARGET_SINGLE_FRIEND_2: |
| 1539 | | { |
| 1540 | | if(m_targets.getUnitTarget()) |
| 1541 | | TagUnitMap.push_back(m_targets.getUnitTarget()); |
| 1542 | | }break; |
| 1543 | | case TARGET_NONCOMBAT_PET: |
| 1544 | | { |
| 1545 | | if(Unit* target = m_targets.getUnitTarget()) |
| 1546 | | if( target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && ((Pet*)target)->getPetType() == MINI_PET) |
| 1547 | | TagUnitMap.push_back(target); |
| 1548 | | }break; |
| 1549 | | case TARGET_ALL_AROUND_CASTER: |
| 1550 | | { |
| 1551 | | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| 1552 | | Cell cell(p); |
| 1553 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1554 | | cell.SetNoCreate(); |
| 1555 | | |
| 1556 | | Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_AOE_DAMAGE); |
| 1557 | | |
| 1558 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); |
| 1559 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); |
| 1560 | | |
| 1561 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1562 | | cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1563 | | cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1564 | | }break; |
| 1565 | | case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: |
| 1566 | | { |
| 1567 | | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| 1568 | | Cell cell(p); |
| 1569 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1570 | | cell.SetNoCreate(); |
| 1571 | | |
| 1572 | | Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_FRIENDLY); |
| 1573 | | |
| 1574 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); |
| 1575 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); |
| 1576 | | |
| 1577 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1578 | | cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1579 | | cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1580 | | }break; |
| 1581 | | case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: |
| 1582 | | { |
| 1583 | | CellPair p(Trinity::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); |
| 1584 | | Cell cell(p); |
| 1585 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1586 | | cell.SetNoCreate(); |
| 1587 | | |
| 1588 | | Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_FRIENDLY); |
| 1589 | | |
| 1590 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); |
| 1591 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); |
| 1592 | | |
| 1593 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1594 | | cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1595 | | cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1652 | | case TARGET_GAMEOBJECT: |
| 1653 | | { |
| 1654 | | if(m_targets.getGOTarget()) |
| 1655 | | AddGOTarget(m_targets.getGOTarget(), i); |
| 1656 | | }break; |
| 1657 | | case TARGET_IN_FRONT_OF_CASTER: |
| 1658 | | { |
| 1659 | | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| 1660 | | Cell cell(p); |
| 1661 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1662 | | cell.SetNoCreate(); |
| 1663 | | |
| 1664 | | bool inFront = m_spellInfo->SpellVisual != 3879; |
| 1665 | | Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, inFront ? PUSH_IN_FRONT : PUSH_IN_BACK,SPELL_TARGETS_AOE_DAMAGE); |
| 1666 | | |
| 1667 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); |
| 1668 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); |
| 1669 | | |
| 1670 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1671 | | cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1672 | | cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1673 | | }break; |
| 1674 | | case TARGET_DUELVSPLAYER: |
| 1675 | | { |
| 1676 | | Unit *target = m_targets.getUnitTarget(); |
| 1677 | | if(target) |
| 1678 | | { |
| 1679 | | if(m_caster->IsFriendlyTo(target)) |
| 1680 | | { |
| 1681 | | TagUnitMap.push_back(target); |
| 1682 | | } |
| 1683 | | else |
| 1684 | | { |
| 1685 | | Unit* pUnitTarget = SelectMagnetTarget(); |
| 1686 | | if(pUnitTarget) |
| 1687 | | TagUnitMap.push_back(pUnitTarget); |
| 1688 | | } |
| 1689 | | } |
| 1690 | | }break; |
| 1691 | | case TARGET_GAMEOBJECT_ITEM: |
| 1692 | | { |
| 1693 | | if(m_targets.getGOTargetGUID()) |
| 1694 | | AddGOTarget(m_targets.getGOTarget(), i); |
| 1695 | | else if(m_targets.getItemTarget()) |
| 1696 | | AddItemTarget(m_targets.getItemTarget(), i); |
| 1697 | | break; |
| 1698 | | } |
| 1699 | | case TARGET_MASTER: |
| 1700 | | { |
| 1701 | | if(Unit* owner = m_caster->GetCharmerOrOwner()) |
| 1702 | | TagUnitMap.push_back(owner); |
| 1703 | | break; |
| 1704 | | } |
| 1885 | | } |
| 1886 | | } |
| 1887 | | }break; |
| 1888 | | case TARGET_CURRENT_ENEMY_COORDINATES: |
| 1889 | | { |
| 1890 | | Unit* currentTarget = m_targets.getUnitTarget(); |
| 1891 | | if(currentTarget) |
| 1892 | | { |
| 1893 | | TagUnitMap.push_back(currentTarget); |
| 1894 | | m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ()); |
| 1895 | | if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA_INSTANT) |
| 1896 | | { |
| 1897 | | CellPair p(Trinity::ComputeCellPair(currentTarget->GetPositionX(), currentTarget->GetPositionY())); |
| 1898 | | Cell cell(p); |
| 1899 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1900 | | cell.SetNoCreate(); |
| 1901 | | Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_TARGET_CENTER, SPELL_TARGETS_AOE_DAMAGE); |
| 1902 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_notifier(notifier); |
| 1903 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_notifier(notifier); |
| 1904 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1905 | | cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1906 | | cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1935 | | case TARGET_TABLE_X_Y_Z_COORDINATES: |
| 1936 | | { |
| 1937 | | SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); |
| 1938 | | if(st) |
| 1939 | | { |
| 1940 | | if (st->target_mapId == m_caster->GetMapId()) |
| 1941 | | m_targets.setDestination(st->target_X, st->target_Y, st->target_Z); |
| 1942 | | |
| 1943 | | // if B==TARGET_TABLE_X_Y_Z_COORDINATES then A already fill all required targets |
| 1944 | | if (m_spellInfo->EffectImplicitTargetB[i] && m_spellInfo->EffectImplicitTargetB[i]!=TARGET_TABLE_X_Y_Z_COORDINATES) |
| 1945 | | { |
| 1946 | | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| 1947 | | Cell cell(p); |
| 1948 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 1949 | | cell.SetNoCreate(); |
| 1950 | | |
| 1951 | | SpellTargets targetB = SPELL_TARGETS_AOE_DAMAGE; |
| 1952 | | // Select friendly targets for positive effect |
| 1953 | | if (IsPositiveEffect(m_spellInfo->Id, i)) |
| 1954 | | targetB = SPELL_TARGETS_FRIENDLY; |
| 1955 | | |
| 1956 | | Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_DEST_CENTER, targetB); |
| 1957 | | |
| 1958 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_notifier(notifier); |
| 1959 | | TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_notifier(notifier); |
| 1960 | | |
| 1961 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 1962 | | cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1963 | | cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 1964 | | } |
| 1965 | | } |
| | 1834 | |
| | 1835 | // destination around caster |
| | 1836 | case TARGET_DEST_CASTER_FRONT_LEFT: |
| | 1837 | case TARGET_DEST_CASTER_BACK_LEFT: |
| | 1838 | case TARGET_DEST_CASTER_BACK_RIGHT: |
| | 1839 | case TARGET_DEST_CASTER_FRONT_RIGHT: |
| | 1840 | case TARGET_DEST_CASTER_FRONT: |
| | 1841 | case TARGET_DEST_CASTER_BACK: |
| | 1842 | case TARGET_DEST_CASTER_RIGHT: |
| | 1843 | case TARGET_DEST_CASTER_LEFT: |
| | 1844 | case TARGET_DEST_CASTER_RANDOM: |
| | 1845 | case TARGET_DEST_CASTER_RADIUS: |
| | 1846 | { |
| | 1847 | float x, y, z, angle, dist; |
| | 1848 | |
| | 1849 | if (m_spellInfo->EffectRadiusIndex[i]) |
| | 1850 | dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); |
| 1967 | | sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id ); |
| | 1852 | dist = 3.0f;//do we need this? |
| | 1853 | if (cur == TARGET_DEST_CASTER_RANDOM) |
| | 1854 | dist *= rand_norm(); // This case we need to consider caster size |
| | 1855 | else |
| | 1856 | dist -= m_caster->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it |
| | 1857 | //need a new function to remove this repeated work |
| | 1858 | |
| | 1859 | switch(cur) |
| | 1860 | { |
| | 1861 | case TARGET_DEST_CASTER_FRONT_LEFT: angle = -M_PI/4; break; |
| | 1862 | case TARGET_DEST_CASTER_BACK_LEFT: angle = -3*M_PI/4; break; |
| | 1863 | case TARGET_DEST_CASTER_BACK_RIGHT: angle = 3*M_PI/4; break; |
| | 1864 | case TARGET_DEST_CASTER_FRONT_RIGHT:angle = M_PI/4; break; |
| | 1865 | case TARGET_DEST_CASTER_FRONT: angle = 0.0f; break; |
| | 1866 | case TARGET_DEST_CASTER_BACK: angle = M_PI; break; |
| | 1867 | case TARGET_DEST_CASTER_RIGHT: angle = M_PI/2; break; |
| | 1868 | case TARGET_DEST_CASTER_LEFT: angle = -M_PI/2; break; |
| | 1869 | default: angle = rand_norm()*2*M_PI; break; |
| | 1870 | } |
| | 1871 | |
| | 1872 | m_caster->GetClosePoint(x, y, z, 0, dist, angle); |
| | 1873 | m_targets.setDestination(x, y, z); // do not know if has ground visual |
| | 1875 | |
| | 1876 | // destination around target |
| | 1877 | case TARGET_DEST_TARGET_FRONT: |
| | 1878 | case TARGET_DEST_TARGET_BACK: |
| | 1879 | case TARGET_DEST_TARGET_RIGHT: |
| | 1880 | case TARGET_DEST_TARGET_LEFT: |
| | 1881 | case TARGET_DEST_TARGET_RANDOM: |
| | 1882 | case TARGET_DEST_TARGET_RADIUS: |
| | 1883 | { |
| | 1884 | Unit *target = m_targets.getUnitTarget(); |
| | 1885 | if(!target) |
| | 1886 | { |
| | 1887 | sLog.outError("SPELL: no unit target for spell ID %u\n", m_spellInfo->Id); |
| | 1888 | break; |
| | 1889 | } |
| | 1890 | |
| | 1891 | float x, y, z, angle, dist; |
| | 1892 | |
| | 1893 | if (m_spellInfo->EffectRadiusIndex[i]) |
| | 1894 | dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); |
| | 1895 | else |
| | 1896 | dist = 3.0f;//do we need this? |
| | 1897 | if (cur == TARGET_DEST_TARGET_RANDOM) |
| | 1898 | dist *= rand_norm(); // This case we need to consider caster size |
| | 1899 | else |
| | 1900 | dist -= target->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it |
| | 1901 | //need a new function to remove this repeated work |
| | 1902 | |
| | 1903 | switch(cur) |
| | 1904 | { |
| | 1905 | case TARGET_DEST_TARGET_FRONT: angle = 0.0f; break; |
| | 1906 | case TARGET_DEST_TARGET_BACK: angle = M_PI; break; |
| | 1907 | case TARGET_DEST_TARGET_RIGHT: angle = M_PI/2; break; |
| | 1908 | case TARGET_DEST_TARGET_LEFT: angle = -M_PI/2; break; |
| | 1909 | default: angle = rand_norm()*2*M_PI; break; |
| | 1910 | } |
| | 1911 | |
| | 1912 | target->GetClosePoint(x, y, z, 0, dist, angle); |
| | 1913 | m_targets.setDestination(x, y, z); // do not know if has ground visual |
| | 1914 | }break; |
| | 1915 | |
| | 1916 | // destination around destination |
| | 1917 | case TARGET_DEST_DEST_RANDOM: |
| | 1918 | { |
| | 1919 | if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) |
| | 1920 | { |
| | 1921 | sLog.outError("SPELL: no destination for spell ID %u\n", m_spellInfo->Id); |
| | 1922 | break; |
| | 1923 | } |
| | 1924 | float x, y, z, dist, px, py, pz; |
| | 1925 | dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); |
| | 1926 | x = m_targets.m_destX; |
| | 1927 | y = m_targets.m_destY; |
| | 1928 | z = m_targets.m_destZ; |
| | 1929 | m_caster->GetRandomPoint(x, y, z, dist, px, py, pz); |
| | 1930 | m_targets.setDestination(px, py, pz); |
| | 1931 | }break; |
| | 1932 | case TARGET_SELF2: |
| | 1933 | break; |
| 3441 | | //ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38 |
| 3442 | | if(m_UniqueTargetInfo.empty()) // skip second canCast apply (for delayed spells for example) |
| 3443 | | { |
| 3444 | | for(uint8 j = 0; j < 3; j++) |
| 3445 | | { |
| 3446 | | if( m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || |
| 3447 | | m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[j] != TARGET_SELF || |
| 3448 | | m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || |
| 3449 | | m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) |
| 3450 | | { |
| 3451 | | bool okDoo = false; |
| 3452 | | |
| 3453 | | SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); |
| 3454 | | SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); |
| 3455 | | if(lower==upper) |
| 3456 | | sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, but does not have record in `spell_script_target`",m_spellInfo->Id); |
| 3457 | | |
| 3458 | | SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); |
| 3459 | | float range = GetSpellMaxRange(srange); |
| 3460 | | |
| 3461 | | Creature* creatureScriptTarget = NULL; |
| 3462 | | GameObject* goScriptTarget = NULL; |
| 3463 | | |
| 3464 | | for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST) |
| 3465 | | { |
| 3466 | | switch(i_spellST->second.type) |
| 3467 | | { |
| 3468 | | case SPELL_TARGET_TYPE_GAMEOBJECT: |
| 3469 | | { |
| 3470 | | GameObject* p_GameObject = NULL; |
| 3471 | | |
| 3472 | | if(i_spellST->second.targetEntry) |
| 3473 | | { |
| 3474 | | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| 3475 | | Cell cell(p); |
| 3476 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 3477 | | |
| 3478 | | Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range); |
| 3479 | | Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(p_GameObject,go_check); |
| 3480 | | |
| 3481 | | TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker); |
| 3482 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 3483 | | cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 3484 | | |
| 3485 | | if(p_GameObject) |
| 3486 | | { |
| 3487 | | // remember found target and range, next attempt will find more near target with another entry |
| 3488 | | creatureScriptTarget = NULL; |
| 3489 | | goScriptTarget = p_GameObject; |
| 3490 | | range = go_check.GetLastRange(); |
| 3491 | | } |
| 3492 | | } |
| 3493 | | else if( focusObject ) //Focus Object |
| 3494 | | { |
| 3495 | | float frange = m_caster->GetDistance(focusObject); |
| 3496 | | if(range >= frange) |
| 3497 | | { |
| 3498 | | creatureScriptTarget = NULL; |
| 3499 | | goScriptTarget = focusObject; |
| 3500 | | range = frange; |
| 3501 | | } |
| 3502 | | } |
| 3503 | | break; |
| 3504 | | } |
| 3505 | | case SPELL_TARGET_TYPE_CREATURE: |
| 3506 | | case SPELL_TARGET_TYPE_DEAD: |
| 3507 | | default: |
| 3508 | | { |
| 3509 | | Creature *p_Creature = NULL; |
| 3510 | | |
| 3511 | | CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); |
| 3512 | | Cell cell(p); |
| 3513 | | cell.data.Part.reserved = ALL_DISTRICT; |
| 3514 | | cell.SetNoCreate(); // Really don't know what is that??? |
| 3515 | | |
| 3516 | | Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range); |
| 3517 | | Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check); |
| 3518 | | |
| 3519 | | TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher); |
| 3520 | | |
| 3521 | | CellLock<GridReadGuard> cell_lock(cell, p); |
| 3522 | | cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); |
| 3523 | | |
| 3524 | | if(p_Creature ) |
| 3525 | | { |
| 3526 | | creatureScriptTarget = p_Creature; |
| 3527 | | goScriptTarget = NULL; |
| 3528 | | range = u_check.GetLastRange(); |
| 3529 | | } |
| 3530 | | break; |
| 3531 | | } |
| 3532 | | } |
| 3533 | | } |
| 3534 | | |
| 3535 | | if(creatureScriptTarget) |
| 3536 | | { |
| 3537 | | // store coordinates for TARGET_SCRIPT_COORDINATES |
| 3538 | | if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || |
| 3539 | | m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) |
| 3540 | | { |
| 3541 | | m_targets.setDestination(creatureScriptTarget->GetPositionX(),creatureScriptTarget->GetPositionY(),creatureScriptTarget->GetPositionZ()); |
| 3542 | | |
| 3543 | | if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) |
| 3544 | | AddUnitTarget(creatureScriptTarget, j); |
| 3545 | | } |
| 3546 | | // store explicit target for TARGET_SCRIPT |
| 3547 | | else |
| 3548 | | AddUnitTarget(creatureScriptTarget, j); |
| 3549 | | } |
| 3550 | | else if(goScriptTarget) |
| 3551 | | { |
| 3552 | | // store coordinates for TARGET_SCRIPT_COORDINATES |
| 3553 | | if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || |
| 3554 | | m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) |
| 3555 | | { |
| 3556 | | m_targets.setDestination(goScriptTarget->GetPositionX(),goScriptTarget->GetPositionY(),goScriptTarget->GetPositionZ()); |
| 3557 | | |
| 3558 | | if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) |
| 3559 | | AddGOTarget(goScriptTarget, j); |
| 3560 | | } |
| 3561 | | // store explicit target for TARGET_SCRIPT |
| 3562 | | else |
| 3563 | | AddGOTarget(goScriptTarget, j); |
| 3564 | | } |
| 3565 | | //Missing DB Entry or targets for this spellEffect. |
| 3566 | | else |
| 3567 | | { |
| 3568 | | // not report target not existence for triggered spells |
| 3569 | | if(m_triggeredByAuraSpell || m_IsTriggeredSpell) |
| 3570 | | return SPELL_FAILED_DONT_REPORT; |
| 3571 | | else |
| 3572 | | return SPELL_FAILED_BAD_TARGETS; |
| 3573 | | } |
| 3574 | | } |
| 3575 | | } |
| 3576 | | } |
| 3577 | | |