/// Spell Target Handling for type 37: all Members of the targets party void Spell::SpellTargetPartyMember(uint32 i, uint32 j) { if(!m_caster->IsInWorld()) return; TargetsList* tmpMap=&m_targetUnits[i]; // if no group target self Player * Target = m_caster->GetMapMgr()->GetPlayer((uint32)m_targets.m_unitTarget); if(!Target) return; SubGroup * subgroup = Target->GetGroup() ? Target->GetGroup()->GetSubGroup(Target->GetSubGroup()) : 0; float rsqr = GetRadius( i ); if( rsqr == 0 ) rsqr = 40*40;//kinda like a bug. 0 range to target a party member ? Highly impossible else rsqr *= rsqr; if(subgroup) { Target->GetGroup()->Lock(); for(GroupMembersSet::iterator itr = subgroup->GetGroupMembersBegin(); itr != subgroup->GetGroupMembersEnd(); ++itr) //if you are picky you could also check if on same map. Let's face it you won't similar positions on different maps if((*itr)->m_loggedInPlayer && IsInrange(Target,(*itr)->m_loggedInPlayer, rsqr) ) SafeAddTarget(tmpMap,(*itr)->m_loggedInPlayer->GetGUID()); Target->GetGroup()->Unlock(); } else { SafeAddTarget(tmpMap,Target->GetGUID()); } }
/// Spell Target Handling for type 18: All Party Members around the Caster in given range NOT RAID void Spell::SpellTargetAllPartyMembersRangeNR(uint32 i, uint32 j) { TargetsList* tmpMap = &m_targetUnits[i]; Player* p = p_caster; if( p == NULL ) { if( static_cast< Creature* >( u_caster)->IsTotem() ) p = static_cast< Player* >( static_cast< Creature* >( u_caster )->GetTotemOwner() ); else if( u_caster->IsPet() && static_cast< Pet* >( u_caster )->GetPetOwner() ) p = static_cast< Pet* >( u_caster )->GetPetOwner(); else if( u_caster->GetUInt64Value( UNIT_FIELD_CREATEDBY ) ) { Unit *t = u_caster->GetMapMgr()->GetUnit( u_caster->GetUInt64Value( UNIT_FIELD_CREATEDBY ) ); if ( t && t->IsPlayer() ) p = static_cast< Player* >( t ); } } if( p == NULL ) return; float r = GetRadius(i); r *= r; if( IsInrange( m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), p, r ) ) SafeAddTarget( tmpMap, p->GetGUID() ); SubGroup* subgroup = p->GetGroup() ? p->GetGroup()->GetSubGroup( p->GetSubGroup() ) : 0; if( subgroup != NULL ) { p->GetGroup()->Lock(); for(GroupMembersSet::iterator itr = subgroup->GetGroupMembersBegin(); itr != subgroup->GetGroupMembersEnd(); ++itr) { if(!(*itr)->m_loggedInPlayer || m_caster == (*itr)->m_loggedInPlayer) continue; if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),(*itr)->m_loggedInPlayer,r)) SafeAddTarget(tmpMap,(*itr)->m_loggedInPlayer->GetGUID()); } p->GetGroup()->Unlock(); } }
/// Spell Target Handling for type 33: Party members of totem, inside given range void Spell::SpellTargetNearbyPartyMembers(uint32 i, uint32 j) { TargetsList* tmpMap=&m_targetUnits[i]; // this implementation is wrong.... this one is for totems if( u_caster != NULL ) { if( u_caster->GetTypeId()==TYPEID_UNIT) { if( static_cast< Creature* >( u_caster )->IsTotem() ) { float r = GetRadius(i); r *= r; Player* p = static_cast< Player* >( static_cast< Creature* >( u_caster )->GetTotemOwner() ); if( p == NULL) return; if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),p,r)) SafeAddTarget(tmpMap,p->GetGUID()); SubGroup * pGroup = p->GetGroup() ? p->GetGroup()->GetSubGroup(p->GetSubGroup()) : 0; if(pGroup) { p->GetGroup()->Lock(); for(GroupMembersSet::iterator itr = pGroup->GetGroupMembersBegin(); itr != pGroup->GetGroupMembersEnd(); ++itr) { if(!(*itr)->m_loggedInPlayer || p == (*itr)->m_loggedInPlayer) continue; if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),(*itr)->m_loggedInPlayer,r)) SafeAddTarget(tmpMap,(*itr)->m_loggedInPlayer->GetGUID()); } p->GetGroup()->Unlock(); } } } } }
// Spell Target Handling for type 35: Single Target Party Member (if not in party then the target can not be himself) // this one requeres more research void Spell::SpellTargetSingleTargetPartyMember(uint32 i, uint32 j) { if(!m_caster->IsInWorld()) return; Unit* Target = m_caster->GetMapMgr()->GetPlayer((uint32)m_targets.m_unitTarget); if(!Target) return; float r=GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex)); if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),Target,r*r)) _AddTargetForced(m_targets.m_unitTarget, i); }
/// Spell Target Handling for type 33: Party members of totem, inside given range void Spell::SpellTargetNearbyPartyMembers(uint32 i, uint32 j) { // this implementation is wrong.... this one is for totems if( u_caster != NULL ) { if( u_caster->GetTypeId()==TYPEID_UNIT) { if( TO_CREATURE( u_caster )->IsTotem() ) { float r = GetDBCCastTime(i); r *= r; Player* p = TO_PLAYER( TO_CREATURE(u_caster)->GetSummonOwner()); if( p == NULL) return; if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),p,r)) _AddTargetForced(p->GetGUID(), i); SubGroup * pGroup = p->GetGroup() ? p->GetGroup()->GetSubGroup(p->GetSubGroup()) : 0; if(pGroup) { p->GetGroup()->Lock(); for(GroupMembersSet::iterator itr = pGroup->GetGroupMembersBegin(); itr != pGroup->GetGroupMembersEnd(); itr++) { if(!(*itr)->m_loggedInPlayer || p == (*itr)->m_loggedInPlayer) continue; if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),(*itr)->m_loggedInPlayer,r)) _AddTargetForced((*itr)->m_loggedInPlayer->GetGUID(), i); } p->GetGroup()->Unlock(); } } } } }
/// Spell Target Handling for type 21: Single Target Friend void Spell::SpellTargetSingleTargetFriend(uint32 i, uint32 j) { Unit* Target; if(m_targets.m_unitTarget == m_caster->GetGUID()) Target = u_caster; else Target = m_caster->GetMapMgr() ? m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget) : NULL; if(!Target) return; float r= GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex)); if(IsInrange (m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),Target, r*r)) _AddTargetForced(Target->GetGUID(), i); }
/// Spell Target Handling for type 18: All Party Members around the Caster in given range NOT RAID void Spell::SpellTargetAllPartyMembersRangeNR(uint32 i, uint32 j) { Player* p = p_caster; if( p == NULL ) { if( TO_CREATURE( u_caster)->IsTotem() ) p = TO_PLAYER( TO_CREATURE(u_caster)->GetSummonOwner()); else if( u_caster->IsPet() && TO_PET( u_caster )->GetPetOwner() ) p = TO_PET( u_caster )->GetPetOwner(); } if( p == NULL ) return; float r = GetDBCCastTime(i); r *= r; if( IsInrange( m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), p, r ) ) _AddTargetForced(p->GetGUID(), i); SubGroup* subgroup = p->GetGroup() ? p->GetGroup()->GetSubGroup( p->GetSubGroup() ) : 0; if( subgroup != NULL ) { p->GetGroup()->Lock(); for(GroupMembersSet::iterator itr = subgroup->GetGroupMembersBegin(); itr != subgroup->GetGroupMembersEnd(); itr++) { if(!(*itr)->m_loggedInPlayer || m_caster == (*itr)->m_loggedInPlayer) continue; if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),(*itr)->m_loggedInPlayer,r)) _AddTargetForced( (*itr)->m_loggedInPlayer->GetGUID(), i ); } p->GetGroup()->Unlock(); } }
/// Spell Target Handling for type 57: Targeted Party Member void Spell::SpellTargetTargetPartyMember(uint32 i, uint32 j) { if(!m_caster->IsInWorld()) return; if (!m_caster->IsPet() && !m_caster->IsPlayer()) return; TargetsList* tmpMap=&m_targetUnits[i]; Unit* Target = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); Unit* Caster = static_cast<Unit*>(m_caster); if(!Target || !Caster) return; if (!Target->IsPet() && !Target->IsPlayer()) return; if (Caster->IsPet() && static_cast<Pet*>(Caster)->GetPetOwner() != NULL) Caster = static_cast<Pet*>(Caster)->GetPetOwner(); if(Target->IsPet() && static_cast<Pet*>(Target)->GetPetOwner() != NULL) Target = static_cast<Pet*>(Target)->GetPetOwner(); if (Caster != Target) { Group *c_group = static_cast<Player*>(Caster)->GetGroup(); if( !c_group ) return; //caster or caster master are not in group, cannot cast spell on this target Group *t_group = static_cast<Player*>(Target)->GetGroup(); if( !t_group ) return; //target does not have a group if( t_group != c_group ) return; //caster and target are not in same group } float r=GetMaxRange(dbcSpellRange.LookupEntry(GetProto()->rangeIndex)); if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),Target,r*r)) SafeAddTarget(tmpMap,m_targets.m_unitTarget); }
void AI_DUMMY_TOWER::Update(uint32 p_time) { //in case they managed somehow to move the tower then just put it back. Ex : deathgrip if( spawn_x != m_Unit->GetPositionX() ) { m_Unit->SetPosition( spawn_x,spawn_y,spawn_z,m_Unit->GetOrientation(), false ); WorldPacket data; m_Unit->BuildHeartBeatMsg( &data ); m_Unit->SendMessageToSet( &data, false ); } //let compiler optimize this. Function calls cannot be always optimized TickNow = GetTickCount(); //constant Regen if( RegenStamp < TickNow ) { m_Unit->SetUInt32Value( UNIT_FIELD_HEALTH, 500000 ); m_Unit->SetUInt32Value( UNIT_FIELD_POWER1, 500000 ); RegenStamp = TickNow + TOWER_REGEN_INTERVAL; WipeTargetList(); //we will never get to fight back :( //provide resource for those that are inrange for( set<Object*>::iterator itr = m_Unit->GetInRangeSetBegin(); itr != m_Unit->GetInRangeSetEnd(); ++itr) { if( (*itr) == NULL || (*itr)->IsInWorld() == false || (*itr)->IsPlayer() == false || (*itr)->GetUInt32Value( UNIT_FIELD_HEALTH ) == 0 || static_cast<Unit *>(*itr)->isAlive() == false ) continue; if( IsInrange( m_Unit, (*itr), cur_range_sq ) == false ) continue; PlayerResourceHolder *h = FetchHolder( static_cast<Player*>(*itr) ); h->ResourceNow += ( TOWER_REGEN_INTERVAL / PLAYER_RESOURCE_SCALEDOWN ); } } }
void AI_SUPPORT_TOWER::Update(uint32 p_time) { //in case they managed somehow to move the tower then just put it back. Ex : deathgrip if( spawn_x != m_Unit->GetPositionX() ) { m_Unit->SetPosition( spawn_x,spawn_y,spawn_z,m_Unit->GetOrientation(), false ); WorldPacket data; m_Unit->BuildHeartBeatMsg( &data ); m_Unit->SendMessageToSet( &data, false ); } //if we are already casting something then ignore trying to cast again // if( m_Unit->isCasting() ) // return; //let compiler optimize this. Function calls cannot be always optimized TickNow = GetTickCount(); //constant Regen if( RegenStamp < TickNow ) { //check for owner, if there is none then we may despawn Player *p = m_Unit->GetMapMgr()->GetPlayer( m_Unit->GetUInt64Value( UNIT_FIELD_CREATEDBY ) ); //we may also despawn if we died if( ( ( p == NULL && m_Unit->GetUInt64Value( UNIT_FIELD_CREATEDBY ) ) || m_Unit->GetUInt32Value( UNIT_FIELD_HEALTH ) == 0 ) && m_Unit->IsCreature() ) { static_cast<Creature *>( m_Unit )->Despawn( 0, 0 ); RegenStamp = 0xFFFFFFFF; //hopefully no more updates GlobalCoolDownFinished = 0xFFFFFFFF; //hopefully no more updates return; } //award owner for spawning us if( p ) { p->ModUnsigned32Value( PLAYER_FIELD_COINAGE, SpellCastsOnPlayers * sWorld.getRate(RATE_MONEY) * 10 ); SpellCastsOnPlayers = 0; } //check if we got upgraded EventLevelUp(); RegenStamp = TickNow + TOWER_REGEN_INTERVAL; m_Unit->ModUnsigned32Value( UNIT_FIELD_HEALTH, in_combat_H_regen ); if( m_Unit->GetUInt32Value( UNIT_FIELD_HEALTH ) > m_Unit->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) ) m_Unit->SetUInt32Value( UNIT_FIELD_HEALTH, m_Unit->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) ); // m_Unit->ModUnsigned32Value( UNIT_FIELD_POWER1, in_combat_P_regen ); // if( m_Unit->GetUInt32Value( UNIT_FIELD_POWER1 ) > m_Unit->GetUInt32Value( UNIT_FIELD_MAXPOWER1 ) ) // m_Unit->SetUInt32Value( UNIT_FIELD_POWER1, m_Unit->GetUInt32Value( UNIT_FIELD_MAXPOWER1 ) ); } //we are still waiting to get a new chance to cast a spell if( GlobalCoolDownFinished >= TickNow ) return; //see if we could find a new target if( NextTargetUpdateStamp < TickNow ) { //do not spam search cause it might be slow NextTargetUpdateStamp = TickNow + TOWER_TARGET_AQUISITION_INTERVAL; bool self_heal = true; //our max visible list for( set<Object*>::iterator itr = m_Unit->GetInRangeSetBegin(); itr != m_Unit->GetInRangeSetEnd(); ++itr) { if( (*itr) == NULL || (*itr)->IsInWorld() == false || (*itr)->IsUnit() == false || (*itr)->GetUInt32Value( UNIT_FIELD_HEALTH ) == 0 || static_cast<Unit *>(*itr)->isAlive() == false || (*itr)->GetEntry() == 123461 //dummy tower should not be targeted ) continue; if( IsInrange( m_Unit, (*itr), cur_range_sq ) == false ) continue; // if( isAttackable( m_Unit, (*itr) ) == true ) if( MyIsAttackable( m_Unit, (*itr) ) == true ) { if( TryNerfCast( static_cast<Unit*>(*itr) ) ) { //count tower contribution to fight if( (*itr)->IsPlayer() ) SpellCastsOnPlayers+=20; self_heal = false; break; } } else { if( TryBeneficCast( static_cast<Unit*>(*itr) ) ) { //count tower contribution to fight // if( (*itr)->IsPlayer() ) // SpellCastsOnPlayers+=20; self_heal = false; break; } if( static_cast<Unit*>(*itr)->GetPowerType() == POWER_TYPE_MANA ) { (*itr)->ModUnsigned32Value( UNIT_FIELD_POWER1 , in_combat_P_regen ); if( (*itr)->GetUInt32Value( UNIT_FIELD_POWER1 ) > (*itr)->GetUInt32Value( UNIT_FIELD_MAXPOWER1 ) ) (*itr)->SetUInt32Value( UNIT_FIELD_POWER1, (*itr)->GetUInt32Value( UNIT_FIELD_MAXPOWER1 ) ); } } } _UpdateTargets(); //requered to clean out hate list if( self_heal == true ) TryBeneficCast( m_Unit ); } }
/// Spell Target Handling for type 45: Chain,!!only for healing!! for chain lightning =6 void Spell::SpellTargetChainTargeting(uint32 i, uint32 j) { if( !m_caster->IsInWorld() ) return; TargetsList* tmpMap=&m_targetUnits[i]; //if selected target is party member, then jumps on party Unit* firstTarget; bool PartyOnly = false; float range = GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong, //this is cast distance, not searching distance range *= range; firstTarget = m_caster->GetMapMgr()->GetPlayer((uint32)m_targets.m_unitTarget); if( firstTarget && p_caster != NULL ) { if( p_caster->InGroup() ) if( p_caster->GetSubGroup() == static_cast< Player* >( firstTarget )->GetSubGroup() ) PartyOnly=true; } else { firstTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!firstTarget) return; } uint32 jumps=m_spellInfo->EffectChainTarget[i]; if(m_spellInfo->SpellGroupType && u_caster) { SM_FIValue(u_caster->SM_FAdditionalTargets,(int32*)&jumps,m_spellInfo->SpellGroupType); } SafeAddTarget(tmpMap,firstTarget->GetGUID()); if(!jumps) return; jumps--; if(PartyOnly) { GroupMembersSet::iterator itr; SubGroup * pGroup = p_caster->GetGroup() ? p_caster->GetGroup()->GetSubGroup(p_caster->GetSubGroup()) : 0; if(pGroup) { p_caster->GetGroup()->Lock(); for(itr = pGroup->GetGroupMembersBegin(); itr != pGroup->GetGroupMembersEnd(); ++itr) { if(!(*itr)->m_loggedInPlayer || (*itr)->m_loggedInPlayer==u_caster || !(*itr)->m_loggedInPlayer->isAlive() ) continue; //we target stuff that has no full health. No idea if we must fill target list or not :( if( (*itr)->m_loggedInPlayer->GetUInt32Value( UNIT_FIELD_HEALTH ) == (*itr)->m_loggedInPlayer->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) ) continue; if( sWorld.Collision && u_caster != NULL ) { if (u_caster->GetMapId() == (*itr)->m_loggedInPlayer->GetMapId() && !CollideInterface.CheckLOS(u_caster->GetMapId(),u_caster->GetPositionNC(),(*itr)->m_loggedInPlayer->GetPositionNC())) continue; } if( IsInrange(u_caster,(*itr)->m_loggedInPlayer, range) ) { SafeAddTarget(tmpMap,(*itr)->m_loggedInPlayer->GetGUID()); if(!--jumps) { p_caster->GetGroup()->Unlock(); return; } } } p_caster->GetGroup()->Unlock(); } }//find nearby friendly target else { std::set<Object*>::iterator itr; firstTarget->AquireInrangeLock(); //make sure to release lock before exit function ! for( itr = firstTarget->GetInRangeSetBegin(); itr != firstTarget->GetInRangeSetEnd(); itr++ ) { if( !(*itr)->IsUnit() || !((Unit*)(*itr))->isAlive()) continue; //we target stuff that has no full health. No idea if we must fill target list or not :( if( (*itr)->GetUInt32Value( UNIT_FIELD_HEALTH ) == (*itr)->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) ) continue; if (sWorld.Collision) { if (u_caster->GetMapId() == (*itr)->GetMapId() && !CollideInterface.CheckLOS(u_caster->GetMapId(),u_caster->GetPositionNC(),(*itr)->GetPositionNC())) continue; } if(IsInrange(firstTarget,*itr, range)) { if(!isAttackable(u_caster,(Unit*)(*itr))) { SafeAddTarget(tmpMap,(*itr)->GetGUID()); if(!--jumps) { firstTarget->ReleaseInrangeLock(); return; } } } } firstTarget->ReleaseInrangeLock(); } }
/// Spell Target Handling for type 31: related to scripted effects void Spell::SpellTargetScriptedEffects( uint32 i, uint32 j ) { // Circle of healing or Wild Growth // - target top 5 hp deficient raid members around target. if( GetProto()->NameHash == SPELL_HASH_CIRCLE_OF_HEALING || GetProto()->NameHash == SPELL_HASH_WILD_GROWTH ) { if( p_caster == NULL || !p_caster->IsInWorld() ) return; TargetsList* tmpMap = &m_targetUnits[i]; Unit * pTarget = p_caster->GetMapMgr()->GetUnit( m_targets.m_unitTarget ); if( !pTarget ) return; if( p_caster == pTarget || IsInrange( p_caster->GetPositionX(), p_caster->GetPositionY(), p_caster->GetPositionZ(), pTarget, GetMaxRange( dbcSpellRange.LookupEntry( GetProto()->rangeIndex ) ) ) ) SafeAddTarget( tmpMap, pTarget->GetGUID() ); else { cancastresult = SPELL_FAILED_OUT_OF_RANGE; return; // No point targeting others if the target is not in casting range. } Group * group = p_caster->GetGroup(); if( group == NULL ) return; std::vector<Player*> raidList; std::vector<Player*>::iterator itr; uint32 count = group->GetSubGroupCount(); group->Lock(); for( uint32 k = 0; k < count; k++ ) { SubGroup * subgroup = group->GetSubGroup( k ); if( subgroup ) { for( GroupMembersSet::iterator itr = subgroup->GetGroupMembersBegin(); itr != subgroup->GetGroupMembersEnd(); ++itr ) { if( (*itr)->m_loggedInPlayer && m_caster != (*itr)->m_loggedInPlayer && IsInrange( pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), (*itr)->m_loggedInPlayer, GetRadius(i) ) ) raidList.push_back( (*itr)->m_loggedInPlayer ); } } } group->Unlock(); std::sort( raidList.begin(), raidList.end(), hpLessThan ); uint32 maxTargets = 4; if( GetProto()->NameHash == SPELL_HASH_CIRCLE_OF_HEALING && p_caster->HasSpell( 55675 ) ) // Glyph of circle of healing maxTargets++; for( itr = raidList.begin(); itr != raidList.end() && maxTargets > 0; ++itr, maxTargets-- ) { SafeAddTarget( tmpMap, (*itr)->GetGUID() ); } } else FillAllTargetsInArea( i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, GetRadius(i) ); }
/// 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(); } }
/// Spell Target Handling for type 45: Chain,!!only for healing!! for chain lightning =6 void Spell::SpellTargetChainTargeting(uint32 i, uint32 j) { if( !m_caster->IsInWorld() ) return; //if selected target is party member, then jumps on party Unit* firstTarget; bool PartyOnly = false; float range = GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong, //this is cast distance, not searching distance range *= range; firstTarget = m_caster->GetMapMgr()->GetPlayer((uint32)m_targets.m_unitTarget); if( firstTarget && p_caster != NULL ) { if( p_caster->InGroup() ) if( p_caster->GetSubGroup() == TO_PLAYER( firstTarget )->GetSubGroup() ) PartyOnly=true; } else { firstTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!firstTarget) return; } uint32 jumps=m_spellInfo->EffectChainTarget[i]; if(m_spellInfo->SpellGroupType && u_caster) { SM_FIValue(u_caster->SM[SMT_ADDITIONAL_TARGET][0],(int32*)&jumps,m_spellInfo->SpellGroupType); } _AddTargetForced(firstTarget->GetGUID(), i); if(!jumps) return; jumps--; if(PartyOnly) { GroupMembersSet::iterator itr; SubGroup * pGroup = p_caster->GetGroup() ? p_caster->GetGroup()->GetSubGroup(p_caster->GetSubGroup()) : 0; if(pGroup) { p_caster->GetGroup()->Lock(); for(itr = pGroup->GetGroupMembersBegin(); itr != pGroup->GetGroupMembersEnd(); itr++) { if(!(*itr)->m_loggedInPlayer || (*itr)->m_loggedInPlayer == u_caster || (*itr)->m_loggedInPlayer->GetUInt32Value(UNIT_FIELD_HEALTH) == (*itr)->m_loggedInPlayer->GetUInt32Value(UNIT_FIELD_MAXHEALTH)) continue; if(IsInrange(u_caster->GetPositionX(),u_caster->GetPositionY(),u_caster->GetPositionZ(),(*itr)->m_loggedInPlayer, range)) { _AddTargetForced((*itr)->m_loggedInPlayer->GetGUID(), i); if(!--jumps) { p_caster->GetGroup()->Unlock(); return; } } } p_caster->GetGroup()->Unlock(); } }//find nearby friendly target else { unordered_set<Object*>::iterator itr; for( itr = firstTarget->GetInRangeSetBegin(); itr != firstTarget->GetInRangeSetEnd(); ++itr ) { if( !(*itr)->IsUnit() || !TO_UNIT(*itr)->isAlive()) continue; if(IsInrange(firstTarget->GetPositionX(),firstTarget->GetPositionY(),firstTarget->GetPositionZ(),*itr, range)) { if(!isAttackable(u_caster,TO_UNIT(*itr)) && (*itr)->GetUInt32Value(UNIT_FIELD_HEALTH) != (*itr)->GetUInt32Value(UNIT_FIELD_MAXHEALTH)) { _AddTargetForced((*itr)->GetGUID(), i); if(!--jumps) return; } } } } }
// 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(m_spellInfo->TargetCreatureType && pTarget->GetTypeId()==TYPEID_UNIT) { Creature* cr = TO_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; } } // magnet!!!!! if( pTarget->IsPlayer() && TO_PLAYER(pTarget)->m_magnetAura != NULL && m_magnetTarget == NULL ) { if(!m_spellInfo->is_melee_spell && GetType() == SPELL_DMG_TYPE_MAGIC ) { // redirect it to the magnet m_magnetTarget = TO_PLAYER(pTarget)->m_magnetAura->GetUnitCaster(); // clear the magnet aura TO_PLAYER(pTarget)->m_magnetAura->Remove(); } } if( m_magnetTarget != NULL ) { // if the target exists, shoot it at him. if( m_magnetTarget != NULL && m_magnetTarget->IsInWorld() && !m_magnetTarget->isDead() ) pTarget = m_magnetTarget; } _AddTarget(pTarget, i); if(m_spellInfo->EffectChainTarget[i]) { uint32 jumps=m_spellInfo->EffectChainTarget[i]-1; float range=GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong range*=range; unordered_set<Object*>::iterator itr; for( itr = m_caster->GetInRangeSetBegin(); itr != m_caster->GetInRangeSetEnd(); ++itr ) { if((*itr)->GetGUID()==m_targets.m_unitTarget) continue; if( !((*itr)->IsUnit()) || !TO_UNIT(*itr)->isAlive()) continue; if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),(*itr),range)) { if(isAttackable(u_caster,TO_UNIT(*itr))) { _AddTarget(TO_UNIT(*itr), i); if(!--jumps) return; } } } } }
void Spell::AddChainTargets(uint32 i, uint32 TargetType, float r, uint32 maxtargets) { if(!m_caster->IsInWorld()) return; Object* targ = m_caster->GetMapMgr()->_GetObject(m_targets.m_unitTarget); if(targ == NULL) return; TargetsList* list = &m_targetUnits[i]; //if selected target is party member, then jumps on party Unit* firstTarget = NULL; if(targ->IsUnit()) firstTarget = TO_UNIT(targ); else firstTarget = u_caster; bool RaidOnly = false; float range = GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong, //this is cast distance, not searching distance range *= range; //is this party only? Player* casterFrom = TO< Player* >(u_caster->GetPlayerOwner()); Player* pfirstTargetFrom = TO< Player* >(firstTarget->GetPlayerOwner()); if(casterFrom != NULL && pfirstTargetFrom != NULL && casterFrom->GetGroup() == pfirstTargetFrom->GetGroup()) RaidOnly = true; uint32 jumps = m_spellInfo->EffectChainTarget[i]; //range range /= jumps; //hacky, needs better implementation! if(m_spellInfo->SpellGroupType && u_caster != NULL) SM_FIValue(u_caster->SM_FAdditionalTargets, (int32*)&jumps, m_spellInfo->SpellGroupType); AddTarget(i, TargetType, firstTarget); if(jumps <= 1 || list->size() == 0) //1 because we've added the first target, 0 size if spell is resisted return; ObjectSet::iterator itr; for(itr = firstTarget->GetInRangeSetBegin(); itr != firstTarget->GetInRangeSetEnd(); itr++) { if(!(*itr)->IsUnit() || !TO_UNIT((*itr))->isAlive()) continue; if(RaidOnly && !pfirstTargetFrom->InRaid(TO_UNIT(*itr))) continue; //healing spell, full health target = NONO if(IsHealingSpell(m_spellInfo) && TO_UNIT(*itr)->GetHealthPct() == 100) continue; size_t oldsize; if(IsInrange(firstTarget->GetPositionX(), firstTarget->GetPositionY(), firstTarget->GetPositionZ(), (*itr), range)) { oldsize = list->size(); AddTarget(i, TargetType, (*itr)); if(list->size() == oldsize || list->size() >= jumps) //either out of jumps or a resist return; } } }