/// Spell Target Handling for type 24: Targets in Front of the Caster void Spell::SpellTargetInFrontOfCaster(uint32 i, uint32 j) { TargetsList* tmpMap=&m_targetUnits[i]; std::set<Object*>::iterator itr; uint8 did_hit_result; m_caster->AquireInrangeLock(); //make sure to release lock before exit function ! for( itr = m_caster->GetInRangeSetBegin(); itr != m_caster->GetInRangeSetEnd(); itr++ ) { if(!((*itr)->IsUnit()) || !((Unit*)(*itr))->isAlive()) continue; //is Creature in range if(m_caster->isInRange((Unit*)(*itr),GetRadius(i))) { if (sWorld.Collision) { if (m_caster->GetMapId() == (*itr)->GetMapId() && !CollideInterface.CheckLOS(m_caster->GetMapId(),m_caster->GetPositionNC(),(*itr)->GetPositionNC())) continue; } if( m_spellInfo->cone_width ? m_caster->isInArc( (Unit*)(*itr) , m_spellInfo->cone_width ) : m_caster->isInFront((Unit*)(*itr)) ) // !!! is the target within our cone ? { if(isAttackable(u_caster, (Unit*)(*itr))) { did_hit_result = DidHit(i,((Unit*)*itr)); if(did_hit_result==SPELL_DID_HIT_SUCCESS) SafeAddTarget(tmpMap,(*itr)->GetGUID()); else SafeAddModeratedTarget((*itr)->GetGUID(), did_hit_result); } } } } m_caster->ReleaseInrangeLock(); }
/// Spell Target Handling for type 54: Targets in Front of the Caster void Spell::SpellTargetInFrontOfCaster2(uint32 i, uint32 j) { TargetsList* tmpMap=&m_targetUnits[i]; std::set<Object*>::iterator itr,itr2; uint8 did_hit_result; m_caster->AquireInrangeLock(); //make sure to release lock before exit function ! for( itr2 = m_caster->GetInRangeSetBegin(); itr2 != m_caster->GetInRangeSetEnd();) { itr = itr2; itr2++; if(!((*itr)->IsUnit()) || !((Unit*)(*itr))->isAlive()) continue; //is Creature in range if(m_caster->isInRange((Unit*)(*itr),GetRadius(i))) { if(m_caster->isInFront((Unit*)(*itr))) { if(isAttackable(u_caster, (Unit*)(*itr))) { did_hit_result = DidHit(i,((Unit*)*itr)); if(did_hit_result==SPELL_DID_HIT_SUCCESS) SafeAddTarget(tmpMap,(*itr)->GetGUID()); else SafeAddModeratedTarget((*itr)->GetGUID(), did_hit_result); } } } } m_caster->ReleaseInrangeLock(); }
/// Spell Target Handling for type 25: Single Target Friend // Used o.a. in Duel void Spell::SpellTargetSingleFriend(uint32 i, uint32 j) { if( !m_caster->IsInWorld() ) return; TargetsList* tmpMap=&m_targetUnits[i]; Unit *target = m_caster->GetMapMgr()->GetUnit((uint32)m_targets.m_unitTarget); if( target != NULL && isAttackable(u_caster, target) ) { uint8 did_hit_result = DidHit(i,target); if(did_hit_result==SPELL_DID_HIT_SUCCESS) SafeAddTarget(tmpMap, m_targets.m_unitTarget); else SafeAddModeratedTarget(m_targets.m_unitTarget, did_hit_result); } else { SafeAddTarget(tmpMap,m_targets.m_unitTarget); } }
/// Spell Target Handling for type 6 and 77: Single Target Enemy (grep thinks 77 fits in 6) void Spell::SpellTargetSingleTargetEnemy(uint32 i, uint32 j) { if(!m_caster->IsInWorld()) return; Unit * pTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!pTarget) return; if(p_caster && p_caster == pTarget) // spell bug: target is supposed to be a single enemy, not self { if(GetProto()) sLog.outDebug("Spell %lu has target single enemy, but is targeting the caster.", GetProto()->Id); } TargetsList* tmpMap=&m_targetUnits[i]; if(m_spellInfo->TargetCreatureType && pTarget->GetTypeId()==TYPEID_UNIT) { Creature* cr = static_cast< Creature* >( pTarget ); if( cr == NULL ) return; if( cr->GetCreatureInfo() ) if(!(1<<(cr->GetCreatureInfo()->Type-1) & m_spellInfo->TargetCreatureType)) return; } if(p_caster && pTarget != p_caster) { // this is mostly used for things like duels if(pTarget->IsPlayer() && !isAttackable(p_caster, pTarget, false)) { cancastresult = SPELL_FAILED_BAD_TARGETS; return; } /* HACK FIX */ /* Please replace if found correct way */ /* SPELL_AURA_SPELL_MAGNET */ int x; for( x = 0; x < 3; ++x ) if( m_spellInfo->EffectApplyAuraName[x] == SPELL_AURA_MOD_POSSESS || m_spellInfo->is_melee_spell ) break; if( pTarget && x == 3 && pTarget->m_magnetcaster != 0) { Unit *MagnetTarget = pTarget->GetMapMgr()->GetUnit(pTarget->m_magnetcaster); if ( MagnetTarget && m_spellInfo->School ) { m_magnetTarget = pTarget->m_magnetcaster; pTarget = MagnetTarget; // Redirected } } } uint8 did_hit_result = DidHit(i,pTarget); if(did_hit_result != SPELL_DID_HIT_SUCCESS) SafeAddModeratedTarget(pTarget->GetGUID(), did_hit_result); else SafeAddTarget(tmpMap, pTarget->GetGUID()); if( m_spellInfo->EffectChainTarget[i] ) { //number of additional targets uint32 jumps = m_spellInfo->EffectChainTarget[i] - 1; // extra targets by auras if( u_caster ) SM_FIValue( u_caster->SM_FAdditionalTargets,(int32*)&jumps, m_spellInfo->SpellGroupType ); float range = GetMaxRange( dbcSpellRange.LookupEntry( m_spellInfo->rangeIndex ) );//this is probably wrong range *= range; std::set<Object*>::iterator itr,itr2; m_caster->AquireInrangeLock(); //make sure to release lock before exit function ! for( itr2 = m_caster->GetInRangeSetBegin(); itr2 != m_caster->GetInRangeSetEnd(); ) { itr = itr2; itr2++; if((*itr)->GetGUID()==m_targets.m_unitTarget) continue; if( !((*itr)->IsUnit()) || !((Unit*)(*itr))->isAlive() || ((*itr)->IsCreature() && ((Creature*)(*itr))->IsTotem())) continue; if( sWorld.Collision && u_caster != NULL ) { if (u_caster->GetMapId() == (*itr)->GetMapId() && !CollideInterface.CheckLOS(u_caster->GetMapId(),u_caster->GetPositionNC(),(*itr)->GetPositionNC())) continue; } if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),(*itr),range)) { if(isAttackable(u_caster,(Unit*)(*itr))) { did_hit_result = DidHit(i,((Unit*)*itr)); if(did_hit_result==SPELL_DID_HIT_SUCCESS) SafeAddTarget(tmpMap, (*itr)->GetGUID()); else SafeAddModeratedTarget((*itr)->GetGUID(), did_hit_result); if(!--jumps) { m_caster->ReleaseInrangeLock(); return; } } } } m_caster->ReleaseInrangeLock(); } }
bool Spell::AddTarget(uint32 i, uint32 TargetType, Object* obj) { TargetsList* t = &m_targetUnits[i]; if(obj == NULL || !obj->IsInWorld()) return false; //GO target, not item if((TargetType & SPELL_TARGET_REQUIRE_GAMEOBJECT) && !(TargetType & SPELL_TARGET_REQUIRE_ITEM) && !obj->IsGameObject()) return false; //target go, not able to target go if(obj->IsGameObject() && !(TargetType & SPELL_TARGET_OBJECT_SCRIPTED) && !(TargetType & SPELL_TARGET_REQUIRE_GAMEOBJECT) && !m_triggeredSpell) return false; //target item, not able to target item if(obj->IsItem() && !(TargetType & SPELL_TARGET_REQUIRE_ITEM) && !m_triggeredSpell) return false; if(u_caster != NULL && u_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9) && ((obj->IsPlayer() || obj->IsPet()) || (p_caster != NULL || m_caster->IsPet()))) return false; if(TargetType & SPELL_TARGET_REQUIRE_FRIENDLY && !isFriendly(m_caster, obj)) return false; if(TargetType & SPELL_TARGET_REQUIRE_ATTACKABLE && !isAttackable(m_caster, obj)) return false; if(TargetType & SPELL_TARGET_OBJECT_TARCLASS) { Object* originaltarget = m_caster->GetMapMgr()->_GetObject(m_targets.m_unitTarget); if(originaltarget == NULL || (originaltarget->IsPlayer() && obj->IsPlayer() && TO_PLAYER(originaltarget)->getClass() != TO_PLAYER(obj)->getClass()) || (originaltarget->IsPlayer() && !obj->IsPlayer()) || (!originaltarget->IsPlayer() && obj->IsPlayer())) return false; } if(TargetType & SPELL_TARGET_OBJECT_CURPET && !obj->IsPet()) return false; if(TargetType & (SPELL_TARGET_AREA | SPELL_TARGET_AREA_SELF | SPELL_TARGET_AREA_CURTARGET | SPELL_TARGET_AREA_CONE | SPELL_TARGET_AREA_PARTY | SPELL_TARGET_AREA_RAID) && ((obj->IsUnit() && !TO_UNIT(obj)->isAlive()) || (obj->IsCreature() && obj->IsTotem()))) return false; uint8 hitresult = TargetType & SPELL_TARGET_REQUIRE_ATTACKABLE && obj->IsUnit() ? DidHit(i, TO_UNIT(obj)) : SPELL_DID_HIT_SUCCESS; if(hitresult != SPELL_DID_HIT_SUCCESS) { uint8 extended = 0; if(hitresult == SPELL_DID_HIT_REFLECT && u_caster != NULL) { //for checks Unit* tmp = u_caster; u_caster = TO_UNIT(obj); extended = DidHit(i, tmp); u_caster = tmp; } ModeratedTargets.push_back(SpellTargetMod(obj->GetGUID(), hitresult)); return false; } else { //check target isnt already in for(TargetsList::iterator itr = m_targetUnits[i].begin(); itr != m_targetUnits[i].end(); ++itr) { if(obj->GetGUID() == *itr) return false; } t->push_back(obj->GetGUID()); } //final checks, require line of sight unless range/radius is 50000 yards SpellRange* r = dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex); if(sWorld.Collision && r->maxRange < 50000 && GetRadius(i) < 50000 && !obj->IsItem()) { float x = m_caster->GetPositionX(), y = m_caster->GetPositionY(), z = m_caster->GetPositionZ() + 0.5f; //are we using a different location? if(TargetType & SPELL_TARGET_AREA) { x = m_targets.m_destX; y = m_targets.m_destY; z = m_targets.m_destZ; } else if(TargetType & SPELL_TARGET_AREA_CHAIN) { //TODO: Add support for this in arcemu /*Object* lasttarget = NULL; if (m_orderedObjects.size() > 0) { lasttarget = m_caster->GetMapMgr()->_GetObject(m_orderedObjects[m_orderedObjects.size() - 1]); if (lasttarget != NULL) { x = lasttarget->GetPositionX(); y = lasttarget->GetPositionY(); z = lasttarget->GetPositionZ(); } }*/ } if(!CollideInterface.CheckLOS(m_caster->GetMapId(), x, y, z + 2, obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ() + 2)) return false; } return true; }