void MoveSplineInitArgs::SetTransportData(Unit& unit) { WorldObject* transport = NULL; ObjectGuid _transportGuid = unit.GetTransportGuid(); switch(_transportGuid.GetHigh()) { case HIGHGUID_PLAYER: case HIGHGUID_VEHICLE: transport = unit.GetMap()->GetUnit(_transportGuid); break; case HIGHGUID_MO_TRANSPORT: transport = unit.GetMap()->GetTransport(_transportGuid); break; case HIGHGUID_TRANSPORT: transport = unit.GetMap()->GetGameObject(_transportGuid); break; } if (!transport) { ERROR_LOG("MoveSplineInitArgs: Unsupported transport %s for %s", _transportGuid.GetString().c_str(), unit.GetObjectGuid().GetString().c_str()); return; } else DEBUG_LOG("MoveSplineInitArgs: Set transport %s for %s", _transportGuid.GetString().c_str(), unit.GetObjectGuid().GetString().c_str()); transportGuid = _transportGuid.GetRawValue(); transportSeat = unit.GetTransSeat(); transportPos = Location(transport->GetPositionX(), transport->GetPositionY(), transport->GetPositionZ(), transport->GetOrientation()); }
void HandleOnHit() { Unit* caster = GetCaster(); int32 damage; int32 count = 1; damage = 675000; if (caster->GetMap()->IsHeroic()) { if (caster->GetMap()->Is25ManRaid()) damage = 2700000; else damage = 1350000; } else { if (caster->GetMap()->Is25ManRaid()) damage = 2000000; else damage = 675000; } Map::PlayerList const &PlayerList = caster->GetMap()->GetPlayers(); if (!PlayerList.isEmpty()) for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (i->getSource()->isAlive()) { if (caster->GetExactDist(i->getSource()) < 26.0f) { count++; } } damage = damage / count; SetHitDamage(damage); }
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) { PreventDefaultAction(); Unit* healer = eventInfo.GetProcTarget(); if (healer->HasAura(SPELL_VITAL_FLAME)) return; bool is25ManHeroic = healer->GetMap()->IsHeroic() && healer->GetMap()->Is25ManRaid(); uint32 stacks = healer->GetAuraCount(SPELL_VITAL_SPARK) + std::min(uint8(ceil(GetStackAmount() / (is25ManHeroic ? 5.0 : 3.0))), uint8(255)); healer->SetAuraStack(SPELL_VITAL_SPARK, healer, stacks); if (Aura* aura = healer->GetAura(SPELL_VITAL_SPARK)) aura->RefreshDuration(); }
uint64 SelectNearbyShallowGrave() { Unit *searcher = instance->GetUnit(ObjectGuid(m_uiGraveyardSearcherGuid)); // Get the list of usable graves (not used already by players) std::list<GameObject*> lGravesInRange; for (GuidList::const_iterator itr = m_lShallowGravesGuidList.begin(); itr != m_lShallowGravesGuidList.end(); ++itr) { GameObject* pGo = searcher->GetMap()->GetGameObject(*itr); // Go spawned and no looting in process if (pGo && pGo->isSpawned() && pGo->getLootState() == GO_READY) { lGravesInRange.push_back(pGo); } } if (lGravesInRange.empty()) { return 0; } // Sort the graves lGravesInRange.sort(ObjectDistanceOrder(searcher)); return (*lGravesInRange.begin())->GetObjectGuid().GetRawValue(); }
void Transport::UpdatePassengerPositions() { for (UnitSet::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr) { Unit* passenger = *itr; // transport teleported but passenger not yet (can happen for players) if (passenger->GetMap() != GetMap()) continue; float x = GetPositionX() + (passenger->m_movementInfo.t_pos.m_positionX * cos(GetOrientation()) + passenger->m_movementInfo.t_pos.m_positionY * sin(GetOrientation() + M_PI)); float y = GetPositionY() + (passenger->m_movementInfo.t_pos.m_positionY * cos(GetOrientation()) + passenger->m_movementInfo.t_pos.m_positionX * sin(GetOrientation())); float z = GetPositionZ() + passenger->m_movementInfo.t_pos.m_positionZ; float o = GetOrientation() + passenger->m_movementInfo.t_pos.m_orientation; MapManager::NormalizeOrientation(o); switch (passenger->GetTypeId()) { case TYPEID_UNIT: passenger->ToCreature()->SetHomePosition(x, y, z, o); GetMap()->CreatureRelocation(passenger->ToCreature(), x, y, z, o, false); break; case TYPEID_PLAYER: GetMap()->PlayerRelocation(passenger->ToPlayer(), x, y, z, o); break; } if (passenger->IsVehicle()) passenger->GetVehicleKit()->RelocatePassengers(x, y, z, o); } }
void HandleScript(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); Unit* target = GetHitUnit(); Unit* caster = GetOriginalCaster(); if (target && caster && caster->GetMap()) { for (uint32 i = 0; i < 3; ++i) { caster->CastSpell(target, 58689, true); caster->CastSpell(target, 58692, true); } caster->CastSpell(target, caster->GetMap()->Is25ManRaid() ? 60883 : 58695, true); } }
void ModDestHeight(SpellDestination& dest) { Unit* caster = GetCaster(); Position pos = caster->GetPosition(); pos.m_positionZ = caster->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 100.0f); dest.Relocate(pos); }
void HandleScript(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); Unit* target = GetHitUnit(); if (!caster || !target) return; if (AuraPtr smash = caster->GetAura(SPELL_SMASH_AURA)) { int32 stacks = smash->GetStackAmount(); if (stacks) { if (stacks > 1) smash->SetStackAmount(stacks - 1); else caster->RemoveAurasDueToSpell(SPELL_SMASH_AURA); } } const SpellInfo* SmashSpell = sSpellMgr->GetSpellInfo(SPELL_SMASH, caster->GetMap()->GetDifficulty()); if (SmashSpell) { std::list<Creature*> verminList; GetCreatureListWithEntryInGrid(verminList, caster, NPC_BOPPER, 6.0f); GetCreatureListWithEntryInGrid(verminList, caster, NPC_HOPPER, 6.0f); GetCreatureListWithEntryInGrid(verminList, caster, NPC_HOPPLING, 6.0f); if (!verminList.empty()) for (auto vermin: verminList) caster->DealDamage(vermin, vermin->GetHealth(), NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, SmashSpell); } }
void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); if (Creature* totem = caster->GetMap()->GetCreature(caster->m_SummonSlot[1])) { uint8 rank = GetSpellInfo()->GetRank(); if (totem->IsTotem()) caster->CastSpell(totem, sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_FIRE_NOVA_TRIGGERED_R1, rank), true); } }
void HandleTriggerMissile(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); Unit* caster = GetCaster(); Unit* target = GetTargetUnit(); if (caster && target) { uint32 id = uint32(caster->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? 61912 : 63494); caster->CastSpell(target, id, true); } }
void HandleScript(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); caster->CastSpell(caster, SPELL_FLAME_SPHERE_SUMMON_1, true); if (caster->GetMap()->IsHeroic()) { caster->CastSpell(caster, SPELL_FLAME_SPHERE_SUMMON_2, true); caster->CastSpell(caster, SPELL_FLAME_SPHERE_SUMMON_3, true); } }
void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); uint8 rank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); if (uint32 spellId = sSpellMgr->GetSpellWithRank(SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1, rank)) { Creature* totem = caster->GetMap()->GetCreature(caster->m_SummonSlot[1]); if (totem && totem->isTotem()) totem->CastSpell(totem, spellId, true); } }
SpellCastResult CheckIfCorpseNear() { Unit* caster = GetCaster(); float max_range = GetSpellInfo()->GetMaxRange(false); WorldObject* result = NULL; // search for nearby enemy corpse in range Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_CHECK_ENEMY); Trinity::WorldObjectSearcher<Trinity::AnyDeadUnitSpellTargetInRangeCheck> searcher(caster, result, check); caster->GetMap()->VisitFirstFound(caster->m_positionX, caster->m_positionY, max_range, searcher); if (!result) return SPELL_FAILED_NO_EDIBLE_CORPSES; return SPELL_CAST_OK; }
void HandleOnCast() { Unit* caster = GetCaster(); Map::PlayerList const &PlayerList = caster->GetMap()->GetPlayers(); if (!PlayerList.isEmpty()) for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (i->getSource()->isAlive()) { if (!caster->IsWithinLOSInMap(i->getSource())) { i->getSource()->RemoveAurasDueToSpell(103785); //TODO this just remove aura stacks but i->getSource() should not receive damage at all } } }
void SetDest(SpellDestination& dest) { // Do our own calculations for the destination position. /// TODO: Remove this once we find a general rule for WorldObject::MovePosition (this spell shouldn't take the Z change into consideration) Unit* caster = GetCaster(); float angle = float(rand_norm()) * static_cast<float>(2 * M_PI); uint32 dist = caster->GetObjectSize() + GetSpellInfo()->GetEffect(EFFECT_0)->CalcRadius(caster) * (float)rand_norm(); float x = caster->GetPositionX() + dist * std::cos(angle); float y = caster->GetPositionY() + dist * std::sin(angle); float z = caster->GetMap()->GetHeight(caster->GetPhases(), x, y, caster->GetPositionZ()); float o = dest._position.GetOrientation(); dest.Relocate({ x, y, z, o }); }
void SetDestPosition(SpellEffIndex effIndex) { // Do our own calculations for the destination position. /// TODO: Remove this once we find a general rule for WorldObject::MovePosition (this spell shouldn't take the Z change into consideration) Unit* caster = GetCaster(); float angle = float(rand_norm()) * static_cast<float>(2 * M_PI); uint32 dist = caster->GetObjectSize() + GetSpellInfo()->GetEffect(effIndex)->CalcRadius(GetCaster()) * (float)rand_norm(); float x = caster->GetPositionX() + dist * std::cos(angle); float y = caster->GetPositionY() + dist * std::sin(angle); float z = caster->GetMap()->GetHeight(x, y, caster->GetPositionZ()); const_cast<WorldLocation*>(GetExplTargetDest())->Relocate(x, y, z); GetHitDest()->Relocate(x, y, z); }
void HandleScript(SpellEffIndex /*effIndex*/) { Unit* target = GetHitUnit(); if (!target || !target->GetVehicle()) return; switch (target->GetMap()->GetDifficulty()) { case RAID_DIFFICULTY_10MAN_NORMAL: target->RemoveAura(GetSpellInfo()->Effects[EFFECT_0].CalcValue()); break; case RAID_DIFFICULTY_25MAN_NORMAL: target->RemoveAura(GetSpellInfo()->Effects[EFFECT_1].CalcValue()); break; default: break; } }
void HandleScript(SpellEffIndex /*effIndex*/) { Unit* target = GetHitUnit(); if (!target || !target->GetVehicle()) return; switch (target->GetMap()->GetDifficultyID()) { case DIFFICULTY_10_N: target->RemoveAura(GetSpellInfo()->GetEffect(EFFECT_0)->CalcValue()); break; case DIFFICULTY_25_N: target->RemoveAura(GetSpellInfo()->GetEffect(EFFECT_1)->CalcValue()); break; default: break; } }
void HandleTriggerSpell(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); PreventHitEffect(EFFECT_0); PreventHitEffect(EFFECT_1); std::list<Creature*> unitList; Unit* target = NULL; caster->GetCreaturesWithEntryInRange(unitList, 30.0f, NPC_BLUE_RACER); if (!unitList.empty()) for (std::list<Creature*>::const_iterator itr = unitList.begin(); itr != unitList.end(); ++itr) if (caster->HasInLine((*itr), 1.0f) && (*itr)->GetGUID() != caster->GetGUID()) { target = (*itr); break; } if (!target) { unitList.clear(); caster->GetCreaturesWithEntryInRange(unitList, 30.0f, NPC_RED_RACER); if (!unitList.empty()) for (std::list<Creature*>::const_iterator itr = unitList.begin(); itr != unitList.end(); ++itr) if (caster->HasInLine((*itr), 1.0f) && (*itr)->GetGUID() != caster->GetGUID()) { target = (*itr); break; } } if (target) { caster->CastSpell(target, SPELL_RACER_CHARGE_TO_OBJECT, true); caster->CastSpell(target, SPELL_RACER_SLAM_HIT, true); } else { Position pos; float x = caster->GetPositionX()+30*cos(caster->GetOrientation()); float y = caster->GetPositionY()+30*sin(caster->GetOrientation()); pos.Relocate(x, y, caster->GetMap()->GetHeight(x, y, MAX_HEIGHT)+0.5f); //caster->GetFirstCollisionPosition(pos, 30.0f, caster->GetOrientation()); caster->CastSpell(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), SPELL_RACER_CHARGE_TO_OBJECT, true); } }
void HandleScript(SpellEffIndex /*effIndex*/) { Unit* target = this->GetHitPlayer(); if (!target) return; if (!target->GetVehicle()) return; switch (target->GetMap()->GetDifficulty()) { case RAID_DIFFICULTY_10MAN_NORMAL: target->RemoveAura(SpellMgr::CalculateSpellEffectAmount(GetSpellInfo(), EFFECT_0)); break; case RAID_DIFFICULTY_25MAN_NORMAL: target->RemoveAura(SpellMgr::CalculateSpellEffectAmount(GetSpellInfo(), EFFECT_1)); break; } }
void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); if (Unit* unitTarget = GetHitUnit()) { if (!unitTarget->isAlive()) return; uint8 rank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); if (caster->IsFriendlyTo(unitTarget)) caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(PRIEST_SPELL_PENANCE_R1_HEAL, rank), false, 0); // AllowTwoSide.Interaction.Group will break this spell so // set friendly also players in your party or raid group only in arena or bg else if (caster->IsInRaidWith(unitTarget) && caster->GetMap()->IsBattlegroundOrArena()) caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(PRIEST_SPELL_PENANCE_R1_HEAL, rank), false, 0); else caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(PRIEST_SPELL_PENANCE_R1_DAMAGE, rank), false, 0); } }
void JustDied(Unit *victim) { if(pInstance && IsEvent) { pInstance->SetData(DATA_AZGALOREVENT, DONE); Unit* pCreature = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_AZGALOR)); if(pCreature) { Creature* pUnit = pCreature->SummonCreature(21987,pCreature->GetPositionX(),pCreature->GetPositionY(),pCreature->GetPositionZ(),0,TEMPSUMMON_TIMED_DESPAWN,10000); Map *map = pCreature->GetMap(); if (map->IsDungeon() && pUnit) { pUnit->SetVisibility(VISIBILITY_OFF); Map::PlayerList const &PlayerList = map->GetPlayers(); if (PlayerList.isEmpty()) return; for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { if (i->getSource()) { WorldPacket data(SMSG_MESSAGECHAT, 200); pUnit->BuildMonsterChat(&data,CHAT_MSG_MONSTER_YELL,"All of your efforts have been in vain, for the draining of the World Tree has already begun. Soon the heart of your world will beat no more.",0,"Archimonde",i->getSource()->GetGUID()); i->getSource()->GetSession()->SendPacket(&data); WorldPacket data2(SMSG_PLAY_SOUND, 4); data2 << 10986; i->getSource()->GetSession()->SendPacket(&data2); } } } } } DoPlaySoundToSet(m_creature, SOUND_ONDEATH); }
void HandleAfterEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Unit* target = GetTarget(); if(Creature* sha = target->FindNearestCreature(NPC_SHA, 100.0f)) { if (target->GetTypeId() == TYPEID_PLAYER) { sha->CastSpell(target, SPELL_AGGRESSIVE_BEHAVIOUR); Map* map = target->GetMap(); Map::PlayerList const& players = map->GetPlayers(); for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) { Player* player = i->getSource(); if (player && player->IsInRange(target, 0.0f, 5.0f, false)) sha->CastSpell(player, SPELL_AGGRESSIVE_BEHAVIOUR); } } } }
void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) { Opcodes opcode = recv_data.GetOpcodeEnum(); recv_data.hexlike(); Unit *mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a mover Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plMover && plMover->IsBeingTeleported()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* extract packet */ MovementInfo movementInfo; ReadMovementInfo(recv_data, &movementInfo); recv_data.rpos(recv_data.wpos()); // prevent warnings spam // prevent tampered movement data if (movementInfo.guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.flags & 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.t_pos.GetPositionX() > 50 || movementInfo.t_pos.GetPositionY() > 50 || movementInfo.t_pos.GetPositionZ() > 50) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if (!Voragine::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.t_pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.t_pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.t_pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.t_pos.GetOrientation())) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->GetTransport()) { // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.t_guid) { plMover->m_transport = (*iter); (*iter)->AddPassenger(plMover); break; } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject *go = mover->GetMap()->GetGameObject(movementInfo.t_guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } } else if (plMover && plMover->GetTransport()) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); movementInfo.t_time = 0; movementInfo.t_seat = -1; } // 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 && plMover && !plMover->isInFlight()) plMover->HandleFall(movementInfo); if (plMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater()) { // now client not include swimming flag in case jumping under water plMover->SetInWater(!plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } /*----------------------*/ /* process position-change */ WorldPacket data(SMSG_PLAYER_MOVE/*recv_data.GetOpcode()*/, recv_data.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->SetPosition(movementInfo.pos); if (plMover) // nothing is charmed, or player charmed { if (plMover->GetEmoteState() != 0 && opcode == MSG_MOVE_START_FORWARD && opcode != MSG_MOVE_SET_FACING && opcode != MSG_MOVE_START_TURN_LEFT && opcode != MSG_MOVE_START_TURN_RIGHT && opcode != MSG_MOVE_STOP_TURN) plMover->SetEmoteState(0); plMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.pos.GetPositionZ() < -500.0f) { if (!(plMover->InBattleground() && plMover->GetBattleground() && plMover->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 (plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // pl can be alive if GM/etc if (!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } }
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { uint32 opcode = recv_data.GetOpcode(); DEBUG_LOG("WORLD: Recvd %s (%u, 0x%X) opcode", opCodes.LookupOpcode(opcode)->name, opcode, opcode); Unit *mover = _player; // for better code compatibiltiy until mover not backported from master Player *plMover = _player; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if(plMover && plMover->IsBeingTeleported()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* extract packet */ MovementInfo movementInfo; recv_data >> movementInfo; /*----------------*/ if (!MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o)) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT)) { // transports size limited // (also received at zeppelin/lift leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if( movementInfo.GetTransportPos()->x > 50 || movementInfo.GetTransportPos()->y > 50 || movementInfo.GetTransportPos()->z > 100 ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if( !MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x + movementInfo.GetTransportPos()->x, movementInfo.GetPos()->y + movementInfo.GetTransportPos()->y, movementInfo.GetPos()->z + movementInfo.GetTransportPos()->z, movementInfo.GetPos()->o + movementInfo.GetTransportPos()->o) ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->m_transport) { // elevators also cause the client to send MOVEFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) { if ((*iter)->GetObjectGuid() == movementInfo.GetTransportGuid()) { // unmount before boarding plMover->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); GetPlayer()->m_transport = (*iter); (*iter)->AddPassenger(plMover); break; } } } } else if (plMover && plMover->m_transport) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.ClearTransportData(); } // 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 && plMover && !plMover->isInFlight()) plMover->HandleFall(movementInfo); if (plMover && (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING) != plMover->IsInWater())) { // now client not include swimming flag in case jumping under water plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) ); } /*----------------------*/ /* process position-change */ movementInfo.UpdateTime(getMSTime()); WorldPacket data(opcode, recv_data.size()); data.appendPackGUID(mover->GetGUID()); // write guid movementInfo.Write(data); // write data mover->SendMessageToSetExcept(&data, _player); if(plMover) // nothing is charmed, or player charmed { plMover->SetPosition(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); plMover->m_movementInfo = movementInfo; plMover->UpdateFallInformationIfNeed(movementInfo, opcode); // after move info set if ((opcode == MSG_MOVE_SET_WALK_MODE || opcode == MSG_MOVE_SET_RUN_MODE)) plMover->UpdateWalkMode(plMover, false); if(plMover->isMovingOrTurning()) plMover->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if(movementInfo.GetPos()->z < -500.0f) { if(plMover->InBattleGround() && plMover->GetBattleGround() && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // 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(plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // pl can be alive if GM/etc if(!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } else // creature charmed { if(mover->IsInWorld()) mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); } }
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 // prevent tampered movement data if (guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recvData.rfinish(); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.flags & 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) { if (!plrMover->GetTransport()) { // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just dismount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.transport.guid) { plrMover->m_transport = *iter; (*iter)->AddPassenger(plrMover); break; } } } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { bool foundNewTransport = false; plrMover->m_transport->RemovePassenger(plrMover); for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.transport.guid) { foundNewTransport = true; plrMover->m_transport = *iter; (*iter)->AddPassenger(plrMover); break; } } if (!foundNewTransport) { plrMover->m_transport = NULL; movementInfo.transport.Reset(); } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) 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(); } // 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()) 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); /*----------------------*/ /* process position-change */ WorldPacket data(opcode, recvData.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->UpdatePosition(movementInfo.pos); if (plrMover) // nothing is charmed, or player charmed { plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.pos.GetPositionZ() < -500.0f) { 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->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(); } } } } }
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { uint32 opcode = recv_data.GetOpcode(); sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); Unit *mover = _player->m_mover; Player *plMover = mover->GetTypeId()==TYPEID_PLAYER ? (Player*)mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if(plMover && plMover->IsBeingTeleported()) return; /* extract packet */ MovementInfo movementInfo; ReadMovementInfo(recv_data, &movementInfo); /*----------------*/ if(recv_data.size() != recv_data.rpos()) { sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is %u bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos()); KickPlayer(); return; } if (!MaNGOS::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o)) 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.t_x > 50 || movementInfo.t_y > 50 || movementInfo.t_z > 50 ) return; if( !MaNGOS::IsValidMapCoord(movementInfo.x+movementInfo.t_x, movementInfo.y + movementInfo.t_y, movementInfo.z + movementInfo.t_z, movementInfo.o + movementInfo.t_o) ) return; // if we boarded a transport, add us to it if (plMover && !plMover->m_transport) { // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.t_guid) { plMover->m_transport = (*iter); (*iter)->AddPassenger(plMover); break; } } } } else if (plMover && plMover->m_transport) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.t_x = 0.0f; movementInfo.t_y = 0.0f; movementInfo.t_z = 0.0f; movementInfo.t_o = 0.0f; movementInfo.t_time = 0; movementInfo.t_seat = -1; } // 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 && plMover && !plMover->isInFlight()) plMover->HandleFall(movementInfo); if (plMover && (movementInfo.HasMovementFlag(MOVEMENTFLAG_SWIMMING) != plMover->IsInWater())) { // now client not include swimming flag in case jumping under water plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z) ); } /*----------------------*/ /* process position-change */ recv_data.put<uint32>(6, getMSTime()); // fix time, offset flags(4) + unk(2) WorldPacket data(recv_data.GetOpcode(), (mover->GetPackGUID().size()+recv_data.size())); data.append(mover->GetPackGUID()); // use mover guid data.append(recv_data.contents(), recv_data.size()); GetPlayer()->SendMessageToSet(&data, false); if(plMover) // nothing is charmed, or player charmed { plMover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); plMover->m_movementInfo = movementInfo; plMover->UpdateFallInformationIfNeed(movementInfo, recv_data.GetOpcode()); if(plMover->isMovingOrTurning()) plMover->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if(movementInfo.z < -500.0f) { if(plMover->InBattleGround() && plMover->GetBattleGround() && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // 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(plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // pl can be alive if GM/etc if(!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } else // creature charmed { if(Map *map = mover->GetMap()) map->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); } }
void WorldSession::HandleMoverRelocation(MovementInfo& movementInfo) { if (m_clientTimeDelay == 0) m_clientTimeDelay = WorldTimer::getMSTime() - movementInfo.GetTime(); movementInfo.UpdateTime(movementInfo.GetTime() + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY); Unit* mover = _player->GetMover(); if (Player* plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : nullptr) { if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT)) { if (!plMover->m_transport) { // elevators also cause the client to send MOVEFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) { if ((*iter)->GetObjectGuid() == movementInfo.GetTransportGuid()) { plMover->m_transport = (*iter); (*iter)->AddPassenger(plMover); break; } } } } else if (plMover->m_transport) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = nullptr; movementInfo.ClearTransportData(); } if (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING) != plMover->IsInWater()) { // now client not include swimming flag in case jumping under water plMover->SetInWater(!plMover->IsInWater() || plMover->GetTerrain()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z)); } plMover->SetPosition(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); plMover->m_movementInfo = movementInfo; if (movementInfo.GetPos()->z < -500.0f) { if (plMover->GetBattleGround() && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // 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 (plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, plMover->GetMaxHealth()); // pl can be alive if GM/etc if (!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } else // creature charmed { if (mover->IsInWorld()) mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); } }
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { uint32 opcode = recv_data.GetOpcode(); DEBUG_LOG("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); recv_data.hexlike(); Unit *mover = _player->GetMover(); Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if(plMover && plMover->IsBeingTeleported()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* extract packet */ ObjectGuid guid; MovementInfo movementInfo; recv_data >> guid.ReadAsPacked(); recv_data >> movementInfo; /*----------------*/ // ignore wrong guid (player attempt cheating own session for not own guid possible...) if (guid != mover->GetObjectGuid()) return; if (!MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o)) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT) && !mover->GetVehicleGUID()) { // transports size limited // (also received at zeppelin/lift leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if( movementInfo.GetTransportPos()->x > 50 || movementInfo.GetTransportPos()->y > 50 || movementInfo.GetTransportPos()->z > 100 ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if( !MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x + movementInfo.GetTransportPos()->x, movementInfo.GetPos()->y + movementInfo.GetTransportPos()->y, movementInfo.GetPos()->z + movementInfo.GetTransportPos()->z, movementInfo.GetPos()->o + movementInfo.GetTransportPos()->o) ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->m_transport) { float trans_rad = movementInfo.GetTransportPos()->x*movementInfo.GetTransportPos()->x + movementInfo.GetTransportPos()->y*movementInfo.GetTransportPos()->y + movementInfo.GetTransportPos()->z*movementInfo.GetTransportPos()->z; if (trans_rad > 3600.0f) // transport radius = 60 yards //cheater with on_transport_flag { return; } // elevators also cause the client to send MOVEFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) { if ((*iter)->GetObjectGuid() == movementInfo.GetTransportGuid()) { plMover->m_transport = (*iter); (*iter)->AddPassenger(plMover); break; } } } } else if (plMover && plMover->m_transport) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.ClearTransportData(); } // 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 && plMover && !plMover->IsTaxiFlying()) plMover->HandleFall(movementInfo); if (plMover && (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING) != plMover->IsInWater())) { // now client not include swimming flag in case jumping under water plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) ); if(plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z-7.0f)) { plMover->m_anti_BeginFallZ=INVALID_HEIGHT; } } if (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING)) { if(mover->GetTypeId() == TYPEID_UNIT) { if(((Creature*)mover)->isVehicle() && !((Creature*)mover)->canSwim()) { // NOTE : we should enter evade mode here, but... ((Vehicle*)mover)->SetSpawnDuration(1); } } } // ---- anti-cheat features -->>> uint32 Anti_TeleTimeDiff=plMover ? time(NULL) - plMover->Anti__GetLastTeleTime() : time(NULL); static const uint32 Anti_TeleTimeIgnoreDiff=sWorld.GetMvAnticheatIgnoreAfterTeleport(); if (plMover && (plMover->m_transport == 0) && sWorld.GetMvAnticheatEnable() && GetPlayer()->GetSession()->GetSecurity() <= sWorld.GetMvAnticheatGmLevel() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()!=FLIGHT_MOTION_TYPE && Anti_TeleTimeDiff>Anti_TeleTimeIgnoreDiff) { const uint32 CurTime=getMSTime(); if(getMSTimeDiff(GetPlayer()->m_anti_lastalarmtime,CurTime) > sWorld.GetMvAnticheatAlarmPeriod()) { GetPlayer()->m_anti_alarmcount = 0; } /* I really don't care about movement-type yet (todo) UnitMoveType move_type; if (movementInfo.flags & MOVEMENTFLAG_FLYING) move_type = MOVE_FLY; else if (movementInfo.flags & MOVEMENTFLAG_SWIMMING) move_type = MOVE_SWIM; else if (movementInfo.flags & MOVEMENTFLAG_WALK_MODE) move_type = MOVE_WALK; else move_type = MOVE_RUN;*/ float delta_x = GetPlayer()->GetPositionX() - movementInfo.GetPos()->x; float delta_y = GetPlayer()->GetPositionY() - movementInfo.GetPos()->y; float delta_z = GetPlayer()->GetPositionZ() - movementInfo.GetPos()->z; float delta = sqrt(delta_x * delta_x + delta_y * delta_y); // Len of movement-vector via Pythagoras (a^2+b^2=Len^2) float tg_z = 0.0f; //tangens float delta_t = getMSTimeDiff(GetPlayer()->m_anti_lastmovetime,CurTime); GetPlayer()->m_anti_lastmovetime = CurTime; GetPlayer()->m_anti_MovedLen += delta; if(delta_t > 15000.0f) { delta_t = 15000.0f; } // Tangens of walking angel if (!(movementInfo.GetMovementFlags() & (MOVEFLAG_FLYING | MOVEFLAG_SWIMMING))) { tg_z = ((delta !=0.0f) && (delta_z > 0.0f)) ? (atan((delta_z*delta_z) / delta) * 180.0f / M_PI) : 0.0f; } //antiOFF fall-damage, MOVEMENTFLAG_UNK4 seted by client if player try movement when falling and unset in this case the MOVEMENTFLAG_FALLING flag. if((GetPlayer()->m_anti_BeginFallZ == INVALID_HEIGHT) && (movementInfo.GetMovementFlags() & (MOVEFLAG_FALLING | MOVEFLAG_FALLINGFAR)) != 0) { GetPlayer()->m_anti_BeginFallZ=(float)(movementInfo.GetPos()->z); } if(GetPlayer()->m_anti_NextLenCheck <= CurTime) { // Check every 500ms is a lot more advisable then 1000ms, because normal movment packet arrives every 500ms uint32 OldNextLenCheck=GetPlayer()->m_anti_NextLenCheck; float delta_xyt=GetPlayer()->m_anti_MovedLen/(float)(getMSTimeDiff(OldNextLenCheck-500,CurTime)); GetPlayer()->m_anti_NextLenCheck = CurTime+500; GetPlayer()->m_anti_MovedLen = 0.0f; static const float MaxDeltaXYT = sWorld.GetMvAnticheatMaxXYT(); if(delta_xyt > MaxDeltaXYT && delta<=100.0f && GetPlayer()->GetZoneId() != 2257) { if(sWorld.GetMvAnticheatSpeedCheck()) Anti__CheatOccurred(CurTime,"Speed hack",delta_xyt,LookupOpcodeName(opcode), (float)(GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()), (float)(getMSTimeDiff(OldNextLenCheck-500,CurTime))); } } if(delta > 100.0f && GetPlayer()->GetZoneId() != 2257) { Anti__ReportCheat("Tele hack",delta,LookupOpcodeName(opcode)); } // Check for waterwalking . Fix new way of checking for waterwalking by Darky88 if (movementInfo.HasMovementFlag(MOVEFLAG_WATERWALKING) && !(GetPlayer()->HasAuraType(SPELL_AURA_WATER_WALK) || GetPlayer()->HasAuraType(SPELL_AURA_GHOST))) { if(sWorld.GetMvAnticheatWaterCheck()) Anti__CheatOccurred(CurTime,"Water walking",0.0f,NULL,0.0f,(uint32)(movementInfo.GetMovementFlags())); } // Check for walking upwards a mountain while not beeing able to do that, New check by Darky88 if((delta_z < -2.3f) && (tg_z > 2.37f)) { if(sWorld.GetMvAnticheatMountainCheck()) Anti__CheatOccurred(CurTime,"Mountain hack",tg_z,NULL,delta,delta_z); } static const float DIFF_OVERGROUND = 10.0f; float Anti__GroundZ = GetPlayer()->GetMap()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),MAX_HEIGHT); float Anti__FloorZ = GetPlayer()->GetMap()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),GetPlayer()->GetPositionZ()); float Anti__MapZ = ((Anti__FloorZ <= (INVALID_HEIGHT+5.0f)) ? Anti__GroundZ : Anti__FloorZ) + DIFF_OVERGROUND; if(!GetPlayer()->CanFly() && !GetPlayer()->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z-7.0f) && Anti__MapZ < GetPlayer()->GetPositionZ() && Anti__MapZ > (INVALID_HEIGHT+DIFF_OVERGROUND + 5.0f)) { static const float DIFF_AIRJUMP=25.0f; // 25 is realy high, but to many false positives... // Air-Jump-Detection definitively needs a better way to be detected... if((movementInfo.GetMovementFlags() & (MOVEFLAG_CAN_FLY | MOVEFLAG_FLYING | MOVEFLAG_ROOT)) != 0) // Fly Hack { // Fix Aura 55164 by KAPATEJIb if (!GetPlayer()->HasAura(55164)) if(sWorld.GetMvAnticheatFlyCheck()) Anti__CheatOccurred(CurTime,"Fly hack", ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_FLY))) + /*((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED))*2),*/ ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED))*2), NULL,GetPlayer()->GetPositionZ()-Anti__MapZ); } // Need a better way to do that - currently a lot of fake alarms else if((Anti__MapZ+DIFF_AIRJUMP < GetPlayer()->GetPositionZ() && (movementInfo.GetMovementFlags() & (MOVEFLAG_FALLING /*| MOVEMENTFLAG_UNK4*/))==0) || (Anti__MapZ < GetPlayer()->GetPositionZ() && opcode==MSG_MOVE_JUMP)) { Anti__CheatOccurred(CurTime,"Possible Air Jump Hack", 0.0f,LookupOpcodeName(opcode),0.0f,movementInfo.GetMovementFlags()); } } /*if(Anti__FloorZ < -199900.0f && Anti__GroundZ >= -199900.0f && GetPlayer()->GetPositionZ()+5.0f < Anti__GroundZ) { Anti__CheatOccurred(CurTime,"Teleport2Plane hack", GetPlayer()->GetPositionZ(),NULL,Anti__GroundZ); }*/ } // <<---- anti-cheat features /* process position-change */ movementInfo.UpdateTime(getMSTime()); WorldPacket data(opcode, recv_data.size()); data.appendPackGUID(mover->GetGUID()); // write guid movementInfo.Write(data); // write data mover->SendMessageToSetExcept(&data, _player); if(plMover) // nothing is charmed, or player charmed { plMover->SetPosition(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); plMover->m_movementInfo = movementInfo; plMover->UpdateFallInformationIfNeed(movementInfo, opcode); // after move info set if ((opcode == MSG_MOVE_SET_WALK_MODE || opcode == MSG_MOVE_SET_RUN_MODE)) plMover->UpdateWalkMode(plMover, false); if(plMover->isMovingOrTurning()) plMover->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if(movementInfo.GetPos()->z < -500.0f) { if(plMover->InBattleGround() && plMover->GetBattleGround() && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // 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(plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, plMover->GetMaxHealth()); // pl can be alive if GM/etc if(!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } else // creature charmed { if(mover->IsInWorld()) { mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); if(((Creature*)mover)->isVehicle()) ((Vehicle*)mover)->RellocatePassengers(mover->GetMap()); } } }
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { uint32 opcode = recv_data.GetOpcode(); sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); if(GetPlayer()->GetDontMove()) return; /* extract packet */ MovementInfo movementInfo; ReadMovementInfo(recv_data, &movementInfo); /*----------------*/ if(recv_data.size() != recv_data.rpos()) { sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is %u bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos()); KickPlayer(); return; } if (!MaNGOS::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o)) return; /* handle special cases */ if (movementInfo.flags & 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.t_x > 50 || movementInfo.t_y > 50 || movementInfo.t_z > 50 ) return; if( !MaNGOS::IsValidMapCoord(movementInfo.x+movementInfo.t_x, movementInfo.y+movementInfo.t_y, movementInfo.z+movementInfo.t_z, movementInfo.o+movementInfo.t_o) ) return; // if we boarded a transport, add us to it if (!GetPlayer()->m_transport) { // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.t_guid) { GetPlayer()->m_transport = (*iter); (*iter)->AddPassenger(GetPlayer()); break; } } } } else if (GetPlayer()->m_transport) // if we were on a transport, leave { GetPlayer()->m_transport->RemovePassenger(GetPlayer()); GetPlayer()->m_transport = NULL; movementInfo.t_x = 0.0f; movementInfo.t_y = 0.0f; movementInfo.t_z = 0.0f; movementInfo.t_o = 0.0f; movementInfo.t_time = 0; movementInfo.t_seat = -1; } // 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 && !GetPlayer()->isInFlight()) { // calculate total z distance of the fall float z_diff = GetPlayer()->m_lastFallZ - movementInfo.z; sLog.outDebug("zDiff = %f", z_diff); Player *target = GetPlayer(); //Players with low fall distance, Feather Fall or physical immunity (charges used) are ignored // 14.57 can be calculated by resolving damageperc formular below to 0 if (z_diff >= 14.57f && !target->isDead() && !target->isGameMaster() && !target->HasAuraType(SPELL_AURA_HOVER) && !target->HasAuraType(SPELL_AURA_FEATHER_FALL) && !target->HasAuraType(SPELL_AURA_FLY) && !target->IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL) ) { //Safe fall, fall height reduction int32 safe_fall = target->GetTotalAuraModifier(SPELL_AURA_SAFE_FALL); float damageperc = 0.018f*(z_diff-safe_fall)-0.2426f; if(damageperc >0 ) { uint32 damage = (uint32)(damageperc * target->GetMaxHealth()*sWorld.getRate(RATE_DAMAGE_FALL)); float height = movementInfo.z; target->UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height); if (damage > 0) { //Prevent fall damage from being more than the player maximum health if (damage > target->GetMaxHealth()) damage = target->GetMaxHealth(); // Gust of Wind if (target->GetDummyAura(43621)) damage = target->GetMaxHealth()/2; target->EnvironmentalDamage(target->GetGUID(), DAMAGE_FALL, damage); // recheck alive, might have died of EnvironmentalDamage if (target->isAlive()) target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING, uint32(z_diff*100)); } //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, target->GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall); } } } if(((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != GetPlayer()->IsInWater()) { // now client not include swimming flag in case jumping under water GetPlayer()->SetInWater( !GetPlayer()->IsInWater() || GetPlayer()->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z) ); } /*----------------------*/ /* process position-change */ Unit *mover = _player->m_mover; recv_data.put<uint32>(6, getMSTime()); // fix time, offset flags(4) + unk(2) WorldPacket data(recv_data.GetOpcode(), (mover->GetPackGUID().size()+recv_data.size())); data.append(_player->m_mover->GetPackGUID()); // use mover guid data.append(recv_data.contents(), recv_data.size()); GetPlayer()->SendMessageToSet(&data, false); if(!_player->GetCharmGUID()) // nothing is charmed { _player->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); _player->m_movementInfo = movementInfo; _player->SetUnitMovementFlags(movementInfo.flags); } else { if(mover->GetTypeId() != TYPEID_PLAYER) // unit, creature, pet, vehicle... { if(Map *map = mover->GetMap()) map->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); mover->SetUnitMovementFlags(movementInfo.flags); } else // player { ((Player*)mover)->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); ((Player*)mover)->m_movementInfo = movementInfo; ((Player*)mover)->SetUnitMovementFlags(movementInfo.flags); } } if (GetPlayer()->m_lastFallTime >= movementInfo.fallTime || GetPlayer()->m_lastFallZ <=movementInfo.z || recv_data.GetOpcode() == MSG_MOVE_FALL_LAND) GetPlayer()->SetFallInformation(movementInfo.fallTime, movementInfo.z); if(GetPlayer()->isMovingOrTurning()) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if(movementInfo.z < -500.0f) { if(GetPlayer()->InBattleGround() && GetPlayer()->GetBattleGround() && GetPlayer()->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // 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(GetPlayer()->isAlive()) { GetPlayer()->EnvironmentalDamage(GetPlayer()->GetGUID(),DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // change the death state to CORPSE to prevent the death timer from // starting in the next player update GetPlayer()->KillPlayer(); GetPlayer()->BuildPlayerRepop(); } // cancel the death timer here if started GetPlayer()->RepopAtGraveyard(); } } }