2008-10-11 14:16:25 -05:00
/*
2008-10-14 11:57:03 -05:00
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
*
* Thanks to the original authors: MaNGOS <http://www.mangosproject.org/>
2008-10-11 14:16:25 -05:00
*
* 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 2 of the License, or
* (at your option) 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
2008-10-14 11:57:03 -05:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-11 14:16:25 -05:00
* 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, write to the Free Software
2008-10-14 11:57:03 -05:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-11 14:16:25 -05:00
*/
#include "Common.h"
#include "SharedDefines.h"
#include "WorldPacket.h"
#include "Opcodes.h"
#include "Log.h"
#include "World.h"
#include "Object.h"
#include "Creature.h"
#include "Player.h"
#include "ObjectMgr.h"
#include "WorldSession.h"
#include "UpdateData.h"
#include "UpdateMask.h"
#include "Util.h"
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "Log.h"
#include "Transports.h"
#include "TargetedMovementGenerator.h"
#include "WaypointMovementGenerator.h"
#include "VMapFactory.h"
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "TemporarySummon.h"
uint32 GuidHigh2TypeId ( uint32 guid_hi )
{
switch ( guid_hi )
{
case HIGHGUID_ITEM : return TYPEID_ITEM ;
//case HIGHGUID_CONTAINER: return TYPEID_CONTAINER; HIGHGUID_CONTAINER==HIGHGUID_ITEM currently
case HIGHGUID_UNIT : return TYPEID_UNIT ;
case HIGHGUID_PET : return TYPEID_UNIT ;
case HIGHGUID_PLAYER : return TYPEID_PLAYER ;
case HIGHGUID_GAMEOBJECT : return TYPEID_GAMEOBJECT ;
case HIGHGUID_DYNAMICOBJECT : return TYPEID_DYNAMICOBJECT ;
case HIGHGUID_CORPSE : return TYPEID_CORPSE ;
case HIGHGUID_MO_TRANSPORT : return TYPEID_GAMEOBJECT ;
}
return 10 ; // unknown
}
Object :: Object ( )
{
m_objectTypeId = TYPEID_OBJECT ;
m_objectType = TYPEMASK_OBJECT ;
m_uint32Values = 0 ;
m_uint32Values_mirror = 0 ;
m_valuesCount = 0 ;
m_inWorld = false ;
m_objectUpdated = false ;
m_PackGUID . clear ();
m_PackGUID . appendPackGUID ( 0 );
}
Object ::~ Object ( )
{
if ( m_objectUpdated )
ObjectAccessor :: Instance (). RemoveUpdateObject ( this );
if ( m_uint32Values )
{
if ( IsInWorld ())
{
///- Do NOT call RemoveFromWorld here, if the object is a player it will crash
sLog . outError ( "Object::~Object - guid=" I64FMTD ", typeid=%d deleted but still in world!!" , GetGUID (), GetTypeId ());
//assert(0);
}
//DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
delete [] m_uint32Values ;
delete [] m_uint32Values_mirror ;
//DEBUG_LOG("Object desctr 2 check (%p)",(void*)this);
}
}
void Object :: _InitValues ()
{
m_uint32Values = new uint32 [ m_valuesCount ];
memset ( m_uint32Values , 0 , m_valuesCount * sizeof ( uint32 ));
m_uint32Values_mirror = new uint32 [ m_valuesCount ];
memset ( m_uint32Values_mirror , 0 , m_valuesCount * sizeof ( uint32 ));
m_objectUpdated = false ;
}
void Object :: _Create ( uint32 guidlow , uint32 entry , HighGuid guidhigh )
{
if ( ! m_uint32Values ) _InitValues ();
uint64 guid = MAKE_NEW_GUID ( guidlow , entry , guidhigh ); // required more changes to make it working
SetUInt64Value ( OBJECT_FIELD_GUID , guid );
SetUInt32Value ( OBJECT_FIELD_TYPE , m_objectType );
m_PackGUID . clear ();
m_PackGUID . appendPackGUID ( GetGUID ());
}
void Object :: BuildMovementUpdateBlock ( UpdateData * data , uint32 flags ) const
{
ByteBuffer buf ( 500 );
buf << uint8 ( UPDATETYPE_MOVEMENT );
buf << GetGUID ();
_BuildMovementUpdate ( & buf , flags , 0x00000000 );
data -> AddUpdateBlock ( buf );
}
void Object :: BuildCreateUpdateBlockForPlayer ( UpdateData * data , Player * target ) const
{
if ( ! target )
{
return ;
}
uint8 updatetype = UPDATETYPE_CREATE_OBJECT ;
uint8 flags = m_updateFlag ;
uint32 flags2 = 0 ;
/** lower flag1 **/
if ( target == this ) // building packet for oneself
{
flags |= UPDATEFLAG_SELF ;
/*** temporary reverted - until real source of stack corruption will not found
updatetype = UPDATETYPE_CREATE_OBJECT2;
****/
}
if ( flags & UPDATEFLAG_HASPOSITION )
{
// UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
if ( isType ( TYPEMASK_DYNAMICOBJECT ) || isType ( TYPEMASK_CORPSE ) || isType ( TYPEMASK_PLAYER ))
updatetype = UPDATETYPE_CREATE_OBJECT2 ;
// UPDATETYPE_CREATE_OBJECT2 for pets...
if ( target -> GetPetGUID () == GetGUID ())
updatetype = UPDATETYPE_CREATE_OBJECT2 ;
// UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
if ( isType ( TYPEMASK_GAMEOBJECT ))
{
switch ((( GameObject * ) this ) -> GetGoType ())
{
case GAMEOBJECT_TYPE_TRAP :
case GAMEOBJECT_TYPE_DUEL_ARBITER :
case GAMEOBJECT_TYPE_FLAGSTAND :
case GAMEOBJECT_TYPE_FLAGDROP :
updatetype = UPDATETYPE_CREATE_OBJECT2 ;
break ;
case GAMEOBJECT_TYPE_TRANSPORT :
flags |= UPDATEFLAG_TRANSPORT ;
break ;
}
}
}
//sLog.outDebug("BuildCreateUpdate: update-type: %u, object-type: %u got flags: %X, flags2: %X", updatetype, m_objectTypeId, flags, flags2);
ByteBuffer buf ( 500 );
buf << ( uint8 ) updatetype ;
//buf.append(GetPackGUID()); //client crashes when using this
buf << ( uint8 ) 0xFF << GetGUID ();
buf << ( uint8 ) m_objectTypeId ;
_BuildMovementUpdate ( & buf , flags , flags2 );
UpdateMask updateMask ;
updateMask . SetCount ( m_valuesCount );
_SetCreateBits ( & updateMask , target );
_BuildValuesUpdate ( updatetype , & buf , & updateMask , target );
data -> AddUpdateBlock ( buf );
}
void Object :: BuildUpdate ( UpdateDataMapType & update_players )
{
ObjectAccessor :: _buildUpdateObject ( this , update_players );
ClearUpdateMask ( true );
}
void Object :: SendUpdateToPlayer ( Player * player )
{
// send update to another players
SendUpdateObjectToAllExcept ( player );
// send create update to player
UpdateData upd ;
WorldPacket packet ;
upd . Clear ();
BuildCreateUpdateBlockForPlayer ( & upd , player );
upd . BuildPacket ( & packet );
player -> GetSession () -> SendPacket ( & packet );
// now object updated/(create updated)
}
void Object :: BuildValuesUpdateBlockForPlayer ( UpdateData * data , Player * target ) const
{
ByteBuffer buf ( 500 );
buf << ( uint8 ) UPDATETYPE_VALUES ;
//buf.append(GetPackGUID()); //client crashes when using this. but not have crash in debug mode
buf << ( uint8 ) 0xFF ;
buf << GetGUID ();
UpdateMask updateMask ;
updateMask . SetCount ( m_valuesCount );
_SetUpdateBits ( & updateMask , target );
_BuildValuesUpdate ( UPDATETYPE_VALUES , & buf , & updateMask , target );
data -> AddUpdateBlock ( buf );
}
void Object :: BuildOutOfRangeUpdateBlock ( UpdateData * data ) const
{
data -> AddOutOfRangeGUID ( GetGUID ());
}
void Object :: DestroyForPlayer ( Player * target ) const
{
ASSERT ( target );
WorldPacket data ( SMSG_DESTROY_OBJECT , 8 );
data << GetGUID ();
target -> GetSession () -> SendPacket ( & data );
}
void Object :: _BuildMovementUpdate ( ByteBuffer * data , uint8 flags , uint32 flags2 ) const
{
* data << ( uint8 ) flags ; // update flags
// 0x20
if ( flags & UPDATEFLAG_LIVING )
{
switch ( GetTypeId ())
{
case TYPEID_UNIT :
{
flags2 = (( Unit * ) this ) -> GetUnitMovementFlags ();
2008-10-12 18:26:26 -05:00
flags2 &= ~ MOVEMENTFLAG_ONTRANSPORT ;
flags2 &= ~ MOVEMENTFLAG_SPLINE2 ;
2008-10-11 14:16:25 -05:00
}
break ;
case TYPEID_PLAYER :
{
flags2 = (( Player * ) this ) -> GetUnitMovementFlags ();
if ((( Player * ) this ) -> GetTransport ())
flags2 |= MOVEMENTFLAG_ONTRANSPORT ;
else
flags2 &= ~ MOVEMENTFLAG_ONTRANSPORT ;
// remove unknown, unused etc flags for now
flags2 &= ~ MOVEMENTFLAG_SPLINE2 ; // will be set manually
if ((( Player * ) this ) -> isInFlight ())
{
WPAssert ((( Player * ) this ) -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == FLIGHT_MOTION_TYPE );
flags2 = ( MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_SPLINE2 );
}
}
break ;
}
* data << uint32 ( flags2 ); // movement flags
* data << uint8 ( 0 ); // unk 2.3.0
* data << uint32 ( getMSTime ()); // time (in milliseconds)
}
// 0x40
if ( flags & UPDATEFLAG_HASPOSITION )
{
// 0x02
if ( flags & UPDATEFLAG_TRANSPORT && (( GameObject * ) this ) -> GetGoType () == GAMEOBJECT_TYPE_MO_TRANSPORT )
{
* data << ( float ) 0 ;
* data << ( float ) 0 ;
* data << ( float ) 0 ;
* data << (( WorldObject * ) this ) -> GetOrientation ();
}
else
{
* data << (( WorldObject * ) this ) -> GetPositionX ();
* data << (( WorldObject * ) this ) -> GetPositionY ();
* data << (( WorldObject * ) this ) -> GetPositionZ ();
* data << (( WorldObject * ) this ) -> GetOrientation ();
}
}
// 0x20
if ( flags & UPDATEFLAG_LIVING )
{
// 0x00000200
if ( flags2 & MOVEMENTFLAG_ONTRANSPORT )
{
if ( GetTypeId () == TYPEID_PLAYER )
{
* data << ( uint64 )(( Player * ) this ) -> GetTransport () -> GetGUID ();
* data << ( float )(( Player * ) this ) -> GetTransOffsetX ();
* data << ( float )(( Player * ) this ) -> GetTransOffsetY ();
* data << ( float )(( Player * ) this ) -> GetTransOffsetZ ();
* data << ( float )(( Player * ) this ) -> GetTransOffsetO ();
* data << ( uint32 )(( Player * ) this ) -> GetTransTime ();
}
2008-10-14 11:57:03 -05:00
//TrinIty currently not have support for other than player on transport
2008-10-11 14:16:25 -05:00
}
// 0x02200000
if ( flags2 & ( MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2 ))
{
if ( GetTypeId () == TYPEID_PLAYER )
* data << ( float )(( Player * ) this ) -> m_movementInfo . s_pitch ;
else
* data << ( float ) 0 ; // is't part of movement packet, we must store and send it...
}
if ( GetTypeId () == TYPEID_PLAYER )
* data << ( uint32 )(( Player * ) this ) -> m_movementInfo . fallTime ;
else
* data << ( uint32 ) 0 ; // last fall time
// 0x00001000
if ( flags2 & MOVEMENTFLAG_JUMPING )
{
if ( GetTypeId () == TYPEID_PLAYER )
{
* data << ( float )(( Player * ) this ) -> m_movementInfo . j_unk ;
* data << ( float )(( Player * ) this ) -> m_movementInfo . j_sinAngle ;
* data << ( float )(( Player * ) this ) -> m_movementInfo . j_cosAngle ;
* data << ( float )(( Player * ) this ) -> m_movementInfo . j_xyspeed ;
}
else
{
* data << ( float ) 0 ;
* data << ( float ) 0 ;
* data << ( float ) 0 ;
* data << ( float ) 0 ;
}
}
// 0x04000000
if ( flags2 & MOVEMENTFLAG_SPLINE )
{
if ( GetTypeId () == TYPEID_PLAYER )
* data << ( float )(( Player * ) this ) -> m_movementInfo . u_unk1 ;
else
* data << ( float ) 0 ;
}
* data << (( Unit * ) this ) -> GetSpeed ( MOVE_WALK );
* data << (( Unit * ) this ) -> GetSpeed ( MOVE_RUN );
* data << (( Unit * ) this ) -> GetSpeed ( MOVE_SWIMBACK );
* data << (( Unit * ) this ) -> GetSpeed ( MOVE_SWIM );
* data << (( Unit * ) this ) -> GetSpeed ( MOVE_WALKBACK );
* data << (( Unit * ) this ) -> GetSpeed ( MOVE_FLY );
* data << (( Unit * ) this ) -> GetSpeed ( MOVE_FLYBACK );
* data << (( Unit * ) this ) -> GetSpeed ( MOVE_TURN );
// 0x08000000
if ( flags2 & MOVEMENTFLAG_SPLINE2 )
{
if ( GetTypeId () != TYPEID_PLAYER )
{
sLog . outDebug ( "_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 for non-player" );
return ;
}
if ( ! (( Player * ) this ) -> isInFlight ())
{
sLog . outDebug ( "_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 but not in flight" );
return ;
}
WPAssert ((( Player * ) this ) -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == FLIGHT_MOTION_TYPE );
FlightPathMovementGenerator * fmg = ( FlightPathMovementGenerator * )((( Player * ) this ) -> GetMotionMaster () -> top ());
uint32 flags3 = 0x00000300 ;
* data << uint32 ( flags3 ); // splines flag?
if ( flags3 & 0x10000 ) // probably x,y,z coords there
{
* data << ( float ) 0 ;
* data << ( float ) 0 ;
* data << ( float ) 0 ;
}
if ( flags3 & 0x20000 ) // probably guid there
{
* data << uint64 ( 0 );
}
if ( flags3 & 0x40000 ) // may be orientation
{
* data << ( float ) 0 ;
}
Path & path = fmg -> GetPath ();
float x , y , z ;
(( Player * ) this ) -> GetPosition ( x , y , z );
uint32 inflighttime = uint32 ( path . GetPassedLength ( fmg -> GetCurrentNode (), x , y , z ) * 32 );
uint32 traveltime = uint32 ( path . GetTotalLength () * 32 );
* data << uint32 ( inflighttime ); // passed move time?
* data << uint32 ( traveltime ); // full move time?
* data << uint32 ( 0 ); // ticks count?
uint32 poscount = uint32 ( path . Size ());
* data << uint32 ( poscount ); // points count
for ( uint32 i = 0 ; i < poscount ; ++ i )
{
* data << path . GetNodes ()[ i ]. x ;
* data << path . GetNodes ()[ i ]. y ;
* data << path . GetNodes ()[ i ]. z ;
}
/*for(uint32 i = 0; i < poscount; i++)
{
// path points
*data << (float)0;
*data << (float)0;
*data << (float)0;
}*/
* data << path . GetNodes ()[ poscount - 1 ]. x ;
* data << path . GetNodes ()[ poscount - 1 ]. y ;
* data << path . GetNodes ()[ poscount - 1 ]. z ;
// target position (path end)
/**data << ((Unit*)this)->GetPositionX();
*data << ((Unit*)this)->GetPositionY();
*data << ((Unit*)this)->GetPositionZ();*/
}
}
// 0x8
if ( flags & UPDATEFLAG_LOWGUID )
{
switch ( GetTypeId ())
{
case TYPEID_OBJECT :
case TYPEID_ITEM :
case TYPEID_CONTAINER :
case TYPEID_GAMEOBJECT :
case TYPEID_DYNAMICOBJECT :
case TYPEID_CORPSE :
* data << uint32 ( GetGUIDLow ()); // GetGUIDLow()
break ;
case TYPEID_UNIT :
* data << uint32 ( 0x0000000B ); // unk, can be 0xB or 0xC
break ;
case TYPEID_PLAYER :
if ( flags & UPDATEFLAG_SELF )
* data << uint32 ( 0x00000015 ); // unk, can be 0x15 or 0x22
else
* data << uint32 ( 0x00000008 ); // unk, can be 0x7 or 0x8
break ;
default :
* data << uint32 ( 0x00000000 ); // unk
break ;
}
}
// 0x10
if ( flags & UPDATEFLAG_HIGHGUID )
{
switch ( GetTypeId ())
{
case TYPEID_OBJECT :
case TYPEID_ITEM :
case TYPEID_CONTAINER :
case TYPEID_GAMEOBJECT :
case TYPEID_DYNAMICOBJECT :
case TYPEID_CORPSE :
* data << uint32 ( GetGUIDHigh ()); // GetGUIDHigh()
break ;
default :
* data << uint32 ( 0x00000000 ); // unk
break ;
}
}
// 0x4
if ( flags & UPDATEFLAG_FULLGUID )
{
* data << uint8 ( 0 ); // packed guid (probably target guid)
}
// 0x2
if ( flags & UPDATEFLAG_TRANSPORT )
{
* data << uint32 ( getMSTime ()); // ms time
}
}
void Object :: _BuildValuesUpdate ( uint8 updatetype , ByteBuffer * data , UpdateMask * updateMask , Player * target ) const
{
if ( ! target )
return ;
bool IsActivateToQuest = false ;
if ( updatetype == UPDATETYPE_CREATE_OBJECT || updatetype == UPDATETYPE_CREATE_OBJECT2 )
{
if ( isType ( TYPEMASK_GAMEOBJECT ) && ! (( GameObject * ) this ) -> IsTransport ())
{
if ( (( GameObject * ) this ) -> ActivateToQuest ( target ) || target -> isGameMaster ())
{
IsActivateToQuest = true ;
updateMask -> SetBit ( GAMEOBJECT_DYN_FLAGS );
}
2008-10-14 11:57:03 -05:00
if ( GetUInt32Value ( GAMEOBJECT_ARTKIT ))
updateMask -> SetBit ( GAMEOBJECT_ARTKIT );
2008-10-11 14:16:25 -05:00
}
}
else //case UPDATETYPE_VALUES
{
if ( isType ( TYPEMASK_GAMEOBJECT ) && ! (( GameObject * ) this ) -> IsTransport ())
{
if ( (( GameObject * ) this ) -> ActivateToQuest ( target ) || target -> isGameMaster ())
{
IsActivateToQuest = true ;
}
updateMask -> SetBit ( GAMEOBJECT_DYN_FLAGS );
updateMask -> SetBit ( GAMEOBJECT_ANIMPROGRESS );
}
}
WPAssert ( updateMask && updateMask -> GetCount () == m_valuesCount );
* data << ( uint8 ) updateMask -> GetBlockCount ();
data -> append ( updateMask -> GetMask (), updateMask -> GetLength () );
// 2 specialized loops for speed optimization in non-unit case
if ( isType ( TYPEMASK_UNIT )) // unit (creature/player) case
{
for ( uint16 index = 0 ; index < m_valuesCount ; index ++ )
{
if ( updateMask -> GetBit ( index ) )
{
// remove custom flag before send
2008-10-14 11:57:03 -05:00
2008-10-11 14:16:25 -05:00
if ( index == UNIT_NPC_FLAGS )
2008-10-14 11:57:03 -05:00
* data << uint32 ( m_uint32Values [ index ] & ~ ( UNIT_NPC_FLAG_GUARD + UNIT_NPC_FLAG_OUTDOORPVP ));
2008-10-11 14:16:25 -05:00
// FIXME: Some values at server stored in float format but must be sent to client in uint32 format
else if ( index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME )
{
// convert from float to uint32 and send
* data << uint32 ( m_floatValues [ index ] < 0 ? 0 : m_floatValues [ index ]);
}
// there are some float values which may be negative or can't get negative due to other checks
else if ( index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4 ||
index >= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE && index <= ( UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 6 ) ||
index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE && index <= ( UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6 ) ||
index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4 )
{
* data << uint32 ( m_floatValues [ index ]);
}
// Gamemasters should be always able to select units - remove not selectable flag
else if ( index == UNIT_FIELD_FLAGS && target -> isGameMaster ())
{
* data << ( m_uint32Values [ index ] & ~ UNIT_FLAG_NOT_SELECTABLE );
}
// hide lootable animation for unallowed players
else if ( index == UNIT_DYNAMIC_FLAGS && GetTypeId () == TYPEID_UNIT )
{
if ( ! target -> isAllowedToLoot (( Creature * ) this ))
* data << ( m_uint32Values [ index ] & ~ UNIT_DYNFLAG_LOOTABLE );
else
* data << ( m_uint32Values [ index ] & ~ UNIT_DYNFLAG_OTHER_TAGGER );
}
else
{
// send in current format (float as float, uint32 as uint32)
* data << m_uint32Values [ index ];
}
}
}
}
else if ( isType ( TYPEMASK_GAMEOBJECT )) // gameobject case
{
for ( uint16 index = 0 ; index < m_valuesCount ; index ++ )
{
if ( updateMask -> GetBit ( index ) )
{
// send in current format (float as float, uint32 as uint32)
if ( index == GAMEOBJECT_DYN_FLAGS )
{
if ( IsActivateToQuest )
{
switch ((( GameObject * ) this ) -> GetGoType ())
{
case GAMEOBJECT_TYPE_CHEST :
* data << uint32 ( 9 ); // enable quest object. Represent 9, but 1 for client before 2.3.0
break ;
case GAMEOBJECT_TYPE_GOOBER :
* data << uint32 ( 1 );
break ;
default :
* data << uint32 ( 0 ); //unknown. not happen.
break ;
}
}
else
* data << uint32 ( 0 ); // disable quest object
}
else
* data << m_uint32Values [ index ]; // other cases
}
}
}
else // other objects case (no special index checks)
{
for ( uint16 index = 0 ; index < m_valuesCount ; index ++ )
{
if ( updateMask -> GetBit ( index ) )
{
// send in current format (float as float, uint32 as uint32)
* data << m_uint32Values [ index ];
}
}
}
}
void Object :: ClearUpdateMask ( bool remove )
{
for ( uint16 index = 0 ; index < m_valuesCount ; index ++ )
{
if ( m_uint32Values_mirror [ index ] != m_uint32Values [ index ])
m_uint32Values_mirror [ index ] = m_uint32Values [ index ];
}
if ( m_objectUpdated )
{
if ( remove )
ObjectAccessor :: Instance (). RemoveUpdateObject ( this );
m_objectUpdated = false ;
}
}
// Send current value fields changes to all viewers
void Object :: SendUpdateObjectToAllExcept ( Player * exceptPlayer )
{
// changes will be send in create packet
if ( ! IsInWorld ())
return ;
// nothing do
if ( ! m_objectUpdated )
return ;
ObjectAccessor :: UpdateObject ( this , exceptPlayer );
}
bool Object :: LoadValues ( const char * data )
{
if ( ! m_uint32Values ) _InitValues ();
Tokens tokens = StrSplit ( data , " " );
if ( tokens . size () != m_valuesCount )
return false ;
Tokens :: iterator iter ;
int index ;
for ( iter = tokens . begin (), index = 0 ; index < m_valuesCount ; ++ iter , ++ index )
{
m_uint32Values [ index ] = atol (( * iter ). c_str ());
}
return true ;
}
void Object :: _SetUpdateBits ( UpdateMask * updateMask , Player * /*target*/ ) const
{
for ( uint16 index = 0 ; index < m_valuesCount ; index ++ )
{
if ( m_uint32Values_mirror [ index ] != m_uint32Values [ index ])
updateMask -> SetBit ( index );
}
}
void Object :: _SetCreateBits ( UpdateMask * updateMask , Player * /*target*/ ) const
{
for ( uint16 index = 0 ; index < m_valuesCount ; index ++ )
{
if ( GetUInt32Value ( index ) != 0 )
updateMask -> SetBit ( index );
}
}
void Object :: SetInt32Value ( uint16 index , int32 value )
{
ASSERT ( index < m_valuesCount || PrintIndexError ( index , true ) );
if ( m_int32Values [ index ] != value )
{
m_int32Values [ index ] = value ;
if ( m_inWorld )
{
if ( ! m_objectUpdated )
{
ObjectAccessor :: Instance (). AddUpdateObject ( this );
m_objectUpdated = true ;
}
}
}
}
void Object :: SetUInt32Value ( uint16 index , uint32 value )
{
ASSERT ( index < m_valuesCount || PrintIndexError ( index , true ) );
if ( m_uint32Values [ index ] != value )
{
m_uint32Values [ index ] = value ;
if ( m_inWorld )
{
if ( ! m_objectUpdated )
{
ObjectAccessor :: Instance (). AddUpdateObject ( this );
m_objectUpdated = true ;
}
}
}
}
void Object :: SetUInt64Value ( uint16 index , const uint64 & value )
{
ASSERT ( index + 1 < m_valuesCount || PrintIndexError ( index , true ) );
if ( * (( uint64 * ) & ( m_uint32Values [ index ])) != value )
{
m_uint32Values [ index ] = * (( uint32 * ) & value );
m_uint32Values [ index + 1 ] = * ((( uint32 * ) & value ) + 1 );
if ( m_inWorld )
{
if ( ! m_objectUpdated )
{
ObjectAccessor :: Instance (). AddUpdateObject ( this );
m_objectUpdated = true ;
}
}
}
}
void Object :: SetFloatValue ( uint16 index , float value )
{
ASSERT ( index < m_valuesCount || PrintIndexError ( index , true ) );
if ( m_floatValues [ index ] != value )
{
m_floatValues [ index ] = value ;
if ( m_inWorld )
{
if ( ! m_objectUpdated )
{
ObjectAccessor :: Instance (). AddUpdateObject ( this );
m_objectUpdated = true ;
}
}
}
}
void Object :: SetByteValue ( uint16 index , uint8 offset , uint8 value )
{
ASSERT ( index < m_valuesCount || PrintIndexError ( index , true ) );
if ( offset > 4 )
{
sLog . outError ( "Object::SetByteValue: wrong offset %u" , offset );
return ;
}
if ( uint8 ( m_uint32Values [ index ] >> ( offset * 8 )) != value )
{
m_uint32Values [ index ] &= ~ uint32 ( uint32 ( 0xFF ) << ( offset * 8 ));
m_uint32Values [ index ] |= uint32 ( uint32 ( value ) << ( offset * 8 ));
if ( m_inWorld )
{
if ( ! m_objectUpdated )
{
ObjectAccessor :: Instance (). AddUpdateObject ( this );
m_objectUpdated = true ;
}
}
}
}
void Object :: SetUInt16Value ( uint16 index , uint8 offset , uint16 value )
{
ASSERT ( index < m_valuesCount || PrintIndexError ( index , true ) );
if ( offset > 2 )
{
sLog . outError ( "Object::SetUInt16Value: wrong offset %u" , offset );
return ;
}
if ( uint8 ( m_uint32Values [ index ] >> ( offset * 16 )) != value )
{
m_uint32Values [ index ] &= ~ uint32 ( uint32 ( 0xFFFF ) << ( offset * 16 ));
m_uint32Values [ index ] |= uint32 ( uint32 ( value ) << ( offset * 16 ));
if ( m_inWorld )
{
if ( ! m_objectUpdated )
{
ObjectAccessor :: Instance (). AddUpdateObject ( this );
m_objectUpdated = true ;
}
}
}
}
void Object :: SetStatFloatValue ( uint16 index , float value )
{
if ( value < 0 )
value = 0.0f ;
SetFloatValue ( index , value );
}
void Object :: SetStatInt32Value ( uint16 index , int32 value )
{
if ( value < 0 )
value = 0 ;
SetUInt32Value ( index , uint32 ( value ));
}
void Object :: ApplyModUInt32Value ( uint16 index , int32 val , bool apply )
{
int32 cur = GetUInt32Value ( index );
cur += ( apply ? val : - val );
if ( cur < 0 )
cur = 0 ;
SetUInt32Value ( index , cur );
}
void Object :: ApplyModInt32Value ( uint16 index , int32 val , bool apply )
{
int32 cur = GetInt32Value ( index );
cur += ( apply ? val : - val );
SetInt32Value ( index , cur );
}
void Object :: ApplyModSignedFloatValue ( uint16 index , float val , bool apply )
{
float cur = GetFloatValue ( index );
cur += ( apply ? val : - val );
SetFloatValue ( index , cur );
}
void Object :: ApplyModPositiveFloatValue ( uint16 index , float val , bool apply )
{
float cur = GetFloatValue ( index );
cur += ( apply ? val : - val );
if ( cur < 0 )
cur = 0 ;
SetFloatValue ( index , cur );
}
void Object :: SetFlag ( uint16 index , uint32 newFlag )
{
ASSERT ( index < m_valuesCount || PrintIndexError ( index , true ) );
uint32 oldval = m_uint32Values [ index ];
uint32 newval = oldval | newFlag ;
if ( oldval != newval )
{
m_uint32Values [ index ] = newval ;
if ( m_inWorld )
{
if ( ! m_objectUpdated )
{
ObjectAccessor :: Instance (). AddUpdateObject ( this );
m_objectUpdated = true ;
}
}
}
}
void Object :: RemoveFlag ( uint16 index , uint32 oldFlag )
{
ASSERT ( index < m_valuesCount || PrintIndexError ( index , true ) );
uint32 oldval = m_uint32Values [ index ];
uint32 newval = oldval & ~ oldFlag ;
if ( oldval != newval )
{
m_uint32Values [ index ] = newval ;
if ( m_inWorld )
{
if ( ! m_objectUpdated )
{
ObjectAccessor :: Instance (). AddUpdateObject ( this );
m_objectUpdated = true ;
}
}
}
}
bool Object :: PrintIndexError ( uint32 index , bool set ) const
{
sLog . outError ( "ERROR: Attempt %s non-existed value field: %u (count: %u) for object typeid: %u type mask: %u" ,( set ? "set value to" : "get value from" ), index , m_valuesCount , GetTypeId (), m_objectType );
// assert must fail after function call
return false ;
}
WorldObject :: WorldObject ()
{
m_positionX = 0.0f ;
m_positionY = 0.0f ;
m_positionZ = 0.0f ;
m_orientation = 0.0f ;
m_mapId = 0 ;
m_InstanceId = 0 ;
m_name = "" ;
mSemaphoreTeleport = false ;
}
void WorldObject :: _Create ( uint32 guidlow , HighGuid guidhigh , uint32 mapid )
{
Object :: _Create ( guidlow , 0 , guidhigh );
m_mapId = mapid ;
}
uint32 WorldObject :: GetZoneId () const
{
return MapManager :: Instance (). GetBaseMap ( m_mapId ) -> GetZoneId ( m_positionX , m_positionY );
}
uint32 WorldObject :: GetAreaId () const
{
return MapManager :: Instance (). GetBaseMap ( m_mapId ) -> GetAreaId ( m_positionX , m_positionY );
}
InstanceData * WorldObject :: GetInstanceData ()
{
Map * map = MapManager :: Instance (). GetMap ( m_mapId , this );
return map -> IsDungeon () ? (( InstanceMap * ) map ) -> GetInstanceData () : NULL ;
}
//slow
float WorldObject :: GetDistance ( const WorldObject * obj ) const
{
float dx = GetPositionX () - obj -> GetPositionX ();
float dy = GetPositionY () - obj -> GetPositionY ();
float dz = GetPositionZ () - obj -> GetPositionZ ();
float sizefactor = GetObjectSize () + obj -> GetObjectSize ();
float dist = sqrt (( dx * dx ) + ( dy * dy ) + ( dz * dz )) - sizefactor ;
return ( dist > 0 ? dist : 0 );
}
float WorldObject :: GetDistance2d ( float x , float y ) const
{
float dx = GetPositionX () - x ;
float dy = GetPositionY () - y ;
float sizefactor = GetObjectSize ();
float dist = sqrt (( dx * dx ) + ( dy * dy )) - sizefactor ;
return ( dist > 0 ? dist : 0 );
}
float WorldObject :: GetDistance ( const float x , const float y , const float z ) const
{
float dx = GetPositionX () - x ;
float dy = GetPositionY () - y ;
float dz = GetPositionZ () - z ;
float sizefactor = GetObjectSize ();
float dist = sqrt (( dx * dx ) + ( dy * dy ) + ( dz * dz )) - sizefactor ;
return ( dist > 0 ? dist : 0 );
}
float WorldObject :: GetDistance2d ( const WorldObject * obj ) const
{
float dx = GetPositionX () - obj -> GetPositionX ();
float dy = GetPositionY () - obj -> GetPositionY ();
float sizefactor = GetObjectSize () + obj -> GetObjectSize ();
float dist = sqrt (( dx * dx ) + ( dy * dy )) - sizefactor ;
return ( dist > 0 ? dist : 0 );
}
float WorldObject :: GetDistanceZ ( const WorldObject * obj ) const
{
float dz = fabs ( GetPositionZ () - obj -> GetPositionZ ());
float sizefactor = GetObjectSize () + obj -> GetObjectSize ();
float dist = dz - sizefactor ;
return ( dist > 0 ? dist : 0 );
}
bool WorldObject :: IsWithinDistInMap ( const WorldObject * obj , const float dist2compare ) const
{
if ( ! obj || ! IsInMap ( obj )) return false ;
float dx = GetPositionX () - obj -> GetPositionX ();
float dy = GetPositionY () - obj -> GetPositionY ();
float dz = GetPositionZ () - obj -> GetPositionZ ();
float distsq = dx * dx + dy * dy + dz * dz ;
float sizefactor = GetObjectSize () + obj -> GetObjectSize ();
float maxdist = dist2compare + sizefactor ;
return distsq < maxdist * maxdist ;
}
bool WorldObject :: IsWithinLOSInMap ( const WorldObject * obj ) const
{
if ( ! IsInMap ( obj )) return false ;
float ox , oy , oz ;
obj -> GetPosition ( ox , oy , oz );
return ( IsWithinLOS ( ox , oy , oz ));
}
bool WorldObject :: IsWithinLOS ( const float ox , const float oy , const float oz ) const
{
float x , y , z ;
GetPosition ( x , y , z );
VMAP :: IVMapManager * vMapManager = VMAP :: VMapFactory :: createOrGetVMapManager ();
return vMapManager -> isInLineOfSight ( GetMapId (), x , y , z + 2.0f , ox , oy , oz + 2.0f );
}
float WorldObject :: GetAngle ( const WorldObject * obj ) const
{
if ( ! obj ) return 0 ;
return GetAngle ( obj -> GetPositionX (), obj -> GetPositionY () );
}
// Return angle in range 0..2*pi
float WorldObject :: GetAngle ( const float x , const float y ) const
{
float dx = x - GetPositionX ();
float dy = y - GetPositionY ();
float ang = atan2 ( dy , dx );
ang = ( ang >= 0 ) ? ang : 2 * M_PI + ang ;
return ang ;
}
bool WorldObject :: HasInArc ( const float arcangle , const WorldObject * obj ) const
{
float arc = arcangle ;
// move arc to range 0.. 2*pi
while ( arc >= 2.0f * M_PI )
arc -= 2.0f * M_PI ;
while ( arc < 0 )
arc += 2.0f * M_PI ;
float angle = GetAngle ( obj );
angle -= m_orientation ;
// move angle to range -pi ... +pi
while ( angle > M_PI )
angle -= 2.0f * M_PI ;
while ( angle < - M_PI )
angle += 2.0f * M_PI ;
float lborder = - 1 * ( arc / 2.0f ); // in range -pi..0
float rborder = ( arc / 2.0f ); // in range 0..pi
return (( angle >= lborder ) && ( angle <= rborder ));
}
void WorldObject :: GetRandomPoint ( float x , float y , float z , float distance , float & rand_x , float & rand_y , float & rand_z ) const
{
if ( distance == 0 )
{
rand_x = x ;
rand_y = y ;
rand_z = z ;
return ;
}
// angle to face `obj` to `this`
float angle = rand_norm () * 2 * M_PI ;
float new_dist = rand_norm () * distance ;
rand_x = x + new_dist * cos ( angle );
rand_y = y + new_dist * sin ( angle );
rand_z = z ;
2008-10-14 11:57:03 -05:00
Trinity :: NormalizeMapCoord ( rand_x );
Trinity :: NormalizeMapCoord ( rand_y );
2008-10-11 14:16:25 -05:00
UpdateGroundPositionZ ( rand_x , rand_y , rand_z ); // update to LOS height if available
}
void WorldObject :: UpdateGroundPositionZ ( float x , float y , float & z ) const
{
float new_z = MapManager :: Instance (). GetBaseMap ( GetMapId ()) -> GetHeight ( x , y , z , true );
if ( new_z > INVALID_HEIGHT )
z = new_z + 0.05f ; // just to be sure that we are not a few pixel under the surface
}
bool WorldObject :: IsPositionValid () const
{
2008-10-14 11:57:03 -05:00
return Trinity :: IsValidMapCoord ( m_positionX , m_positionY , m_positionZ , m_orientation );
2008-10-11 14:16:25 -05:00
}
void WorldObject :: MonsterSay ( const char * text , uint32 language , uint64 TargetGuid )
{
WorldPacket data ( SMSG_MESSAGECHAT , 200 );
BuildMonsterChat ( & data , CHAT_MSG_MONSTER_SAY , text , language , GetName (), TargetGuid );
SendMessageToSetInRange ( & data , sWorld . getConfig ( CONFIG_LISTEN_RANGE_SAY ), true );
}
void WorldObject :: MonsterYell ( const char * text , uint32 language , uint64 TargetGuid )
{
WorldPacket data ( SMSG_MESSAGECHAT , 200 );
BuildMonsterChat ( & data , CHAT_MSG_MONSTER_YELL , text , language , GetName (), TargetGuid );
SendMessageToSetInRange ( & data , sWorld . getConfig ( CONFIG_LISTEN_RANGE_YELL ), true );
}
void WorldObject :: MonsterTextEmote ( const char * text , uint64 TargetGuid , bool IsBossEmote )
{
WorldPacket data ( SMSG_MESSAGECHAT , 200 );
BuildMonsterChat ( & data , IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE , text , LANG_UNIVERSAL , GetName (), TargetGuid );
SendMessageToSetInRange ( & data , sWorld . getConfig ( CONFIG_LISTEN_RANGE_TEXTEMOTE ), true );
}
void WorldObject :: MonsterWhisper ( const char * text , uint64 receiver , bool IsBossWhisper )
{
Player * player = objmgr . GetPlayer ( receiver );
if ( ! player || ! player -> GetSession ())
return ;
WorldPacket data ( SMSG_MESSAGECHAT , 200 );
BuildMonsterChat ( & data , IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER , text , LANG_UNIVERSAL , GetName (), receiver );
player -> GetSession () -> SendPacket ( & data );
}
void WorldObject :: SendPlaySound ( uint32 Sound , bool OnlySelf )
{
WorldPacket data ( SMSG_PLAY_SOUND , 4 );
data << Sound ;
if ( OnlySelf && GetTypeId () == TYPEID_PLAYER )
(( Player * ) this ) -> GetSession () -> SendPacket ( & data );
else
SendMessageToSet ( & data , true ); // ToSelf ignored in this case
}
2008-10-14 11:57:03 -05:00
namespace Trinity
2008-10-11 14:16:25 -05:00
{
class MessageChatLocaleCacheDo
{
public :
MessageChatLocaleCacheDo ( WorldObject const & obj , ChatMsg msgtype , int32 textId , uint32 language , uint64 targetGUID , float dist )
: i_object ( obj ), i_msgtype ( msgtype ), i_textId ( textId ), i_language ( language ),
i_targetGUID ( targetGUID ), i_dist ( dist )
{
}
~ MessageChatLocaleCacheDo ()
{
for ( int i = 0 ; i < i_data_cache . size (); ++ i )
delete i_data_cache [ i ];
}
void operator ()( Player * p )
{
// skip far away players
if ( p -> GetDistance ( & i_object ) > i_dist )
return ;
uint32 loc_idx = p -> GetSession () -> GetSessionDbLocaleIndex ();
uint32 cache_idx = loc_idx + 1 ;
WorldPacket * data ;
// create if not cached yet
if ( i_data_cache . size () < cache_idx + 1 || ! i_data_cache [ cache_idx ])
{
if ( i_data_cache . size () < cache_idx + 1 )
i_data_cache . resize ( cache_idx + 1 );
2008-10-14 11:57:03 -05:00
char const * text = objmgr . GetTrinityString ( i_textId , loc_idx );
2008-10-11 14:16:25 -05:00
data = new WorldPacket ( SMSG_MESSAGECHAT , 200 );
// TODO: i_object.GetName() also must be localized?
i_object . BuildMonsterChat ( data , i_msgtype , text , i_language , i_object . GetName (), i_targetGUID );
i_data_cache [ cache_idx ] = data ;
}
else
data = i_data_cache [ cache_idx ];
p -> SendDirectMessage ( data );
}
private :
WorldObject const & i_object ;
ChatMsg i_msgtype ;
int32 i_textId ;
uint32 i_language ;
uint64 i_targetGUID ;
float i_dist ;
std :: vector < WorldPacket *> i_data_cache ; // 0 = default, i => i-1 locale index
};
2008-10-14 11:57:03 -05:00
} // namespace Trinity
2008-10-11 14:16:25 -05:00
void WorldObject :: MonsterSay ( int32 textId , uint32 language , uint64 TargetGuid )
{
2008-10-14 11:57:03 -05:00
CellPair p = Trinity :: ComputeCellPair ( GetPositionX (), GetPositionY ());
2008-10-11 14:16:25 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
2008-10-14 11:57:03 -05:00
Trinity :: MessageChatLocaleCacheDo say_do ( * this , CHAT_MSG_MONSTER_SAY , textId , language , TargetGuid , sWorld . getConfig ( CONFIG_LISTEN_RANGE_SAY ));
Trinity :: PlayerWorker < Trinity :: MessageChatLocaleCacheDo > say_worker ( say_do );
TypeContainerVisitor < Trinity :: PlayerWorker < Trinity :: MessageChatLocaleCacheDo > , WorldTypeMapContainer > message ( say_worker );
2008-10-11 14:16:25 -05:00
CellLock < GridReadGuard > cell_lock ( cell , p );
cell_lock -> Visit ( cell_lock , message , * GetMap ());
}
void WorldObject :: MonsterYell ( int32 textId , uint32 language , uint64 TargetGuid )
{
2008-10-14 11:57:03 -05:00
CellPair p = Trinity :: ComputeCellPair ( GetPositionX (), GetPositionY ());
2008-10-11 14:16:25 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
2008-10-14 11:57:03 -05:00
Trinity :: MessageChatLocaleCacheDo say_do ( * this , CHAT_MSG_MONSTER_YELL , textId , language , TargetGuid , sWorld . getConfig ( CONFIG_LISTEN_RANGE_YELL ));
Trinity :: PlayerWorker < Trinity :: MessageChatLocaleCacheDo > say_worker ( say_do );
TypeContainerVisitor < Trinity :: PlayerWorker < Trinity :: MessageChatLocaleCacheDo > , WorldTypeMapContainer > message ( say_worker );
2008-10-11 14:16:25 -05:00
CellLock < GridReadGuard > cell_lock ( cell , p );
cell_lock -> Visit ( cell_lock , message , * GetMap ());
}
void WorldObject :: MonsterTextEmote ( int32 textId , uint64 TargetGuid , bool IsBossEmote )
{
2008-10-14 11:57:03 -05:00
CellPair p = Trinity :: ComputeCellPair ( GetPositionX (), GetPositionY ());
2008-10-11 14:16:25 -05:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
2008-10-14 11:57:03 -05:00
Trinity :: MessageChatLocaleCacheDo say_do ( * this , IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE , textId , LANG_UNIVERSAL , TargetGuid , sWorld . getConfig ( CONFIG_LISTEN_RANGE_TEXTEMOTE ));
Trinity :: PlayerWorker < Trinity :: MessageChatLocaleCacheDo > say_worker ( say_do );
TypeContainerVisitor < Trinity :: PlayerWorker < Trinity :: MessageChatLocaleCacheDo > , WorldTypeMapContainer > message ( say_worker );
2008-10-11 14:16:25 -05:00
CellLock < GridReadGuard > cell_lock ( cell , p );
cell_lock -> Visit ( cell_lock , message , * GetMap ());
}
void WorldObject :: MonsterWhisper ( int32 textId , uint64 receiver , bool IsBossWhisper )
{
Player * player = objmgr . GetPlayer ( receiver );
if ( ! player || ! player -> GetSession ())
return ;
uint32 loc_idx = player -> GetSession () -> GetSessionDbLocaleIndex ();
2008-10-14 11:57:03 -05:00
char const * text = objmgr . GetTrinityString ( textId , loc_idx );
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_MESSAGECHAT , 200 );
BuildMonsterChat ( & data , IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER , text , LANG_UNIVERSAL , GetName (), receiver );
player -> GetSession () -> SendPacket ( & data );
}
void WorldObject :: BuildMonsterChat ( WorldPacket * data , uint8 msgtype , char const * text , uint32 language , char const * name , uint64 targetGuid ) const
{
bool pre = ( msgtype == CHAT_MSG_MONSTER_EMOTE || msgtype == CHAT_MSG_RAID_BOSS_EMOTE );
* data << ( uint8 ) msgtype ;
* data << ( uint32 ) language ;
* data << ( uint64 ) GetGUID ();
* data << ( uint32 ) 0 ; //2.1.0
* data << ( uint32 )( strlen ( name ) + 1 );
* data << name ;
* data << ( uint64 ) targetGuid ; //Unit Target
if ( targetGuid && ! IS_PLAYER_GUID ( targetGuid ) )
{
* data << ( uint32 ) 1 ; // target name length
* data << ( uint8 ) 0 ; // target name
}
* data << ( uint32 )( strlen ( text ) + 1 + ( pre ? 3 : 0 ));
if ( pre )
data -> append ( "%s " , 3 );
* data << text ;
* data << ( uint8 ) 0 ; // ChatTag
}
void WorldObject :: BuildHeartBeatMsg ( WorldPacket * data ) const
{
//Heartbeat message cannot be used for non-units
if ( ! isType ( TYPEMASK_UNIT ))
return ;
data -> Initialize ( MSG_MOVE_HEARTBEAT , 32 );
data -> append ( GetPackGUID ());
* data << uint32 ((( Unit * ) this ) -> GetUnitMovementFlags ()); // movement flags
* data << uint8 ( 0 ); // 2.3.0
* data << getMSTime (); // time
* data << m_positionX ;
* data << m_positionY ;
* data << m_positionZ ;
* data << m_orientation ;
* data << uint32 ( 0 );
}
void WorldObject :: BuildTeleportAckMsg ( WorldPacket * data , float x , float y , float z , float ang ) const
{
//TeleportAck message cannot be used for non-units
if ( ! isType ( TYPEMASK_UNIT ))
return ;
data -> Initialize ( MSG_MOVE_TELEPORT_ACK , 41 );
data -> append ( GetPackGUID ());
* data << uint32 ( 0 ); // this value increments every time
* data << uint32 ((( Unit * ) this ) -> GetUnitMovementFlags ()); // movement flags
* data << uint8 ( 0 ); // 2.3.0
* data << getMSTime (); // time
* data << x ;
* data << y ;
* data << z ;
* data << ang ;
* data << uint32 ( 0 );
}
void WorldObject :: SendMessageToSet ( WorldPacket * data , bool /*bToSelf*/ )
{
MapManager :: Instance (). GetMap ( m_mapId , this ) -> MessageBroadcast ( this , data );
}
void WorldObject :: SendMessageToSetInRange ( WorldPacket * data , float dist , bool /*bToSelf*/ )
{
MapManager :: Instance (). GetMap ( m_mapId , this ) -> MessageDistBroadcast ( this , data , dist );
}
void WorldObject :: SendObjectDeSpawnAnim ( uint64 guid )
{
WorldPacket data ( SMSG_GAMEOBJECT_DESPAWN_ANIM , 8 );
data << guid ;
SendMessageToSet ( & data , true );
}
Map * WorldObject :: GetMap () const
{
return MapManager :: Instance (). GetMap ( GetMapId (), this );
}
Map const * WorldObject :: GetBaseMap () const
{
return MapManager :: Instance (). GetBaseMap ( GetMapId ());
}
void WorldObject :: AddObjectToRemoveList ()
{
Map * map = GetMap ();
if ( ! map )
{
sLog . outError ( "Object (TypeId: %u Entry: %u GUID: %u) at attempt add to move list not have valid map (Id: %u)." , GetTypeId (), GetEntry (), GetGUIDLow (), GetMapId ());
return ;
}
map -> AddObjectToRemoveList ( this );
}
Creature * WorldObject :: SummonCreature ( uint32 id , float x , float y , float z , float ang , TempSummonType spwtype , uint32 despwtime )
{
TemporarySummon * pCreature = new TemporarySummon ( GetGUID ());
pCreature -> SetInstanceId ( GetInstanceId ());
uint32 team = 0 ;
if ( GetTypeId () == TYPEID_PLAYER )
team = (( Player * ) this ) -> GetTeam ();
if ( ! pCreature -> Create ( objmgr . GenerateLowGuid ( HIGHGUID_UNIT ), GetMap (), id , team ))
{
delete pCreature ;
return NULL ;
}
if ( x == 0.0f && y == 0.0f && z == 0.0f )
GetClosePoint ( x , y , z , pCreature -> GetObjectSize ());
pCreature -> Relocate ( x , y , z , ang );
if ( ! pCreature -> IsPositionValid ())
{
sLog . outError ( "ERROR: Creature (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)" , pCreature -> GetGUIDLow (), pCreature -> GetEntry (), pCreature -> GetPositionX (), pCreature -> GetPositionY ());
delete pCreature ;
return NULL ;
}
pCreature -> Summon ( spwtype , despwtime );
if ( GetTypeId () == TYPEID_UNIT && (( Creature * ) this ) -> AI ())
(( Creature * ) this ) -> AI () -> JustSummoned ( pCreature );
//return the creature therewith the summoner has access to it
return pCreature ;
}
2008-10-17 18:13:04 -05:00
GameObject * WorldObject :: SummonGameObject ( uint32 entry , float x , float y , float z , float ang , float rotation0 , float rotation1 , float rotation2 , float rotation3 , uint32 respawnTime )
{
if ( ! IsInWorld ())
return NULL ;
Map * map = GetMap ();
if ( ! map )
return NULL ;
GameObjectInfo const * goinfo = objmgr . GetGameObjectInfo ( entry );
if ( ! goinfo )
{
sLog . outErrorDb ( "Gameobject template %u not found in database!" , entry );
return NULL ;
}
GameObject * go = new GameObject ();
if ( ! go -> Create ( objmgr . GenerateLowGuid ( HIGHGUID_GAMEOBJECT ), entry , map , x , y , z , ang , rotation0 , rotation1 , rotation2 , rotation3 , 100 , 1 ))
return NULL ;
go -> SetRespawnTime ( respawnTime );
go -> SetSpawnedByDefault ( false ); // do not save respawn time
2008-10-18 12:02:47 -05:00
go -> SetOwnerGUID ( GetGUID ());
2008-10-17 18:13:04 -05:00
map -> Add ( go );
return go ;
}
2008-10-11 14:16:25 -05:00
void WorldObject :: GetNearPoint2D ( float & x , float & y , float distance2d , float absAngle ) const
{
x = GetPositionX () + ( GetObjectSize () + distance2d ) * cos ( absAngle );
y = GetPositionY () + ( GetObjectSize () + distance2d ) * sin ( absAngle );
2008-10-14 11:57:03 -05:00
Trinity :: NormalizeMapCoord ( x );
Trinity :: NormalizeMapCoord ( y );
2008-10-11 14:16:25 -05:00
}
void WorldObject :: GetNearPoint ( WorldObject const * searcher , float & x , float & y , float & z , float searcher_size , float distance2d , float absAngle ) const
{
GetNearPoint2D ( x , y , distance2d + searcher_size , absAngle );
z = GetPositionZ ();
UpdateGroundPositionZ ( x , y , z );
}