2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
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 "SharedDefines.h"
21 #include "WorldPacket.h"
29 #include "ObjectMgr.h"
30 #include "UpdateData.h"
31 #include "UpdateMask.h"
33 #include "MapManager.h"
35 #include "Transports.h"
36 #include "TargetedMovementGenerator.h"
37 #include "WaypointMovementGenerator.h"
38 #include "VMapFactory.h"
40 #include "GridNotifiers.h"
41 #include "GridNotifiersImpl.h"
43 #include "ObjectPosSelector.h"
45 #include "TemporarySummon.h"
47 uint32
GuidHigh2TypeId(uint32 guid_hi
)
51 case HIGHGUID_ITEM
: return TYPEID_ITEM
;
52 //case HIGHGUID_CONTAINER: return TYPEID_CONTAINER; HIGHGUID_CONTAINER==HIGHGUID_ITEM currently
53 case HIGHGUID_UNIT
: return TYPEID_UNIT
;
54 case HIGHGUID_PET
: return TYPEID_UNIT
;
55 case HIGHGUID_PLAYER
: return TYPEID_PLAYER
;
56 case HIGHGUID_GAMEOBJECT
: return TYPEID_GAMEOBJECT
;
57 case HIGHGUID_DYNAMICOBJECT
:return TYPEID_DYNAMICOBJECT
;
58 case HIGHGUID_CORPSE
: return TYPEID_CORPSE
;
59 case HIGHGUID_MO_TRANSPORT
: return TYPEID_GAMEOBJECT
;
60 case HIGHGUID_VEHICLE
: return TYPEID_UNIT
;
62 return NUM_CLIENT_OBJECT_TYPES
; // unknown
65 Object::Object( ) : m_PackGUID(sizeof(uint64
)+1)
67 m_objectTypeId
= TYPEID_OBJECT
;
68 m_objectType
= TYPEMASK_OBJECT
;
71 m_uint32Values_mirror
= 0;
75 m_objectUpdated
= false;
77 m_PackGUID
.appendPackGUID(0);
86 ///- Do NOT call RemoveFromWorld here, if the object is a player it will crash
87 sLog
.outError("Object::~Object (GUID: %u TypeId: %u) deleted but still in world!!", GetGUIDLow(), GetTypeId());
91 //DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
92 delete [] m_uint32Values
;
93 delete [] m_uint32Values_mirror
;
94 //DEBUG_LOG("Object desctr 2 check (%p)",(void*)this);
98 void Object::_InitValues()
100 m_uint32Values
= new uint32
[ m_valuesCount
];
101 memset(m_uint32Values
, 0, m_valuesCount
*sizeof(uint32
));
103 m_uint32Values_mirror
= new uint32
[ m_valuesCount
];
104 memset(m_uint32Values_mirror
, 0, m_valuesCount
*sizeof(uint32
));
106 m_objectUpdated
= false;
109 void Object::_Create( uint32 guidlow
, uint32 entry
, HighGuid guidhigh
)
111 if(!m_uint32Values
) _InitValues();
113 uint64 guid
= MAKE_NEW_GUID(guidlow
, entry
, guidhigh
);
114 SetUInt64Value( OBJECT_FIELD_GUID
, guid
);
115 SetUInt32Value( OBJECT_FIELD_TYPE
, m_objectType
);
117 m_PackGUID
.appendPackGUID(GetGUID());
120 void Object::BuildMovementUpdateBlock(UpdateData
* data
, uint32 flags
) const
124 buf
<< uint8( UPDATETYPE_MOVEMENT
);
125 buf
.append(GetPackGUID());
127 BuildMovementUpdate(&buf
, flags
, 0x00000000);
129 data
->AddUpdateBlock(buf
);
132 void Object::BuildCreateUpdateBlockForPlayer(UpdateData
*data
, Player
*target
) const
137 uint8 updatetype
= UPDATETYPE_CREATE_OBJECT
;
138 uint16 flags
= m_updateFlag
;
142 if(target
== this) // building packet for yourself
143 flags
|= UPDATEFLAG_SELF
;
145 if(flags
& UPDATEFLAG_HAS_POSITION
)
147 // UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
148 if(isType(TYPEMASK_DYNAMICOBJECT
) || isType(TYPEMASK_CORPSE
) || isType(TYPEMASK_PLAYER
))
149 updatetype
= UPDATETYPE_CREATE_OBJECT2
;
151 // UPDATETYPE_CREATE_OBJECT2 for pets...
152 if(target
->GetPetGUID() == GetGUID())
153 updatetype
= UPDATETYPE_CREATE_OBJECT2
;
155 // UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
156 if(isType(TYPEMASK_GAMEOBJECT
))
158 switch(((GameObject
*)this)->GetGoType())
160 case GAMEOBJECT_TYPE_TRAP
:
161 case GAMEOBJECT_TYPE_DUEL_ARBITER
:
162 case GAMEOBJECT_TYPE_FLAGSTAND
:
163 case GAMEOBJECT_TYPE_FLAGDROP
:
164 updatetype
= UPDATETYPE_CREATE_OBJECT2
;
166 case GAMEOBJECT_TYPE_TRANSPORT
:
167 flags
|= UPDATEFLAG_TRANSPORT
;
174 if(isType(TYPEMASK_UNIT
))
176 if(((Unit
*)this)->GetTargetGUID())
177 flags
|= UPDATEFLAG_HAS_TARGET
;
181 //sLog.outDebug("BuildCreateUpdate: update-type: %u, object-type: %u got flags: %X, flags2: %X", updatetype, m_objectTypeId, flags, flags2);
184 buf
<< (uint8
)updatetype
;
185 buf
.append(GetPackGUID());
186 buf
<< (uint8
)m_objectTypeId
;
188 BuildMovementUpdate(&buf
, flags
, flags2
);
190 UpdateMask updateMask
;
191 updateMask
.SetCount( m_valuesCount
);
192 _SetCreateBits( &updateMask
, target
);
193 BuildValuesUpdate(updatetype
, &buf
, &updateMask
, target
);
194 data
->AddUpdateBlock(buf
);
197 void Object::SendCreateUpdateToPlayer(Player
* player
)
199 // send create update to player
203 BuildCreateUpdateBlockForPlayer(&upd
, player
);
204 upd
.BuildPacket(&packet
);
205 player
->GetSession()->SendPacket(&packet
);
208 void Object::BuildValuesUpdateBlockForPlayer(UpdateData
*data
, Player
*target
) const
212 buf
<< (uint8
) UPDATETYPE_VALUES
;
213 buf
.append(GetPackGUID());
215 UpdateMask updateMask
;
216 updateMask
.SetCount( m_valuesCount
);
218 _SetUpdateBits( &updateMask
, target
);
219 BuildValuesUpdate(UPDATETYPE_VALUES
, &buf
, &updateMask
, target
);
221 data
->AddUpdateBlock(buf
);
224 void Object::BuildOutOfRangeUpdateBlock(UpdateData
* data
) const
226 data
->AddOutOfRangeGUID(GetGUID());
229 void Object::DestroyForPlayer( Player
*target
, bool anim
) const
233 WorldPacket
data(SMSG_DESTROY_OBJECT
, 8);
234 data
<< uint64(GetGUID());
235 data
<< uint8(anim
? 1 : 0); // WotLK (bool), may be despawn animation
236 target
->GetSession()->SendPacket( &data
);
239 void Object::BuildMovementUpdate(ByteBuffer
* data
, uint16 flags
, uint32 flags2
) const
241 uint16 unk_flags
= ((GetTypeId() == TYPEID_PLAYER
) ? ((Player
*)this)->m_movementInfo
.unk1
: 0);
243 if(GetTypeId() == TYPEID_UNIT
)
244 if(((Creature
*)this)->isVehicle())
245 unk_flags
|= 0x20; // always allow pitch
247 *data
<< (uint16
)flags
; // update flags
250 if (flags
& UPDATEFLAG_LIVING
)
256 flags2
= ((Creature
*)this)->canFly() ? (MOVEMENTFLAG_FORWARD
| MOVEMENTFLAG_LEVITATING
) : MOVEMENTFLAG_NONE
;
261 flags2
= ((Player
*)this)->m_movementInfo
.GetMovementFlags();
263 if(((Player
*)this)->GetTransport())
264 flags2
|= MOVEMENTFLAG_ONTRANSPORT
;
266 flags2
&= ~MOVEMENTFLAG_ONTRANSPORT
;
268 // remove unknown, unused etc flags for now
269 flags2
&= ~MOVEMENTFLAG_SPLINE2
; // will be set manually
271 if(((Player
*)this)->isInFlight())
273 WPAssert(((Player
*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE
);
274 flags2
= (MOVEMENTFLAG_FORWARD
| MOVEMENTFLAG_SPLINE2
);
280 *data
<< uint32(flags2
); // movement flags
281 *data
<< uint16(unk_flags
); // unknown 2.3.0
282 *data
<< uint32(getMSTime()); // time (in milliseconds)
285 *data
<< ((WorldObject
*)this)->GetPositionX();
286 *data
<< ((WorldObject
*)this)->GetPositionY();
287 *data
<< ((WorldObject
*)this)->GetPositionZ();
288 *data
<< ((WorldObject
*)this)->GetOrientation();
291 if(flags2
& MOVEMENTFLAG_ONTRANSPORT
)
293 if(GetTypeId() == TYPEID_PLAYER
)
295 data
->append(((Player
*)this)->GetTransport()->GetPackGUID());
296 *data
<< (float)((Player
*)this)->GetTransOffsetX();
297 *data
<< (float)((Player
*)this)->GetTransOffsetY();
298 *data
<< (float)((Player
*)this)->GetTransOffsetZ();
299 *data
<< (float)((Player
*)this)->GetTransOffsetO();
300 *data
<< (uint32
)((Player
*)this)->GetTransTime();
301 *data
<< (int8
)((Player
*)this)->GetTransSeat();
305 //MaNGOS currently not have support for other than player on transport
307 *data
<< float(0) << float(0) << float(0) << float(0);
314 if((flags2
& (MOVEMENTFLAG_SWIMMING
| MOVEMENTFLAG_FLYING2
)) || (unk_flags
& 0x20))
316 if(GetTypeId() == TYPEID_PLAYER
)
317 *data
<< (float)((Player
*)this)->m_movementInfo
.s_pitch
;
319 *data
<< (float)0; // is't part of movement packet, we must store and send it...
322 if(GetTypeId() == TYPEID_PLAYER
)
323 *data
<< (uint32
)((Player
*)this)->m_movementInfo
.fallTime
;
325 *data
<< (uint32
)0; // last fall time
328 if(flags2
& MOVEMENTFLAG_JUMPING
)
330 if(GetTypeId() == TYPEID_PLAYER
)
332 *data
<< (float)((Player
*)this)->m_movementInfo
.j_unk
;
333 *data
<< (float)((Player
*)this)->m_movementInfo
.j_sinAngle
;
334 *data
<< (float)((Player
*)this)->m_movementInfo
.j_cosAngle
;
335 *data
<< (float)((Player
*)this)->m_movementInfo
.j_xyspeed
;
347 if(flags2
& MOVEMENTFLAG_SPLINE
)
349 if(GetTypeId() == TYPEID_PLAYER
)
350 *data
<< (float)((Player
*)this)->m_movementInfo
.u_unk1
;
355 *data
<< ((Unit
*)this)->GetSpeed( MOVE_WALK
);
356 *data
<< ((Unit
*)this)->GetSpeed( MOVE_RUN
);
357 *data
<< ((Unit
*)this)->GetSpeed( MOVE_SWIM_BACK
);
358 *data
<< ((Unit
*)this)->GetSpeed( MOVE_SWIM
);
359 *data
<< ((Unit
*)this)->GetSpeed( MOVE_RUN_BACK
);
360 *data
<< ((Unit
*)this)->GetSpeed( MOVE_FLIGHT
);
361 *data
<< ((Unit
*)this)->GetSpeed( MOVE_FLIGHT_BACK
);
362 *data
<< ((Unit
*)this)->GetSpeed( MOVE_TURN_RATE
);
363 *data
<< ((Unit
*)this)->GetSpeed( MOVE_PITCH_RATE
);
366 if(flags2
& MOVEMENTFLAG_SPLINE2
)
368 if(GetTypeId() != TYPEID_PLAYER
)
370 sLog
.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 for non-player");
374 if(!((Player
*)this)->isInFlight())
376 sLog
.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 but not in flight");
380 WPAssert(((Player
*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE
);
382 FlightPathMovementGenerator
*fmg
= (FlightPathMovementGenerator
*)(((Player
*)this)->GetMotionMaster()->top());
384 uint32 flags3
= MONSTER_MOVE_SPLINE_FLY
;
386 *data
<< uint32(flags3
); // splines flag?
388 if(flags3
& 0x20000) // may be orientation
394 if(flags3
& 0x8000) // probably x,y,z coords there
401 if(flags3
& 0x10000) // probably guid there
407 Path
&path
= fmg
->GetPath();
410 ((Player
*)this)->GetPosition(x
, y
, z
);
412 uint32 inflighttime
= uint32(path
.GetPassedLength(fmg
->GetCurrentNode(), x
, y
, z
) * 32);
413 uint32 traveltime
= uint32(path
.GetTotalLength() * 32);
415 *data
<< uint32(inflighttime
); // passed move time?
416 *data
<< uint32(traveltime
); // full move time?
417 *data
<< uint32(0); // ticks count?
419 *data
<< float(0); // added in 3.1
420 *data
<< float(0); // added in 3.1
421 *data
<< float(0); // added in 3.1
423 *data
<< uint32(0); // added in 3.1
425 uint32 poscount
= uint32(path
.Size());
426 *data
<< uint32(poscount
); // points count
428 for(uint32 i
= 0; i
< poscount
; ++i
)
430 *data
<< path
.GetNodes()[i
].x
;
431 *data
<< path
.GetNodes()[i
].y
;
432 *data
<< path
.GetNodes()[i
].z
;
435 *data
<< uint8(0); // added in 3.0.8
437 *data
<< path
.GetNodes()[poscount
-1].x
;
438 *data
<< path
.GetNodes()[poscount
-1].y
;
439 *data
<< path
.GetNodes()[poscount
-1].z
;
444 if(flags
& UPDATEFLAG_POSITION
)
446 *data
<< uint8(0); // unk PGUID!
447 *data
<< ((WorldObject
*)this)->GetPositionX();
448 *data
<< ((WorldObject
*)this)->GetPositionY();
449 *data
<< ((WorldObject
*)this)->GetPositionZ();
450 *data
<< ((WorldObject
*)this)->GetPositionX();
451 *data
<< ((WorldObject
*)this)->GetPositionY();
452 *data
<< ((WorldObject
*)this)->GetPositionZ();
453 *data
<< ((WorldObject
*)this)->GetOrientation();
455 if(GetTypeId() == TYPEID_CORPSE
)
456 *data
<< float(((WorldObject
*)this)->GetOrientation());
463 if (flags
& UPDATEFLAG_HAS_POSITION
)
466 if(flags
& UPDATEFLAG_TRANSPORT
&& ((GameObject
*)this)->GetGoType() == GAMEOBJECT_TYPE_MO_TRANSPORT
)
471 *data
<< ((WorldObject
*)this)->GetOrientation();
475 *data
<< ((WorldObject
*)this)->GetPositionX();
476 *data
<< ((WorldObject
*)this)->GetPositionY();
477 *data
<< ((WorldObject
*)this)->GetPositionZ();
478 *data
<< ((WorldObject
*)this)->GetOrientation();
485 if(flags
& UPDATEFLAG_LOWGUID
)
491 case TYPEID_CONTAINER
:
492 case TYPEID_GAMEOBJECT
:
493 case TYPEID_DYNAMICOBJECT
:
495 *data
<< uint32(GetGUIDLow()); // GetGUIDLow()
498 *data
<< uint32(0x0000000B); // unk, can be 0xB or 0xC
501 if(flags
& UPDATEFLAG_SELF
)
502 *data
<< uint32(0x0000002F); // unk, can be 0x15 or 0x22
504 *data
<< uint32(0x00000008); // unk, can be 0x7 or 0x8
507 *data
<< uint32(0x00000000); // unk
513 if(flags
& UPDATEFLAG_HIGHGUID
)
519 case TYPEID_CONTAINER
:
520 case TYPEID_GAMEOBJECT
:
521 case TYPEID_DYNAMICOBJECT
:
523 *data
<< uint32(GetGUIDHigh()); // GetGUIDHigh()
526 *data
<< uint32(0x0000000B); // unk, can be 0xB or 0xC
529 if(flags
& UPDATEFLAG_SELF
)
530 *data
<< uint32(0x0000002F); // unk, can be 0x15 or 0x22
532 *data
<< uint32(0x00000008); // unk, can be 0x7 or 0x8
535 *data
<< uint32(0x00000000); // unk
541 if(flags
& UPDATEFLAG_HAS_TARGET
) // packed guid (current target guid)
543 data
->appendPackGUID(((Unit
*)this)->GetTargetGUID());
547 if(flags
& UPDATEFLAG_TRANSPORT
)
549 *data
<< uint32(getMSTime()); // ms time
553 if(flags
& UPDATEFLAG_VEHICLE
) // unused for now
555 *data
<< uint32(((Vehicle
*)this)->GetVehicleId()); // vehicle id
556 *data
<< float(0); // facing adjustment
560 if(flags
& UPDATEFLAG_ROTATION
)
562 *data
<< uint64(((GameObject
*)this)->GetRotation());
566 void Object::BuildValuesUpdate(uint8 updatetype
, ByteBuffer
* data
, UpdateMask
*updateMask
, Player
*target
) const
571 bool IsActivateToQuest
= false;
572 bool IsPerCasterAuraState
= false;
573 if (updatetype
== UPDATETYPE_CREATE_OBJECT
|| updatetype
== UPDATETYPE_CREATE_OBJECT2
)
575 if (isType(TYPEMASK_GAMEOBJECT
) && !((GameObject
*)this)->IsTransport())
577 if ( ((GameObject
*)this)->ActivateToQuest(target
) || target
->isGameMaster())
578 IsActivateToQuest
= true;
580 updateMask
->SetBit(GAMEOBJECT_DYNAMIC
);
582 else if (isType(TYPEMASK_UNIT
))
584 if( ((Unit
*)this)->HasAuraState(AURA_STATE_CONFLAGRATE
))
586 IsPerCasterAuraState
= true;
587 updateMask
->SetBit(UNIT_FIELD_AURASTATE
);
591 else // case UPDATETYPE_VALUES
593 if (isType(TYPEMASK_GAMEOBJECT
) && !((GameObject
*)this)->IsTransport())
595 if ( ((GameObject
*)this)->ActivateToQuest(target
) || target
->isGameMaster())
597 IsActivateToQuest
= true;
599 updateMask
->SetBit(GAMEOBJECT_DYNAMIC
);
600 updateMask
->SetBit(GAMEOBJECT_BYTES_1
);
602 else if (isType(TYPEMASK_UNIT
))
604 if( ((Unit
*)this)->HasAuraState(AURA_STATE_CONFLAGRATE
))
606 IsPerCasterAuraState
= true;
607 updateMask
->SetBit(UNIT_FIELD_AURASTATE
);
612 WPAssert(updateMask
&& updateMask
->GetCount() == m_valuesCount
);
614 *data
<< (uint8
)updateMask
->GetBlockCount();
615 data
->append( updateMask
->GetMask(), updateMask
->GetLength() );
617 // 2 specialized loops for speed optimization in non-unit case
618 if(isType(TYPEMASK_UNIT
)) // unit (creature/player) case
620 for( uint16 index
= 0; index
< m_valuesCount
; ++index
)
622 if( updateMask
->GetBit( index
) )
624 if( index
== UNIT_NPC_FLAGS
)
626 // remove custom flag before sending
627 uint32 appendValue
= m_uint32Values
[ index
] & ~UNIT_NPC_FLAG_GUARD
;
629 if (GetTypeId() == TYPEID_UNIT
&& !target
->canSeeSpellClickOn((Creature
*)this))
630 appendValue
&= ~UNIT_NPC_FLAG_SPELLCLICK
;
632 *data
<< uint32(appendValue
);
634 else if (index
== UNIT_FIELD_AURASTATE
)
636 if(IsPerCasterAuraState
)
638 // IsPerCasterAuraState set if related pet caster aura state set already
639 if (((Unit
*)this)->HasAuraStateForCaster(AURA_STATE_CONFLAGRATE
,target
->GetGUID()))
640 *data
<< m_uint32Values
[ index
];
642 *data
<< (m_uint32Values
[ index
] & ~(1 << (AURA_STATE_CONFLAGRATE
-1)));
645 *data
<< m_uint32Values
[ index
];
647 // FIXME: Some values at server stored in float format but must be sent to client in uint32 format
648 else if(index
>= UNIT_FIELD_BASEATTACKTIME
&& index
<= UNIT_FIELD_RANGEDATTACKTIME
)
650 // convert from float to uint32 and send
651 *data
<< uint32(m_floatValues
[ index
] < 0 ? 0 : m_floatValues
[ index
]);
653 // there are some float values which may be negative or can't get negative due to other checks
654 else if ((index
>= UNIT_FIELD_NEGSTAT0
&& index
<= UNIT_FIELD_NEGSTAT4
) ||
655 (index
>= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE
&& index
<= (UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE
+ 6)) ||
656 (index
>= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE
&& index
<= (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE
+ 6)) ||
657 (index
>= UNIT_FIELD_POSSTAT0
&& index
<= UNIT_FIELD_POSSTAT4
))
659 *data
<< uint32(m_floatValues
[ index
]);
661 // Gamemasters should be always able to select units - remove not selectable flag
662 else if(index
== UNIT_FIELD_FLAGS
&& target
->isGameMaster())
664 *data
<< (m_uint32Values
[ index
] & ~UNIT_FLAG_NOT_SELECTABLE
);
666 // hide lootable animation for unallowed players
667 else if(index
== UNIT_DYNAMIC_FLAGS
&& GetTypeId() == TYPEID_UNIT
)
669 if(!target
->isAllowedToLoot((Creature
*)this))
670 *data
<< (m_uint32Values
[ index
] & ~UNIT_DYNFLAG_LOOTABLE
);
672 *data
<< (m_uint32Values
[ index
] & ~UNIT_DYNFLAG_OTHER_TAGGER
);
676 // send in current format (float as float, uint32 as uint32)
677 *data
<< m_uint32Values
[ index
];
682 else if(isType(TYPEMASK_GAMEOBJECT
)) // gameobject case
684 for( uint16 index
= 0; index
< m_valuesCount
; ++index
)
686 if( updateMask
->GetBit( index
) )
688 // send in current format (float as float, uint32 as uint32)
689 if ( index
== GAMEOBJECT_DYNAMIC
)
691 if(IsActivateToQuest
)
693 switch(((GameObject
*)this)->GetGoType())
695 case GAMEOBJECT_TYPE_CHEST
:
696 // enable quest object. Represent 9, but 1 for client before 2.3.0
700 case GAMEOBJECT_TYPE_GOOBER
:
705 // unknown, not happen.
713 // disable quest object
719 *data
<< m_uint32Values
[ index
]; // other cases
723 else // other objects case (no special index checks)
725 for( uint16 index
= 0; index
< m_valuesCount
; ++index
)
727 if( updateMask
->GetBit( index
) )
729 // send in current format (float as float, uint32 as uint32)
730 *data
<< m_uint32Values
[ index
];
736 void Object::ClearUpdateMask(bool remove
)
738 for( uint16 index
= 0; index
< m_valuesCount
; ++index
)
740 if(m_uint32Values_mirror
[index
]!= m_uint32Values
[index
])
741 m_uint32Values_mirror
[index
] = m_uint32Values
[index
];
747 RemoveFromClientUpdateList();
748 m_objectUpdated
= false;
752 bool Object::LoadValues(const char* data
)
754 if(!m_uint32Values
) _InitValues();
756 Tokens tokens
= StrSplit(data
, " ");
758 if(tokens
.size() != m_valuesCount
)
761 Tokens::iterator iter
;
763 for (iter
= tokens
.begin(), index
= 0; index
< m_valuesCount
; ++iter
, ++index
)
765 m_uint32Values
[index
] = atol((*iter
).c_str());
771 void Object::_SetUpdateBits(UpdateMask
*updateMask
, Player
* /*target*/) const
773 for( uint16 index
= 0; index
< m_valuesCount
; ++index
)
775 if(m_uint32Values_mirror
[index
]!= m_uint32Values
[index
])
776 updateMask
->SetBit(index
);
780 void Object::_SetCreateBits(UpdateMask
*updateMask
, Player
* /*target*/) const
782 for( uint16 index
= 0; index
< m_valuesCount
; ++index
)
784 if(GetUInt32Value(index
) != 0)
785 updateMask
->SetBit(index
);
789 void Object::SetInt32Value( uint16 index
, int32 value
)
791 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
793 if(m_int32Values
[ index
] != value
)
795 m_int32Values
[ index
] = value
;
801 AddToClientUpdateList();
802 m_objectUpdated
= true;
808 void Object::SetUInt32Value( uint16 index
, uint32 value
)
810 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
812 if(m_uint32Values
[ index
] != value
)
814 m_uint32Values
[ index
] = value
;
820 AddToClientUpdateList();
821 m_objectUpdated
= true;
827 void Object::SetUInt64Value( uint16 index
, const uint64
&value
)
829 ASSERT( index
+ 1 < m_valuesCount
|| PrintIndexError( index
, true ) );
830 if(*((uint64
*)&(m_uint32Values
[ index
])) != value
)
832 m_uint32Values
[ index
] = *((uint32
*)&value
);
833 m_uint32Values
[ index
+ 1 ] = *(((uint32
*)&value
) + 1);
839 AddToClientUpdateList();
840 m_objectUpdated
= true;
846 void Object::SetFloatValue( uint16 index
, float value
)
848 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
850 if(m_floatValues
[ index
] != value
)
852 m_floatValues
[ index
] = value
;
858 AddToClientUpdateList();
859 m_objectUpdated
= true;
865 void Object::SetByteValue( uint16 index
, uint8 offset
, uint8 value
)
867 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
871 sLog
.outError("Object::SetByteValue: wrong offset %u", offset
);
875 if(uint8(m_uint32Values
[ index
] >> (offset
* 8)) != value
)
877 m_uint32Values
[ index
] &= ~uint32(uint32(0xFF) << (offset
* 8));
878 m_uint32Values
[ index
] |= uint32(uint32(value
) << (offset
* 8));
884 AddToClientUpdateList();
885 m_objectUpdated
= true;
891 void Object::SetUInt16Value( uint16 index
, uint8 offset
, uint16 value
)
893 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
897 sLog
.outError("Object::SetUInt16Value: wrong offset %u", offset
);
901 if(uint16(m_uint32Values
[ index
] >> (offset
* 16)) != value
)
903 m_uint32Values
[ index
] &= ~uint32(uint32(0xFFFF) << (offset
* 16));
904 m_uint32Values
[ index
] |= uint32(uint32(value
) << (offset
* 16));
910 AddToClientUpdateList();
911 m_objectUpdated
= true;
917 void Object::SetStatFloatValue( uint16 index
, float value
)
922 SetFloatValue(index
, value
);
925 void Object::SetStatInt32Value( uint16 index
, int32 value
)
930 SetUInt32Value(index
, uint32(value
));
933 void Object::ApplyModUInt32Value(uint16 index
, int32 val
, bool apply
)
935 int32 cur
= GetUInt32Value(index
);
936 cur
+= (apply
? val
: -val
);
939 SetUInt32Value(index
, cur
);
942 void Object::ApplyModInt32Value(uint16 index
, int32 val
, bool apply
)
944 int32 cur
= GetInt32Value(index
);
945 cur
+= (apply
? val
: -val
);
946 SetInt32Value(index
, cur
);
949 void Object::ApplyModSignedFloatValue(uint16 index
, float val
, bool apply
)
951 float cur
= GetFloatValue(index
);
952 cur
+= (apply
? val
: -val
);
953 SetFloatValue(index
, cur
);
956 void Object::ApplyModPositiveFloatValue(uint16 index
, float val
, bool apply
)
958 float cur
= GetFloatValue(index
);
959 cur
+= (apply
? val
: -val
);
962 SetFloatValue(index
, cur
);
965 void Object::SetFlag( uint16 index
, uint32 newFlag
)
967 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
968 uint32 oldval
= m_uint32Values
[ index
];
969 uint32 newval
= oldval
| newFlag
;
973 m_uint32Values
[ index
] = newval
;
979 AddToClientUpdateList();
980 m_objectUpdated
= true;
986 void Object::RemoveFlag( uint16 index
, uint32 oldFlag
)
988 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
989 uint32 oldval
= m_uint32Values
[ index
];
990 uint32 newval
= oldval
& ~oldFlag
;
994 m_uint32Values
[ index
] = newval
;
1000 AddToClientUpdateList();
1001 m_objectUpdated
= true;
1007 void Object::SetByteFlag( uint16 index
, uint8 offset
, uint8 newFlag
)
1009 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
1013 sLog
.outError("Object::SetByteFlag: wrong offset %u", offset
);
1017 if(!(uint8(m_uint32Values
[ index
] >> (offset
* 8)) & newFlag
))
1019 m_uint32Values
[ index
] |= uint32(uint32(newFlag
) << (offset
* 8));
1023 if(!m_objectUpdated
)
1025 AddToClientUpdateList();
1026 m_objectUpdated
= true;
1032 void Object::RemoveByteFlag( uint16 index
, uint8 offset
, uint8 oldFlag
)
1034 ASSERT( index
< m_valuesCount
|| PrintIndexError( index
, true ) );
1038 sLog
.outError("Object::RemoveByteFlag: wrong offset %u", offset
);
1042 if(uint8(m_uint32Values
[ index
] >> (offset
* 8)) & oldFlag
)
1044 m_uint32Values
[ index
] &= ~uint32(uint32(oldFlag
) << (offset
* 8));
1048 if(!m_objectUpdated
)
1050 AddToClientUpdateList();
1051 m_objectUpdated
= true;
1057 bool Object::PrintIndexError(uint32 index
, bool set
) const
1059 sLog
.outError("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
);
1061 // assert must fail after function call
1065 void Object::BuildUpdateDataForPlayer(Player
* pl
, UpdateDataMapType
& update_players
)
1067 UpdateDataMapType::iterator iter
= update_players
.find(pl
);
1069 if (iter
== update_players
.end())
1071 std::pair
<UpdateDataMapType::iterator
, bool> p
= update_players
.insert( UpdateDataMapType::value_type(pl
, UpdateData()) );
1076 BuildValuesUpdateBlockForPlayer(&iter
->second
, iter
->first
);
1079 WorldObject::WorldObject()
1080 : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL
),
1081 m_positionX(0.0f
), m_positionY(0.0f
), m_positionZ(0.0f
), m_orientation(0.0f
), m_currMap(NULL
)
1085 void WorldObject::CleanupsBeforeDelete()
1089 void WorldObject::_Create( uint32 guidlow
, HighGuid guidhigh
, uint32 phaseMask
)
1091 Object::_Create(guidlow
, 0, guidhigh
);
1092 m_phaseMask
= phaseMask
;
1095 uint32
WorldObject::GetZoneId() const
1097 return GetBaseMap()->GetZoneId(m_positionX
, m_positionY
, m_positionZ
);
1100 uint32
WorldObject::GetAreaId() const
1102 return GetBaseMap()->GetAreaId(m_positionX
, m_positionY
, m_positionZ
);
1105 void WorldObject::GetZoneAndAreaId(uint32
& zoneid
, uint32
& areaid
) const
1107 GetBaseMap()->GetZoneAndAreaId(zoneid
, areaid
, m_positionX
, m_positionY
, m_positionZ
);
1110 InstanceData
* WorldObject::GetInstanceData()
1112 Map
*map
= GetMap();
1113 return map
->IsDungeon() ? ((InstanceMap
*)map
)->GetInstanceData() : NULL
;
1117 float WorldObject::GetDistance(const WorldObject
* obj
) const
1119 float dx
= GetPositionX() - obj
->GetPositionX();
1120 float dy
= GetPositionY() - obj
->GetPositionY();
1121 float dz
= GetPositionZ() - obj
->GetPositionZ();
1122 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
1123 float dist
= sqrt((dx
*dx
) + (dy
*dy
) + (dz
*dz
)) - sizefactor
;
1124 return ( dist
> 0 ? dist
: 0);
1127 float WorldObject::GetDistance2d(float x
, float y
) const
1129 float dx
= GetPositionX() - x
;
1130 float dy
= GetPositionY() - y
;
1131 float sizefactor
= GetObjectSize();
1132 float dist
= sqrt((dx
*dx
) + (dy
*dy
)) - sizefactor
;
1133 return ( dist
> 0 ? dist
: 0);
1136 float WorldObject::GetDistance(float x
, float y
, float z
) const
1138 float dx
= GetPositionX() - x
;
1139 float dy
= GetPositionY() - y
;
1140 float dz
= GetPositionZ() - z
;
1141 float sizefactor
= GetObjectSize();
1142 float dist
= sqrt((dx
*dx
) + (dy
*dy
) + (dz
*dz
)) - sizefactor
;
1143 return ( dist
> 0 ? dist
: 0);
1146 float WorldObject::GetDistance2d(const WorldObject
* obj
) const
1148 float dx
= GetPositionX() - obj
->GetPositionX();
1149 float dy
= GetPositionY() - obj
->GetPositionY();
1150 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
1151 float dist
= sqrt((dx
*dx
) + (dy
*dy
)) - sizefactor
;
1152 return ( dist
> 0 ? dist
: 0);
1155 float WorldObject::GetDistanceZ(const WorldObject
* obj
) const
1157 float dz
= fabs(GetPositionZ() - obj
->GetPositionZ());
1158 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
1159 float dist
= dz
- sizefactor
;
1160 return ( dist
> 0 ? dist
: 0);
1163 bool WorldObject::IsWithinDist3d(float x
, float y
, float z
, float dist2compare
) const
1165 float dx
= GetPositionX() - x
;
1166 float dy
= GetPositionY() - y
;
1167 float dz
= GetPositionZ() - z
;
1168 float distsq
= dx
*dx
+ dy
*dy
+ dz
*dz
;
1170 float sizefactor
= GetObjectSize();
1171 float maxdist
= dist2compare
+ sizefactor
;
1173 return distsq
< maxdist
* maxdist
;
1176 bool WorldObject::IsWithinDist2d(float x
, float y
, float dist2compare
) const
1178 float dx
= GetPositionX() - x
;
1179 float dy
= GetPositionY() - y
;
1180 float distsq
= dx
*dx
+ dy
*dy
;
1182 float sizefactor
= GetObjectSize();
1183 float maxdist
= dist2compare
+ sizefactor
;
1185 return distsq
< maxdist
* maxdist
;
1188 bool WorldObject::_IsWithinDist(WorldObject
const* obj
, float dist2compare
, bool is3D
) const
1190 float dx
= GetPositionX() - obj
->GetPositionX();
1191 float dy
= GetPositionY() - obj
->GetPositionY();
1192 float distsq
= dx
*dx
+ dy
*dy
;
1195 float dz
= GetPositionZ() - obj
->GetPositionZ();
1198 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
1199 float maxdist
= dist2compare
+ sizefactor
;
1201 return distsq
< maxdist
* maxdist
;
1204 bool WorldObject::IsWithinLOSInMap(const WorldObject
* obj
) const
1206 if (!IsInMap(obj
)) return false;
1208 obj
->GetPosition(ox
,oy
,oz
);
1209 return(IsWithinLOS(ox
, oy
, oz
));
1212 bool WorldObject::IsWithinLOS(float ox
, float oy
, float oz
) const
1216 VMAP::IVMapManager
*vMapManager
= VMAP::VMapFactory::createOrGetVMapManager();
1217 return vMapManager
->isInLineOfSight(GetMapId(), x
, y
, z
+2.0f
, ox
, oy
, oz
+2.0f
);
1220 bool WorldObject::GetDistanceOrder(WorldObject
const* obj1
, WorldObject
const* obj2
, bool is3D
/* = true */) const
1222 float dx1
= GetPositionX() - obj1
->GetPositionX();
1223 float dy1
= GetPositionY() - obj1
->GetPositionY();
1224 float distsq1
= dx1
*dx1
+ dy1
*dy1
;
1227 float dz1
= GetPositionZ() - obj1
->GetPositionZ();
1231 float dx2
= GetPositionX() - obj2
->GetPositionX();
1232 float dy2
= GetPositionY() - obj2
->GetPositionY();
1233 float distsq2
= dx2
*dx2
+ dy2
*dy2
;
1236 float dz2
= GetPositionZ() - obj2
->GetPositionZ();
1240 return distsq1
< distsq2
;
1243 bool WorldObject::IsInRange(WorldObject
const* obj
, float minRange
, float maxRange
, bool is3D
/* = true */) const
1245 float dx
= GetPositionX() - obj
->GetPositionX();
1246 float dy
= GetPositionY() - obj
->GetPositionY();
1247 float distsq
= dx
*dx
+ dy
*dy
;
1250 float dz
= GetPositionZ() - obj
->GetPositionZ();
1254 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
1256 // check only for real range
1259 float mindist
= minRange
+ sizefactor
;
1260 if(distsq
< mindist
* mindist
)
1264 float maxdist
= maxRange
+ sizefactor
;
1265 return distsq
< maxdist
* maxdist
;
1268 bool WorldObject::IsInRange2d(float x
, float y
, float minRange
, float maxRange
) const
1270 float dx
= GetPositionX() - x
;
1271 float dy
= GetPositionY() - y
;
1272 float distsq
= dx
*dx
+ dy
*dy
;
1274 float sizefactor
= GetObjectSize();
1276 // check only for real range
1279 float mindist
= minRange
+ sizefactor
;
1280 if(distsq
< mindist
* mindist
)
1284 float maxdist
= maxRange
+ sizefactor
;
1285 return distsq
< maxdist
* maxdist
;
1288 bool WorldObject::IsInRange3d(float x
, float y
, float z
, float minRange
, float maxRange
) const
1290 float dx
= GetPositionX() - x
;
1291 float dy
= GetPositionY() - y
;
1292 float dz
= GetPositionZ() - z
;
1293 float distsq
= dx
*dx
+ dy
*dy
+ dz
*dz
;
1295 float sizefactor
= GetObjectSize();
1297 // check only for real range
1300 float mindist
= minRange
+ sizefactor
;
1301 if(distsq
< mindist
* mindist
)
1305 float maxdist
= maxRange
+ sizefactor
;
1306 return distsq
< maxdist
* maxdist
;
1309 float WorldObject::GetAngle(const WorldObject
* obj
) const
1312 return GetAngle( obj
->GetPositionX(), obj
->GetPositionY() );
1315 // Return angle in range 0..2*pi
1316 float WorldObject::GetAngle( const float x
, const float y
) const
1318 float dx
= x
- GetPositionX();
1319 float dy
= y
- GetPositionY();
1321 float ang
= atan2(dy
, dx
);
1322 ang
= (ang
>= 0) ? ang
: 2 * M_PI
+ ang
;
1326 bool WorldObject::HasInArc(const float arcangle
, const WorldObject
* obj
) const
1328 // always have self in arc
1332 float arc
= arcangle
;
1334 // move arc to range 0.. 2*pi
1335 while( arc
>= 2.0f
* M_PI
)
1340 float angle
= GetAngle( obj
);
1341 angle
-= m_orientation
;
1343 // move angle to range -pi ... +pi
1344 while( angle
> M_PI
)
1345 angle
-= 2.0f
* M_PI
;
1346 while(angle
< -M_PI
)
1347 angle
+= 2.0f
* M_PI
;
1349 float lborder
= -1 * (arc
/2.0f
); // in range -pi..0
1350 float rborder
= (arc
/2.0f
); // in range 0..pi
1351 return (( angle
>= lborder
) && ( angle
<= rborder
));
1354 bool WorldObject::isInFrontInMap(WorldObject
const* target
, float distance
, float arc
) const
1356 return IsWithinDistInMap(target
, distance
) && HasInArc( arc
, target
);
1359 bool WorldObject::isInBackInMap(WorldObject
const* target
, float distance
, float arc
) const
1361 return IsWithinDistInMap(target
, distance
) && !HasInArc( 2 * M_PI
- arc
, target
);
1364 void WorldObject::GetRandomPoint( float x
, float y
, float z
, float distance
, float &rand_x
, float &rand_y
, float &rand_z
) const
1374 // angle to face `obj` to `this`
1375 float angle
= rand_norm()*2*M_PI
;
1376 float new_dist
= rand_norm()*distance
;
1378 rand_x
= x
+ new_dist
* cos(angle
);
1379 rand_y
= y
+ new_dist
* sin(angle
);
1382 MaNGOS::NormalizeMapCoord(rand_x
);
1383 MaNGOS::NormalizeMapCoord(rand_y
);
1384 UpdateGroundPositionZ(rand_x
,rand_y
,rand_z
); // update to LOS height if available
1387 void WorldObject::UpdateGroundPositionZ(float x
, float y
, float &z
) const
1389 float new_z
= GetBaseMap()->GetHeight(x
,y
,z
,true);
1390 if(new_z
> INVALID_HEIGHT
)
1391 z
= new_z
+ 0.05f
; // just to be sure that we are not a few pixel under the surface
1394 bool WorldObject::IsPositionValid() const
1396 return MaNGOS::IsValidMapCoord(m_positionX
,m_positionY
,m_positionZ
,m_orientation
);
1399 void WorldObject::MonsterSay(const char* text
, uint32 language
, uint64 TargetGuid
)
1401 WorldPacket
data(SMSG_MESSAGECHAT
, 200);
1402 BuildMonsterChat(&data
,CHAT_MSG_MONSTER_SAY
,text
,language
,GetName(),TargetGuid
);
1403 SendMessageToSetInRange(&data
,sWorld
.getConfig(CONFIG_LISTEN_RANGE_SAY
),true);
1406 void WorldObject::MonsterYell(const char* text
, uint32 language
, uint64 TargetGuid
)
1408 WorldPacket
data(SMSG_MESSAGECHAT
, 200);
1409 BuildMonsterChat(&data
,CHAT_MSG_MONSTER_YELL
,text
,language
,GetName(),TargetGuid
);
1410 SendMessageToSetInRange(&data
,sWorld
.getConfig(CONFIG_LISTEN_RANGE_YELL
),true);
1413 void WorldObject::MonsterTextEmote(const char* text
, uint64 TargetGuid
, bool IsBossEmote
)
1415 WorldPacket
data(SMSG_MESSAGECHAT
, 200);
1416 BuildMonsterChat(&data
,IsBossEmote
? CHAT_MSG_RAID_BOSS_EMOTE
: CHAT_MSG_MONSTER_EMOTE
,text
,LANG_UNIVERSAL
,GetName(),TargetGuid
);
1417 SendMessageToSetInRange(&data
,sWorld
.getConfig(IsBossEmote
? CONFIG_LISTEN_RANGE_YELL
: CONFIG_LISTEN_RANGE_TEXTEMOTE
),true);
1420 void WorldObject::MonsterWhisper(const char* text
, uint64 receiver
, bool IsBossWhisper
)
1422 Player
*player
= objmgr
.GetPlayer(receiver
);
1423 if(!player
|| !player
->GetSession())
1426 WorldPacket
data(SMSG_MESSAGECHAT
, 200);
1427 BuildMonsterChat(&data
,IsBossWhisper
? CHAT_MSG_RAID_BOSS_WHISPER
: CHAT_MSG_MONSTER_WHISPER
,text
,LANG_UNIVERSAL
,GetName(),receiver
);
1429 player
->GetSession()->SendPacket(&data
);
1434 class MonsterChatBuilder
1437 MonsterChatBuilder(WorldObject
const& obj
, ChatMsg msgtype
, int32 textId
, uint32 language
, uint64 targetGUID
)
1438 : i_object(obj
), i_msgtype(msgtype
), i_textId(textId
), i_language(language
), i_targetGUID(targetGUID
) {}
1439 void operator()(WorldPacket
& data
, int32 loc_idx
)
1441 char const* text
= objmgr
.GetMangosString(i_textId
,loc_idx
);
1443 // TODO: i_object.GetName() also must be localized?
1444 i_object
.BuildMonsterChat(&data
,i_msgtype
,text
,i_language
,i_object
.GetNameForLocaleIdx(loc_idx
),i_targetGUID
);
1448 WorldObject
const& i_object
;
1452 uint64 i_targetGUID
;
1454 } // namespace MaNGOS
1456 void WorldObject::MonsterSay(int32 textId
, uint32 language
, uint64 TargetGuid
)
1458 CellPair p
= MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
1461 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
1464 MaNGOS::MonsterChatBuilder
say_build(*this, CHAT_MSG_MONSTER_SAY
, textId
,language
,TargetGuid
);
1465 MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> say_do(say_build
);
1466 MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> > say_worker(this,sWorld
.getConfig(CONFIG_LISTEN_RANGE_SAY
),say_do
);
1467 TypeContainerVisitor
<MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> >, WorldTypeMapContainer
> message(say_worker
);
1468 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
1469 cell_lock
->Visit(cell_lock
, message
, *GetMap(), *this, sWorld
.getConfig(CONFIG_LISTEN_RANGE_SAY
));
1472 void WorldObject::MonsterYell(int32 textId
, uint32 language
, uint64 TargetGuid
)
1474 CellPair p
= MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
1477 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
1480 MaNGOS::MonsterChatBuilder
say_build(*this, CHAT_MSG_MONSTER_YELL
, textId
,language
,TargetGuid
);
1481 MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> say_do(say_build
);
1482 MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> > say_worker(this,sWorld
.getConfig(CONFIG_LISTEN_RANGE_YELL
),say_do
);
1483 TypeContainerVisitor
<MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> >, WorldTypeMapContainer
> message(say_worker
);
1484 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
1485 cell_lock
->Visit(cell_lock
, message
, *GetMap(), *this, sWorld
.getConfig(CONFIG_LISTEN_RANGE_YELL
));
1488 void WorldObject::MonsterYellToZone(int32 textId
, uint32 language
, uint64 TargetGuid
)
1490 MaNGOS::MonsterChatBuilder
say_build(*this, CHAT_MSG_MONSTER_YELL
, textId
,language
,TargetGuid
);
1491 MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> say_do(say_build
);
1493 uint32 zoneid
= GetZoneId();
1495 Map::PlayerList
const& pList
= GetMap()->GetPlayers();
1496 for(Map::PlayerList::const_iterator itr
= pList
.begin(); itr
!= pList
.end(); ++itr
)
1497 if(itr
->getSource()->GetZoneId()==zoneid
)
1498 say_do(itr
->getSource());
1501 void WorldObject::MonsterTextEmote(int32 textId
, uint64 TargetGuid
, bool IsBossEmote
)
1503 CellPair p
= MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
1506 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
1509 MaNGOS::MonsterChatBuilder
say_build(*this, IsBossEmote
? CHAT_MSG_RAID_BOSS_EMOTE
: CHAT_MSG_MONSTER_EMOTE
, textId
,LANG_UNIVERSAL
,TargetGuid
);
1510 MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> say_do(say_build
);
1511 MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> > say_worker(this,sWorld
.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE
),say_do
);
1512 TypeContainerVisitor
<MaNGOS::PlayerDistWorker
<MaNGOS::LocalizedPacketDo
<MaNGOS::MonsterChatBuilder
> >, WorldTypeMapContainer
> message(say_worker
);
1513 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
1514 cell_lock
->Visit(cell_lock
, message
, *GetMap(), *this, sWorld
.getConfig(IsBossEmote
? CONFIG_LISTEN_RANGE_YELL
: CONFIG_LISTEN_RANGE_TEXTEMOTE
));
1517 void WorldObject::MonsterWhisper(int32 textId
, uint64 receiver
, bool IsBossWhisper
)
1519 Player
*player
= objmgr
.GetPlayer(receiver
);
1520 if(!player
|| !player
->GetSession())
1523 uint32 loc_idx
= player
->GetSession()->GetSessionDbLocaleIndex();
1524 char const* text
= objmgr
.GetMangosString(textId
,loc_idx
);
1526 WorldPacket
data(SMSG_MESSAGECHAT
, 200);
1527 BuildMonsterChat(&data
,IsBossWhisper
? CHAT_MSG_RAID_BOSS_WHISPER
: CHAT_MSG_MONSTER_WHISPER
,text
,LANG_UNIVERSAL
,GetNameForLocaleIdx(loc_idx
),receiver
);
1529 player
->GetSession()->SendPacket(&data
);
1532 void WorldObject::BuildMonsterChat(WorldPacket
*data
, uint8 msgtype
, char const* text
, uint32 language
, char const* name
, uint64 targetGuid
) const
1534 *data
<< (uint8
)msgtype
;
1535 *data
<< (uint32
)language
;
1536 *data
<< (uint64
)GetGUID();
1537 *data
<< (uint32
)0; // 2.1.0
1538 *data
<< (uint32
)(strlen(name
)+1);
1540 *data
<< (uint64
)targetGuid
; // Unit Target
1541 if( targetGuid
&& !IS_PLAYER_GUID(targetGuid
) )
1543 *data
<< (uint32
)1; // target name length
1544 *data
<< (uint8
)0; // target name
1546 *data
<< (uint32
)(strlen(text
)+1);
1548 *data
<< (uint8
)0; // ChatTag
1551 void WorldObject::SendMessageToSet(WorldPacket
*data
, bool /*bToSelf*/)
1553 //if object is in world, map for it already created!
1554 Map
* _map
= IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId());
1556 _map
->MessageBroadcast(this, data
);
1559 void WorldObject::SendMessageToSetInRange(WorldPacket
*data
, float dist
, bool /*bToSelf*/)
1561 //if object is in world, map for it already created!
1562 Map
* _map
= IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId());
1564 _map
->MessageDistBroadcast(this, data
, dist
);
1567 void WorldObject::SendObjectDeSpawnAnim(uint64 guid
)
1569 WorldPacket
data(SMSG_GAMEOBJECT_DESPAWN_ANIM
, 8);
1570 data
<< uint64(guid
);
1571 SendMessageToSet(&data
, true);
1574 void WorldObject::SetMap(Map
* map
)
1578 //lets save current map's Id/instanceId
1579 m_mapId
= map
->GetId();
1580 m_InstanceId
= map
->GetInstanceId();
1583 Map
const* WorldObject::GetBaseMap() const
1586 return m_currMap
->GetParent();
1589 void WorldObject::AddObjectToRemoveList()
1591 GetMap()->AddObjectToRemoveList(this);
1594 Creature
* WorldObject::SummonCreature(uint32 id
, float x
, float y
, float z
, float ang
,TempSummonType spwtype
,uint32 despwtime
)
1596 TemporarySummon
* pCreature
= new TemporarySummon(GetGUID());
1599 if (GetTypeId()==TYPEID_PLAYER
)
1600 team
= ((Player
*)this)->GetTeam();
1602 if (!pCreature
->Create(objmgr
.GenerateLowGuid(HIGHGUID_UNIT
), GetMap(), GetPhaseMask(), id
, team
))
1608 if (x
== 0.0f
&& y
== 0.0f
&& z
== 0.0f
)
1609 GetClosePoint(x
, y
, z
, pCreature
->GetObjectSize());
1611 pCreature
->Relocate(x
, y
, z
, ang
);
1613 if(!pCreature
->IsPositionValid())
1615 sLog
.outError("Creature (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature
->GetGUIDLow(),pCreature
->GetEntry(),pCreature
->GetPositionX(),pCreature
->GetPositionY());
1620 pCreature
->Summon(spwtype
, despwtime
);
1622 if(GetTypeId()==TYPEID_UNIT
&& ((Creature
*)this)->AI())
1623 ((Creature
*)this)->AI()->JustSummoned(pCreature
);
1625 // return the creature therewith the summoner has access to it
1634 NearUsedPosDo(WorldObject
const& obj
, WorldObject
const* searcher
, float angle
, ObjectPosSelector
& selector
)
1635 : i_object(obj
), i_searcher(searcher
), i_angle(angle
), i_selector(selector
) {}
1637 void operator()(Corpse
*) const {}
1638 void operator()(DynamicObject
*) const {}
1640 void operator()(Creature
* c
) const
1642 // skip self or target
1643 if(c
==i_searcher
|| c
==&i_object
)
1648 if( !c
->isAlive() || c
->hasUnitState(UNIT_STAT_ROOT
| UNIT_STAT_STUNNED
| UNIT_STAT_DISTRACTED
| UNIT_STAT_DIED
) ||
1649 !c
->GetMotionMaster()->GetDestination(x
,y
,z
) )
1651 x
= c
->GetPositionX();
1652 y
= c
->GetPositionY();
1659 void operator()(T
* u
) const
1661 // skip self or target
1662 if(u
==i_searcher
|| u
==&i_object
)
1667 x
= u
->GetPositionX();
1668 y
= u
->GetPositionY();
1673 // we must add used pos that can fill places around center
1674 void add(WorldObject
* u
, float x
, float y
) const
1676 // u is too nearest/far away to i_object
1677 if(!i_object
.IsInRange2d(x
,y
,i_selector
.m_dist
- i_selector
.m_size
,i_selector
.m_dist
+ i_selector
.m_size
))
1680 float angle
= i_object
.GetAngle(u
)-i_angle
;
1682 // move angle to range -pi ... +pi
1683 while( angle
> M_PI
)
1684 angle
-= 2.0f
* M_PI
;
1685 while(angle
< -M_PI
)
1686 angle
+= 2.0f
* M_PI
;
1688 // dist include size of u
1689 float dist2d
= i_object
.GetDistance2d(x
,y
);
1690 i_selector
.AddUsedPos(u
->GetObjectSize(),angle
,dist2d
+ i_object
.GetObjectSize());
1693 WorldObject
const& i_object
;
1694 WorldObject
const* i_searcher
;
1696 ObjectPosSelector
& i_selector
;
1698 } // namespace MaNGOS
1700 //===================================================================================================
1702 void WorldObject::GetNearPoint2D(float &x
, float &y
, float distance2d
, float absAngle
) const
1704 x
= GetPositionX() + (GetObjectSize() + distance2d
) * cos(absAngle
);
1705 y
= GetPositionY() + (GetObjectSize() + distance2d
) * sin(absAngle
);
1707 MaNGOS::NormalizeMapCoord(x
);
1708 MaNGOS::NormalizeMapCoord(y
);
1711 void WorldObject::GetNearPoint(WorldObject
const* searcher
, float &x
, float &y
, float &z
, float searcher_size
, float distance2d
, float absAngle
) const
1713 GetNearPoint2D(x
,y
,distance2d
+searcher_size
,absAngle
);
1716 // if detection disabled, return first point
1717 if(!sWorld
.getConfig(CONFIG_DETECT_POS_COLLISION
))
1719 UpdateGroundPositionZ(x
,y
,z
); // update to LOS height if available
1723 // or remember first point
1726 bool first_los_conflict
= false; // first point LOS problems
1728 // prepare selector for work
1729 ObjectPosSelector
selector(GetPositionX(),GetPositionY(),GetObjectSize(),distance2d
+searcher_size
);
1731 // adding used positions around object
1733 CellPair
p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
1735 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
1738 MaNGOS::NearUsedPosDo
u_do(*this,searcher
,absAngle
,selector
);
1739 MaNGOS::WorldObjectWorker
<MaNGOS::NearUsedPosDo
> worker(this,u_do
);
1741 TypeContainerVisitor
<MaNGOS::WorldObjectWorker
<MaNGOS::NearUsedPosDo
>, GridTypeMapContainer
> grid_obj_worker(worker
);
1742 TypeContainerVisitor
<MaNGOS::WorldObjectWorker
<MaNGOS::NearUsedPosDo
>, WorldTypeMapContainer
> world_obj_worker(worker
);
1744 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
1745 cell_lock
->Visit(cell_lock
, grid_obj_worker
, *GetMap(), *this, distance2d
);
1746 cell_lock
->Visit(cell_lock
, world_obj_worker
, *GetMap(), *this, distance2d
);
1749 // maybe can just place in primary position
1750 if( selector
.CheckOriginal() )
1752 UpdateGroundPositionZ(x
,y
,z
); // update to LOS height if available
1754 if(IsWithinLOS(x
,y
,z
))
1757 first_los_conflict
= true; // first point have LOS problems
1760 float angle
; // candidate of angle for free pos
1762 // special case when one from list empty and then empty side preferred
1763 if(selector
.FirstAngle(angle
))
1765 GetNearPoint2D(x
,y
,distance2d
,absAngle
+angle
);
1767 UpdateGroundPositionZ(x
,y
,z
); // update to LOS height if available
1769 if(IsWithinLOS(x
,y
,z
))
1773 // set first used pos in lists
1774 selector
.InitializeAngle();
1776 // select in positions after current nodes (selection one by one)
1777 while(selector
.NextAngle(angle
)) // angle for free pos
1779 GetNearPoint2D(x
,y
,distance2d
,absAngle
+angle
);
1781 UpdateGroundPositionZ(x
,y
,z
); // update to LOS height if available
1783 if(IsWithinLOS(x
,y
,z
))
1787 // BAD NEWS: not free pos (or used or have LOS problems)
1788 // Attempt find _used_ pos without LOS problem
1790 if(!first_los_conflict
)
1795 UpdateGroundPositionZ(x
,y
,z
); // update to LOS height if available
1799 // special case when one from list empty and then empty side preferred
1800 if( selector
.IsNonBalanced() )
1802 if(!selector
.FirstAngle(angle
)) // _used_ pos
1804 GetNearPoint2D(x
,y
,distance2d
,absAngle
+angle
);
1806 UpdateGroundPositionZ(x
,y
,z
); // update to LOS height if available
1808 if(IsWithinLOS(x
,y
,z
))
1813 // set first used pos in lists
1814 selector
.InitializeAngle();
1816 // select in positions after current nodes (selection one by one)
1817 while(selector
.NextUsedAngle(angle
)) // angle for used pos but maybe without LOS problem
1819 GetNearPoint2D(x
,y
,distance2d
,absAngle
+angle
);
1821 UpdateGroundPositionZ(x
,y
,z
); // update to LOS height if available
1823 if(IsWithinLOS(x
,y
,z
))
1827 // BAD BAD NEWS: all found pos (free and used) have LOS problem :(
1831 UpdateGroundPositionZ(x
,y
,z
); // update to LOS height if available
1834 void WorldObject::SetPhaseMask(uint32 newPhaseMask
, bool update
)
1836 m_phaseMask
= newPhaseMask
;
1838 if(update
&& IsInWorld())
1839 UpdateObjectVisibility();
1842 void WorldObject::PlayDistanceSound( uint32 sound_id
, Player
* target
/*= NULL*/ )
1844 WorldPacket
data(SMSG_PLAY_OBJECT_SOUND
,4+8);
1845 data
<< uint32(sound_id
);
1846 data
<< uint64(GetGUID());
1848 target
->SendDirectMessage( &data
);
1850 SendMessageToSet( &data
, true );
1853 void WorldObject::PlayDirectSound( uint32 sound_id
, Player
* target
/*= NULL*/ )
1855 WorldPacket
data(SMSG_PLAY_SOUND
, 4);
1856 data
<< uint32(sound_id
);
1858 target
->SendDirectMessage( &data
);
1860 SendMessageToSet( &data
, true );
1863 void WorldObject::UpdateObjectVisibility()
1865 CellPair p
= MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
1868 GetMap()->UpdateObjectVisibility(this, cell
, p
);
1871 void WorldObject::AddToClientUpdateList()
1873 GetMap()->AddUpdateObject(this);
1876 void WorldObject::RemoveFromClientUpdateList()
1878 GetMap()->RemoveUpdateObject(this);
1881 struct WorldObjectChangeAccumulator
1883 UpdateDataMapType
&i_updateDatas
;
1884 WorldObject
&i_object
;
1885 WorldObjectChangeAccumulator(WorldObject
&obj
, UpdateDataMapType
&d
) : i_updateDatas(d
), i_object(obj
) {}
1886 void Visit(PlayerMapType
&m
)
1888 for(PlayerMapType::iterator iter
= m
.begin(); iter
!= m
.end(); ++iter
)
1889 if(iter
->getSource()->HaveAtClient(&i_object
))
1890 i_object
.BuildUpdateDataForPlayer(iter
->getSource(), i_updateDatas
);
1893 template<class SKIP
> void Visit(GridRefManager
<SKIP
> &) {}
1896 void WorldObject::BuildUpdateData( UpdateDataMapType
& update_players
)
1898 CellPair p
= MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
1900 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
1902 WorldObjectChangeAccumulator
notifier(*this, update_players
);
1903 TypeContainerVisitor
<WorldObjectChangeAccumulator
, WorldTypeMapContainer
> player_notifier(notifier
);
1904 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
1905 Map
* aMap
= GetMap();
1906 //we must build packets for all visible players
1907 cell_lock
->Visit(cell_lock
, player_notifier
, *aMap
, *this, aMap
->GetVisibilityDistance());
1909 ClearUpdateMask(false);