/*
* Ascent MMORPG Server
* Copyright (C) 2005-2007 Ascent Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "StdAfx.h"
#define SWIMMING_TOLERANCE_LEVEL -0.08f
#define MOVEMENT_PACKET_TIME_DELAY 50
void WorldSession::HandleMoveWorldportAckOpcode( WorldPacket & recv_data )
{
if(_player->IsInWorld())
{
// get outta here
return;
}
sLog.outDebug( "WORLD: got MSG_MOVE_WORLDPORT_ACK." );
GetPlayer()->SendInitialLogonPackets();
GetPlayer()->clearAttackers(true);
GetPlayer()->m_TeleportState = 2;
GetPlayer()->AddToWorld();
GetPlayer()->SetPlayerStatus(NONE);
}
void WorldSession::HandleMoveTeleportAckOpcode( WorldPacket & recv_data )
{
uint64 guid;
recv_data >> guid;
if(guid == _player->GetGUID())
{
if(sWorld.antihack_teleport && !(HasGMPermissions() && sWorld.no_antihack_on_gm) && _player->GetPlayerStatus() != TRANSFER_PENDING)
{
/* we're obviously cheating */
sCheatLog.writefromsession(this, "Used teleport hack, disconnecting.");
Disconnect();
return;
}
if(sWorld.antihack_teleport && !(HasGMPermissions() && sWorld.no_antihack_on_gm) && _player->m_position.Distance2DSq(_player->m_sentTeleportPosition) > 625.0f) /* 25.0f*25.0f */
{
/* cheating.... :( */
sCheatLog.writefromsession(this, "Used teleport hack {2}, disconnecting.");
Disconnect();
return;
}
sLog.outDebug( "WORLD: got MSG_MOVE_TELEPORT_ACK." );
GetPlayer()->SetPlayerStatus(NONE);
GetPlayer()->clearAttackers(true);
GetPlayer()->SetMovement(MOVE_UNROOT,5);
_player->ResetHeartbeatCoords();
if(GetPlayer()->GetSummon() != NULL) // move pet too
GetPlayer()->GetSummon()->SetPosition((GetPlayer()->GetPositionX() + 2), (GetPlayer()->GetPositionY() + 2), GetPlayer()->GetPositionZ(), M_PI);
_player->m_sentTeleportPosition.ChangeCoords(999999.0f,999999.0f,999999.0f);
}
}
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
{
if(_player == 0)
return;
if(GetPlayer()->GetPlayerStatus() == TRANSFER_PENDING) //dont update coords
return;
if(!_player->IsInWorld() || _player->m_uint32Values[UNIT_FIELD_CHARMEDBY])
return;
// spell cancel on movement, for now only fishing is added
Object * t_go = GetPlayer()->m_SummonedObject;
if (t_go)
if (t_go->GetEntry() == GO_FISHING_BOBBER)
((GameObject*)t_go)->EndFishing(GetPlayer(),true);
movement_info.init(recv_data);
GetPlayer()->m_isMoving = true;
// check for bad coords
if( !((movement_info.y >= _minY) && (movement_info.y <= _maxY)) ||
!((movement_info.x >= _minX) && (movement_info.x <= _maxX)) )
{
sLog.outError("%s might be cheating, bad coords specified in movement packet.", _player->GetName());
return;
}
if(GetPlayer()->cannibalize)
{
sEventMgr.RemoveEvents(GetPlayer(), EVENT_CANNIBALIZE);
GetPlayer()->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
GetPlayer()->cannibalize = false;
}
//Send packet to other players
if(recv_data.size() > 80)
{
Disconnect();
return;
}
if(sWorld.antihack_teleport && !(HasGMPermissions() && sWorld.no_antihack_on_gm) && _player->m_position.Distance2DSq(movement_info.x, movement_info.y) > 2500.0f && _player->m_runSpeed < 50.0f) /*50*50*/
{
sCheatLog.writefromsession(this, "Used teleport hack {3}, speed was %f", _player->m_runSpeed);
Disconnect();
return;
}
if(sWorld.antihack_flight && !(HasGMPermissions() && sWorld.no_antihack_on_gm) && !_player->FlyCheat && movement_info.flags & MOVEFLAG_FLYING && !(movement_info.flags & MOVEFLAG_FALLING))
{
sCheatLog.writefromsession(this, "Used flying hack {1}, movement flags: %u", movement_info.flags);
Disconnect();
return;
}
if(movement_info.flags & MOVEFLAG_FALLING_FAR && !movement_info.FallTime && sWorld.antihack_falldmg && !(HasGMPermissions() && sWorld.no_antihack_on_gm) && !_player->bSafeFall && !_player->GodModeCheat)
{
sCheatLog.writefromsession(this, "Used fall damage hack, falltime is 0 and flags are %u", movement_info.flags);
Disconnect();
return;
}
uint32 pos = m_MoverWoWGuid.GetNewGuidLen() + 1;
uint32 mstime = getMSTime();
int32 new_move_time = (MOVEMENT_PACKET_TIME_DELAY + (movement_info.time - mstime))+mstime;
memcpy(&movement_packet[pos], recv_data.contents(), recv_data.size());
for(set::iterator itr = _player->m_inRangePlayers.begin(); itr != _player->m_inRangePlayers.end(); ++itr)
{
#ifdef USING_BIG_ENDIAN
*(uint32*)&movement_packet[pos+4] = swap32(new_move_time+(*itr)->GetSession()->m_moveDelayTime);
#else
*(uint32*)&movement_packet[pos+4] = new_move_time+(*itr)->GetSession()->m_moveDelayTime;
#endif
(*itr)->GetSession()->OutPacket(recv_data.GetOpcode(), recv_data.size() + pos, movement_packet);
}
//Setup Transporter Positioning
if(movement_info.transGuid != 0 && !_player->m_lockTransportVariables)
{
if(!_player->m_TransporterGUID)
{
_player->m_CurrentTransporter = objmgr.GetTransporter(movement_info.transGuid);
if(_player->m_CurrentTransporter)
{
GetPlayer()->m_TransporterGUID = movement_info.transGuid;
_player->m_CurrentTransporter->AddPlayer(_player);
}
}
GetPlayer()->m_TransporterX = movement_info.transX;
GetPlayer()->m_TransporterY = movement_info.transY;
GetPlayer()->m_TransporterZ = movement_info.transZ;
GetPlayer()->m_TransporterO = movement_info.transO;
GetPlayer()->m_TransporterUnk = movement_info.transUnk;
//float x = movement_info.x - movement_info.transX;
//float y = movement_info.y - movement_info.transY;
//float z = movement_info.z - movement_info.transZ;
/*Transporter* trans = _player->m_CurrentTransporter;
if(trans) sChatHandler.SystemMessageToPlr(_player, "Client t pos: %f %f\nServer t pos: %f %f Diff: %f %f", x,y, trans->GetPositionX(), trans->GetPositionY(), trans->CalcDistance(x,y,z), trans->CalcDistance(movement_info.x, movement_info.y, movement_info.z));*/
}
else
{
if(_player->m_TransporterGUID && !_player->m_lockTransportVariables)
{
// remove us from the porter
GetPlayer()->m_TransporterGUID = 0;
GetPlayer()->m_TransporterX = 0.0f;
GetPlayer()->m_TransporterY = 0.0f;
GetPlayer()->m_TransporterZ = 0.0f;
GetPlayer()->m_TransporterO = 0.0f;
if(_player->m_CurrentTransporter)
_player->m_CurrentTransporter->RemovePlayer(_player);
GetPlayer()->m_CurrentTransporter = NULL;
}
}
_HandleBreathing(recv_data, movement_info);
_player->RemoveAurasByInterruptFlag(AURA_INTERRUPT_ON_MOVEMENT);
if( _player->m_CurrentCharm )
{
_player->m_CurrentCharm->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation);
}
else
{
if(!_player->m_CurrentTransporter)
{
if( !_player->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation) )
{
GetPlayer()->SetUInt32Value(UNIT_FIELD_HEALTH, 0);
GetPlayer()->KillPlayer();
}
}
else
{
_player->SetPosition(_player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(),
movement_info.orientation + movement_info.transO, false);
}
}
//Falling Handler
if (movement_info.flags & 0x2000) // Falling
{
if( GetPlayer()->m_fallTime < movement_info.FallTime)
GetPlayer()->m_fallTime = movement_info.FallTime;
_player->ResetHeartbeatCoords();
}
else //once we done falling lets do some damage
{
if(GetPlayer()->m_fallTime > 1000 && GetPlayer()->isAlive() && !_player->GodModeCheat)
{
//Check if we aren't falling in water
if(!_player->bSafeFall)
{
if( !(movement_info.flags & 0x200000) && !_player->blinked)
{
uint8 type = DAMAGE_FALL;
//10% dmg per sec after first 3 seconds
//it rL a*t*t
double coeff = 0.000000075*(_player->m_fallTime*_player->m_fallTime - _player->m_fallTime);
if (coeff<0)
coeff=0;
uint32 damage = (uint32)(_player->GetUInt32Value(UNIT_FIELD_MAXHEALTH)*coeff);
if(damage > GetPlayer()->GetUInt32Value(UNIT_FIELD_MAXHEALTH)) // Can only deal 100% damage.
damage = GetPlayer()->GetUInt32Value(UNIT_FIELD_MAXHEALTH);
WorldPacket data(13);
data.SetOpcode(SMSG_ENVIRONMENTALDAMAGELOG);
data << GetPlayer()->GetGUID();
data << type;
data << damage;
SendPacket(&data);
_player->DealDamage(GetPlayer(), damage, 0, 0, 0);
}
}
GetPlayer()->m_fallTime = 0;
_player->blinked = false;
_player->ResetHeartbeatCoords();
}
else
{
//player is dead, no need to keep increasing falltime
GetPlayer()->m_fallTime = 0;
/*_player->ResetHeartbeatCoords();*/
_player->blinked = false;
}
}
//// speedhack protection
if(sWorld.SpeedhackProtection && GetPermissionCount() == 0 && !_player->blinked)
_SpeedCheck(movement_info);
}
void WorldSession::HandleMoveStopOpcode( WorldPacket & recv_data )
{
HandleMovementOpcodes( recv_data );
_player->m_isMoving = false;
}
void WorldSession::HandleMoveTimeSkippedOpcode( WorldPacket & recv_data )
{
uint64 guid;
recv_data >> guid >> m_moveDelayTime;
//Log.Debug("MoveTimeSkipped", "Client %s is out of sync by %u ms", GetSocket()->GetRemoteIP().c_str(), m_moveDelayTime);
}
void WorldSession::HandleMoveNotActiveMoverOpcode( WorldPacket & recv_data )
{
/* uint64 guid;
recv_data >> guid;
MovementInfo mi(recv_data);
WorldPacket data;
data.SetOpcode(MSG_MOVE_TELEPORT); // meh..
FastGUIDPack(data, guid); // faaast.
mi >> data;
_player->SendMessageToSet(&data, false);*/
}
void WorldSession::HandleSetActiveMoverOpcode( WorldPacket & recv_data )
{
// set current movement object
uint64 guid;
recv_data >> guid;
if(guid != m_MoverWoWGuid.GetOldGuid())
{
// generate wowguid
if(guid != 0)
m_MoverWoWGuid.Init(guid);
else
m_MoverWoWGuid.Init(_player->GetGUID());
// set up to the movement packet
movement_packet[0] = m_MoverWoWGuid.GetNewGuidMask();
memcpy(&movement_packet[1], m_MoverWoWGuid.GetNewGuid(), m_MoverWoWGuid.GetNewGuidLen());
}
}
void WorldSession::HandleMoveSplineCompleteOpcode(WorldPacket &recvPacket)
{
}
void WorldSession::HandleBasicMovementOpcodes( WorldPacket & recv_data )
{
if(GetPlayer()->GetPlayerStatus() == TRANSFER_PENDING) //don't update coords
return;
if(!_player->IsInWorld() || _player->m_uint32Values[UNIT_FIELD_CHARMEDBY])
return;
movement_info.init(recv_data);
// check for bad coords
if( !((movement_info.y >= _minY) && (movement_info.y <= _maxY)) ||
!((movement_info.x >= _minX) && (movement_info.x <= _maxX)) )
{
sLog.outError("%s might be cheating, bad coords specified in movement packet.", _player->GetName());
return;
}
GetPlayer()->m_isMoving = true;
//Send packet to other players
if(recv_data.size() > 80)
{
Disconnect();
return;
}
if(sWorld.antihack_teleport && !(HasGMPermissions() && sWorld.no_antihack_on_gm) && _player->m_position.Distance2DSq(movement_info.x, movement_info.y) > 2500.0f) /*50*50*/
{
sCheatLog.writefromsession(this, "Used teleport hack {3}, speed was %f", _player->m_runSpeed);
Disconnect();
return;
}
if(sWorld.antihack_flight && !(HasGMPermissions() && sWorld.no_antihack_on_gm) && !_player->FlyCheat && movement_info.flags & MOVEFLAG_FLYING)
{
sCheatLog.writefromsession(this, "Used flying hack {1}, movement flags: %u", movement_info.flags);
Disconnect();
return;
}
if(movement_info.flags & MOVEFLAG_FALLING_FAR && !movement_info.FallTime && sWorld.antihack_falldmg && !(HasGMPermissions() && sWorld.no_antihack_on_gm) && !_player->bSafeFall && !_player->GodModeCheat)
{
sCheatLog.writefromsession(this, "Used fall damage hack, falltime is 0 and flags are %u", movement_info.flags);
Disconnect();
return;
}
uint32 pos = m_MoverWoWGuid.GetNewGuidLen() + 1;
uint32 mstime = getMSTime();
int32 new_move_time = (MOVEMENT_PACKET_TIME_DELAY + (movement_info.time - mstime))+mstime;
memcpy(&movement_packet[pos], recv_data.contents(), recv_data.size());
for(set::iterator itr = _player->m_inRangePlayers.begin(); itr != _player->m_inRangePlayers.end(); ++itr)
{
#ifdef USING_BIG_ENDIAN
*(uint32*)&movement_packet[pos+4] = swap32(new_move_time+(*itr)->GetSession()->m_moveDelayTime);
#else
*(uint32*)&movement_packet[pos+4] = new_move_time+(*itr)->GetSession()->m_moveDelayTime;
#endif
(*itr)->GetSession()->OutPacket(recv_data.GetOpcode(), recv_data.size() + pos, movement_packet);
}
//Setup Transporter Positioning
if(movement_info.transGuid != 0 && !_player->m_lockTransportVariables)
{
if(!_player->m_TransporterGUID)
{
_player->m_CurrentTransporter = objmgr.GetTransporter(movement_info.transGuid);
if(_player->m_CurrentTransporter)
{
GetPlayer()->m_TransporterGUID = movement_info.transGuid;
_player->m_CurrentTransporter->AddPlayer(_player);
}
}
GetPlayer()->m_TransporterX = movement_info.transX;
GetPlayer()->m_TransporterY = movement_info.transY;
GetPlayer()->m_TransporterZ = movement_info.transZ;
GetPlayer()->m_TransporterO = movement_info.transO;
GetPlayer()->m_TransporterUnk = movement_info.transUnk;
// float x = movement_info.x - movement_info.transX;
// float y = movement_info.y - movement_info.transY;
// float z = movement_info.z - movement_info.transZ;
/*Transporter* trans = _player->m_CurrentTransporter;
if(trans) sChatHandler.SystemMessageToPlr(_player, "Client t pos: %f %f\nServer t pos: %f %f Diff: %f %f", x,y, trans->GetPositionX(), trans->GetPositionY(), trans->CalcDistance(x,y,z), trans->CalcDistance(movement_info.x, movement_info.y, movement_info.z));*/
}
else
{
if(_player->m_TransporterGUID && !_player->m_lockTransportVariables)
{
// remove us from the porter
GetPlayer()->m_TransporterGUID = 0;
GetPlayer()->m_TransporterX = 0.0f;
GetPlayer()->m_TransporterY = 0.0f;
GetPlayer()->m_TransporterZ = 0.0f;
GetPlayer()->m_TransporterO = 0.0f;
if(_player->m_CurrentTransporter)
_player->m_CurrentTransporter->RemovePlayer(_player);
GetPlayer()->m_CurrentTransporter = NULL;
}
}
_HandleBreathing(recv_data, movement_info);
if( _player->m_CurrentCharm )
{
_player->m_CurrentCharm->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation);
}
else
{
if( !_player->m_CurrentTransporter)
{
if(!GetPlayer( )->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation) )
{
GetPlayer()->SetUInt32Value(UNIT_FIELD_HEALTH, 0);
GetPlayer()->KillPlayer();
}
}
else
{
_player->SetPosition(_player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(),
movement_info.orientation + movement_info.transO, false);
}
}
// speedhack protection
if(sWorld.SpeedhackProtection && GetPermissionCount() == 0 && !_player->blinked)
_SpeedCheck(movement_info);
}
void WorldSession::_HandleBreathing(WorldPacket &recv_data, MovementInfo &mi)
{
//player swiming.
if(movement_info.flags & 0x200000)
{
if(!_player->m_lastMoveType)
{
if(_player->FlyCheat)
{
if(_player->m_lastMoveType != 2)
{
_player->m_lastMoveType = 2; // flying
_player->ResetHeartbeatCoords();
}
}
else
{
if(_player->m_lastMoveType != 1)
{
_player->m_lastMoveType = 1; // swimming
_player->ResetHeartbeatCoords();
}
}
}
// get water level only if it was not set before
if (!m_bIsWLevelSet)
{
// water level is somewhere below the nose of the character when entering water
m_wLevel = movement_info.z + _player->m_noseLevel*0.95;
m_bIsWLevelSet = true;
}
if(!(_player->m_UnderwaterState & UNDERWATERSTATE_SWIMMING))
_player->m_UnderwaterState |= UNDERWATERSTATE_SWIMMING;
}
if(movement_info.flags & 0x2000 && _player->m_UnderwaterState)
{
//player jumped inside water but still underwater.
if(m_bIsWLevelSet && (movement_info.z + _player->m_noseLevel) < m_wLevel)
{
return;
}
else
{
if(!sWorld.BreathingEnabled || _player->FlyCheat || _player->m_bUnlimitedBreath || !_player->isAlive() || _player->GodModeCheat)
{
}
else
{
//only swiming and can breath, stop bar
if(_player->m_UnderwaterState & UNDERWATERSTATE_UNDERWATER)
{
WorldPacket data(SMSG_START_MIRROR_TIMER, 20);
data << uint32(1) << _player->m_UnderwaterTime << _player->m_UnderwaterMaxTime << uint32(10) << uint32(0);
SendPacket(&data);
_player->m_UnderwaterState &= ~UNDERWATERSTATE_UNDERWATER;
}
}
}
return;
}
//player not swiming
if(!(movement_info.flags & 0x200000) && _player->m_UnderwaterState)
{
if(_player->m_lastMoveType)
{
_player->m_lastMoveType = 0;
_player->ResetHeartbeatCoords();
}
if(_player->m_UnderwaterState & UNDERWATERSTATE_SWIMMING)
{
_player->m_UnderwaterState &= ~UNDERWATERSTATE_SWIMMING;
_player->RemoveAura(1066);//remove aquatic form on land
m_bIsWLevelSet = false;
}
if(_player->m_UnderwaterState & UNDERWATERSTATE_UNDERWATER)
_player->m_UnderwaterState &= ~UNDERWATERSTATE_UNDERWATER;
return;
}
if(m_bIsWLevelSet && (movement_info.z + _player->m_noseLevel) < m_wLevel)
{
// underwater, w000t!
if(_player->m_MountSpellId)
_player->RemoveAura(_player->m_MountSpellId);
if(!(_player->m_UnderwaterState & UNDERWATERSTATE_UNDERWATER))
{
// we only just entered the water
_player->m_UnderwaterState |= UNDERWATERSTATE_UNDERWATER;
if(!sWorld.BreathingEnabled || _player->FlyCheat || _player->m_bUnlimitedBreath || !_player->isAlive() || _player->GodModeCheat)
{
}
else
{
// send packet
WorldPacket data(SMSG_START_MIRROR_TIMER, 20);
data << uint32(1) << _player->m_UnderwaterTime << _player->m_UnderwaterMaxTime << int32(-1) << uint32(0);
SendPacket(&data);
}
}
}
else
{
if(_player->m_UnderwaterState & UNDERWATERSTATE_UNDERWATER)
{
if(!sWorld.BreathingEnabled || _player->FlyCheat || _player->m_bUnlimitedBreath || !_player->isAlive() || _player->GodModeCheat)
{
}
else
{
WorldPacket data(SMSG_START_MIRROR_TIMER, 20);
data << uint32(1) << _player->m_UnderwaterTime << _player->m_UnderwaterMaxTime << uint32(10) << uint32(0);
SendPacket(&data);
}
_player->m_UnderwaterState &= ~UNDERWATERSTATE_UNDERWATER;
}
}
}
void WorldSession::_SpeedCheck(MovementInfo &mi)
{
// beat!
// calculate distance between last heartbeat and this
if(_player->_lastHeartbeatTime && _player->_lastHeartbeatX &&
_player->_lastHeartbeatY && _player->_lastHeartbeatZ)
{
uint32 new_time = getMSTime();
float distance_travelled = _player->CalcDistance(_player->_lastHeartbeatX,
_player->_lastHeartbeatY, _player->_lastHeartbeatZ, movement_info.x, movement_info.y, movement_info.z);
// get our time difference
uint32 time_difference = new_time - _player->_lastHeartbeatTime;
// do our check calculation
float speed = _player->m_runSpeed;
// underwater or flying
switch(_player->m_lastMoveType)
{
case 1: // swimming
speed = _player->m_swimSpeed;
break;
case 2: // flying
speed = _player->m_flySpeed;
break;
}
uint32 move_time = (uint32)((float)distance_travelled / (float)(speed*0.001f));
// check if we're in the correct bounds
if(move_time > time_difference)
{
int32 difference = move_time - time_difference;
if(difference > 350) // say this for now
{
if(_player->m_speedhackChances)
{
sChatHandler.SystemMessage(this, "Speedhack detected. This has been logged for later processing by the server admins. If you are caught again, you will be kicked from the server. You will be unrooted in 5 seconds.");
_player->SetMovement(MOVE_ROOT, 1);
sEventMgr.AddEvent(_player, &Player::SetMovement, uint8(MOVE_UNROOT), uint32(1), EVENT_DELETE_TIMER, 5000, 1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
_player->ResetHeartbeatCoords();
_player->m_speedhackChances--;
// TODO: replace with server plugin system later on
sCheatLog.writefromsession(this, "Speedhack warning, time diff of %u", time_difference);
}
else if(_player->m_speedhackChances == 0)
{
sChatHandler.SystemMessage(this, "You will now be removed from the server for speed hacking. Your account has been flagged for further investigation by the admins.");
// TODO: replace with server plugin system later on
sCheatLog.writefromsession(this, "Kicked for speedhack, time diff of %u", difference);
_player->m_KickDelay = 0;
sEventMgr.AddEvent(_player, &Player::_Kick, EVENT_PLAYER_KICK, 10000, 1,0);
// Root movement :p heheheh evil
_player->SetMovement(MOVE_ROOT, 1);
}
}
//printf("Move shit: %ums\n", abs(difference));
//sChatHandler.SystemMessage(this, "Move time : %u / %u, diff: %u", move_time, time_difference, difference);
}
}
_player->_lastHeartbeatTime = getMSTime();
_player->_lastHeartbeatX = movement_info.x;
_player->_lastHeartbeatY = movement_info.y;
_player->_lastHeartbeatZ = movement_info.z;
}
void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket &recvdata)
{
WorldPacket data(SMSG_MOUNTSPECIAL_ANIM,8);
data << _player->GetGUID();
_player->SendMessageToSet(&data, true);
}