bool ArcScriptCreatureAI::IsValidUnitTarget(Object* pObject, TargetFilter pFilter) { //Make sure its a valid unit if( !pObject->IsUnit() ) return false; if( pObject->GetInstanceID() != _unit->GetInstanceID() ) return false; Unit* UnitTarget = static_cast<Unit*>(pObject); //Skip dead, feign death or invisible targets if( !UnitTarget->isAlive() ) return false; if( UnitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FEIGN_DEATH) ) return false; if( UnitTarget->m_invisible ) return false; //Skip units not on threat list if( _unit->GetAIInterface()->getThreatByPtr(UnitTarget) == 0 ) return false; //Check if we apply target filtering if( pFilter != TargetFilter_None ) { //Skip current attacking target if requested if( (pFilter & TargetFilter_NotCurrent) && UnitTarget == _unit->GetAIInterface()->GetNextTarget() ) return false; //Keep only wounded targets if requested if( (pFilter & TargetFilter_Wounded) && UnitTarget->GetHealthPct() >= 99 ) return false; //Handle hostile/friendly if( pFilter & TargetFilter_Friendly ) { if( !UnitTarget->CombatStatus.IsInCombat() ) return false; //Skip not-in-combat targets if friendly if( isHostile(_unit, UnitTarget) || _unit->GetAIInterface()->getThreatByPtr(UnitTarget) > 0 ) return false; } } return true; //This is a valid unit target }
SpellCastError CanCast(bool tolerate) { u_target = _spell->GetUnitTarget(); if( u_target == NULL || !u_target->HasFlag(UNIT_FIELD_AURASTATE, AURASTATE_FLAG_IMMOLATE)) return SPELL_FAILED_CASTER_AURASTATE; return SPELL_CANCAST_OK; }
bool Deep_Freeze(uint32 i, Spell *pSpell) { Unit *pTarget = pSpell->GetUnitTarget(); if(!pSpell->p_caster || !pTarget) return true; if(!pTarget->HasFlag(UNIT_FIELD_AURASTATE, AURASTATE_FLAG_FROZEN)){ // TODO: why isn't client updated with frozen state information // when mobs on serverside clearly has this info. // pTarget->SendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, "lol I r frozen"); return true; } return true; }
//Edit Unit field static bool HandleModifyBitCommand(ChatHandler* handler, const char* args) { if (!*args) return false; Unit* target = handler->getSelectedUnit(); if (!target) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); handler->SetSentErrorMessage(true); return false; } // check online security if (target->GetTypeId() == TYPEID_PLAYER && handler->HasLowerSecurity(target->ToPlayer(), 0)) return false; char* pField = strtok((char*)args, " "); if (!pField) return false; char* pBit = strtok(NULL, " "); if (!pBit) return false; uint16 field = atoi(pField); uint32 bit = atoi(pBit); if (field < OBJECT_END || field >= target->GetValuesCount()) { handler->SendSysMessage(LANG_BAD_VALUE); handler->SetSentErrorMessage(true); return false; } if (bit < 1 || bit > 32) { handler->SendSysMessage(LANG_BAD_VALUE); handler->SetSentErrorMessage(true); return false; } if (target->HasFlag(field, (1<<(bit-1)))) { target->RemoveFlag(field, (1<<(bit-1))); handler->PSendSysMessage(LANG_REMOVE_BIT, bit, field); } else { target->SetFlag(field, (1<<(bit-1))); handler->PSendSysMessage(LANG_SET_BIT, bit, field); } return true; }
void FetchDragons() { Unit* pTene = Unit::GetUnit(*m_creature,m_pInstance->GetData64(DATA_TENEBRON)); Unit* pShad = Unit::GetUnit(*m_creature,m_pInstance->GetData64(DATA_SHADRON)); Unit* pVesp = Unit::GetUnit(*m_creature,m_pInstance->GetData64(DATA_VESPERON)); //if at least one of the dragons are alive and are being called bool bCanUseWill = false; if (pTene && pTene->isAlive() && !pTene->getVictim()) { bCanUseWill = true; pTene->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aTene[0].m_fX, m_aTene[0].m_fY, m_aTene[0].m_fZ); if (!pTene->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) pTene->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } if (pShad && pShad->isAlive() && !pShad->getVictim()) { bCanUseWill = true; pShad->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aShad[0].m_fX, m_aShad[0].m_fY, m_aShad[0].m_fZ); if (!pShad->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) pShad->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } if (pVesp && pVesp->isAlive() && !pVesp->getVictim()) { bCanUseWill = true; pVesp->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aVesp[0].m_fX, m_aVesp[0].m_fY, m_aVesp[0].m_fZ); if (!pVesp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) pVesp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } if (bCanUseWill) DoCastSpellIfCan(m_creature, SPELL_WILL_OF_SARTHARION); }
void WorldSession::HandleAttackSwingOpcode(WorldPacket& recv_data) { ObjectGuid guid; recv_data >> guid; DEBUG_FILTER_LOG(LOG_FILTER_COMBAT, "WORLD: Received opcode CMSG_ATTACKSWING %s", guid.GetString().c_str()); if (!guid.IsUnit()) { sLog.outError("WORLD: %s isn't unit", guid.GetString().c_str()); return; } Unit* pEnemy = _player->GetMap()->GetUnit(guid); if (!pEnemy) { sLog.outError("WORLD: Enemy %s not found", guid.GetString().c_str()); // stop attack state at client SendAttackStop(NULL); return; } if (_player->IsFriendlyTo(pEnemy) || pEnemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) { sLog.outError("WORLD: Enemy %s is friendly", guid.GetString().c_str()); // stop attack state at client SendAttackStop(pEnemy); return; } if (!pEnemy->isAlive()) { // client can generate swing to known dead target if autoswitch between autoshot and autohit is enabled in client options // stop attack state at client SendAttackStop(pEnemy); return; } _player->Attack(pEnemy, true); }
void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z) { Map const* oldMap = GetMap(); Relocate(x, y, z); for (UnitSet::iterator itr = m_passengers.begin(); itr != m_passengers.end();) { UnitSet::iterator it2 = itr; ++itr; Unit* plr = *it2; if(plr->GetTypeId() == TYPEID_PLAYER) { if (!plr) { m_passengers.erase(it2); continue; } if (plr->IsDead() && !plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) { ((Player*)plr)->ResurrectPlayer(1.0); } ((Player*)plr)->TeleportTo(newMapid, x, y, z, GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT); } // WorldPacket data(SMSG_811, 4); // data << uint32(0); // plr->GetSession()->SendPacket(&data); } // we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference... // player far teleport would try to create same instance, but we need it NOW for transport... // correct me if I'm wrong O.o Map* newMap = sMapMgr.CreateMap(newMapid, this); SetMap(newMap); if (oldMap != newMap) { UpdateForMap(oldMap); UpdateForMap(newMap); } }
void WorldSession::HandleAttackSwingOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8); uint64 guid; recv_data >> guid; DEBUG_LOG( "WORLD: Recvd CMSG_ATTACKSWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid) ); Unit *pEnemy = ObjectAccessor::GetUnit(*_player, guid); if(!pEnemy) { if(!IS_UNIT_GUID(guid)) sLog.outError("WORLD: Object %u (TypeID: %u) isn't player, pet or creature",GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid))); else sLog.outError( "WORLD: Enemy %s %u not found",GetLogNameForGuid(guid),GUID_LOPART(guid)); // stop attack state at client SendAttackStop(NULL); return; } if(_player->IsFriendlyTo(pEnemy) || pEnemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) { sLog.outError( "WORLD: Enemy %s %u is friendly",(IS_PLAYER_GUID(guid) ? "player" : "creature"),GUID_LOPART(guid)); // stop attack state at client SendAttackStop(pEnemy); return; } if(!pEnemy->isAlive()) { // client can generate swing to known dead target if autoswitch between autoshot and autohit is enabled in client options // stop attack state at client SendAttackStop(pEnemy); return; } _player->Attack(pEnemy,true); }
void WorldSession::HandleAttackSwingOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8); uint64 guid; recv_data >> guid; DEBUG_LOG( "WORLD: Recvd CMSG_ATTACKSWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid) ); Unit *pEnemy = ObjectAccessor::GetUnit(*_player, guid); if(!pEnemy) { if(GUID_HIPART(guid)!=HIGHGUID_PLAYER && GUID_HIPART(guid)!=HIGHGUID_UNIT) sLog.outError("WORLD: Object %u (TypeID: %u) isn't player or creature",GUID_LOPART(guid),GuidHigh2TypeId(GUID_HIPART(guid))); else sLog.outError( "WORLD: Enemy %s %u not found",(GUID_HIPART(guid)==HIGHGUID_PLAYER ? "player" : "creature"),GUID_LOPART(guid)); // stop attack state at client WorldPacket data( SMSG_ATTACKSTOP, (4+20) ); // we guess size data.append(GetPlayer()->GetPackGUID()); data << uint8(0x00); // must be packed guid data << uint32(0); // unk, can be 1 also SendPacket(&data); return; } if(_player->IsFriendlyTo(pEnemy) || pEnemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) { sLog.outError( "WORLD: Enemy %s %u is friendly",(GUID_HIPART(guid)==HIGHGUID_PLAYER ? "player" : "creature"),GUID_LOPART(guid)); // stop attack state at client WorldPacket data( SMSG_ATTACKSTOP, (4+20) ); // we guess size data.append(GetPlayer()->GetPackGUID()); data.append(pEnemy->GetPackGUID()); // must be packed guid data << uint32(0); // unk, can be 1 also SendPacket(&data); return; } _player->Attack(pEnemy,true); }
void WorldSession::HandleAttackSwingOpcode( WorldPacket & recv_data ) { ObjectGuid guid; recv_data >> guid; DEBUG_LOG("WORLD: Recvd CMSG_ATTACKSWING Message %s", guid.GetString().c_str()); Unit *pEnemy = ObjectAccessor::GetUnit(*_player, guid); if(!pEnemy) { if(!guid.IsUnit()) sLog.outError("WORLD: %u isn't player, pet or creature", guid.GetString().c_str()); else sLog.outError( "WORLD: Enemy %s not found", guid.GetString().c_str()); // stop attack state at client SendAttackStop(NULL); return; } if(_player->IsFriendlyTo(pEnemy) || pEnemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) { sLog.outError( "WORLD: Enemy %s is friendly",guid.GetString().c_str()); // stop attack state at client SendAttackStop(pEnemy); return; } if(!pEnemy->isAlive()) { // client can generate swing to known dead target if autoswitch between autoshot and autohit is enabled in client options // stop attack state at client SendAttackStop(pEnemy); return; } _player->Attack(pEnemy,true); }
void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z) { Map const* oldMap = GetMap(); Relocate(x, y, z); // we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference... // player far teleport would try to create same instance, but we need it NOW for transport... RemoveFromWorld(); ResetMap(); Map* newMap = sMapMgr->CreateBaseMap(newMapid); SetMap(newMap); ASSERT(GetMap()); AddToWorld(); for (UnitSet::iterator itr = _passengers.begin(); itr != _passengers.end();) { Unit* passenger = *itr; ++itr; switch (passenger->GetTypeId()) { case TYPEID_UNIT: passenger->ToCreature()->FarTeleportTo(newMap, x, y, z, passenger->GetOrientation()); break; case TYPEID_PLAYER: if (passenger->isDead() && !passenger->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) passenger->ToPlayer()->ResurrectPlayer(1.0f); passenger->ToPlayer()->TeleportTo(newMapid, x, y, z, GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT); break; } } if (oldMap != newMap) { UpdateForMap(oldMap); UpdateForMap(newMap); } MoveToNextWayPoint(); }
void WorldSession::HandleMovementOpcodes(WorldPacket & recvData) { uint16 opcode = recvData.GetOpcode(); Unit* mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a mover Player* plrMover = mover->ToPlayer(); // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plrMover && plrMover->IsBeingTeleported()) { recvData.rfinish(); // prevent warnings spam return; } /* extract packet */ uint64 guid; recvData.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recvData, &movementInfo); recvData.rfinish(); // prevent warnings spam // pussywizard: typical check for incomming movement packets if (!mover || !mover->IsInWorld() || mover->IsDuringRemoveFromWorld() || guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recvData.rfinish(); // prevent warnings spam return; } if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // T_POS ON VEHICLES! if (mover->GetVehicle()) movementInfo.transport.pos = mover->m_movementInfo.transport.pos; // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if (movementInfo.transport.pos.GetPositionX() > 75.0f || movementInfo.transport.pos.GetPositionY() > 75.0f || movementInfo.transport.pos.GetPositionZ() > 75.0f || movementInfo.transport.pos.GetPositionX() < -75.0f || movementInfo.transport.pos.GetPositionY() < -75.0f || movementInfo.transport.pos.GetPositionZ() < -75.0f) { recvData.rfinish(); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.transport.pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.transport.pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.transport.pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.transport.pos.GetOrientation())) { recvData.rfinish(); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plrMover) { if (!plrMover->GetTransport()) { if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) { plrMover->m_transport = transport; transport->AddPassenger(plrMover); } } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { bool foundNewTransport = false; plrMover->m_transport->RemovePassenger(plrMover); if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) { foundNewTransport = true; plrMover->m_transport = transport; transport->AddPassenger(plrMover); } if (!foundNewTransport) { plrMover->m_transport = NULL; movementInfo.transport.Reset(); } } } if (!mover->GetTransport() && !mover->GetVehicle()) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave { plrMover->m_transport->RemovePassenger(plrMover); plrMover->m_transport = NULL; movementInfo.transport.Reset(); } if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater()) { // now client not include swimming flag in case jumping under water plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } // Dont allow to turn on walking if charming other player if (mover->GetGUID() != _player->GetGUID()) movementInfo.flags &= ~MOVEMENTFLAG_WALKING; uint32 mstime = World::GetGameTimeMS(); /*----------------------*/ if(m_clientTimeDelay == 0) m_clientTimeDelay = mstime > movementInfo.time ? std::min(mstime - movementInfo.time, (uint32)100) : 0; // Xinef: do not allow to move with UNIT_FLAG_DISABLE_MOVE if (mover->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) { // Xinef: skip moving packets if (movementInfo.HasMovementFlag(MOVEMENTFLAG_MASK_MOVING)) return; movementInfo.pos.Relocate(mover->GetPositionX(), mover->GetPositionY(), mover->GetPositionZ()); if (mover->GetTypeId() == TYPEID_UNIT) { movementInfo.transport.guid = mover->m_movementInfo.transport.guid; movementInfo.transport.pos.Relocate(mover->m_movementInfo.transport.pos.GetPositionX(), mover->m_movementInfo.transport.pos.GetPositionY(), mover->m_movementInfo.transport.pos.GetPositionZ()); movementInfo.transport.seat = mover->m_movementInfo.transport.seat; } } /* process position-change */ WorldPacket data(opcode, recvData.size()); //movementInfo.time = movementInfo.time + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY; movementInfo.time = mstime; // pussywizard: set to time of relocation (server time), constant addition may smoothen movement clientside, but client sees target on different position than the real serverside position movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (pussywizard: only one packet when entering vehicle), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); mover->UpdatePosition(movementInfo.pos); return; } // pussywizard: previously always mover->UpdatePosition(movementInfo.pos); if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT && mover->GetTransport()) { float x, y, z, o; movementInfo.transport.pos.GetPosition(x, y, z, o); mover->GetTransport()->CalculatePassengerPosition(x, y, z, &o); mover->UpdatePosition(x, y, z, o); } else mover->UpdatePosition(movementInfo.pos); // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). // Xinef: moved it here, previously StopMoving function called when player died relocated him to last saved coordinates (which were in air) if (opcode == MSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight() && (!plrMover->GetTransport() || plrMover->GetTransport()->IsStaticTransport())) plrMover->HandleFall(movementInfo); // Xinef: interrupt parachutes upon falling or landing in water if (opcode == MSG_MOVE_FALL_LAND || opcode == MSG_MOVE_START_SWIM) mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_LANDING); // Parachutes if (plrMover) // nothing is charmed, or player charmed { if (plrMover->IsSitState() && (movementInfo.flags & (MOVEMENTFLAG_MASK_MOVING | MOVEMENTFLAG_MASK_TURNING))) plrMover->SetStandState(UNIT_STAND_STATE_STAND); plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.pos.GetPositionZ() < -500.0f) if (!plrMover->GetBattleground() || !plrMover->GetBattleground()->HandlePlayerUnderMap(_player)) { if (plrMover->IsAlive()) { plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM if (plrMover->IsAlive()) plrMover->KillPlayer(); } plrMover->StopMovingOnCurrentPos(); // pussywizard: moving corpse can't release spirit } } }
bool MoonScriptCreatureAI::IsValidUnitTarget( Object *pObject, TargetFilters pFilter, float pMinRange, float pMaxRange ) { //Make sure its a valid unit if ( !pObject->IsUnit() ) return false; if ( pObject->GetInstanceID() != _unit->GetInstanceID() ) return false; Unit *UnitTarget = TO_UNIT( pObject ); //Skip dead ( if required ), feign death or invisible targets if ( pFilter & TargetFilter_Corpse ) { if ( UnitTarget->isAlive() || !UnitTarget->IsCreature() || TO_CREATURE( UnitTarget )->creature_info->Rank == ELITE_WORLDBOSS ) return false; } else if ( !UnitTarget->isAlive() ) return false; if ( UnitTarget->IsPlayer() && TO_PLAYER( UnitTarget )->m_isGmInvisible ) return false; if ( UnitTarget->HasFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_FEIGN_DEATH ) ) return false; //Check if we apply target filtering if ( pFilter != TargetFilter_None ) { //Skip units not on threat list if ( ( pFilter & TargetFilter_Aggroed ) && _unit->GetAIInterface()->getThreatByPtr( UnitTarget ) == 0 ) return false; //Skip current attacking target if requested if ( ( pFilter & TargetFilter_NotCurrent ) && UnitTarget == _unit->GetAIInterface()->GetNextTarget() ) return false; //Keep only wounded targets if requested if ( ( pFilter & TargetFilter_Wounded ) && UnitTarget->GetHealthPct() >= 99 ) return false; //Skip targets not in melee range if requested if ( ( pFilter & TargetFilter_InMeleeRange ) && GetRangeToUnit( UnitTarget ) > _unit->GetAIInterface()->_CalcCombatRange( UnitTarget, false ) ) return false; //Skip targets not in strict range if requested if ( ( pFilter & TargetFilter_InRangeOnly ) && ( pMinRange > 0 || pMaxRange > 0 ) ) { float Range = GetRangeToUnit( UnitTarget ); if ( pMinRange > 0 && Range < pMinRange ) return false; if ( pMaxRange > 0 && Range > pMaxRange ) return false; }; //Skip targets not in Line Of Sight if requested if ( ( ~pFilter & TargetFilter_IgnoreLineOfSight ) && !_unit->IsInLineOfSight( UnitTarget ) ) return false; //Handle hostile/friendly if ( ( ~pFilter & TargetFilter_Corpse ) && ( pFilter & TargetFilter_Friendly ) ) { if ( !UnitTarget->CombatStatus.IsInCombat() ) return false; //Skip not-in-combat targets if friendly if ( isHostile( _unit, UnitTarget ) || _unit->GetAIInterface()->getThreatByPtr( UnitTarget ) > 0 ) return false; }; }; return true; //This is a valid unit target };
bool AIInterface::IsValidUnitTarget( Object *pObject, uint32 pFilter, float pMinRange, float pMaxRange ) { // Make sure its a valid unit if (!pObject->IsUnit() ) return false; Unit *UnitTarget = TO_UNIT( pObject ); if ( UnitTarget->GetInstanceID() != m_Unit->GetInstanceID() ) return false; // if ( !m_is_in_instance ) // skip instance check for spell casting if ( m_outOfCombatRange ) if ( UnitTarget->GetDistanceSq( GetReturnPos() ) > m_outOfCombatRange ) return false; float dist = m_Unit->CalcDistance( UnitTarget ); if ( UnitTarget != m_nextTarget ) if ( dist > _CalcAggroRange( UnitTarget ) ) return false; if ( pFilter & TargetFilter_Corpse ) { //Skip dead ( if required ), feign death or invisible targets if ( UnitTarget->isAlive() || !UnitTarget->IsCreature() || TO_CREATURE( UnitTarget )->creature_info->Rank == ELITE_WORLDBOSS ) return false; } else if ( !UnitTarget->isAlive() ) return false; if ( UnitTarget->IsPlayer() && TO_PLAYER( UnitTarget )->m_isGmInvisible ) return false; if ( UnitTarget->HasFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_FEIGN_DEATH ) ) return false; //Check if we apply target filtering if ( pFilter != TargetFilter_None ) { //Skip units not on threat list if ( ( pFilter & TargetFilter_Aggroed ) && getThreatByPtr( UnitTarget ) == 0 ) return false; //Skip current attacking target if requested if ( ( pFilter & TargetFilter_NotCurrent ) && UnitTarget == GetNextTarget() ) return false; //Keep only wounded targets if requested if ( ( pFilter & TargetFilter_Wounded ) && UnitTarget->GetHealthPct() >= 99 ) return false; //Skip targets not in melee range if requested if ( ( pFilter & TargetFilter_InMeleeRange ) && dist > _CalcCombatRange( UnitTarget, false ) ) return false; //Skip targets not in strict range if requested if ( ( pFilter & TargetFilter_InRangeOnly ) && ( pMinRange > 0 || pMaxRange > 0 ) ) { if ( pMinRange > 0 && dist < pMinRange ) return false; if ( pMaxRange > 0 && dist > pMaxRange ) return false; } //Skip targets not in Line Of Sight if requested if ( ( ~pFilter & TargetFilter_IgnoreLineOfSight ) && !m_Unit->IsInLineOfSight( UnitTarget ) ) return false; //Handle hostile/friendly if ( ( ~pFilter & TargetFilter_Corpse ) && ( pFilter & TargetFilter_Friendly ) ) { if ( !UnitTarget->CombatStatus.IsInCombat() ) return false; //Skip not-in-combat targets if friendly if ( isHostile( m_Unit, UnitTarget ) || getThreatByPtr( UnitTarget ) > 0 ) return false; } } return true; //This is a valid unit target }
void WorldSession::HandleMovementOpcodes(WorldPacket & recvData) { uint16 opcode = recvData.GetOpcode(); Unit* mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a mover Player* plrMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; Vehicle* vehMover = mover->GetVehicleKit(); if (vehMover) if (mover->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)) if (Unit* charmer = mover->GetCharmer()) if (charmer->GetTypeId() == TYPEID_PLAYER) plrMover = (Player*)charmer; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plrMover && plrMover->IsBeingTeleported()) { recvData.rfinish(); // prevent warnings spam return; } /* extract packet */ ObjectGuid guid; recvData >> guid.ReadAsPacked(); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recvData, &movementInfo); recvData.rfinish(); // prevent warnings spam // prevent tampered movement data if (guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recvData.rfinish(); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if (movementInfo.transport.pos.GetPositionX() > 50 || movementInfo.transport.pos.GetPositionY() > 50 || movementInfo.transport.pos.GetPositionZ() > 50) { recvData.rfinish(); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.transport.pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.transport.pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.transport.pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.transport.pos.GetOrientation())) { recvData.rfinish(); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plrMover && !plrMover->m_transport && !plrMover->m_temp_transport) { if (!plrMover->GetTransport()) { if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) transport->AddPassenger(plrMover); } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { plrMover->GetTransport()->RemovePassenger(plrMover); if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) transport->AddPassenger(plrMover); else movementInfo.transport.Reset(); } } if (!plrMover->m_transport) if (Map *tempMap = mover->GetMap()) if (GameObject *tempTransport = tempMap->GetGameObject(movementInfo.transport.guid)) if (tempTransport->IsTransport()) plrMover->m_temp_transport = tempTransport; if ((!plrMover && !mover->GetTransport() && !mover->GetVehicle()) || (plrMover && !plrMover->m_vehicle && !plrMover->m_transport && !plrMover->m_temp_transport)) // Not sure if the first part is needed. Just added it for verbosity. { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); } } else if (plrMover && (plrMover->m_transport || plrMover->m_temp_transport)) // if we were on a transport, leave { if (plrMover->m_transport) { plrMover->m_transport->RemovePassenger(plrMover); plrMover->m_transport = NULL; } plrMover->m_temp_transport = NULL; movementInfo.transport.Reset(); } // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight()) { // movement anticheat plrMover->m_anti_JumpCount = 0; plrMover->m_anti_JumpBaseZ = 0; if (!vehMover) plrMover->HandleFall(movementInfo); } if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater()) { // now client not include swimming flag in case jumping under water plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } if (plrMover) sAnticheatMgr->StartHackDetection(plrMover, movementInfo, opcode); uint32 mstime = getMSTime(); /*----------------------*/ if (m_clientTimeDelay == 0) m_clientTimeDelay = mstime - movementInfo.time; // begin anti cheat bool check_passed = true; #ifdef ANTICHEAT_DEBUG TC_LOG_WARN("cheat", "AC2-%s > time: %d fall-time: %d | xyzo: %f, %f, %fo(%f) flags[%X] opcode[%s] | transport (xyzo): %f, %f, %fo(%f)", plrMover->GetName(), movementInfo.time, movementInfo.fallTime, movementInfo.pos.m_positionX, movementInfo.pos.m_positionY, movementInfo.pos.m_positionZ, movementInfo.pos.m_orientation, movementInfo.flags, LookupOpcodeName(opcode), movementInfo.transport.pos.m_positionX, movementInfo.transport.pos.m_positionY, movementInfo.transport.pos.m_positionZ, movementInfo.transport.pos.m_orientation); TC_LOG_WARN("cheat", "AC2-%s Transport > GUID: (low)%d - (high)%d", plrMover->GetName(), GUID_LOPART(movementInfo.transport.guid), GUID_HIPART(movementInfo.transport.guid)); #endif if (plrMover) { if (World::GetEnableMvAnticheat() && !plrMover->IsGameMaster() && !plrMover->GetCharmerOrOwnerPlayerOrPlayerItself()->IsGameMaster() && !plrMover->GetCharmerOrOwnerPlayerOrPlayerItself()->GetVehicle()) { // calc time deltas int32 cClientTimeDelta = 1500; if (plrMover->m_anti_LastClientTime != 0) { cClientTimeDelta = movementInfo.time - plrMover->m_anti_LastClientTime; plrMover->m_anti_DeltaClientTime += cClientTimeDelta; plrMover->m_anti_LastClientTime = movementInfo.time; } else plrMover->m_anti_LastClientTime = movementInfo.time; const uint64 cServerTime = getMSTime(); uint32 cServerTimeDelta = 1500; if (plrMover->m_anti_LastServerTime != 0) { cServerTimeDelta = cServerTime - plrMover->m_anti_LastServerTime; plrMover->m_anti_DeltaServerTime += cServerTimeDelta; plrMover->m_anti_LastServerTime = cServerTime; } else plrMover->m_anti_LastServerTime = cServerTime; // resync times on client login (first 15 sec for heavy areas) if (plrMover->m_anti_DeltaServerTime < 15000 && plrMover->m_anti_DeltaClientTime < 15000) plrMover->m_anti_DeltaClientTime = plrMover->m_anti_DeltaServerTime; const int32 sync_time = plrMover->m_anti_DeltaClientTime - plrMover->m_anti_DeltaServerTime; #ifdef ANTICHEAT_DEBUG TC_LOG_WARN("cheat", "AC2-%s Time > cClientTimeDelta: %d, cServerTime: %d | deltaC: %d - deltaS: %d | SyncTime: %d", plrMover->GetName(), cClientTimeDelta, cServerTime, plrMover->m_anti_DeltaClientTime, plrMover->m_anti_DeltaServerTime, sync_time); #endif // mistiming checks const int32 GetMistimingDelta = abs(int32(World::GetMistimingDelta())); if (sync_time > GetMistimingDelta) { cClientTimeDelta = cServerTimeDelta; ++(plrMover->m_anti_MistimingCount); const bool bMistimingModulo = plrMover->m_anti_MistimingCount % 50 == 0; if (bMistimingModulo) { #ifdef ANTICHEAT_EXCEPTION_INFO TC_LOG_WARN("cheat", "AC2-%s, mistiming exception #%d, mistiming: %dms Action: %s", plrMover->GetName().c_str(), plrMover->m_anti_MistimingCount, sync_time, &Warden::Penalty); #endif check_passed = false; } //if (vehMover) // vehMover->Die(); // Tell the player "Sure, you can fly!" { WorldPacket data(SMSG_MOVE_SET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } // Then tell the player "Wait, no, you can't." { WorldPacket data(SMSG_MOVE_UNSET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } //plrMover->FallGround(2); /* Disabled, not passive at all, and apparently causing crashes: if (plrMover->m_anti_MistimingCount > World::GetMistimingAlarms()) { sWorld.SendWorldText(3, strcat("Kicking cheater: ", plrMover->GetName())); KickPlayer(); return; } */ } // end mistiming checks const uint32 curDest = plrMover->m_taxi.GetTaxiDestination(); // check taxi flight if (!curDest) { UnitMoveType move_type; // calculating section // current speed if (movementInfo.flags & MOVEMENTFLAG_FLYING) move_type = movementInfo.flags & MOVEMENTFLAG_BACKWARD ? MOVE_FLIGHT_BACK : MOVE_FLIGHT; else if (movementInfo.flags & MOVEMENTFLAG_SWIMMING) move_type = movementInfo.flags & MOVEMENTFLAG_BACKWARD ? MOVE_SWIM_BACK : MOVE_SWIM; else if (movementInfo.flags & MOVEMENTFLAG_WALKING) move_type = MOVE_WALK; // hmm... in first time after login player has MOVE_SWIMBACK instead MOVE_WALKBACK else move_type = movementInfo.flags & MOVEMENTFLAG_BACKWARD ? MOVE_SWIM_BACK : MOVE_RUN; const float current_speed = mover->GetSpeed(move_type); // end current speed // movement distance const float delta_x = plrMover->m_transport || plrMover->m_temp_transport ? 0 : plrMover->GetPositionX() - movementInfo.pos.GetPositionX(); const float delta_y = plrMover->m_transport || plrMover->m_temp_transport ? 0 : plrMover->GetPositionY() - movementInfo.pos.GetPositionY(); const float delta_z = plrMover->m_transport || plrMover->m_temp_transport ? 0 : plrMover->GetPositionZ() - movementInfo.pos.GetPositionZ(); const float real_delta = plrMover->m_transport || plrMover->m_temp_transport ? 0 : pow(delta_x, 2) + pow(delta_y, 2); // end movement distance const bool no_fly_auras = !(plrMover->HasAuraType(SPELL_AURA_FLY) || plrMover->HasAuraType(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED) || plrMover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || plrMover->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED) || plrMover->HasAuraType(SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS) || plrMover->HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK)); const bool no_fly_flags = (movementInfo.flags & (MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_FLYING)) == 0; const bool no_swim_flags = (movementInfo.flags & MOVEMENTFLAG_SWIMMING) == 0; const bool no_swim_in_water = !mover->IsInWater(); const bool no_swim_above_water = movementInfo.pos.GetPositionZ() - 7.0f >= mover->GetBaseMap()->GetWaterLevel(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY()); const bool no_swim_water = no_swim_in_water && no_swim_above_water; const bool no_waterwalk_flags = (movementInfo.flags & MOVEMENTFLAG_WATERWALKING) == 0; const bool no_waterwalk_auras = !(plrMover->HasAuraType(SPELL_AURA_WATER_WALK) || plrMover->HasAuraType(SPELL_AURA_GHOST)); if (cClientTimeDelta < 0) cClientTimeDelta = 0; const float time_delta = cClientTimeDelta < 1500 ? float(cClientTimeDelta) / 1000.0f : 1.5f; // normalize time - 1.5 second allowed for heavy loaded server const float tg_z = (real_delta != 0 && no_fly_auras && no_swim_flags) ? (pow(delta_z, 2) / real_delta) : -99999; // movement distance tangents if (current_speed < plrMover->m_anti_Last_HSpeed && plrMover->m_anti_LastSpeedChangeTime == 0) plrMover->m_anti_LastSpeedChangeTime = movementInfo.time + uint32(floor(((plrMover->m_anti_Last_HSpeed / current_speed) * 1500)) + 100); // 100ms above for random fluctuation const float allowed_delta = plrMover->m_transport || plrMover->m_temp_transport ? 2 : // movement distance allowed delta pow(std::max(current_speed, plrMover->m_anti_Last_HSpeed) * time_delta, 2) +2 // minimum allowed delta +(tg_z > 2.2 ? pow(delta_z, 2) / 2.37f : 0); // mountain fall allowed delta if (movementInfo.time > plrMover->m_anti_LastSpeedChangeTime) { plrMover->m_anti_Last_HSpeed = current_speed; // store current speed plrMover->m_anti_Last_VSpeed = -2.3f; plrMover->m_anti_LastSpeedChangeTime = 0; } // end calculating section // AntiGravity (thanks to Meekro) const float JumpHeight = plrMover->m_anti_JumpBaseZ - movementInfo.pos.GetPositionZ(); if (no_fly_auras && no_swim_in_water && plrMover->m_anti_JumpBaseZ != 0 && JumpHeight < plrMover->m_anti_Last_VSpeed) { #ifdef ANTICHEAT_EXCEPTION_INFO TC_LOG_WARN("cheat", "AC2-%s, AntiGravity exception. JumpHeight = %f, Allowed Vertical Speed = %f", plrMover->GetName().c_str(), JumpHeight, plrMover->m_anti_Last_VSpeed); #endif check_passed = false; //if (vehMover) // vehMover->Die(); // Tell the player "Sure, you can fly!" { WorldPacket data(SMSG_MOVE_SET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } // Then tell the player "Wait, no, you can't." { WorldPacket data(SMSG_MOVE_UNSET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } //plrMover->FallGround(2); } // multi jump checks if (opcode == MSG_MOVE_JUMP) { if (no_fly_auras && no_swim_water) { if (plrMover->m_anti_JumpCount >= 1) { // don't process new jump packet check_passed = false; #ifdef ANTICHEAT_EXCEPTION_INFO TC_LOG_WARN("cheat", "AC2-%s, Multijump exception.", plrMover->GetName().c_str(), JumpHeight, plrMover->m_anti_Last_VSpeed); #endif //if (vehMover) // vehMover->Die(); // Tell the player "Sure, you can fly!" { WorldPacket data(SMSG_MOVE_SET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } // Then tell the player "Wait, no, you can't." { WorldPacket data(SMSG_MOVE_UNSET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } //plrMover->FallGround(2); plrMover->m_anti_JumpCount = 0; } else { plrMover->m_anti_JumpCount += 1; plrMover->m_anti_JumpBaseZ = movementInfo.pos.GetPositionZ(); } } else plrMover->m_anti_JumpCount = 0; } // speed and teleport hack checks if (real_delta > allowed_delta) { #ifdef ANTICHEAT_EXCEPTION_INFO if (real_delta < 4900.0f) { TC_LOG_WARN("cheat", "AC2-%s, speed exception | cDelta=%f aDelta=%f | cSpeed=%f lSpeed=%f deltaTime=%f", plrMover->GetName().c_str(), real_delta, allowed_delta, current_speed, plrMover->m_anti_Last_HSpeed, time_delta); } else { TC_LOG_WARN("cheat", "AC2-%s, teleport exception | cDelta=%f aDelta=%f | cSpeed=%f lSpeed=%f deltaTime=%f", plrMover->GetName().c_str(), real_delta, allowed_delta, current_speed, plrMover->m_anti_Last_HSpeed, time_delta); } #endif check_passed = false; //if (vehMover) // vehMover->Die(); //plrMover->FallGround(2); } // mountain hack checks // 1.56f (delta_z < GetPlayer()->m_anti_Last_VSpeed)) if (delta_z < plrMover->m_anti_Last_VSpeed && plrMover->m_anti_JumpCount == 0 && tg_z > 2.37f) { #ifdef ANTICHEAT_EXCEPTION_INFO TC_LOG_WARN("cheat", "AC2-%s, mountain exception | tg_z=%f", plrMover->GetName().c_str(), tg_z); #endif check_passed = false; // if (vehMover) // vehMover->Die(); } // Fly hack checks if (no_fly_auras && !no_fly_flags) { #ifdef ANTICHEAT_EXCEPTION_INFO // Aura numbers: 201, 206, 207, 208, 209, 211 //TC_LOG_WARN("cheat", "AC2-%s, flight exception. {SPELL_AURA_FLY=[%X]} {SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED=[%X]} {SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED=[%X]} {SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS=[%X]} {SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK=[%X]} {plrMover->GetVehicle()=[%X]}", plrMover->GetName().c_str(), //Last Updated By ShopWoW.ir plrMover->HasAuraType(SPELL_AURA_FLY), plrMover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED), plrMover->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED), plrMover->HasAuraType(SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS), plrMover->HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK), plrMover->GetVehicle(); #endif check_passed = false; //if (vehMover) // vehMover->Die(); // Tell the player "Sure, you can fly!" { WorldPacket data(SMSG_MOVE_SET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } // Then tell the player "Wait, no, you can't." { WorldPacket data(SMSG_MOVE_UNSET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } //plrMover->FallGround(2); } // Waterwalk checks if (no_waterwalk_auras && !no_waterwalk_flags) { #ifdef ANTICHEAT_EXCEPTION_INFO TC_LOG_WARN("cheat", "AC2-%s, waterwalk exception. [%X]{SPELL_AURA_WATER_WALK=[%X]}", plrMover->GetName().c_str(), movementInfo.flags, plrMover->HasAuraType(SPELL_AURA_WATER_WALK)); #endif check_passed = false; //if (vehMover) // vehMover->Die(); // Tell the player "Sure, you can fly!" { WorldPacket data(SMSG_MOVE_SET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } // Then tell the player "Wait, no, you can't." { WorldPacket data(SMSG_MOVE_UNSET_CAN_FLY, 12); data << plrMover->GetPackGUID(); data << uint32(0); SendPacket(&data); } //plrMover->FallGround(2); } // Teleport To Plane checks if (no_swim_in_water && movementInfo.pos.GetPositionZ() < 0.0001f && movementInfo.pos.GetPositionZ() > -0.0001f) { if (const Map *map = plrMover->GetMap()) { float plane_z = map->GetHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), MAX_HEIGHT) - movementInfo.pos.GetPositionZ(); plane_z = (plane_z < -500.0f) ? 0.0f : plane_z; // check holes in height map if (plane_z > 0.1f || plane_z < -0.1f) { #ifdef ANTICHEAT_DEBUG TC_LOG_WARN("cheat", "AC2-%s, teleport to plane exception. plane_z: %f", plrMover->GetName(), plane_z); #endif #ifdef ANTICHEAT_EXCEPTION_INFO if (plrMover->m_anti_TeleToPlane_Count > World::GetTeleportToPlaneAlarms()) { TC_LOG_WARN("cheat", "AC2-%s, teleport to plane exception. Exception count: %d", plrMover->GetName().c_str(), plrMover->m_anti_TeleToPlane_Count); /* Disabled, not passive at all, and apparently causing crashes: sWorld.SendWorldText(3, strcat("Kicking cheater: ", plrMover->GetName())); KickPlayer(); return; */ } #endif ++(plrMover->m_anti_TeleToPlane_Count); check_passed = false; //if (vehMover) // vehMover->Die(); } } } else plrMover->m_anti_TeleToPlane_Count = 0; } } } /* process position-change */ if (check_passed) { WorldPacket data(opcode, recvData.size()); movementInfo.time = movementInfo.time + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY; movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // Some vehicles allow the passenger to turn by himself if (Vehicle* vehicle = mover->GetVehicle()) { if (VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(mover)) { if (seat->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING) { if (movementInfo.pos.GetOrientation() != mover->GetOrientation()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); } } } return; } mover->UpdatePosition(movementInfo.pos); if (plrMover && !vehMover) // nothing is charmed, or player charmed { if (plrMover->IsSitState() && (movementInfo.flags & (MOVEMENTFLAG_MASK_MOVING | MOVEMENTFLAG_MASK_TURNING))) plrMover->SetStandState(UNIT_STAND_STATE_STAND); plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); float underMapValueZ; switch (plrMover->GetMapId()) { case 617: underMapValueZ = 3.0f; break; // Dalaran Sewers case 618: underMapValueZ = 28.0f; break; // Ring of Valor default: underMapValueZ = -500.0f; break; } if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY()) || movementInfo.pos.GetPositionZ() < underMapValueZ) { if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { // NOTE: this is actually called many times while falling // even after the player has been teleported away /// @todo discard movement packets after the player is rooted if (plrMover->IsAlive()) { plrMover->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM/etc // change the death state to CORPSE to prevent the death timer from // starting in the next player update if (!plrMover->IsAlive()) plrMover->KillPlayer(); } } } // movement anticheat if (plrMover->m_anti_AlarmCount > 0) { TC_LOG_WARN("cheat", "AC2-%s produce %d anticheat alarms.", plrMover->GetName().c_str(), plrMover->m_anti_AlarmCount); plrMover->m_anti_AlarmCount = 0; } // end movement anticheat } } else if (plrMover) { if (plrMover->m_transport) { plrMover->m_transport->RemovePassenger(plrMover); plrMover->m_transport = NULL; } plrMover->m_temp_transport = NULL; ++(plrMover->m_anti_AlarmCount); WorldPacket data; plrMover->SetUnitMovementFlags(0); plrMover->SendTeleportAckPacket(); plrMover->BuildHeartBeatMsg(&data); plrMover->SendMessageToSet(&data, true); } }