2 * Copyright (C) 2005,2006 MaNGOS <http://www.mangosproject.org/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "WorldPacket.h"
26 #include "ObjectMgr.h"
27 #include "WorldSession.h"
28 #include "UpdateData.h"
30 #include "MapManager.h"
31 #include "ObjectAccessor.h"
33 #include "Transports.h"
39 m_objectTypeId
= TYPEID_OBJECT
;
40 m_objectType
= TYPE_OBJECT
;
58 m_moveType
= MOVE_STOP
;
60 mSemaphoreTeleport
= false;
62 m_objectUpdated
= false;
69 ObjectAccessor::Instance().RemoveUpdateObject(this);
73 //DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
74 delete [] m_uint32Values
;
75 //DEBUG_LOG("Object desctr 2 check (%p)",(void*)this);
79 void Object::_Create( uint32 guidlow
, uint32 guidhigh
)
81 if(!m_uint32Values
) _InitValues();
83 SetUInt32Value( OBJECT_FIELD_GUID
, guidlow
);
84 SetUInt32Value( OBJECT_FIELD_GUID
+1, guidhigh
);
85 SetUInt32Value( OBJECT_FIELD_TYPE
, m_objectType
);
86 _SetPackGUID(&m_PackGUID
,GetGUID());
89 void Object::_Create( uint32 guidlow
, uint32 guidhigh
, uint32 mapid
, float x
, float y
, float z
, float ang
, uint32 nameId
)
91 _Create(guidlow
, guidhigh
);
93 SetUInt32Value( OBJECT_FIELD_ENTRY
,nameId
);
102 void Object::BuildMovementUpdateBlock(UpdateData
* data
, uint32 flags
) const
106 buf
<< uint8( UPDATETYPE_MOVEMENT
);
109 _BuildMovementUpdate(&buf
, flags
, 0x00000000);
111 data
->AddUpdateBlock(buf
);
114 void Object::BuildCreateUpdateBlockForPlayer(UpdateData
*data
, Player
*target
) const
119 buf
<< uint8( UPDATETYPE_CREATE_OBJECT
);
120 buf
<< uint8( 0xFF );
122 buf
<< m_objectTypeId
;
124 switch(m_objectTypeId
)
126 case TYPEID_OBJECT
: //do nothing
129 case TYPEID_CONTAINER
:
130 _BuildMovementUpdate( &buf
, 0x10, 0x0 );
133 _BuildMovementUpdate( &buf
, 0x70, 0x800000 );
137 if( target
== this ) //build for self
140 buf
<< uint8( UPDATETYPE_CREATE_OBJECT2
);
141 buf
<< uint8( 0xFF ); // must be packet GUID ?
143 buf
<< m_objectTypeId
;
144 _BuildMovementUpdate( &buf
, 0x71, 0x2000 );
146 //build for other player
149 _BuildMovementUpdate( &buf
, 0x70, 0x0 );
153 case TYPEID_GAMEOBJECT
:
154 case TYPEID_DYNAMICOBJECT
:
156 if ((GUID_HIPART(GetGUID())==HIGHGUID_PLAYER_CORPSE
) || (GUID_HIPART(GetGUID()) == HIGHGUID_TRANSPORT
))
157 _BuildMovementUpdate( &buf
, 0x52, 0x0 );
159 _BuildMovementUpdate( &buf
, 0x50, 0x0 );
161 //case TYPEID_AIGROUP:
162 //case TYPEID_AREATRIGGER:
165 sLog
.outDetail("Unknown Object Type %u Create Update Block.\n", m_objectTypeId
);
169 UpdateMask updateMask
;
170 updateMask
.SetCount( m_valuesCount
);
171 _SetCreateBits( &updateMask
, target
);
172 _BuildValuesUpdate( &buf
, &updateMask
);
173 data
->AddUpdateBlock(buf
);
177 void Object::SendUpdateToPlayer(Player
* player
) const
179 //if (!player->IsInWorld()) return;
185 BuildCreateUpdateBlockForPlayer(&upd
, player
);
186 upd
.BuildPacket(&packet
);
187 player
->GetSession()->SendPacket(&packet
);
190 void Object::BuildValuesUpdateBlockForPlayer(UpdateData
*data
, Player
*target
) const
194 buf
<< (uint8
) UPDATETYPE_VALUES
;
195 buf
<< (uint8
) 0xFF; // must be packed GUID ?
198 UpdateMask updateMask
;
199 updateMask
.SetCount( m_valuesCount
);
200 _SetUpdateBits( &updateMask
, target
);
201 _BuildValuesUpdate( &buf
, &updateMask
);
203 data
->AddUpdateBlock(buf
);
206 void Object::BuildOutOfRangeUpdateBlock(UpdateData
* data
) const
208 data
->AddOutOfRangeGUID(GetGUID());
211 void Object::DestroyForPlayer(Player
*target
) const
216 data
.Initialize( SMSG_DESTROY_OBJECT
);
219 target
->GetSession()->SendPacket( &data
);
222 void Object::_BuildMovementUpdate(ByteBuffer
* data
, uint8 flags
, uint32 flags2
) const
224 *data
<< (uint8
)flags
;
225 if( m_objectTypeId
==TYPEID_PLAYER
)
227 if(((Player
*)this)->GetTransport())
229 flags2
|= 0x02000000;
231 *data
<< (uint32
)flags2
;
233 *data
<< (uint32
)getMSTime();
235 if (!((Player
*)this)->GetTransport())
237 *data
<< (float)m_positionX
;
238 *data
<< (float)m_positionY
;
239 *data
<< (float)m_positionZ
;
240 *data
<< (float)m_orientation
;
244 //*data << ((Player *)this)->m_transport->GetPositionX() + (float)((Player *)this)->m_transX;
245 //*data << ((Player *)this)->m_transport->GetPositionY() + (float)((Player *)this)->m_transY;
246 //*data << ((Player *)this)->m_transport->GetPositionZ() + (float)((Player *)this)->m_transZ;
248 *data
<< ((Player
*)this)->GetTransport()->GetPositionX();
249 *data
<< ((Player
*)this)->GetTransport()->GetPositionY();
250 *data
<< ((Player
*)this)->GetTransport()->GetPositionZ();
251 *data
<< ((Player
*)this)->GetTransport()->GetOrientation();
253 *data
<< (uint64
)(((Player
*)this)->GetTransport()->GetGUID());
254 *data
<< ((Player
*)this)->GetTransOffsetX();
255 *data
<< ((Player
*)this)->GetTransOffsetY();
256 *data
<< ((Player
*)this)->GetTransOffsetZ();
257 *data
<< ((Player
*)this)->GetTransOffsetO();
262 if(flags2
& 0x2000) //update self
269 *data
<< GetSpeed( MOVE_WALK
);
270 *data
<< GetSpeed( MOVE_RUN
);
271 *data
<< GetSpeed( MOVE_SWIMBACK
);
272 *data
<< GetSpeed( MOVE_SWIM
);
273 *data
<< GetSpeed( MOVE_WALKBACK
);
274 *data
<< GetSpeed( MOVE_TURN
);
276 if( m_objectTypeId
==TYPEID_UNIT
)
278 *data
<< (uint32
)flags2
;
279 *data
<< (uint32
)0xB5771D7F;
280 *data
<< (float)m_positionX
;
281 *data
<< (float)m_positionY
;
282 *data
<< (float)m_positionZ
;
283 *data
<< (float)m_orientation
;
285 *data
<< GetSpeed( MOVE_WALK
);
286 *data
<< GetSpeed( MOVE_RUN
);
287 *data
<< GetSpeed( MOVE_SWIMBACK
);
288 *data
<< GetSpeed( MOVE_SWIM
);
289 *data
<< GetSpeed( MOVE_WALKBACK
);
290 *data
<< GetSpeed( MOVE_TURN
);
292 if(flags2
& 0x400000)
294 *data
<< (uint32
)0x0;
295 *data
<< (uint32
)0x659;
296 *data
<< (uint32
)0xB7B;
297 *data
<< (uint32
)0xFDA0B4;
298 *data
<< (uint32
)PosCount
;
299 for(int i
=0;i
<PosCount
+1;i
++)
301 *data
<< (float)0; //x
302 *data
<< (float)0; //y
303 *data
<< (float)0; //z
307 if( (m_objectTypeId
==TYPEID_CORPSE
) || (m_objectTypeId
==TYPEID_GAMEOBJECT
) || (m_objectTypeId
==TYPEID_DYNAMICOBJECT
))
309 if(GUID_HIPART(GetGUID()) != HIGHGUID_TRANSPORT
)
311 *data
<< (float)m_positionX
;
312 *data
<< (float)m_positionY
;
313 *data
<< (float)m_positionZ
;
321 *data
<< (float)m_orientation
;
324 *data
<< (uint32
)0x1;
326 if ((GUID_HIPART(GetGUID()) == HIGHGUID_TRANSPORT
))
328 uint32 updT
= (uint32
)getMSTime();
329 *data
<< (uint32
)updT
;
332 if( GUID_HIPART(GetGUID()) == HIGHGUID_PLAYER_CORPSE
)
333 *data
<< (uint32
)0xBD38BA14; //fix me
336 void Object::_BuildValuesUpdate(ByteBuffer
* data
, UpdateMask
*updateMask
) const
338 WPAssert(updateMask
&& updateMask
->GetCount() == m_valuesCount
);
340 *data
<< (uint8
)updateMask
->GetBlockCount();
341 data
->append( updateMask
->GetMask(), updateMask
->GetLength() );
343 for( uint16 index
= 0; index
< m_valuesCount
; index
++ )
345 if( updateMask
->GetBit( index
) )
347 // Some values at server stored in float format but must be sended to client in uint32 format
348 if( isType(TYPE_UNIT
) && (
349 index
>= UNIT_FIELD_POWER1
&& index
<= UNIT_FIELD_MAXPOWER5
||
350 index
>= UNIT_FIELD_BASEATTACKTIME
&& index
<= UNIT_FIELD_RANGEDATTACKTIME
||
351 index
>= UNIT_FIELD_STR
&& index
<= UNIT_FIELD_RESISTANCES_06
)
352 || isType(TYPE_PLAYER
) &&
353 index
>= PLAYER_FIELD_POSSTAT0
&& index
<= PLAYER_FIELD_RESISTANCEBUFFMODSNEGATIVE_06
)
355 // convert from float to uint32 and send
356 *data
<< uint32(m_floatValues
[ index
]);
360 // send in current format (float as float, uint32 as uint32)
361 *data
<< m_uint32Values
[ index
];
367 void Object::BuildHeartBeatMsg(WorldPacket
*data
) const
369 data
->Initialize(MSG_MOVE_HEARTBEAT
); //2
371 *data
<< GetGUID(); //8
372 *data
<< uint32(0); //4
373 *data
<< uint32(0); //4
375 *data
<< m_positionX
; //4
376 *data
<< m_positionY
; //4
377 *data
<< m_positionZ
; //4
379 *data
<< m_orientation
; //4
382 void Object::BuildTeleportAckMsg(WorldPacket
*data
, float x
, float y
, float z
, float ang
) const
384 data
->Initialize(MSG_MOVE_TELEPORT_ACK
);
385 *data
<< uint8(0xFF);
387 *data
<< uint32(0x800000);
388 *data
<< uint16(0x67EE);
389 *data
<< uint16(0xD1EB);
390 *data
<< m_orientation
; // instead of *data << z;
393 *data
<< z
; // instead of *data << ang;
395 *data
<< uint32(0x0);
398 void Object::SendMessageToSet(WorldPacket
*data
, bool bToSelf
)
400 MapManager::Instance().GetMap(m_mapId
)->MessageBoardcast(this, data
);
403 bool Object::LoadValues(const char* data
)
405 if(!m_uint32Values
) _InitValues();
407 vector
<string
> tokens
= StrSplit(data
, " ");
409 if(tokens
.size() != m_valuesCount
)
412 vector
<string
>::iterator iter
;
415 for (iter
= tokens
.begin(), index
= 0; index
< m_valuesCount
; ++iter
, ++index
)
417 m_uint32Values
[index
] = atol((*iter
).c_str());
422 void Object::_SetUpdateBits(UpdateMask
*updateMask
, Player
*target
) const
424 *updateMask
= m_updateMask
;
427 void Object::_SetCreateBits(UpdateMask
*updateMask
, Player
*target
) const
429 for( uint16 index
= 0; index
< m_valuesCount
; index
++ )
431 if(GetUInt32Value(index
) != 0)
432 updateMask
->SetBit(index
);
436 void Object::SetUInt32Value( uint16 index
, uint32 value
)
438 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
439 if(m_uint32Values
[ index
] != value
)
441 m_uint32Values
[ index
] = value
;
445 m_updateMask
.SetBit( index
);
449 ObjectAccessor::Instance().AddUpdateObject(this);
450 m_objectUpdated
= true;
456 void Object::SetUInt64Value( uint16 index
, const uint64
&value
)
458 ASSERT( index
+ 1 < m_valuesCount
|| PrintIndexError( index
, true ) );
459 if(*((uint64
*)&(m_uint32Values
[ index
])) != value
)
461 m_uint32Values
[ index
] = *((uint32
*)&value
);
462 m_uint32Values
[ index
+ 1 ] = *(((uint32
*)&value
) + 1);
466 m_updateMask
.SetBit( index
);
467 m_updateMask
.SetBit( index
+ 1 );
471 ObjectAccessor::Instance().AddUpdateObject(this);
472 m_objectUpdated
= true;
478 void Object::SetFloatValue( uint16 index
, float value
)
480 ASSERT( index
+ 1 < m_valuesCount
|| PrintIndexError( index
, true ) );
481 if(m_floatValues
[ index
] != value
)
483 m_floatValues
[ index
] = value
;
487 m_updateMask
.SetBit( index
);
491 ObjectAccessor::Instance().AddUpdateObject(this);
492 m_objectUpdated
= true;
498 void Object::ApplyModUInt32Value(uint16 index
, int32 val
, bool apply
)
500 int32 cur
= GetUInt32Value(index
);
501 cur
+= (apply
? val
: -val
);
504 SetUInt32Value(index
,cur
);
507 void Object::ApplyModFloatValue(uint16 index
, float val
, bool apply
)
509 float cur
= GetFloatValue(index
);
510 cur
+= (apply
? val
: -val
);
513 SetFloatValue(index
,cur
);
516 void Object::SetFlag( uint16 index
, uint32 newFlag
)
518 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
519 uint32 oldval
= m_uint32Values
[ index
];
520 uint32 newval
= oldval
| newFlag
;
524 m_uint32Values
[ index
] = newval
;
528 m_updateMask
.SetBit( index
);
532 ObjectAccessor::Instance().AddUpdateObject(this);
533 m_objectUpdated
= true;
539 void Object::RemoveFlag( uint16 index
, uint32 oldFlag
)
541 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
542 uint32 oldval
= m_uint32Values
[ index
];
543 uint32 newval
= oldval
& ~oldFlag
;
547 m_uint32Values
[ index
] = newval
;
551 m_updateMask
.SetBit( index
);
555 ObjectAccessor::Instance().AddUpdateObject(this);
556 m_objectUpdated
= true;
562 uint32
Object::GetZoneId() const
564 return MapManager::Instance().GetMap(m_mapId
)->GetZoneId(m_positionX
,m_positionY
);
567 uint32
Object::GetAreaId() const
569 return MapManager::Instance().GetMap(m_mapId
)->GetAreaId(m_positionX
,m_positionY
);
572 float Object::GetDistanceSq(const Object
* obj
) const //slow
574 float dx
= GetPositionX() - obj
->GetPositionX();
575 float dy
= GetPositionY() - obj
->GetPositionY();
576 float dz
= GetPositionZ() - obj
->GetPositionZ();
577 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
578 float dist
= sqrt((dx
*dx
) + (dy
*dy
) + (dz
*dz
)) - sizefactor
;
579 return ( dist
> 0 ? dist
* dist
: 0);
582 float Object::GetDistanceSq(const float x
, const float y
, const float z
) const
584 float dx
= GetPositionX() - x
;
585 float dy
= GetPositionY() - y
;
586 float dz
= GetPositionZ() - z
;
587 float sizefactor
= GetObjectSize();
588 float dist
= sqrt((dx
*dx
) + (dy
*dy
) + (dz
*dz
)) - sizefactor
;
589 return ( dist
> 0 ? dist
* dist
: 0);
592 float Object::GetDistance2dSq(const Object
* obj
) const //slow
594 float dx
= GetPositionX() - obj
->GetPositionX();
595 float dy
= GetPositionY() - obj
->GetPositionY();
596 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
597 float dist
= sqrt((dx
*dx
) + (dy
*dy
)) - sizefactor
;
598 return ( dist
> 0 ? dist
* dist
: 0);
601 float Object::GetDistanceZ(const Object
* obj
) const
603 float dz
= fabs(GetPositionZ() - obj
->GetPositionZ());
604 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
605 float dist
= dz
- sizefactor
;
606 return ( dist
> 0 ? dist
: 0);
609 bool Object::IsWithinDistInMap(const Object
* obj
, const float dist2compare
) const
611 if (GetMapId()!=obj
->GetMapId()) return false;
612 return IsWithinDist(obj
, dist2compare
);
615 bool Object::IsWithinDist(const Object
* obj
, const float dist2compare
) const
617 float dx
= GetPositionX() - obj
->GetPositionX();
618 float dy
= GetPositionY() - obj
->GetPositionY();
619 float dz
= GetPositionZ() - obj
->GetPositionZ();
620 float distsq
= dx
*dx
+ dy
*dy
+ dz
*dz
;
621 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
622 float maxdist
= dist2compare
+ sizefactor
;
623 return distsq
< maxdist
* maxdist
;
626 float Object::GetAngle(const Object
* obj
) const
629 return GetAngle( obj
->GetPositionX(), obj
->GetPositionY() );
632 // Retirn angle in range 0..2*pi
633 float Object::GetAngle( const float x
, const float y
) const
635 float dx
= x
- GetPositionX();
636 float dy
= y
- GetPositionY();
638 float ang
= atan2(dy
, dx
);
639 ang
= (ang
>= 0) ? ang
: 2 * M_PI
+ ang
;
643 bool Object::HasInArc(const float arcangle
, const Object
* obj
) const
645 float arc
= arcangle
;
647 // move arc to range 0.. 2*pi
648 while( arc
>= 2.0f
* M_PI
)
653 float angle
= GetAngle( obj
);
654 angle
-= m_orientation
;
656 // move angle to range -pi ... +pi
658 angle
-= 2.0f
* M_PI
;
660 angle
+= 2.0f
* M_PI
;
662 float lborder
= -1 * (arc
/2.0f
); // in range -pi..0
663 float rborder
= (arc
/2.0f
); // in range 0..pi
664 return (( angle
>= lborder
) && ( angle
<= rborder
));
667 void Object::GetContactPoint( const Object
* obj
, float &x
, float &y
, float &z
) const
669 float angle
= GetAngle( obj
);
670 x
= GetPositionX() + (GetObjectSize() + obj
->GetObjectSize() + OBJECT_CONTACT_DISTANCE
) * cos(angle
);
671 y
= GetPositionY() + (GetObjectSize() + obj
->GetObjectSize() + OBJECT_CONTACT_DISTANCE
) * sin(angle
);
675 void Object::GetClosePoint( const Object
* victim
, float &x
, float &y
, float &z
) const
678 GetClosePoint( victim
->GetPositionX(), victim
->GetPositionY(), victim
->GetPositionZ(), x
, y
, z
);
680 GetClosePoint( 0, 0, 0, x
, y
, z
);
683 void Object::GetClosePoint( const float ox
, const float oy
, const float oz
, float &x
, float &y
, float &z
) const
686 if( ox
== 0 && oy
== 0 )
687 angle
= GetOrientation();
689 angle
= GetAngle( ox
, oy
);
690 x
= GetPositionX() + GetObjectSize() * cos(angle
);
691 y
= GetPositionY() + GetObjectSize() * sin(angle
);
696 bool Object::IsPositionValid() const
698 return MaNGOS::IsValidMapCoord(m_positionX
) && MaNGOS::IsValidMapCoord(m_positionY
);
701 bool Object::hasQuest(uint32 quest_id
)
703 return (find(mQuests
.begin(), mQuests
.end(), quest_id
) != mQuests
.end());
706 bool Object::hasInvolvedQuest(uint32 quest_id
)
708 return (find(mInvolvedQuests
.begin(), mInvolvedQuests
.end(), quest_id
) != mInvolvedQuests
.end());
711 bool Object::PrintIndexError(uint32 index
, bool set
) const
713 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
);
715 // assert must fail after function call
719 void Object::_SetPackGUID(ByteBuffer
*buffer
, const uint64
&guid64
) const
721 size_t mask_position
= buffer
->wpos();
723 for(uint8 i
= 0; i
< 8; i
++)
725 if(((uint8
*)&guid64
)[i
])
727 const_cast<uint8
*>(buffer
->contents())[mask_position
] |= (1<<i
);
728 *buffer
<< ((uint8
*)&guid64
)[i
];