[2612] Applied MaNGOS coding style (see trunk/bcpp.cfg).
[mangos-git.git] / src / game / Object.cpp
blobfae1b0eac79e7393a3f731c32fbe31781eefaf48
1 /*
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
19 #include "Common.h"
20 #include "WorldPacket.h"
21 #include "Opcodes.h"
22 #include "Log.h"
23 #include "World.h"
24 #include "Object.h"
25 #include "Player.h"
26 #include "ObjectMgr.h"
27 #include "WorldSession.h"
28 #include "UpdateData.h"
29 #include "Util.h"
30 #include "MapManager.h"
31 #include "ObjectAccessor.h"
32 #include "Log.h"
34 using namespace std;
36 Object::Object( )
38 m_objectTypeId = TYPEID_OBJECT;
39 m_objectType = TYPE_OBJECT;
41 m_positionX = 0.0f;
42 m_positionY = 0.0f;
43 m_positionZ = 0.0f;
44 m_orientation = 0.0f;
46 m_mapId = 0;
48 m_uint32Values = 0;
50 m_inWorld = false;
52 m_minZ = -500;
54 m_valuesCount = 0;
56 m_speed = 1.0f;
57 m_moveType = MOVE_STOP;
59 mSemaphoreTeleport = false;
60 m_inWorld = false;
61 m_objectUpdated = false;
64 Object::~Object( )
67 if(m_objectUpdated)
68 ObjectAccessor::Instance().RemoveUpdateObject(this);
70 if(m_uint32Values)
72 //DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
73 delete [] m_uint32Values;
74 //DEBUG_LOG("Object desctr 2 check (%p)",(void*)this);
78 void Object::_Create( uint32 guidlow, uint32 guidhigh )
80 if(!m_uint32Values) _InitValues();
82 SetUInt32Value( OBJECT_FIELD_GUID, guidlow );
83 SetUInt32Value( OBJECT_FIELD_GUID+1, guidhigh );
84 SetUInt32Value( OBJECT_FIELD_TYPE, m_objectType );
85 _SetPackGUID(&m_PackGUID,GetGUID());
88 void Object::_Create( uint32 guidlow, uint32 guidhigh, uint32 mapid, float x, float y, float z, float ang, uint32 nameId )
90 _Create(guidlow, guidhigh);
92 SetUInt32Value( OBJECT_FIELD_ENTRY,nameId);
94 m_mapId = mapid;
95 m_positionX = x;
96 m_positionY = y;
97 m_positionZ = z;
98 m_orientation = ang;
101 void Object::BuildMovementUpdateBlock(UpdateData * data, uint32 flags ) const
103 ByteBuffer buf(500);
105 buf << uint8( UPDATETYPE_MOVEMENT );
106 buf << GetGUID();
108 _BuildMovementUpdate(&buf, flags, 0x00000000);
110 data->AddUpdateBlock(buf);
113 void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const
115 if(!target) return;
117 ByteBuffer buf(500);
118 buf << uint8( UPDATETYPE_CREATE_OBJECT );
119 buf << uint8( 0xFF );
120 buf << GetGUID() ;
121 buf << m_objectTypeId;
123 switch(m_objectTypeId)
125 case TYPEID_OBJECT: //do nothing
126 break;
127 case TYPEID_ITEM:
128 case TYPEID_CONTAINER:
129 _BuildMovementUpdate( &buf, 0x10, 0x0 );
130 break;
131 case TYPEID_UNIT:
132 _BuildMovementUpdate( &buf, 0x70, 0x800000 );
133 break;
134 case TYPEID_PLAYER:
136 if( target == this ) //build for self
138 buf.clear();
139 buf << uint8( UPDATETYPE_CREATE_OBJECT2 );
140 buf << uint8( 0xFF );
141 buf << GetGUID() ;
142 buf << m_objectTypeId;
143 _BuildMovementUpdate( &buf, 0x71, 0x2000 );
145 //build for other player
146 else
148 _BuildMovementUpdate( &buf, 0x70, 0x0 );
150 }break;
151 case TYPEID_CORPSE:
152 case TYPEID_GAMEOBJECT:
153 case TYPEID_DYNAMICOBJECT:
155 if(GUID_HIPART(GetGUID())==HIGHGUID_PLAYER_CORPSE)
156 _BuildMovementUpdate( &buf, 0x52, 0x0 );
157 else
158 _BuildMovementUpdate( &buf, 0x50, 0x0 );
159 }break;
160 //case TYPEID_AIGROUP:
161 //case TYPEID_AREATRIGGER:
162 //break;
163 default: //know type
164 sLog.outDetail("Unknow Object Type %u Create Update Block.\n", m_objectTypeId);
165 break;
168 UpdateMask updateMask;
169 updateMask.SetCount( m_valuesCount );
170 _SetCreateBits( &updateMask, target );
171 _BuildValuesUpdate( &buf, &updateMask );
172 data->AddUpdateBlock(buf);
176 void Object::SendUpdateToPlayer(Player* player) const
178 //if (!player->IsInWorld()) return;
180 UpdateData upd;
181 WorldPacket packet;
183 upd.Clear();
184 BuildCreateUpdateBlockForPlayer(&upd, player);
185 upd.BuildPacket(&packet);
186 player->GetSession()->SendPacket(&packet);
189 void Object::BuildValuesUpdateBlockForPlayer(UpdateData *data, Player *target) const
191 ByteBuffer buf(500);
193 buf << (uint8) UPDATETYPE_VALUES;
194 buf << (uint8) 0xFF;
195 buf << GetGUID();
197 UpdateMask updateMask;
198 updateMask.SetCount( m_valuesCount );
199 _SetUpdateBits( &updateMask, target );
200 _BuildValuesUpdate( &buf, &updateMask );
202 data->AddUpdateBlock(buf);
205 void Object::BuildOutOfRangeUpdateBlock(UpdateData * data) const
207 data->AddOutOfRangeGUID(GetGUID());
210 void Object::DestroyForPlayer(Player *target) const
212 ASSERT(target);
214 WorldPacket data;
215 data.Initialize( SMSG_DESTROY_OBJECT );
216 data << GetGUID();
218 target->GetSession()->SendPacket( &data );
221 void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2 ) const
223 *data << (uint8)flags;
224 if( m_objectTypeId==TYPEID_PLAYER )
226 *data << (uint32)flags2;
227 *data << (uint32)0xB74D85D1;
228 *data << (float)m_positionX;
229 *data << (float)m_positionY;
230 *data << (float)m_positionZ;
231 *data << (float)m_orientation;
232 *data << (float)0;
233 if(flags2 == 0x2000) //update self
235 *data << (float)0;
236 *data << (float)1.0;
237 *data << (float)0;
238 *data << (float)0;
240 *data << GetSpeed( MOVE_WALK );
241 *data << GetSpeed( MOVE_RUN );
242 *data << GetSpeed( MOVE_SWIMBACK );
243 *data << GetSpeed( MOVE_SWIM );
244 *data << GetSpeed( MOVE_WALKBACK );
245 *data << GetSpeed( MOVE_TURN );
247 if( m_objectTypeId==TYPEID_UNIT )
249 *data << (uint32)flags2;
250 *data << (uint32)0xB5771D7F;
251 *data << (float)m_positionX;
252 *data << (float)m_positionY;
253 *data << (float)m_positionZ;
254 *data << (float)m_orientation;
255 *data << (float)0;
256 *data << GetSpeed( MOVE_WALK );
257 *data << GetSpeed( MOVE_RUN );
258 *data << GetSpeed( MOVE_SWIMBACK );
259 *data << GetSpeed( MOVE_SWIM );
260 *data << GetSpeed( MOVE_WALKBACK );
261 *data << GetSpeed( MOVE_TURN );
262 uint8 PosCount=0;
263 if(flags2 & 0x400000)
265 *data << (uint32)0x0;
266 *data << (uint32)0x659;
267 *data << (uint32)0xB7B;
268 *data << (uint32)0xFDA0B4;
269 *data << (uint32)PosCount;
270 for(int i=0;i<PosCount+1;i++)
272 *data << (float)0; //x
273 *data << (float)0; //y
274 *data << (float)0; //z
278 if( (m_objectTypeId==TYPEID_CORPSE) || (m_objectTypeId==TYPEID_GAMEOBJECT) || (m_objectTypeId==TYPEID_DYNAMICOBJECT))
280 *data << (float)m_positionX;
281 *data << (float)m_positionY;
282 *data << (float)m_positionZ;
283 *data << (float)m_orientation;
286 *data << (uint32)0x6297848C;
288 if( GUID_HIPART(GetGUID()) == HIGHGUID_PLAYER_CORPSE)
289 *data << (uint32)0xBD38BA14; //fix me
292 void Object::_BuildValuesUpdate(ByteBuffer * data, UpdateMask *updateMask) const
294 WPAssert(updateMask && updateMask->GetCount() == m_valuesCount);
296 *data << (uint8)updateMask->GetBlockCount();
297 data->append( updateMask->GetMask(), updateMask->GetLength() );
299 for( uint16 index = 0; index < m_valuesCount; index ++ )
301 if( updateMask->GetBit( index ) )
303 // Some values at server stored in float format but must be sended to client in uint32 format
304 if( isType(TYPE_UNIT) && (
305 index >= UNIT_FIELD_POWER1 && index <= UNIT_FIELD_MAXPOWER5 ||
306 index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME ||
307 index >= UNIT_FIELD_STR && index <= UNIT_FIELD_RESISTANCES_06 )
308 || isType(TYPE_PLAYER) &&
309 index >= PLAYER_FIELD_POSSTAT0 && index <= PLAYER_FIELD_RESISTANCEBUFFMODSNEGATIVE_06 )
311 // convert from float to uint32 and send
312 *data << uint32(m_floatValues[ index ]);
314 else
316 // send in current format (float as float, uint32 as uint32)
317 *data << m_uint32Values[ index ];
323 void Object::BuildHeartBeatMsg(WorldPacket *data) const
325 data->Initialize(MSG_MOVE_HEARTBEAT); //2
327 *data << GetGUID(); //8
328 *data << uint32(0); //4
329 *data << uint32(0); //4
331 *data << m_positionX; //4
332 *data << m_positionY; //4
333 *data << m_positionZ; //4
335 *data << m_orientation; //4
338 void Object::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float z, float ang) const
340 data->Initialize(MSG_MOVE_TELEPORT_ACK);
341 *data << uint8(0xFF);
342 *data << GetGUID();
343 *data << uint32(0x800000);
344 *data << uint16(0x67EE);
345 *data << uint16(0xD1EB);
346 *data << m_orientation; // instead of *data << z;
347 *data << x;
348 *data << y;
349 *data << z; // instead of *data << ang;
350 *data << ang;
351 *data << uint32(0x0);
354 void Object::SendMessageToSet(WorldPacket *data, bool bToSelf)
356 MapManager::Instance().GetMap(m_mapId)->MessageBoardcast(this, data);
359 bool Object::LoadValues(const char* data)
361 if(!m_uint32Values) _InitValues();
363 vector<string> tokens = StrSplit(data, " ");
365 if(tokens.size() != m_valuesCount)
366 return false;
368 vector<string>::iterator iter;
369 int index;
371 for (iter = tokens.begin(), index = 0; index < m_valuesCount; ++iter, ++index)
373 m_uint32Values[index] = atol((*iter).c_str());
375 return true;
378 void Object::_SetUpdateBits(UpdateMask *updateMask, Player *target) const
380 *updateMask = m_updateMask;
383 void Object::_SetCreateBits(UpdateMask *updateMask, Player *target) const
385 for( uint16 index = 0; index < m_valuesCount; index++ )
387 if(GetUInt32Value(index) != 0)
388 updateMask->SetBit(index);
392 void Object::SetUInt32Value( uint16 index, uint32 value )
394 ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
395 if(m_uint32Values[ index ] != value)
397 m_uint32Values[ index ] = value;
399 if(m_inWorld)
401 m_updateMask.SetBit( index );
403 if(!m_objectUpdated)
405 ObjectAccessor::Instance().AddUpdateObject(this);
406 m_objectUpdated = true;
412 void Object::SetUInt64Value( uint16 index, const uint64 &value )
414 ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
415 if(*((uint64*)&(m_uint32Values[ index ])) != value)
417 m_uint32Values[ index ] = *((uint32*)&value);
418 m_uint32Values[ index + 1 ] = *(((uint32*)&value) + 1);
420 if(m_inWorld)
422 m_updateMask.SetBit( index );
423 m_updateMask.SetBit( index + 1 );
425 if(!m_objectUpdated)
427 ObjectAccessor::Instance().AddUpdateObject(this);
428 m_objectUpdated = true;
434 void Object::SetFloatValue( uint16 index, float value )
436 ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
437 if(m_floatValues[ index ] != value)
439 m_floatValues[ index ] = value;
441 if(m_inWorld)
443 m_updateMask.SetBit( index );
445 if(!m_objectUpdated)
447 ObjectAccessor::Instance().AddUpdateObject(this);
448 m_objectUpdated = true;
454 void Object::ApplyModUInt32Value(uint16 index, int32 val, bool apply)
456 int32 cur = GetUInt32Value(index);
457 cur += (apply ? val : -val);
458 if(cur < 0)
459 cur = 0;
460 SetUInt32Value(index,cur);
463 void Object::ApplyModFloatValue(uint16 index, float val, bool apply)
465 float cur = GetFloatValue(index);
466 cur += (apply ? val : -val);
467 if(cur < 0)
468 cur = 0;
469 SetFloatValue(index,cur);
472 void Object::SetFlag( uint16 index, uint32 newFlag )
474 ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
475 uint32 oldval = m_uint32Values[ index ];
476 uint32 newval = oldval | newFlag;
478 if(oldval != newval)
480 m_uint32Values[ index ] = newval;
482 if(m_inWorld)
484 m_updateMask.SetBit( index );
486 if(!m_objectUpdated)
488 ObjectAccessor::Instance().AddUpdateObject(this);
489 m_objectUpdated = true;
495 void Object::RemoveFlag( uint16 index, uint32 oldFlag )
497 ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
498 uint32 oldval = m_uint32Values[ index ];
499 uint32 newval = oldval & ~oldFlag;
501 if(oldval != newval)
503 m_uint32Values[ index ] = newval;
505 if(m_inWorld)
507 m_updateMask.SetBit( index );
509 if(!m_objectUpdated)
511 ObjectAccessor::Instance().AddUpdateObject(this);
512 m_objectUpdated = true;
518 uint32 Object::GetZoneId() const
520 return MapManager::Instance().GetMap(m_mapId)->GetZoneId(m_positionX,m_positionY);
523 uint32 Object::GetAreaId() const
525 return MapManager::Instance().GetMap(m_mapId)->GetAreaId(m_positionX,m_positionY);
528 float Object::GetDistanceSq(const Object* obj) const //slow
530 float dx = GetPositionX() - obj->GetPositionX();
531 float dy = GetPositionY() - obj->GetPositionY();
532 float dz = GetPositionZ() - obj->GetPositionZ();
533 float sizefactor = GetObjectSize() + obj->GetObjectSize();
534 float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
535 return ( dist > 0 ? dist * dist : 0);
538 float Object::GetDistanceSq(const float x, const float y, const float z) const
540 float dx = GetPositionX() - x;
541 float dy = GetPositionY() - y;
542 float dz = GetPositionZ() - z;
543 float sizefactor = GetObjectSize();
544 float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
545 return ( dist > 0 ? dist * dist : 0);
548 float Object::GetDistance2dSq(const Object* obj) const //slow
550 float dx = GetPositionX() - obj->GetPositionX();
551 float dy = GetPositionY() - obj->GetPositionY();
552 float sizefactor = GetObjectSize() + obj->GetObjectSize();
553 float dist = sqrt((dx*dx) + (dy*dy)) - sizefactor;
554 return ( dist > 0 ? dist * dist : 0);
557 float Object::GetDistanceZ(const Object* obj) const
559 float dz = fabs(GetPositionZ() - obj->GetPositionZ());
560 float sizefactor = GetObjectSize() + obj->GetObjectSize();
561 float dist = dz - sizefactor;
562 return ( dist > 0 ? dist : 0);
565 bool Object::IsWithinDistInMap(const Object* obj, const float dist2compare) const
567 if (GetMapId()!=obj->GetMapId()) return false;
568 return IsWithinDist(obj, dist2compare);
571 bool Object::IsWithinDist(const Object* obj, const float dist2compare) const
573 float dx = GetPositionX() - obj->GetPositionX();
574 float dy = GetPositionY() - obj->GetPositionY();
575 float dz = GetPositionZ() - obj->GetPositionZ();
576 float distsq = dx*dx + dy*dy + dz*dz;
577 float sizefactor = GetObjectSize() + obj->GetObjectSize();
578 float maxdist = dist2compare + sizefactor;
579 return distsq < maxdist * maxdist;
582 float Object::GetAngle(const Object* obj) const
584 if(!obj) return 0;
585 return GetAngle( obj->GetPositionX(), obj->GetPositionY() );
588 // Retirn angle in range 0..2*pi
589 float Object::GetAngle( const float x, const float y ) const
591 float dx = x - GetPositionX();
592 float dy = y - GetPositionY();
594 float ang = atan2(dy, dx);
595 ang = (ang >= 0) ? ang : 2 * M_PI + ang;
596 return ang;
599 bool Object::HasInArc(const float arcangle, const Object* obj) const
601 float arc = arcangle;
603 // move arc to range 0.. 2*pi
604 while( arc > 2.0f * M_PI )
605 arc -= 2.0f * M_PI;
606 while( arc < 0 )
607 arc += 2.0f * M_PI;
609 float angle = GetAngle( obj );
610 angle -= m_orientation;
612 // move angle to range -pi ... +pi
613 while( angle > M_PI)
614 angle -= 2.0f * M_PI;
615 while(angle < -M_PI)
616 angle += 2.0f * M_PI;
618 float lborder = -1 * (arc/2.0f); // in range -pi..0
619 float rborder = (arc/2.0f); // in range 0..pi
620 return (( angle >= lborder ) && ( angle <= rborder ));
623 void Object::GetContactPoint( const Object* obj, float &x, float &y, float &z ) const
625 float angle = GetAngle( obj );
626 x = GetPositionX() + (GetObjectSize() + obj->GetObjectSize() + OBJECT_CONTACT_DISTANCE) * cos(angle);
627 y = GetPositionY() + (GetObjectSize() + obj->GetObjectSize() + OBJECT_CONTACT_DISTANCE) * sin(angle);
628 z = GetPositionZ();
631 void Object::GetClosePoint( const Object* victim, float &x, float &y, float &z ) const
633 if( victim )
634 GetClosePoint( victim->GetPositionX(), victim->GetPositionY(), victim->GetPositionZ(), x, y, z);
635 else
636 GetClosePoint( 0, 0, 0, x, y, z);
639 void Object::GetClosePoint( const float ox, const float oy, const float oz, float &x, float &y, float &z ) const
641 float angle;
642 if( ox == 0 && oy == 0 )
643 angle = GetOrientation();
644 else
645 angle = GetAngle( ox, oy );
646 x = GetPositionX() + GetObjectSize() * cos(angle);
647 y = GetPositionY() + GetObjectSize() * sin(angle);
648 z = GetPositionZ();
652 bool Object::IsPositionValid() const
654 return MaNGOS::IsValidMapCoord(m_positionX) && MaNGOS::IsValidMapCoord(m_positionY);
657 bool Object::hasQuest(uint32 quest_id)
659 for( std::list<Quest*>::iterator i = mQuests.begin( ); i != mQuests.end( ); i++ )
661 if ((*i)->GetQuestInfo()->QuestId == quest_id)
662 return true;
665 return false;
668 bool Object::hasInvolvedQuest(uint32 quest_id)
670 for( std::list<Quest*>::iterator i = mInvolvedQuests.begin( ); i != mInvolvedQuests.end( ); i++ )
672 if ((*i)->GetQuestInfo()->QuestId == quest_id)
673 return true;
676 return false;
679 bool Object::PrintIndexError(uint32 index, bool set) const
681 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);
683 // assert must fail after function call
684 return false;
687 void Object::_SetPackGUID(ByteBuffer *buffer, const uint64 &guid64) const
689 size_t mask_position = buffer->wpos();
690 *buffer << uint8(0);
691 for(uint8 i = 0; i < 8; i++)
693 if(((uint8*)&guid64)[i])
695 const_cast<uint8*>(buffer->contents())[mask_position] |= (1<<i);
696 *buffer << ((uint8*)&guid64)[i];