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 | | |