void DynamicObject::AddInRangeObject( Object* pObj ) { if( pObj->IsUnit() ) { bool attackable; if( p_caster != NULL) attackable = isAttackable( m_caster, pObj ); else attackable = isAttackable( TO_DYNAMICOBJECT(this), pObj ); if( attackable ) m_inRangeOppFactions.insert( TO_UNIT( pObj ) ); } Object::AddInRangeObject( pObj ); }
void DynamicObject::AddInRangeObject(Object* pObj) { if(pObj->IsUnit()) { bool attackable; if(p_caster) attackable = isAttackable(p_caster, pObj); else attackable = isAttackable(this, pObj); if(attackable) m_inRangeOppFactions.insert(((Unit*)pObj)); } Object::AddInRangeObject(pObj); }
/// 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 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(); }
bool Pestilence(uint32 i, Spell* pSpell) { if(i == 1) // Script Effect that has been identified to handle the spread of diseases. { if(!pSpell->u_caster || !pSpell->u_caster->GetTargetGUID() || !pSpell->u_caster->IsInWorld()) return true; Unit* u_caster = pSpell->u_caster; Unit* Main = u_caster->GetMapMgr()->GetUnit(u_caster->GetTargetGUID()); if(Main == NULL) return true; bool blood = Main->HasAura(BLOOD_PLAGUE); bool frost = Main->HasAura(FROST_FEVER); int inc = (u_caster->HasAura(59309) ? 10 : 5); for(Object::InRangeSet::iterator itr = u_caster->GetInRangeSetBegin(); itr != u_caster->GetInRangeSetEnd(); ++itr) { if(!(*itr)->IsUnit()) continue; Unit* Target = TO< Unit* >((*itr)); if(Main->GetGUID() == Target->GetGUID() && !u_caster->HasAura(63334)) continue; if(isAttackable(Target, u_caster) && u_caster->CalcDistance((*itr)) <= (pSpell->GetRadius(i) + inc)) { if(blood) u_caster->CastSpell(Target, BLOOD_PLAGUE, true); if(frost) u_caster->CastSpell(Target, FROST_FEVER, true); } } return true; } return true; }
void DynamicObject::RemoveInRangeObject(Object* pObj) { if(pObj->IsUnit()) { bool attackable; if(p_caster) attackable = isAttackable(p_caster, pObj); else attackable = isAttackable(this, pObj); if(attackable) m_inRangeOppFactions.erase(((Unit*)pObj)); targets.erase(((Unit*)pObj)); } Object::RemoveInRangeObject(pObj); }
bool Penance(uint32 i, Spell * pSpell) { if( !pSpell->p_caster || !pSpell->p_caster->isAlive() || !pSpell->GetUnitTarget() || !pSpell->GetUnitTarget()->isAlive() ) return false; Unit *target = pSpell->GetUnitTarget(); Player *player = pSpell->p_caster; // index 0 contains the spell for the first tick, index 1 is the peroidic cast spell. uint32 hostileSpell[] = {0, 0}; uint32 friendlySpell[] = {0, 0}; switch( pSpell->GetProto()->Id ) { case 47540: //Rank 1 hostileSpell[0] = 47666; hostileSpell[1] = 47758; friendlySpell[0] = 47750; friendlySpell[1] = 47757; break; case 53005: hostileSpell[0] = 52998; hostileSpell[1] = 53001; friendlySpell[0] = 52983; friendlySpell[1] = 52986; break; case 53006: hostileSpell[0] = 52999; hostileSpell[1] = 53002; friendlySpell[0] = 52984; friendlySpell[1] = 52987; break; case 53007: hostileSpell[0] = 53000; hostileSpell[1] = 53003; friendlySpell[0] = 52985; friendlySpell[1] = 52988; break; } if( isAttackable(player, target) ) // Do holy damage { // First tick is instant. player->CastSpell(target, hostileSpell[0], true); player->CastSpell(target, hostileSpell[1], false); } else // Heal { player->CastSpell(target, friendlySpell[0], true); player->CastSpell(target, friendlySpell[1], false); } return true; }
bool HolyShock(uint32 i, Spell *pSpell) { Unit *target = pSpell->GetUnitTarget(); if(!pSpell->p_caster || !target) return true; uint32 newspell = 0; if(isAttackable(pSpell->p_caster,target)) // if its an enemy { switch(pSpell->GetProto()->Id) { case 20473: newspell = 25912; break; case 20929: newspell = 25911; break; case 20930: newspell = 25902; break; case 27174: newspell = 27176; break; case 33072: newspell = 33073; break; } } else // if its friendly { switch(pSpell->GetProto()->Id) { case 20473: newspell = 25914; break; case 20929: newspell = 25913; break; case 20930: newspell = 25903; break; case 27174: newspell = 27175; break; case 33072: newspell = 33074; break; } } SpellEntry *spInfo = dbcSpell.LookupEntry(newspell); if(!spInfo) return true; pSpell->p_caster->CastSpell(target, spInfo, true); return true; }
/// Spell Target Handling for type 24: Targets in Front of the Caster void Spell::SpellTargetInFrontOfCaster(uint32 i, uint32 j) { unordered_set<Object*>::iterator itr,itr2; if( m_spellInfo->cone_width == 0.0f ) { for( itr = m_caster->GetInRangeSetBegin(); itr != m_caster->GetInRangeSetEnd();) { itr2 = itr; itr++; if(!((*itr2)->IsUnit()) || !TO_UNIT(*itr2)->isAlive()) continue; //is Creature in range if(m_caster->isInRange((*itr2),GetDBCCastTime(i))) { if(m_caster->isInFront(*itr2)) { if(isAttackable(u_caster, (*itr2))) _AddTarget(TO_UNIT(*itr2), i); } } } } else { for( itr = m_caster->GetInRangeSetBegin(); itr != m_caster->GetInRangeSetEnd();) { itr2 = itr; itr++; if(!((*itr2)->IsUnit()) || !TO_UNIT(*itr2)->isAlive()) continue; //is Creature in range if(m_caster->isInArc(*itr2, m_spellInfo->cone_width)) { if(m_caster->isInFront((*itr2))) { if(isAttackable(u_caster, (*itr2))) _AddTarget(TO_UNIT(*itr2), i); } } } } }
void WorldSession::HandleAttackSwingOpcode( WorldPacket & recv_data ) { CHECK_INWORLD_RETURN; CHECK_PACKET_SIZE(recv_data, 8); uint64 guid; recv_data >> guid; if(!guid) { // does this mean cancel combat? HandleAttackStopOpcode(recv_data); return; } // AttackSwing DEBUG_LOG( "WORLD"," Recvd CMSG_ATTACKSWING Message" ); if(GetPlayer()->IsPacified() || GetPlayer()->IsStunned() || GetPlayer()->IsFeared()) return; // printf("Got ATTACK SWING: %08X %08X\n", GUID_HIPART(guid), GUID_LOPART(guid)); Unit* pEnemy = _player->GetMapMgr()->GetUnit(guid); //printf("Pointer: %08X\n", pEnemy); if(!pEnemy) { OUT_DEBUG("WORLD: "I64FMT" does not exist.", guid); return; } if(pEnemy->isDead() || _player->isDead()) // haxors :( return; // Faction "Hack" by Deathshit if( !isAttackable( GetPlayer(), pEnemy, false ) && !pEnemy->IsInRangeOppFactSet(_player) && !pEnemy->CombatStatus.DidDamageTo(GetPlayer()->GetGUID())) { GetPlayer()->BroadcastMessage("Faction exploit detected. You will be disconnected in 5 seconds."); GetPlayer()->Kick(5000); return; } GetPlayer()->smsg_AttackStart(pEnemy); GetPlayer()->EventAttackStart(); // Set PVP Flag. /*if(pEnemy->IsPlayer() && isHostile(_player, pEnemy)) { // don't in duel.. this should be done in dealdamage anyway :S if( TO_PLAYER( pEnemy )->GetTeam() != _player->GetTeam() ) _player->SetPvPFlag(); }*/ }
uint8 CanCast(bool tolerate) { uint8 result = Spell::CanCast(tolerate); if(result == SPELL_CANCAST_OK) { if(m_caster != NULL && m_caster->IsInWorld()) { Unit* target = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(target == NULL || !(isAttackable(m_caster, target, false) || target->getRace() == RACE_UNDEAD)) result = SPELL_FAILED_BAD_TARGETS; } } return result; }
/// 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 54: Targets in Front of the Caster void Spell::SpellTargetInFrontOfCaster2(uint32 i, uint32 j) { unordered_set<Object*>::iterator itr; for( itr = m_caster->GetInRangeSetBegin(); itr != m_caster->GetInRangeSetEnd(); ++itr ) { if(!((*itr)->IsUnit()) || !TO_UNIT(*itr)->isAlive()) continue; //is Creature in range if(m_caster->isInRange(TO_UNIT(*itr),GetDBCCastTime(i))) { if(m_caster->isInFront(TO_UNIT(*itr))) { if(isAttackable(u_caster, TO_UNIT(*itr))) _AddTarget(TO_UNIT(*itr), i); } } } }
bool Starfall(uint32 i, Spell* pSpell) { Unit* m_caster = pSpell->u_caster; if(m_caster == NULL) return true; uint8 am = 0; for(Object::InRangeSet::iterator itr = m_caster->GetInRangeSetBegin(); itr != m_caster->GetInRangeSetEnd(); ++itr) { if(!(*itr)->IsUnit()) continue; Unit* Target = static_cast< Unit* >((*itr)); if(isAttackable(Target, m_caster) && m_caster->CalcDistance((*itr)) <= pSpell->GetRadius(i)) { m_caster->CastSpell(Target, pSpell->CalculateEffect(i, Target), true); ++am; if(am >= 2) return true; } } return true; }
bool HolidayCheer(uint32 i, Spell *pSpell) { if(!pSpell->m_caster) return true; Unit *target; float dist = pSpell->GetDBCCastTime(i); for(ObjectSet::iterator itr = pSpell->m_caster->GetInRangeSetBegin(); itr != pSpell->m_caster->GetInRangeSetEnd(); ++itr) { if((*itr)->IsUnit()) target = TO_UNIT(*itr); else continue; if(pSpell->m_caster->CalcDistance(target) > dist || isAttackable(pSpell->m_caster, target)) continue; target->Emote(EMOTE_ONESHOT_LAUGH); } return true; }
bool DeathCoil(uint32 i, Spell* s) { Unit* unitTarget = s->GetUnitTarget(); if(s->p_caster == NULL || unitTarget == NULL) return false; int32 dmg = s->damage; if(isAttackable(s->p_caster, unitTarget, false)) { s->p_caster->CastSpell(unitTarget, 47632, dmg, true); } else if(unitTarget->IsPlayer() && unitTarget->getRace() == RACE_UNDEAD) { dmg *= 1.5; s->p_caster->CastSpell(unitTarget, 47633, dmg, true); } return true; }
void WorldSession::HandleAttackSwingOpcode(WorldPacket & recv_data) { CHECK_INWORLD_RETURN CHECK_PACKET_SIZE(recv_data, 8); uint64 guid; recv_data >> guid; if(!guid) { // does this mean cancel combat? HandleAttackStopOpcode(recv_data); return; } // AttackSwing Log.Debug("WORLD", "Recvd CMSG_ATTACKSWING Message"); if(GetPlayer()->IsPacified() || GetPlayer()->IsStunned() || GetPlayer()->IsFeared()) return; // printf("Got ATTACK SWING: %08X %08X\n", GUID_HIPART(guid), Arcemu::Util::GUID_LOPART( guid )); Unit* pEnemy = _player->GetMapMgr()->GetUnit(guid); //printf("Pointer: %08X\n", pEnemy); if(!pEnemy) { LOG_DEBUG("WORLD: "I64FMT" does not exist.", guid); return; } if(pEnemy->IsDead() || _player->IsDead() || !isAttackable(_player, pEnemy, false)) // haxors :( return; GetPlayer()->smsg_AttackStart(pEnemy); GetPlayer()->EventAttackStart(); }
bool Starfall(uint8_t effectIndex, Spell* pSpell) { Unit* m_caster = pSpell->u_caster; if (m_caster == NULL) return true; uint8 am = 0; for (const auto& itr : m_caster->getInRangeObjectsSet()) { if (!itr || !itr->isCreatureOrPlayer()) continue; Unit* Target = static_cast<Unit*>(itr); if (isAttackable(Target, m_caster) && m_caster->CalcDistance(itr) <= pSpell->GetRadius(effectIndex)) { m_caster->castSpell(Target, pSpell->CalculateEffect(effectIndex, Target), true); ++am; if (am >= 2) return true; } } return true; }
void OnLoad() { if (_unit->IsPet()) { Pet* s = TO< Pet* >(_unit); Player* owner = s->GetPetOwner(); float owner_bonus = static_cast<float>(owner->GetDamageDoneMod(SCHOOL_SHADOW) * 0.375f); // 37.5% s->BaseAttackType = SCHOOL_SHADOW; // Melee hits are supposed to do damage with the shadow school s->SetBaseAttackTime(MELEE, 1500); // Shadowfiend is supposed to do 10 attacks, sometimes it can be 11 s->SetMinDamage(s->GetMinDamage() + owner_bonus); s->SetMaxDamage(s->GetMaxDamage() + owner_bonus); s->BaseDamage[0] += owner_bonus; s->BaseDamage[1] += owner_bonus; Unit* uTarget = s->GetMapMgr()->GetUnit(owner->GetTargetGUID()); if ((uTarget != NULL) && isAttackable(owner, uTarget)) { s->GetAIInterface()->AttackReaction(uTarget, 1); s->GetAIInterface()->setNextTarget(uTarget); } } }
void WorldSession::HandleAttackSwingOpcode( WorldPacket & recv_data ) { /*Apply a bugfix to prevent players from attacking people of the same faction. --Hemi*/ if(!_player->IsInWorld()) return; CHECK_PACKET_SIZE(recv_data, 8); uint64 guid; recv_data >> guid; if(!guid) { // does this mean cancel combat? HandleAttackStopOpcode(recv_data); return; } Log.Debug( "WORLD","Recvd CMSG_ATTACKSWING Message" ); // AttackSwing if(GetPlayer()->IsPacified() || GetPlayer()->IsStunned() || GetPlayer()->IsFeared()) return; Unit *pEnemy = _player->GetMapMgr()->GetUnit(guid); if(!pEnemy) { sLog.outDebug("WORLD: "I64FMT" does not exist.", guid); return; } if(pEnemy->isDead() || _player->isDead()) // haxors :( return; bool attackablestatus = isAttackable( GetPlayer(), pEnemy, false ); if( attackablestatus == false ) { //Prevent attacking people of the same faction. --Hemi HandleAttackStopOpcode(recv_data); return; } GetPlayer()->smsg_AttackStart(pEnemy); GetPlayer()->EventAttackStart(); }
// 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 DynamicObject::UpdateTargets() { if(m_aliveDuration == 0) return; if(m_aliveDuration >= 100) { Unit* target; Aura* pAura; float radius = m_floatValues[ DYNAMICOBJECT_RADIUS ] * m_floatValues[ DYNAMICOBJECT_RADIUS ]; // Looking for targets in the Object set for(std::set< Object* >::iterator itr = m_objectsInRange.begin(); itr != m_objectsInRange.end(); ++itr) { Object* o = *itr; if(!o->IsUnit() || !TO< Unit* >(o)->isAlive()) continue; target = TO< Unit* >(o); if(!isAttackable(u_caster, target, !(m_spellProto->c_is_flags & SPELL_FLAG_IS_TARGETINGSTEALTHED))) continue; // skip units already hit, their range will be tested later if(targets.find(target->GetGUID()) != targets.end()) continue; if(GetDistanceSq(target) <= radius) { pAura = sSpellFactoryMgr.NewAura(m_spellProto, m_aliveDuration, u_caster, target, true); for(uint32 i = 0; i < 3; ++i) { if(m_spellProto->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA) { pAura->AddMod(m_spellProto->EffectApplyAuraName[i], m_spellProto->EffectBasePoints[i] + 1, m_spellProto->EffectMiscValue[i], i); } } target->AddAura(pAura); if(p_caster) { p_caster->HandleProc(PROC_ON_CAST_SPECIFIC_SPELL | PROC_ON_CAST_SPELL, target, m_spellProto); p_caster->m_procCounter = 0; } // add to target list targets.insert(target->GetGUID()); } } // loop the targets, check the range of all of them DynamicObjectList::iterator jtr = targets.begin(); DynamicObjectList::iterator jtr2; DynamicObjectList::iterator jend = targets.end(); while(jtr != jend) { target = GetMapMgr() ? GetMapMgr()->GetUnit(*jtr) : NULL; jtr2 = jtr; ++jtr; if((target != NULL) && (GetDistanceSq(target) > radius)) { target->RemoveAura(m_spellProto->Id); targets.erase(jtr2); } } m_aliveDuration -= 100; } else { m_aliveDuration = 0; } if(m_aliveDuration == 0) { Remove(); } }
void DynamicObject::UpdateTargets() { if(m_aliveDuration == 0) return; if(m_aliveDuration >= 100) { std::set<Object*>::iterator itr = GetInRangeSetBegin(),itr2; std::set<Object*>::iterator iend = GetInRangeSetEnd(); Unit * target; Aura * pAura; float radius = m_floatValues[DYNAMICOBJECT_RADIUS]*m_floatValues[DYNAMICOBJECT_RADIUS]; this->AquireInrangeLock(); //make sure to release lock before exit function ! while(itr != iend) { // target = *itr; // ++itr; itr2 = itr; ++itr; if( !( (*itr2)->IsUnit() ) || ! static_cast< Unit* >( *itr2 )->isAlive() || ( static_cast< Creature* >( *itr2 )->IsTotem() && !static_cast< Unit* >( *itr2 )->IsPlayer() ) ) continue; target = static_cast< Unit* >( *itr2 ); if( !isAttackable( p_caster, target, !(m_spellProto->c_is_flags & SPELL_FLAG_IS_TARGETINGSTEALTHED) ) ) continue; // skip units already hit, their range will be tested later if(targets.find(target->GetGUID()) != targets.end()) continue; if(GetDistanceSq(target) <= radius) { pAura = AuraPool.PooledNew(); pAura->Init(m_spellProto, m_aliveDuration, u_caster, target, true); for(uint32 i = 0; i < 3; ++i) { if(m_spellProto->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA) { pAura->AddMod(m_spellProto->EffectApplyAuraName[i], m_spellProto->EffectBasePoints[i]+1, m_spellProto->EffectMiscValue[i], i); } } target->AddAura(pAura, m_spellScript); if(p_caster) { p_caster->HandleProc(PROC_ON_CAST_SPECIFIC_SPELL | PROC_ON_CAST_SPELL,target, m_spellProto); p_caster->m_procCounter = 0; } // add to target list targets.insert(target->GetGUID()); } } this->ReleaseInrangeLock(); // loop the targets, check the range of all of them DynamicObjectList::iterator jtr = targets.begin(); DynamicObjectList::iterator jtr2; DynamicObjectList::iterator jend = targets.end(); while(jtr != jend) { target = GetMapMgr() ? GetMapMgr()->GetUnit(*jtr) : NULL; jtr2 = jtr; ++jtr; if(GetDistanceSq(target) > radius) { target->RemoveAura(m_spellProto->Id); targets.erase(jtr2); } } m_aliveDuration -= 100; } else { m_aliveDuration = 0; } if(m_aliveDuration == 0) { Remove(); } }
void DynamicObject::UpdateTargets() { if(m_aliveDuration == 0) return; if(m_aliveDuration >= 200) { Unit* target; float radius = m_floatValues[DYNAMICOBJECT_RADIUS]*m_floatValues[DYNAMICOBJECT_RADIUS]; Object::InRangeSet::iterator itr,itr2; for( itr = GetInRangeSetBegin(); itr != GetInRangeSetEnd(); itr++) { itr2 = itr; if( !( (*itr2)->IsUnit() ) || ! TO_UNIT( *itr2 )->isAlive() || ((*itr2)->GetTypeId()==TYPEID_UNIT && TO_CREATURE(*itr2)->IsTotem() ) ) continue; target = TO_UNIT( *itr2 ); if( !isAttackable( m_caster, target, !(m_spellProto->c_is_flags & SPELL_FLAG_IS_TARGETINGSTEALTHED) ) ) continue; // skip units already hit, their range will be tested later if(targets.find(target) != targets.end()) continue; if(GetDistanceSq(target) <= radius) { Aura* pAura(new Aura(m_spellProto, m_aliveDuration, m_caster, target)); for(uint32 i = 0; i < 3; ++i) { if(m_spellProto->Effect[i] == 27) { pAura->AddMod(m_spellProto->EffectApplyAuraName[i], m_spellProto->EffectBasePoints[i]+1, m_spellProto->EffectMiscValue[i], i); } } target->AddAura(pAura); if( m_caster->IsPlayer() ) { p_caster->HandleProc(PROC_ON_CAST_SPECIFIC_SPELL | PROC_ON_CAST_SPELL,target, m_spellProto); p_caster->m_procCounter = 0; } // add to target list targets.insert(target); } } // loop the targets, check the range of all of them DynamicObjectList::iterator jtr = targets.begin(); DynamicObjectList::iterator jtr2; DynamicObjectList::iterator jend = targets.end(); while(jtr != jend) { target = *jtr; jtr2 = jtr; ++jtr; if(GetDistanceSq(target) > radius) { targets.erase(jtr2); target->RemoveAura(m_spellProto->Id); } } m_aliveDuration -= 200; } else { m_aliveDuration = 0; } if(m_aliveDuration == 0) { DynamicObjectList::iterator jtr = targets.begin(); DynamicObjectList::iterator jend = targets.end(); Unit* target; while(jtr != jend) { target = *jtr; ++jtr; target->RemoveAura(m_spellProto->Id); } Remove(); } }
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; }
/// 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(); } }
/////////////////////////////////////////////////////////////////////// //Gnomish Shrink Ray dummy effect handler // //Preconditions // Casted by Player // //Effect // Normally casts spell 13010 on the targeted unit. Shrinking it, and // making it weaker // // On malfunction it either shrinks, or enlarges, the the caster, // the caster's party, all enemies, or enlarges the target // // ////////////////////////////////////////////////////////////////////// bool ShrinkRay(uint32 i, Spell* s) { if(s->p_caster == NULL) return true; uint32 spellids[] = { 13004, // grow 13010 // shrink }; uint32 chance = RandomUInt(5); bool malfunction = false; if(chance == 5) malfunction = true; if(!malfunction) { s->p_caster->CastSpell(s->GetUnitTarget(), spellids[ 1 ], true); } else { uint32 spellindex = RandomUInt(1); uint32 who = RandomUInt(3); switch(who) { case 0: // us { s->p_caster->CastSpell(s->p_caster, spellids[ spellindex ], true); } break; case 1: // them { // if it's a malfunction it will only grow the target, since shrinking is normal s->p_caster->CastSpell(s->GetUnitTarget(), spellids[ 0 ], true); } break; case 2: // our party { for(std::set< Object* >::iterator itr = s->p_caster->GetInRangePlayerSetBegin(); itr != s->p_caster->GetInRangePlayerSetEnd(); ++itr) { Player* p = TO_PLAYER(*itr); if((p->GetPhase() & s->p_caster->GetPhase()) == 0) continue; if(p->GetGroup()->GetID() != s->p_caster->GetGroup()->GetID()) continue; s->p_caster->CastSpell(p, spellids[ spellindex ], true); } } break; case 3: // every attacking enemy { for(std::set< Object* >::iterator itr = s->p_caster->GetInRangeOppFactsSetBegin(); itr != s->p_caster->GetInRangeOppFactsSetEnd(); ++itr) { Object* o = *itr; if((o->GetPhase() & s->p_caster->GetPhase()) == 0) continue; if(!o->IsCreature()) continue; Unit* u = TO_UNIT(o); if(u->GetTargetGUID() != s->p_caster->GetGUID()) continue; if(!isAttackable(s->p_caster, u)) continue; s->p_caster->CastSpell(u, spellids[ spellindex ], true); } } break; } } return true; }
void CUser::Attack(Packet & pkt) { int16 sid = -1, tid = -1, damage, delaytime, distance; uint8 bType, bResult = 0; Unit * pTarget = nullptr; pkt >> bType >> bResult >> tid >> delaytime >> distance; // delaytime = delaytime / 100.0f; // distance = distance / 10.0f; if (isIncapacitated()) return; if (isInSafetyArea()) return; if (m_bInvisibilityType != INVIS_NONE) { CMagicProcess::RemoveStealth(this, INVIS_DISPEL_ON_MOVE); CMagicProcess::RemoveStealth(this, INVIS_DISPEL_ON_ATTACK); } // If you're holding a weapon, do a client-based (ugh, do not trust!) delay check. _ITEM_TABLE *pTable = GetItemPrototype(RIGHTHAND); if (pTable != nullptr) { if (delaytime < (pTable->m_sDelay + 10) // client adds 0.1 onto the interval (0.1 of 100 is 10) || distance > pTable->m_sRange) return; } // Empty handed. else if (delaytime < 100) return; pTarget = g_pMain->GetUnitPtr(tid); bResult = ATTACK_FAIL; if (pTarget != nullptr && isInAttackRange(pTarget) && CanAttack(pTarget)) { if (isAttackable(pTarget) && CanCastRHit(GetSocketID())) { if (isInTempleEventZone()) if (GetUserGroup() != -1 && !isSameUserGroup(pTarget)) return; CUser *pUser = g_pMain->GetUserPtr(GetSocketID()); if (pUser != nullptr) pUser->m_RHitRepeatList.insert(std::make_pair(GetSocketID(), UNIXTIME)); damage = GetDamage(pTarget); // Can't use R attacks in the Snow War. if (GetZoneID() == ZONE_SNOW_BATTLE && g_pMain->m_byBattleOpen == SNOW_BATTLE) damage = 0; if (damage > 0) { pTarget->HpChange(-damage, this); if (pTarget->isDead()) bResult = ATTACK_TARGET_DEAD; else bResult = ATTACK_SUCCESS; // Every attack takes a little of your weapon's durability. ItemWoreOut(ATTACK, damage); // Every hit takes a little of the defender's armour durability. if (pTarget->isPlayer()) TO_USER(pTarget)->ItemWoreOut(DEFENCE, damage); } } } Packet result(WIZ_ATTACK, bType); result << bResult << GetSocketID() << tid; SendToRegion(&result); }
/// 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; } } } } }