6175f8c7a0280c40a498fa07d84fa386d5ce2010
[trinitycore] / src / server / game / Entities / Object / Object.cpp
1 /*
2 * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
3 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "Object.h"
20 #include "AreaTriggerTemplate.h"
21 #include "BattlefieldMgr.h"
22 #include "CellImpl.h"
23 #include "CinematicMgr.h"
24 #include "Common.h"
25 #include "Creature.h"
26 #include "GridNotifiersImpl.h"
27 #include "InstanceScenario.h"
28 #include "Item.h"
29 #include "Log.h"
30 #include "MiscPackets.h"
31 #include "MovementPackets.h"
32 #include "MovementTypedefs.h"
33 #include "ObjectAccessor.h"
34 #include "ObjectMgr.h"
35 #include "OutdoorPvPMgr.h"
36 #include "PhasingHandler.h"
37 #include "Player.h"
38 #include "SharedDefines.h"
39 #include "SpellAuraEffects.h"
40 #include "TemporarySummon.h"
41 #include "Totem.h"
42 #include "Transport.h"
43 #include "Unit.h"
44 #include "UpdateData.h"
45 #include "UpdateFieldFlags.h"
46 #include "Util.h"
47 #include "VMapFactory.h"
48 #include "Vehicle.h"
49 #include "World.h"
50 #include "WorldSession.h"
51 #include <G3D/Vector3.h>
52
53 Object::Object()
54 {
55 m_objectTypeId = TYPEID_OBJECT;
56 m_objectType = TYPEMASK_OBJECT;
57 m_updateFlag = UPDATEFLAG_NONE;
58
59 m_uint32Values = nullptr;
60 _dynamicValues = nullptr;
61 _dynamicChangesArrayMask = nullptr;
62 m_valuesCount = 0;
63 _dynamicValuesCount = 0;
64 _fieldNotifyFlags = UF_FLAG_DYNAMIC;
65
66 m_inWorld = false;
67 m_objectUpdated = false;
68 }
69
70 WorldObject::~WorldObject()
71 {
72 // this may happen because there are many !create/delete
73 if (IsWorldObject() && m_currMap)
74 {
75 if (GetTypeId() == TYPEID_CORPSE)
76 {
77 TC_LOG_FATAL("misc", "WorldObject::~WorldObject Corpse Type: %d (%s) deleted but still in map!!",
78 ToCorpse()->GetType(), GetGUID().ToString().c_str());
79 ABORT();
80 }
81 ResetMap();
82 }
83 }
84
85 Object::~Object()
86 {
87 if (IsInWorld())
88 {
89 TC_LOG_FATAL("misc", "Object::~Object %s deleted but still in world!!", GetGUID().ToString().c_str());
90 if (isType(TYPEMASK_ITEM))
91 TC_LOG_FATAL("misc", "Item slot %u", ((Item*)this)->GetSlot());
92 ABORT();
93 }
94
95 if (m_objectUpdated)
96 {
97 TC_LOG_FATAL("misc", "Object::~Object %s deleted but still in update list!!", GetGUID().ToString().c_str());
98 ABORT();
99 }
100
101 delete[] m_uint32Values;
102 m_uint32Values = nullptr;
103
104 delete[] _dynamicValues;
105 _dynamicValues = nullptr;
106
107 delete[] _dynamicChangesArrayMask;
108 _dynamicChangesArrayMask = nullptr;
109 }
110
111 void Object::_InitValues()
112 {
113 m_uint32Values = new uint32[m_valuesCount];
114 memset(m_uint32Values, 0, m_valuesCount * sizeof(uint32));
115
116 _changesMask.resize(m_valuesCount);
117 _dynamicChangesMask.resize(_dynamicValuesCount);
118 if (_dynamicValuesCount)
119 {
120 _dynamicValues = new std::vector<uint32>[_dynamicValuesCount];
121 _dynamicChangesArrayMask = new std::vector<uint8>[_dynamicValuesCount];
122 }
123
124 m_objectUpdated = false;
125 }
126
127 void Object::_Create(ObjectGuid const& guid)
128 {
129 if (!m_uint32Values) _InitValues();
130
131 SetGuidValue(OBJECT_FIELD_GUID, guid);
132 SetUInt16Value(OBJECT_FIELD_TYPE, 0, m_objectType);
133 }
134
135 std::string Object::_ConcatFields(uint16 startIndex, uint16 size) const
136 {
137 std::ostringstream ss;
138 for (uint16 index = 0; index < size; ++index)
139 ss << GetUInt32Value(index + startIndex) << ' ';
140 return ss.str();
141 }
142
143 void Object::AddToWorld()
144 {
145 if (m_inWorld)
146 return;
147
148 ASSERT(m_uint32Values);
149
150 m_inWorld = true;
151
152 // synchronize values mirror with values array (changes will send in updatecreate opcode any way
153 ASSERT(!m_objectUpdated);
154 ClearUpdateMask(false);
155 }
156
157 void Object::RemoveFromWorld()
158 {
159 if (!m_inWorld)
160 return;
161
162 m_inWorld = false;
163
164 // if we remove from world then sending changes not required
165 ClearUpdateMask(true);
166 }
167
168 void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
169 {
170 if (!target)
171 return;
172
173 uint8 updateType = UPDATETYPE_CREATE_OBJECT;
174 uint32 flags = m_updateFlag;
175
176 /** lower flag1 **/
177 if (target == this) // building packet for yourself
178 flags |= UPDATEFLAG_SELF;
179
180 switch (GetGUID().GetHigh())
181 {
182 case HighGuid::Player:
183 case HighGuid::Pet:
184 case HighGuid::Corpse:
185 case HighGuid::DynamicObject:
186 case HighGuid::AreaTrigger:
187 case HighGuid::Conversation:
188 updateType = UPDATETYPE_CREATE_OBJECT2;
189 break;
190 case HighGuid::Creature:
191 case HighGuid::Vehicle:
192 {
193 if (TempSummon const* summon = ToUnit()->ToTempSummon())
194 if (summon->GetSummonerGUID().IsPlayer())
195 updateType = UPDATETYPE_CREATE_OBJECT2;
196
197 break;
198 }
199 case HighGuid::GameObject:
200 {
201 if (ToGameObject()->GetOwnerGUID().IsPlayer())
202 updateType = UPDATETYPE_CREATE_OBJECT2;
203 break;
204 }
205 default:
206 break;
207 }
208
209 if (WorldObject const* worldObject = dynamic_cast<WorldObject const*>(this))
210 {
211 if (!(flags & UPDATEFLAG_LIVING))
212 if (!worldObject->m_movementInfo.transport.guid.IsEmpty())
213 flags |= UPDATEFLAG_TRANSPORT_POSITION;
214
215 if (worldObject->GetAIAnimKitId() || worldObject->GetMovementAnimKitId() || worldObject->GetMeleeAnimKitId())
216 flags |= UPDATEFLAG_ANIMKITS;
217 }
218
219 if (flags & UPDATEFLAG_STATIONARY_POSITION)
220 {
221 // UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
222 if (isType(TYPEMASK_GAMEOBJECT))
223 {
224 switch (ToGameObject()->GetGoType())
225 {
226 case GAMEOBJECT_TYPE_TRAP:
227 case GAMEOBJECT_TYPE_DUEL_ARBITER:
228 case GAMEOBJECT_TYPE_FLAGSTAND:
229 case GAMEOBJECT_TYPE_FLAGDROP:
230 updateType = UPDATETYPE_CREATE_OBJECT2;
231 break;
232 default:
233 break;
234 }
235 }
236 }
237
238 if (Unit const* unit = ToUnit())
239 if (unit->GetVictim())
240 flags |= UPDATEFLAG_HAS_TARGET;
241
242 ByteBuffer buf(0x400);
243 buf << uint8(updateType);
244 buf << GetGUID();
245 buf << uint8(m_objectTypeId);
246
247 BuildMovementUpdate(&buf, flags);
248 BuildValuesUpdate(updateType, &buf, target);
249 BuildDynamicValuesUpdate(updateType, &buf, target);
250 data->AddUpdateBlock(buf);
251 }
252
253 void Object::SendUpdateToPlayer(Player* player)
254 {
255 // send create update to player
256 UpdateData upd(player->GetMapId());
257 WorldPacket packet;
258
259 if (player->HaveAtClient(this))
260 BuildValuesUpdateBlockForPlayer(&upd, player);
261 else
262 BuildCreateUpdateBlockForPlayer(&upd, player);
263 upd.BuildPacket(&packet);
264 player->SendDirectMessage(&packet);
265 }
266
267 void Object::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target) const
268 {
269 ByteBuffer buf(500);
270
271 buf << uint8(UPDATETYPE_VALUES);
272 buf << GetGUID();
273
274 BuildValuesUpdate(UPDATETYPE_VALUES, &buf, target);
275 BuildDynamicValuesUpdate(UPDATETYPE_VALUES, &buf, target);
276
277 data->AddUpdateBlock(buf);
278 }
279
280 void Object::BuildOutOfRangeUpdateBlock(UpdateData* data) const
281 {
282 data->AddOutOfRangeGUID(GetGUID());
283 }
284
285 void Object::DestroyForPlayer(Player* target) const
286 {
287 ASSERT(target);
288
289 UpdateData updateData(target->GetMapId());
290 BuildOutOfRangeUpdateBlock(&updateData);
291 WorldPacket packet;
292 updateData.BuildPacket(&packet);
293 target->SendDirectMessage(&packet);
294 }
295
296 int32 Object::GetInt32Value(uint16 index) const
297 {
298 ASSERT(index < m_valuesCount || PrintIndexError(index, false));
299 return m_int32Values[index];
300 }
301
302 uint32 Object::GetUInt32Value(uint16 index) const
303 {
304 ASSERT(index < m_valuesCount || PrintIndexError(index, false));
305 return m_uint32Values[index];
306 }
307
308 uint64 Object::GetUInt64Value(uint16 index) const
309 {
310 ASSERT(index + 1 < m_valuesCount || PrintIndexError(index, false));
311 return *((uint64*)&(m_uint32Values[index]));
312 }
313
314 float Object::GetFloatValue(uint16 index) const
315 {
316 ASSERT(index < m_valuesCount || PrintIndexError(index, false));
317 return m_floatValues[index];
318 }
319
320 uint8 Object::GetByteValue(uint16 index, uint8 offset) const
321 {
322 ASSERT(index < m_valuesCount || PrintIndexError(index, false));
323 ASSERT(offset < 4);
324 return *(((uint8*)&m_uint32Values[index])+offset);
325 }
326
327 uint16 Object::GetUInt16Value(uint16 index, uint8 offset) const
328 {
329 ASSERT(index < m_valuesCount || PrintIndexError(index, false));
330 ASSERT(offset < 2);
331 return *(((uint16*)&m_uint32Values[index])+offset);
332 }
333
334 ObjectGuid const& Object::GetGuidValue(uint16 index) const
335 {
336 ASSERT(index + 1 < m_valuesCount || PrintIndexError(index, false));
337 return *((ObjectGuid*)&(m_uint32Values[index]));
338 }
339
340 void Object::BuildMovementUpdate(ByteBuffer* data, uint32 flags) const
341 {
342 bool NoBirthAnim = false;
343 bool EnablePortals = false;
344 bool PlayHoverAnim = false;
345 bool HasMovementUpdate = (flags & UPDATEFLAG_LIVING) != 0;
346 bool HasMovementTransport = (flags & UPDATEFLAG_TRANSPORT_POSITION) != 0;
347 bool Stationary = (flags & UPDATEFLAG_STATIONARY_POSITION) != 0;
348 bool CombatVictim = (flags & UPDATEFLAG_HAS_TARGET) != 0;
349 bool ServerTime = (flags & UPDATEFLAG_TRANSPORT) != 0;
350 bool VehicleCreate = (flags & UPDATEFLAG_VEHICLE) != 0;
351 bool AnimKitCreate = (flags & UPDATEFLAG_ANIMKITS) != 0;
352 bool Rotation = (flags & UPDATEFLAG_ROTATION) != 0;
353 bool HasAreaTrigger = (flags & UPDATEFLAG_AREATRIGGER) != 0;
354 bool HasGameObject = (flags & UPDATEFLAG_GAMEOBJECT) != 0;
355 bool ThisIsYou = (flags & UPDATEFLAG_SELF) != 0;
356 bool SmoothPhasing = false;
357 bool SceneObjCreate = false;
358 bool PlayerCreateData = GetTypeId() == TYPEID_PLAYER && ToUnit()->GetPowerIndex(POWER_RUNES) != MAX_POWERS;
359 std::vector<uint32> const* PauseTimes = nullptr;
360 uint32 PauseTimesCount = 0;
361 if (GameObject const* go = ToGameObject())
362 {
363 if (go->GetGoType() == GAMEOBJECT_TYPE_TRANSPORT)
364 {
365 PauseTimes = go->GetGOValue()->Transport.StopFrames;
366 PauseTimesCount = PauseTimes->size();
367 }
368 }
369
370 data->WriteBit(NoBirthAnim);
371 data->WriteBit(EnablePortals);
372 data->WriteBit(PlayHoverAnim);
373 data->WriteBit(HasMovementUpdate);
374 data->WriteBit(HasMovementTransport);
375 data->WriteBit(Stationary);
376 data->WriteBit(CombatVictim);
377 data->WriteBit(ServerTime);
378 data->WriteBit(VehicleCreate);
379 data->WriteBit(AnimKitCreate);
380 data->WriteBit(Rotation);
381 data->WriteBit(HasAreaTrigger);
382 data->WriteBit(HasGameObject);
383 data->WriteBit(SmoothPhasing);
384 data->WriteBit(ThisIsYou);
385 data->WriteBit(SceneObjCreate);
386 data->WriteBit(PlayerCreateData);
387 data->FlushBits();
388
389 if (HasMovementUpdate)
390 {
391 Unit const* unit = ToUnit();
392 bool HasFallDirection = unit->HasUnitMovementFlag(MOVEMENTFLAG_FALLING);
393 bool HasFall = HasFallDirection || unit->m_movementInfo.jump.fallTime != 0;
394 bool HasSpline = unit->IsSplineEnabled();
395
396 *data << GetGUID(); // MoverGUID
397
398 *data << uint32(unit->m_movementInfo.time); // MoveTime
399 *data << float(unit->GetPositionX());
400 *data << float(unit->GetPositionY());
401 *data << float(unit->GetPositionZ());
402 *data << float(unit->GetOrientation());
403
404 *data << float(unit->m_movementInfo.pitch); // Pitch
405 *data << float(unit->m_movementInfo.splineElevation); // StepUpStartElevation
406
407 *data << uint32(0); // RemoveForcesIDs.size()
408 *data << uint32(0); // MoveIndex
409
410 //for (std::size_t i = 0; i < RemoveForcesIDs.size(); ++i)
411 // *data << ObjectGuid(RemoveForcesIDs);
412
413 data->WriteBits(unit->GetUnitMovementFlags(), 30);
414 data->WriteBits(unit->GetExtraUnitMovementFlags(), 18);
415 data->WriteBit(!unit->m_movementInfo.transport.guid.IsEmpty()); // HasTransport
416 data->WriteBit(HasFall); // HasFall
417 data->WriteBit(HasSpline); // HasSpline - marks that the unit uses spline movement
418 data->WriteBit(0); // HeightChangeFailed
419 data->WriteBit(0); // RemoteTimeValid
420
421 if (!unit->m_movementInfo.transport.guid.IsEmpty())
422 *data << unit->m_movementInfo.transport;
423
424 if (HasFall)
425 {
426 *data << uint32(unit->m_movementInfo.jump.fallTime); // Time
427 *data << float(unit->m_movementInfo.jump.zspeed); // JumpVelocity
428
429 if (data->WriteBit(HasFallDirection))
430 {
431 *data << float(unit->m_movementInfo.jump.sinAngle); // Direction
432 *data << float(unit->m_movementInfo.jump.cosAngle);
433 *data << float(unit->m_movementInfo.jump.xyspeed); // Speed
434 }
435 }
436
437 *data << float(unit->GetSpeed(MOVE_WALK));
438 *data << float(unit->GetSpeed(MOVE_RUN));
439 *data << float(unit->GetSpeed(MOVE_RUN_BACK));
440 *data << float(unit->GetSpeed(MOVE_SWIM));
441 *data << float(unit->GetSpeed(MOVE_SWIM_BACK));
442 *data << float(unit->GetSpeed(MOVE_FLIGHT));
443 *data << float(unit->GetSpeed(MOVE_FLIGHT_BACK));
444 *data << float(unit->GetSpeed(MOVE_TURN_RATE));
445 *data << float(unit->GetSpeed(MOVE_PITCH_RATE));
446
447 *data << uint32(0); // unit->m_movementInfo.forces.size()
448
449 data->WriteBit(HasSpline);
450 data->FlushBits();
451
452 //for (std::size_t i = 0; i < unit->m_movementInfo.forces.size(); ++i)
453 //{
454 // *data << ObjectGuid(ID);
455 // *data << Vector3(Origin);
456 // *data << Vector3(Direction);
457 // *data << uint32(TransportID);
458 // *data << float(Magnitude);
459 // data->WriteBits(Type, 2);
460 //}
461
462 if (HasSpline)
463 WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(*unit->movespline, *data);
464 }
465
466 *data << uint32(PauseTimesCount);
467
468 if (Stationary)
469 {
470 WorldObject const* self = static_cast<WorldObject const*>(this);
471 *data << float(self->GetStationaryX());
472 *data << float(self->GetStationaryY());
473 *data << float(self->GetStationaryZ());
474 *data << float(self->GetStationaryO());
475 }
476
477 if (CombatVictim)
478 *data << ToUnit()->GetVictim()->GetGUID(); // CombatVictim
479
480 if (ServerTime)
481 {
482 GameObject const* go = ToGameObject();
483 /** @TODO Use IsTransport() to also handle type 11 (TRANSPORT)
484 Currently grid objects are not updated if there are no nearby players,
485 this causes clients to receive different PathProgress
486 resulting in players seeing the object in a different position
487 */
488 if (go && go->ToTransport()) // ServerTime
489 *data << uint32(go->GetGOValue()->Transport.PathProgress);
490 else
491 *data << uint32(getMSTime());
492 }
493
494 if (VehicleCreate)
495 {
496 Unit const* unit = ToUnit();
497 *data << uint32(unit->GetVehicleKit()->GetVehicleInfo()->ID); // RecID
498 *data << float(unit->GetOrientation()); // InitialRawFacing
499 }
500
501 if (AnimKitCreate)
502 {
503 WorldObject const* self = static_cast<WorldObject const*>(this);
504 *data << uint16(self->GetAIAnimKitId()); // AiID
505 *data << uint16(self->GetMovementAnimKitId()); // MovementID
506 *data << uint16(self->GetMeleeAnimKitId()); // MeleeID
507 }
508
509 if (Rotation)
510 *data << uint64(ToGameObject()->GetPackedWorldRotation()); // Rotation
511
512 if (PauseTimesCount)
513 data->append(PauseTimes->data(), PauseTimes->size());
514
515 if (HasMovementTransport)
516 {
517 WorldObject const* self = static_cast<WorldObject const*>(this);
518 *data << self->m_movementInfo.transport;
519 }
520
521 if (HasAreaTrigger)
522 {
523 AreaTrigger const* areaTrigger = ToAreaTrigger();
524 AreaTriggerMiscTemplate const* areaTriggerMiscTemplate = areaTrigger->GetMiscTemplate();
525 AreaTriggerTemplate const* areaTriggerTemplate = areaTrigger->GetTemplate();
526
527 *data << uint32(areaTrigger->GetTimeSinceCreated());
528
529 *data << areaTrigger->GetRollPitchYaw().PositionXYZStream();
530
531 bool hasAbsoluteOrientation = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_HAS_ABSOLUTE_ORIENTATION);
532 bool hasDynamicShape = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_HAS_DYNAMIC_SHAPE);
533 bool hasAttached = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_HAS_ATTACHED);
534 bool hasFaceMovementDir = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_HAS_FACE_MOVEMENT_DIR);
535 bool hasFollowsTerrain = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_HAS_FOLLOWS_TERRAIN);
536 bool hasUnk1 = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_UNK1);
537 bool hasTargetRollPitchYaw = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_HAS_TARGET_ROLL_PITCH_YAW);
538 bool hasScaleCurveID = areaTriggerMiscTemplate->ScaleCurveId != 0;
539 bool hasMorphCurveID = areaTriggerMiscTemplate->MorphCurveId != 0;
540 bool hasFacingCurveID = areaTriggerMiscTemplate->FacingCurveId != 0;
541 bool hasMoveCurveID = areaTriggerMiscTemplate->MoveCurveId != 0;
542 bool hasUnk2 = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_UNK2);
543 bool hasUnk3 = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_UNK3);
544 bool hasUnk4 = areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_UNK4);
545 bool hasAreaTriggerSphere = areaTriggerTemplate->IsSphere();
546 bool hasAreaTriggerBox = areaTriggerTemplate->IsBox();
547 bool hasAreaTriggerPolygon = areaTriggerTemplate->IsPolygon();
548 bool hasAreaTriggerCylinder = areaTriggerTemplate->IsCylinder();
549 bool hasAreaTriggerSpline = areaTrigger->HasSplines();
550 bool hasAreaTriggerUnkType = false; // areaTriggerTemplate->HasFlag(AREATRIGGER_FLAG_UNK5);
551
552 data->WriteBit(hasAbsoluteOrientation);
553 data->WriteBit(hasDynamicShape);
554 data->WriteBit(hasAttached);
555 data->WriteBit(hasFaceMovementDir);
556 data->WriteBit(hasFollowsTerrain);
557 data->WriteBit(hasUnk1);
558 data->WriteBit(hasTargetRollPitchYaw);
559 data->WriteBit(hasScaleCurveID);
560 data->WriteBit(hasMorphCurveID);
561 data->WriteBit(hasFacingCurveID);
562 data->WriteBit(hasMoveCurveID);
563 data->WriteBit(hasUnk2);
564 data->WriteBit(hasUnk3);
565 data->WriteBit(hasUnk4);
566 data->WriteBit(hasAreaTriggerSphere);
567 data->WriteBit(hasAreaTriggerBox);
568 data->WriteBit(hasAreaTriggerPolygon);
569 data->WriteBit(hasAreaTriggerCylinder);
570 data->WriteBit(hasAreaTriggerSpline);
571 data->WriteBit(hasAreaTriggerUnkType);
572
573 if (hasUnk3)
574 data->WriteBit(0);
575
576 data->FlushBits();
577
578 if (hasAreaTriggerSpline)
579 {
580 *data << uint32(areaTrigger->GetTimeToTarget());
581 *data << uint32(areaTrigger->GetElapsedTimeForMovement());
582
583 WorldPackets::Movement::CommonMovement::WriteCreateObjectAreaTriggerSpline(areaTrigger->GetSpline(), *data);
584 }
585
586 if (hasTargetRollPitchYaw)
587 *data << areaTrigger->GetTargetRollPitchYaw().PositionXYZStream();
588
589 if (hasScaleCurveID)
590 *data << uint32(areaTriggerMiscTemplate->ScaleCurveId);
591
592 if (hasMorphCurveID)
593 *data << uint32(areaTriggerMiscTemplate->MorphCurveId);
594
595 if (hasFacingCurveID)
596 *data << uint32(areaTriggerMiscTemplate->FacingCurveId);
597
598 if (hasMoveCurveID)
599 *data << uint32(areaTriggerMiscTemplate->MoveCurveId);
600
601 if (hasUnk2)
602 *data << int32(0);
603
604 if (hasUnk4)
605 *data << uint32(0);
606
607 if (hasAreaTriggerSphere)
608 {
609 *data << float(areaTriggerTemplate->SphereDatas.Radius);
610 *data << float(areaTriggerTemplate->SphereDatas.RadiusTarget);
611 }
612
613 if (hasAreaTriggerBox)
614 {
615 *data << float(areaTriggerTemplate->BoxDatas.Extents[0]);
616 *data << float(areaTriggerTemplate->BoxDatas.Extents[1]);
617 *data << float(areaTriggerTemplate->BoxDatas.Extents[2]);
618 *data << float(areaTriggerTemplate->BoxDatas.ExtentsTarget[0]);
619 *data << float(areaTriggerTemplate->BoxDatas.ExtentsTarget[1]);
620 *data << float(areaTriggerTemplate->BoxDatas.ExtentsTarget[2]);
621 }
622
623 if (hasAreaTriggerPolygon)
624 {
625 *data << int32(areaTriggerTemplate->PolygonVertices.size());
626 *data << int32(areaTriggerTemplate->PolygonVerticesTarget.size());
627 *data << float(areaTriggerTemplate->PolygonDatas.Height);
628 *data << float(areaTriggerTemplate->PolygonDatas.HeightTarget);
629
630 for (TaggedPosition<Position::XY> const& vertice : areaTriggerTemplate->PolygonVertices)
631 *data << vertice;
632
633 for (TaggedPosition<Position::XY> const& vertice : areaTriggerTemplate->PolygonVerticesTarget)
634 *data << vertice;
635 }
636
637 if (hasAreaTriggerCylinder)
638 {
639 *data << float(areaTriggerTemplate->CylinderDatas.Radius);
640 *data << float(areaTriggerTemplate->CylinderDatas.RadiusTarget);
641 *data << float(areaTriggerTemplate->CylinderDatas.Height);
642 *data << float(areaTriggerTemplate->CylinderDatas.HeightTarget);
643 *data << float(areaTriggerTemplate->CylinderDatas.LocationZOffset);
644 *data << float(areaTriggerTemplate->CylinderDatas.LocationZOffsetTarget);
645 }
646
647 if (hasAreaTriggerUnkType)
648 {
649 /*packet.ResetBitReader();
650 var unk1 = packet.ReadBit("AreaTriggerUnk1");
651 var hasCenter = packet.ReadBit("HasCenter", index);
652 packet.ReadBit("Unk bit 703 1", index);
653 packet.ReadBit("Unk bit 703 2", index);
654
655 packet.ReadUInt32();
656 packet.ReadInt32();
657 packet.ReadUInt32();
658 packet.ReadSingle("Radius", index);
659 packet.ReadSingle("BlendFromRadius", index);
660 packet.ReadSingle("InitialAngel", index);
661 packet.ReadSingle("ZOffset", index);
662
663 if (unk1)
664 packet.ReadPackedGuid128("AreaTriggerUnkGUID", index);
665
666 if (hasCenter)
667 packet.ReadVector3("Center", index);*/
668 }
669 }
670
671 if (HasGameObject)
672 {
673 bool bit8 = false;
674 uint32 Int1 = 0;
675
676 GameObject const* gameObject = ToGameObject();
677
678 *data << uint32(gameObject->GetWorldEffectID());
679
680 data->WriteBit(bit8);
681 data->FlushBits();
682 if (bit8)
683 *data << uint32(Int1);
684 }
685
686 //if (SmoothPhasing)
687 //{
688 // data->WriteBit(ReplaceActive);
689 // data->WriteBit(HasReplaceObject);
690 // data->FlushBits();
691 // if (HasReplaceObject)
692 // *data << ObjectGuid(ReplaceObject);
693 //}
694
695 //if (SceneObjCreate)
696 //{
697 // data->WriteBit(HasLocalScriptData);
698 // data->WriteBit(HasPetBattleFullUpdate);
699 // data->FlushBits();
700
701 // if (HasLocalScriptData)
702 // {
703 // data->WriteBits(Data.length(), 7);
704 // data->FlushBits();
705 // data->WriteString(Data);
706 // }
707
708 // if (HasPetBattleFullUpdate)
709 // {
710 // for (std::size_t i = 0; i < 2; ++i)
711 // {
712 // *data << ObjectGuid(Players[i].CharacterID);
713 // *data << int32(Players[i].TrapAbilityID);
714 // *data << int32(Players[i].TrapStatus);
715 // *data << uint16(Players[i].RoundTimeSecs);
716 // *data << int8(Players[i].FrontPet);
717 // *data << uint8(Players[i].InputFlags);
718
719 // data->WriteBits(Players[i].Pets.size(), 2);
720 // data->FlushBits();
721 // for (std::size_t j = 0; j < Players[i].Pets.size(); ++j)
722 // {
723 // *data << ObjectGuid(Players[i].Pets[j].BattlePetGUID);
724 // *data << int32(Players[i].Pets[j].SpeciesID);
725 // *data << int32(Players[i].Pets[j].DisplayID);
726 // *data << int32(Players[i].Pets[j].CollarID);
727 // *data << int16(Players[i].Pets[j].Level);
728 // *data << int16(Players[i].Pets[j].Xp);
729 // *data << int32(Players[i].Pets[j].CurHealth);
730 // *data << int32(Players[i].Pets[j].MaxHealth);
731 // *data << int32(Players[i].Pets[j].Power);
732 // *data << int32(Players[i].Pets[j].Speed);
733 // *data << int32(Players[i].Pets[j].NpcTeamMemberID);
734 // *data << uint16(Players[i].Pets[j].BreedQuality);
735 // *data << uint16(Players[i].Pets[j].StatusFlags);
736 // *data << int8(Players[i].Pets[j].Slot);
737
738 // *data << uint32(Players[i].Pets[j].Abilities.size());
739 // *data << uint32(Players[i].Pets[j].Auras.size());
740 // *data << uint32(Players[i].Pets[j].States.size());
741 // for (std::size_t k = 0; k < Players[i].Pets[j].Abilities.size(); ++k)
742 // {
743 // *data << int32(Players[i].Pets[j].Abilities[k].AbilityID);
744 // *data << int16(Players[i].Pets[j].Abilities[k].CooldownRemaining);
745 // *data << int16(Players[i].Pets[j].Abilities[k].LockdownRemaining);
746 // *data << int8(Players[i].Pets[j].Abilities[k].AbilityIndex);
747 // *data << uint8(Players[i].Pets[j].Abilities[k].Pboid);
748 // }
749
750 // for (std::size_t k = 0; k < Players[i].Pets[j].Auras.size(); ++k)
751 // {
752 // *data << int32(Players[i].Pets[j].Auras[k].AbilityID);
753 // *data << uint32(Players[i].Pets[j].Auras[k].InstanceID);
754 // *data << int32(Players[i].Pets[j].Auras[k].RoundsRemaining);
755 // *data << int32(Players[i].Pets[j].Auras[k].CurrentRound);
756 // *data << uint8(Players[i].Pets[j].Auras[k].CasterPBOID);
757 // }
758
759 // for (std::size_t k = 0; k < Players[i].Pets[j].States.size(); ++k)
760 // {
761 // *data << uint32(Players[i].Pets[j].States[k].StateID);
762 // *data << int32(Players[i].Pets[j].States[k].StateValue);
763 // }
764
765 // data->WriteBits(Players[i].Pets[j].CustomName.length(), 7);
766 // data->FlushBits();
767 // data->WriteString(Players[i].Pets[j].CustomName);
768 // }
769 // }
770
771 // for (std::size_t i = 0; i < 3; ++i)
772 // {
773 // *data << uint32(Enviros[j].Auras.size());
774 // *data << uint32(Enviros[j].States.size());
775 // for (std::size_t j = 0; j < Enviros[j].Auras.size(); ++j)
776 // {
777 // *data << int32(Enviros[j].Auras[j].AbilityID);
778 // *data << uint32(Enviros[j].Auras[j].InstanceID);
779 // *data << int32(Enviros[j].Auras[j].RoundsRemaining);
780 // *data << int32(Enviros[j].Auras[j].CurrentRound);
781 // *data << uint8(Enviros[j].Auras[j].CasterPBOID);
782 // }
783
784 // for (std::size_t j = 0; j < Enviros[j].States.size(); ++j)
785 // {
786 // *data << uint32(Enviros[i].States[j].StateID);
787 // *data << int32(Enviros[i].States[j].StateValue);
788 // }
789 // }
790
791 // *data << uint16(WaitingForFrontPetsMaxSecs);
792 // *data << uint16(PvpMaxRoundTime);
793 // *data << int32(CurRound);
794 // *data << uint32(NpcCreatureID);
795 // *data << uint32(NpcDisplayID);
796 // *data << int8(CurPetBattleState);
797 // *data << uint8(ForfeitPenalty);
798 // *data << ObjectGuid(InitialWildPetGUID);
799 // data->WriteBit(IsPVP);
800 // data->WriteBit(CanAwardXP);
801 // data->FlushBits();
802 // }
803 //}
804
805 if (PlayerCreateData)
806 {
807 bool HasSceneInstanceIDs = false;
808 bool HasRuneState = ToUnit()->GetPowerIndex(POWER_RUNES) != MAX_POWERS;
809
810 data->WriteBit(HasSceneInstanceIDs);
811 data->WriteBit(HasRuneState);
812 data->FlushBits();
813 //if (HasSceneInstanceIDs)
814 //{
815 // *data << uint32(SceneInstanceIDs.size());
816 // for (std::size_t i = 0; i < SceneInstanceIDs.size(); ++i)
817 // *data << uint32(SceneInstanceIDs[i]);
818 //}
819 if (HasRuneState)
820 {
821 Player const* player = ToPlayer();
822 float baseCd = float(player->GetRuneBaseCooldown());
823 uint32 maxRunes = uint32(player->GetMaxPower(POWER_RUNES));
824
825 *data << uint8((1 << maxRunes) - 1);
826 *data << uint8(player->GetRunesState());
827 *data << uint32(maxRunes);
828 for (uint32 i = 0; i < maxRunes; ++i)
829 *data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255);
830 }
831 }
832 }
833
834 void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
835 {
836 if (!target)
837 return;
838
839 std::size_t blockCount = UpdateMask::GetBlockCount(m_valuesCount);
840
841 uint32* flags = NULL;
842 uint32 visibleFlag = GetUpdateFieldData(target, flags);
843 ASSERT(flags);
844
845 *data << uint8(blockCount);
846 std::size_t maskPos = data->wpos();
847 data->resize(data->size() + blockCount * sizeof(UpdateMask::BlockType));
848
849 for (uint16 index = 0; index < m_valuesCount; ++index)
850 {
851 if (_fieldNotifyFlags & flags[index] ||
852 ((updateType == UPDATETYPE_VALUES ? _changesMask[index] : m_uint32Values[index]) && (flags[index] & visibleFlag)))
853 {
854 UpdateMask::SetUpdateBit(data->contents() + maskPos, index);
855 *data << m_uint32Values[index];
856 }
857 }
858 }
859
860 void Object::BuildDynamicValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
861 {
862 if (!target)
863 return;
864
865 std::size_t blockCount = UpdateMask::GetBlockCount(_dynamicValuesCount);
866
867 uint32* flags = nullptr;
868 uint32 visibleFlag = GetDynamicUpdateFieldData(target, flags);
869
870 *data << uint8(blockCount);
871 std::size_t maskPos = data->wpos();
872 data->resize(data->size() + blockCount * sizeof(UpdateMask::BlockType));
873
874 for (uint16 index = 0; index < _dynamicValuesCount; ++index)
875 {
876 std::vector<uint32> const& values = _dynamicValues[index];
877 if (_fieldNotifyFlags & flags[index] ||
878 ((updateType == UPDATETYPE_VALUES ? _dynamicChangesMask[index] != UpdateMask::UNCHANGED : !values.empty()) && (flags[index] & visibleFlag)))
879 {
880 UpdateMask::SetUpdateBit(data->contents() + maskPos, index);
881
882 std::size_t arrayBlockCount = UpdateMask::GetBlockCount(values.size());
883 *data << uint16(UpdateMask::EncodeDynamicFieldChangeType(arrayBlockCount, _dynamicChangesMask[index], updateType));
884 if (_dynamicChangesMask[index] == UpdateMask::VALUE_AND_SIZE_CHANGED && updateType == UPDATETYPE_VALUES)
885 *data << uint32(values.size());
886
887 std::size_t arrayMaskPos = data->wpos();
888 data->resize(data->size() + arrayBlockCount * sizeof(UpdateMask::BlockType));
889 for (std::size_t v = 0; v < values.size(); ++v)
890 {
891 if (updateType != UPDATETYPE_VALUES || _dynamicChangesArrayMask[index][v])
892 {
893 UpdateMask::SetUpdateBit(data->contents() + arrayMaskPos, v);
894 *data << uint32(values[v]);
895 }
896 }
897 }
898 }
899 }
900
901 void Object::AddToObjectUpdateIfNeeded()
902 {
903 if (m_inWorld && !m_objectUpdated)
904 {
905 AddToObjectUpdate();
906 m_objectUpdated = true;
907 }
908 }
909
910 void Object::ClearUpdateMask(bool remove)
911 {
912 memset(_changesMask.data(), 0, _changesMask.size());
913 _dynamicChangesMask.assign(_dynamicChangesMask.size(), UpdateMask::UNCHANGED);
914 for (uint32 i = 0; i < _dynamicValuesCount; ++i)
915 memset(_dynamicChangesArrayMask[i].data(), 0, _dynamicChangesArrayMask[i].size());
916
917 if (m_objectUpdated)
918 {
919 if (remove)
920 RemoveFromObjectUpdate();
921 m_objectUpdated = false;
922 }
923 }
924
925 void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const
926 {
927 UpdateDataMapType::iterator iter = data_map.find(player);
928
929 if (iter == data_map.end())
930 {
931 std::pair<UpdateDataMapType::iterator, bool> p = data_map.emplace(player, UpdateData(player->GetMapId()));
932 ASSERT(p.second);
933 iter = p.first;
934 }
935
936 BuildValuesUpdateBlockForPlayer(&iter->second, iter->first);
937 }
938
939 uint32 Object::GetUpdateFieldData(Player const* target, uint32*& flags) const
940 {
941 uint32 visibleFlag = UF_FLAG_PUBLIC;
942
943 if (target == this)
944 visibleFlag |= UF_FLAG_PRIVATE;
945
946 switch (GetTypeId())
947 {
948 case TYPEID_ITEM:
949 case TYPEID_CONTAINER:
950 flags = ItemUpdateFieldFlags;
951 if (((Item const*)this)->GetOwnerGUID() == target->GetGUID())
952 visibleFlag |= UF_FLAG_OWNER | UF_FLAG_ITEM_OWNER;
953 break;
954 case TYPEID_UNIT:
955 case TYPEID_PLAYER:
956 {
957 Player* plr = ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself();
958 flags = UnitUpdateFieldFlags;
959 if (ToUnit()->GetOwnerGUID() == target->GetGUID())
960 visibleFlag |= UF_FLAG_OWNER;
961
962 if (HasFlag(OBJECT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO))
963 if (ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY, target->GetGUID()))
964 visibleFlag |= UF_FLAG_SPECIAL_INFO;
965
966 if (plr && plr->IsInSameRaidWith(target))
967 visibleFlag |= UF_FLAG_PARTY_MEMBER;
968 break;
969 }
970 case TYPEID_GAMEOBJECT:
971 flags = GameObjectUpdateFieldFlags;
972 if (ToGameObject()->GetOwnerGUID() == target->GetGUID())
973 visibleFlag |= UF_FLAG_OWNER;
974 break;
975 case TYPEID_DYNAMICOBJECT:
976 flags = DynamicObjectUpdateFieldFlags;
977 if (ToDynObject()->GetCasterGUID() == target->GetGUID())
978 visibleFlag |= UF_FLAG_OWNER;
979 break;
980 case TYPEID_CORPSE:
981 flags = CorpseUpdateFieldFlags;
982 if (ToCorpse()->GetOwnerGUID() == target->GetGUID())
983 visibleFlag |= UF_FLAG_OWNER;
984 break;
985 case TYPEID_AREATRIGGER:
986 flags = AreaTriggerUpdateFieldFlags;
987 break;
988 case TYPEID_SCENEOBJECT:
989 flags = SceneObjectUpdateFieldFlags;
990 break;
991 case TYPEID_CONVERSATION:
992 flags = ConversationUpdateFieldFlags;
993 break;
994 case TYPEID_OBJECT:
995 ABORT();
996 break;
997 }
998
999 return visibleFlag;
1000 }
1001
1002 uint32 Object::GetDynamicUpdateFieldData(Player const* target, uint32*& flags) const
1003 {
1004 uint32 visibleFlag = UF_FLAG_PUBLIC;
1005
1006 if (target == this)
1007 visibleFlag |= UF_FLAG_PRIVATE;
1008
1009 switch (GetTypeId())
1010 {
1011 case TYPEID_ITEM:
1012 case TYPEID_CONTAINER:
1013 flags = ItemDynamicUpdateFieldFlags;
1014 if (((Item const*)this)->GetOwnerGUID() == target->GetGUID())
1015 visibleFlag |= UF_FLAG_OWNER | UF_FLAG_ITEM_OWNER;
1016 break;
1017 case TYPEID_UNIT:
1018 case TYPEID_PLAYER:
1019 {
1020 Player* plr = ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself();
1021 flags = UnitDynamicUpdateFieldFlags;
1022 if (ToUnit()->GetOwnerGUID() == target->GetGUID())
1023 visibleFlag |= UF_FLAG_OWNER;
1024
1025 if (HasFlag(OBJECT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO))
1026 if (ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY, target->GetGUID()))
1027 visibleFlag |= UF_FLAG_SPECIAL_INFO;
1028
1029 if (plr && plr->IsInSameRaidWith(target))
1030 visibleFlag |= UF_FLAG_PARTY_MEMBER;
1031 break;
1032 }
1033 case TYPEID_GAMEOBJECT:
1034 flags = GameObjectDynamicUpdateFieldFlags;
1035 break;
1036 case TYPEID_CONVERSATION:
1037 flags = ConversationDynamicUpdateFieldFlags;
1038
1039 if (ToConversation()->GetCreatorGuid() == target->GetGUID())
1040 visibleFlag |= UF_FLAG_0x100;
1041 break;
1042 default:
1043 flags = nullptr;
1044 break;
1045 }
1046
1047 return visibleFlag;
1048 }
1049
1050 void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count)
1051 {
1052 if (data.empty())
1053 return;
1054
1055 Tokenizer tokens(data, ' ', count);
1056
1057 if (tokens.size() != count)
1058 return;
1059
1060 for (uint32 index = 0; index < count; ++index)
1061 {
1062 m_uint32Values[startOffset + index] = atoul(tokens[index]);
1063 _changesMask[startOffset + index] = 1;
1064 }
1065 }
1066
1067 void Object::SetInt32Value(uint16 index, int32 value)
1068 {
1069 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1070
1071 if (m_int32Values[index] != value)
1072 {
1073 m_int32Values[index] = value;
1074 _changesMask[index] = 1;
1075
1076 AddToObjectUpdateIfNeeded();
1077 }
1078 }
1079
1080 void Object::SetUInt32Value(uint16 index, uint32 value)
1081 {
1082 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1083
1084 if (m_uint32Values[index] != value)
1085 {
1086 m_uint32Values[index] = value;
1087 _changesMask[index] = 1;
1088
1089 AddToObjectUpdateIfNeeded();
1090 }
1091 }
1092
1093 void Object::UpdateUInt32Value(uint16 index, uint32 value)
1094 {
1095 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1096
1097 m_uint32Values[index] = value;
1098 _changesMask[index] = 1;
1099 }
1100
1101 void Object::SetUInt64Value(uint16 index, uint64 value)
1102 {
1103 ASSERT(index + 1 < m_valuesCount || PrintIndexError(index, true));
1104 if (*((uint64*)&(m_uint32Values[index])) != value)
1105 {
1106 m_uint32Values[index] = PAIR64_LOPART(value);
1107 m_uint32Values[index + 1] = PAIR64_HIPART(value);
1108 _changesMask[index] = 1;
1109 _changesMask[index + 1] = 1;
1110
1111 AddToObjectUpdateIfNeeded();
1112 }
1113 }
1114
1115 bool Object::AddGuidValue(uint16 index, ObjectGuid const& value)
1116 {
1117 ASSERT(index + 3 < m_valuesCount || PrintIndexError(index, true));
1118 if (!value.IsEmpty() && ((ObjectGuid*)&(m_uint32Values[index]))->IsEmpty())
1119 {
1120 *((ObjectGuid*)&(m_uint32Values[index])) = value;
1121 _changesMask[index] = 1;
1122 _changesMask[index + 1] = 1;
1123 _changesMask[index + 2] = 1;
1124 _changesMask[index + 3] = 1;
1125
1126 AddToObjectUpdateIfNeeded();
1127 return true;
1128 }
1129
1130 return false;
1131 }
1132
1133 bool Object::RemoveGuidValue(uint16 index, ObjectGuid const& value)
1134 {
1135 ASSERT(index + 3 < m_valuesCount || PrintIndexError(index, true));
1136 if (!value.IsEmpty() && *((ObjectGuid*)&(m_uint32Values[index])) == value)
1137 {
1138 ((ObjectGuid*)&(m_uint32Values[index]))->Clear();
1139 _changesMask[index] = 1;
1140 _changesMask[index + 1] = 1;
1141 _changesMask[index + 2] = 1;
1142 _changesMask[index + 3] = 1;
1143
1144 AddToObjectUpdateIfNeeded();
1145 return true;
1146 }
1147
1148 return false;
1149 }
1150
1151 void Object::SetFloatValue(uint16 index, float value)
1152 {
1153 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1154
1155 if (m_floatValues[index] != value)
1156 {
1157 m_floatValues[index] = value;
1158 _changesMask[index] = 1;
1159
1160 AddToObjectUpdateIfNeeded();
1161 }
1162 }
1163
1164 void Object::SetByteValue(uint16 index, uint8 offset, uint8 value)
1165 {
1166 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1167
1168 if (offset > 3)
1169 {
1170 TC_LOG_ERROR("misc", "Object::SetByteValue: wrong offset %u", offset);
1171 return;
1172 }
1173
1174 if (uint8(m_uint32Values[index] >> (offset * 8)) != value)
1175 {
1176 m_uint32Values[index] &= ~uint32(uint32(0xFF) << (offset * 8));
1177 m_uint32Values[index] |= uint32(uint32(value) << (offset * 8));
1178 _changesMask[index] = 1;
1179
1180 AddToObjectUpdateIfNeeded();
1181 }
1182 }
1183
1184 void Object::SetUInt16Value(uint16 index, uint8 offset, uint16 value)
1185 {
1186 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1187
1188 if (offset > 1)
1189 {
1190 TC_LOG_ERROR("misc", "Object::SetUInt16Value: wrong offset %u", offset);
1191 return;
1192 }
1193
1194 if (uint16(m_uint32Values[index] >> (offset * 16)) != value)
1195 {
1196 m_uint32Values[index] &= ~uint32(uint32(0xFFFF) << (offset * 16));
1197 m_uint32Values[index] |= uint32(uint32(value) << (offset * 16));
1198 _changesMask[index] = 1;
1199
1200 AddToObjectUpdateIfNeeded();
1201 }
1202 }
1203
1204 void Object::SetGuidValue(uint16 index, ObjectGuid const& value)
1205 {
1206 ASSERT(index + 3 < m_valuesCount || PrintIndexError(index, true));
1207 if (*((ObjectGuid*)&(m_uint32Values[index])) != value)
1208 {
1209 *((ObjectGuid*)&(m_uint32Values[index])) = value;
1210 _changesMask[index] = 1;
1211 _changesMask[index + 1] = 1;
1212 _changesMask[index + 2] = 1;
1213 _changesMask[index + 3] = 1;
1214
1215 AddToObjectUpdateIfNeeded();
1216 }
1217 }
1218
1219 void Object::SetStatFloatValue(uint16 index, float value)
1220 {
1221 if (value < 0)
1222 value = 0.0f;
1223
1224 SetFloatValue(index, value);
1225 }
1226
1227 void Object::SetStatInt32Value(uint16 index, int32 value)
1228 {
1229 if (value < 0)
1230 value = 0;
1231
1232 SetUInt32Value(index, uint32(value));
1233 }
1234
1235 void Object::ApplyModUInt32Value(uint16 index, int32 val, bool apply)
1236 {
1237 int32 cur = GetUInt32Value(index);
1238 cur += (apply ? val : -val);
1239 if (cur < 0)
1240 cur = 0;
1241 SetUInt32Value(index, cur);
1242 }
1243
1244 void Object::ApplyModInt32Value(uint16 index, int32 val, bool apply)
1245 {
1246 int32 cur = GetInt32Value(index);
1247 cur += (apply ? val : -val);
1248 SetInt32Value(index, cur);
1249 }
1250
1251 void Object::ApplyModUInt16Value(uint16 index, uint8 offset, int16 val, bool apply)
1252 {
1253 int16 cur = GetUInt16Value(index, offset);
1254 cur += (apply ? val : -val);
1255 if (cur < 0)
1256 cur = 0;
1257 SetUInt16Value(index, offset, cur);
1258 }
1259
1260 void Object::ApplyModSignedFloatValue(uint16 index, float val, bool apply)
1261 {
1262 float cur = GetFloatValue(index);
1263 cur += (apply ? val : -val);
1264 SetFloatValue(index, cur);
1265 }
1266
1267 void Object::ApplyPercentModFloatValue(uint16 index, float val, bool apply)
1268 {
1269 float value = GetFloatValue(index);
1270 ApplyPercentModFloatVar(value, val, apply);
1271 SetFloatValue(index, value);
1272 }
1273
1274 void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply)
1275 {
1276 float cur = GetFloatValue(index);
1277 cur += (apply ? val : -val);
1278 if (cur < 0)
1279 cur = 0;
1280 SetFloatValue(index, cur);
1281 }
1282
1283 void Object::SetFlag(uint16 index, uint32 newFlag)
1284 {
1285 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1286 uint32 oldval = m_uint32Values[index];
1287 uint32 newval = oldval | newFlag;
1288
1289 if (oldval != newval)
1290 {
1291 m_uint32Values[index] = newval;
1292 _changesMask[index] = 1;
1293
1294 AddToObjectUpdateIfNeeded();
1295 }
1296 }
1297
1298 void Object::RemoveFlag(uint16 index, uint32 oldFlag)
1299 {
1300 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1301 ASSERT(m_uint32Values);
1302
1303 uint32 oldval = m_uint32Values[index];
1304 uint32 newval = oldval & ~oldFlag;
1305
1306 if (oldval != newval)
1307 {
1308 m_uint32Values[index] = newval;
1309 _changesMask[index] = 1;
1310
1311 AddToObjectUpdateIfNeeded();
1312 }
1313 }
1314
1315 void Object::ToggleFlag(uint16 index, uint32 flag)
1316 {
1317 if (HasFlag(index, flag))
1318 RemoveFlag(index, flag);
1319 else
1320 SetFlag(index, flag);
1321 }
1322
1323 bool Object::HasFlag(uint16 index, uint32 flag) const
1324 {
1325 if (index >= m_valuesCount && !PrintIndexError(index, false))
1326 return false;
1327
1328 return (m_uint32Values[index] & flag) != 0;
1329 }
1330
1331 void Object::ApplyModFlag(uint16 index, uint32 flag, bool apply)
1332 {
1333 if (apply) SetFlag(index, flag); else RemoveFlag(index, flag);
1334 }
1335
1336 void Object::SetByteFlag(uint16 index, uint8 offset, uint8 newFlag)
1337 {
1338 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1339
1340 if (offset > 3)
1341 {
1342 TC_LOG_ERROR("misc", "Object::SetByteFlag: wrong offset %u", offset);
1343 return;
1344 }
1345
1346 if (!(uint8(m_uint32Values[index] >> (offset * 8)) & newFlag))
1347 {
1348 m_uint32Values[index] |= uint32(uint32(newFlag) << (offset * 8));
1349 _changesMask[index] = 1;
1350
1351 AddToObjectUpdateIfNeeded();
1352 }
1353 }
1354
1355 void Object::RemoveByteFlag(uint16 index, uint8 offset, uint8 oldFlag)
1356 {
1357 ASSERT(index < m_valuesCount || PrintIndexError(index, true));
1358
1359 if (offset > 3)
1360 {
1361 TC_LOG_ERROR("misc", "Object::RemoveByteFlag: wrong offset %u", offset);
1362 return;
1363 }
1364
1365 if (uint8(m_uint32Values[index] >> (offset * 8)) & oldFlag)
1366 {
1367 m_uint32Values[index] &= ~uint32(uint32(oldFlag) << (offset * 8));
1368 _changesMask[index] = 1;
1369
1370 AddToObjectUpdateIfNeeded();
1371 }
1372 }
1373
1374 void Object::ToggleByteFlag(uint16 index, uint8 offset, uint8 flag)
1375 {
1376 if (HasByteFlag(index, offset, flag))
1377 RemoveByteFlag(index, offset, flag);
1378 else
1379 SetByteFlag(index, offset, flag);
1380 }
1381
1382 bool Object::HasByteFlag(uint16 index, uint8 offset, uint8 flag) const
1383 {
1384 ASSERT(index < m_valuesCount || PrintIndexError(index, false));
1385 ASSERT(offset < 4);
1386 return (((uint8*)&m_uint32Values[index])[offset] & flag) != 0;
1387 }
1388
1389 void Object::SetFlag64(uint16 index, uint64 newFlag)
1390 {
1391 uint64 oldval = GetUInt64Value(index);
1392 uint64 newval = oldval | newFlag;
1393 SetUInt64Value(index, newval);
1394 }
1395
1396 void Object::RemoveFlag64(uint16 index, uint64 oldFlag)
1397 {
1398 uint64 oldval = GetUInt64Value(index);
1399 uint64 newval = oldval & ~oldFlag;
1400 SetUInt64Value(index, newval);
1401 }
1402
1403 void Object::ToggleFlag64(uint16 index, uint64 flag)
1404 {
1405 if (HasFlag64(index, flag))
1406 RemoveFlag64(index, flag);
1407 else
1408 SetFlag64(index, flag);
1409 }
1410
1411 bool Object::HasFlag64(uint16 index, uint64 flag) const
1412 {
1413 ASSERT(index < m_valuesCount || PrintIndexError(index, false));
1414 return (GetUInt64Value(index) & flag) != 0;
1415 }
1416
1417 void Object::ApplyModFlag64(uint16 index, uint64 flag, bool apply)
1418 {
1419 if (apply) SetFlag64(index, flag); else RemoveFlag64(index, flag);
1420 }
1421
1422 std::vector<uint32> const& Object::GetDynamicValues(uint16 index) const
1423 {
1424 ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false));
1425 return _dynamicValues[index];
1426 }
1427
1428 uint32 Object::GetDynamicValue(uint16 index, uint16 offset) const
1429 {
1430 ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false));
1431 if (offset >= _dynamicValues[index].size())
1432 return 0;
1433 return _dynamicValues[index][offset];
1434 }
1435
1436 void Object::AddDynamicValue(uint16 index, uint32 value)
1437 {
1438 ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false));
1439 SetDynamicValue(index, _dynamicValues[index].size(), value);
1440 }
1441
1442 void Object::RemoveDynamicValue(uint16 index, uint32 value)
1443 {
1444 ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false));
1445
1446 // TODO: Research if this is blizzlike to just set value to 0
1447 std::vector<uint32>& values = _dynamicValues[index];
1448 for (std::size_t i = 0; i < values.size(); ++i)
1449 {
1450 if (values[i] == value)
1451 {
1452 values[i] = 0;
1453 _dynamicChangesMask[index] = UpdateMask::VALUE_CHANGED;
1454 _dynamicChangesArrayMask[index][i] = 1;
1455
1456 AddToObjectUpdateIfNeeded();
1457 }
1458 }
1459 }
1460
1461 void Object::ClearDynamicValue(uint16 index)
1462 {
1463 ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false));
1464
1465 if (!_dynamicValues[index].empty())
1466 {
1467 _dynamicValues[index].clear();
1468 _dynamicChangesMask[index] = UpdateMask::VALUE_AND_SIZE_CHANGED;
1469 _dynamicChangesArrayMask[index].clear();
1470
1471 AddToObjectUpdateIfNeeded();
1472 }
1473 }
1474
1475 void Object::SetDynamicValue(uint16 index, uint16 offset, uint32 value)
1476 {
1477 ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false));
1478
1479 UpdateMask::DynamicFieldChangeType changeType = UpdateMask::VALUE_CHANGED;
1480 std::vector<uint32>& values = _dynamicValues[index];
1481 if (values.size() <= offset)
1482 {
1483 values.resize(offset + 1);
1484 changeType = UpdateMask::VALUE_AND_SIZE_CHANGED;
1485 }
1486
1487 if (_dynamicChangesArrayMask[index].size() <= offset)
1488 _dynamicChangesArrayMask[index].resize((offset / 32 + 1) * 32);
1489
1490 if (values[offset] != value || changeType == UpdateMask::VALUE_AND_SIZE_CHANGED)
1491 {
1492 values[offset] = value;
1493 _dynamicChangesMask[index] = changeType;
1494 _dynamicChangesArrayMask[index][offset] = 1;
1495
1496 AddToObjectUpdateIfNeeded();
1497 }
1498 }
1499
1500 bool Object::PrintIndexError(uint32 index, bool set) const
1501 {
1502 TC_LOG_ERROR("misc", "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);
1503
1504 // ASSERT must fail after function call
1505 return false;
1506 }
1507
1508 void MovementInfo::OutDebug()
1509 {
1510 TC_LOG_DEBUG("misc", "MOVEMENT INFO");
1511 TC_LOG_DEBUG("misc", "%s", guid.ToString().c_str());
1512 TC_LOG_DEBUG("misc", "flags %s (%u)", Movement::MovementFlags_ToString(flags).c_str(), flags);
1513 TC_LOG_DEBUG("misc", "flags2 %s (%u)", Movement::MovementFlagsExtra_ToString(flags2).c_str(), flags2);
1514 TC_LOG_DEBUG("misc", "time %u current time %u", time, getMSTime());
1515 TC_LOG_DEBUG("misc", "position: `%s`", pos.ToString().c_str());
1516 if (!transport.guid.IsEmpty())
1517 {
1518 TC_LOG_DEBUG("misc", "TRANSPORT:");
1519 TC_LOG_DEBUG("misc", "%s", transport.guid.ToString().c_str());
1520 TC_LOG_DEBUG("misc", "position: `%s`", transport.pos.ToString().c_str());
1521 TC_LOG_DEBUG("misc", "seat: %i", transport.seat);
1522 TC_LOG_DEBUG("misc", "time: %u", transport.time);
1523 if (transport.prevTime)
1524 TC_LOG_DEBUG("misc", "prevTime: %u", transport.prevTime);
1525 if (transport.vehicleId)
1526 TC_LOG_DEBUG("misc", "vehicleId: %u", transport.vehicleId);
1527 }
1528
1529 if ((flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (flags2 & MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING))
1530 TC_LOG_DEBUG("misc", "pitch: %f", pitch);
1531
1532 if (flags & MOVEMENTFLAG_FALLING || jump.fallTime)
1533 {
1534 TC_LOG_DEBUG("misc", "fallTime: %u j_zspeed: %f", jump.fallTime, jump.zspeed);
1535 if (flags & MOVEMENTFLAG_FALLING)
1536 TC_LOG_DEBUG("misc", "j_sinAngle: %f j_cosAngle: %f j_xyspeed: %f", jump.sinAngle, jump.cosAngle, jump.xyspeed);
1537 }
1538
1539 if (flags & MOVEMENTFLAG_SPLINE_ELEVATION)
1540 TC_LOG_DEBUG("misc", "splineElevation: %f", splineElevation);
1541 }
1542
1543 WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0),
1544 m_name(""), m_isActive(false), m_isWorldObject(isWorldObject), m_zoneScript(NULL),
1545 m_transport(NULL), m_currMap(NULL), m_InstanceId(0),
1546 _dbPhase(0), m_notifyflags(0), m_executed_notifies(0)
1547 {
1548 m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST);
1549 m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
1550 }
1551
1552 void WorldObject::SetWorldObject(bool on)
1553 {
1554 if (!IsInWorld())
1555 return;
1556
1557 GetMap()->AddObjectToSwitchList(this, on);
1558 }
1559
1560 bool WorldObject::IsWorldObject() const
1561 {
1562 if (m_isWorldObject)
1563 return true;
1564
1565 if (ToCreature() && ToCreature()->m_isTempWorldObject)
1566 return true;
1567
1568 return false;
1569 }
1570
1571 void WorldObject::setActive(bool on)
1572 {
1573 if (m_isActive == on)
1574 return;
1575
1576 if (GetTypeId() == TYPEID_PLAYER)
1577 return;
1578
1579 m_isActive = on;
1580
1581 if (!IsInWorld())
1582 return;
1583
1584 Map* map = FindMap();
1585 if (!map)
1586 return;
1587
1588 if (on)
1589 {
1590 if (GetTypeId() == TYPEID_UNIT)
1591 map->AddToActive(this->ToCreature());
1592 else if (GetTypeId() == TYPEID_DYNAMICOBJECT)
1593 map->AddToActive((DynamicObject*)this);
1594 }
1595 else
1596 {
1597 if (GetTypeId() == TYPEID_UNIT)
1598 map->RemoveFromActive(this->ToCreature());
1599 else if (GetTypeId() == TYPEID_DYNAMICOBJECT)
1600 map->RemoveFromActive((DynamicObject*)this);
1601 }
1602 }
1603
1604 void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
1605 {
1606 if (IsInWorld())
1607 RemoveFromWorld();
1608
1609 if (Transport* transport = GetTransport())
1610 transport->RemovePassenger(this);
1611 }
1612
1613 void WorldObject::RemoveFromWorld()
1614 {
1615 if (!IsInWorld())
1616 return;
1617
1618 DestroyForNearbyPlayers();
1619
1620 Object::RemoveFromWorld();
1621 }
1622
1623 uint32 WorldObject::GetZoneId() const
1624 {
1625 return GetMap()->GetZoneId(GetPhaseShift(), m_positionX, m_positionY, m_positionZ);
1626 }
1627
1628 uint32 WorldObject::GetAreaId() const
1629 {
1630 return GetMap()->GetAreaId(GetPhaseShift(), m_positionX, m_positionY, m_positionZ);
1631 }
1632
1633 void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const
1634 {
1635 GetMap()->GetZoneAndAreaId(GetPhaseShift(), zoneid, areaid, m_positionX, m_positionY, m_positionZ);
1636 }
1637
1638 InstanceScript* WorldObject::GetInstanceScript()
1639 {
1640 Map* map = GetMap();
1641 return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceScript() : NULL;
1642 }
1643
1644 float WorldObject::GetDistanceZ(const WorldObject* obj) const
1645 {
1646 float dz = std::fabs(GetPositionZ() - obj->GetPositionZ());
1647 float sizefactor = GetObjectSize() + obj->GetObjectSize();
1648 float dist = dz - sizefactor;
1649 return (dist > 0 ? dist : 0);
1650 }
1651
1652 bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const
1653 {
1654 float sizefactor = GetObjectSize() + obj->GetObjectSize();
1655 float maxdist = dist2compare + sizefactor;
1656
1657 if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetGUID() == GetTransport()->GetGUID())
1658 {
1659 float dtx = m_movementInfo.transport.pos.m_positionX - obj->m_movementInfo.transport.pos.m_positionX;
1660 float dty = m_movementInfo.transport.pos.m_positionY - obj->m_movementInfo.transport.pos.m_positionY;
1661 float disttsq = dtx * dtx + dty * dty;
1662 if (is3D)
1663 {
1664 float dtz = m_movementInfo.transport.pos.m_positionZ - obj->m_movementInfo.transport.pos.m_positionZ;
1665 disttsq += dtz * dtz;
1666 }
1667 return disttsq < (maxdist * maxdist);
1668 }
1669
1670 float dx = GetPositionX() - obj->GetPositionX();
1671 float dy = GetPositionY() - obj->GetPositionY();
1672 float distsq = dx*dx + dy*dy;
1673 if (is3D)
1674 {
1675 float dz = GetPositionZ() - obj->GetPositionZ();
1676 distsq += dz*dz;
1677 }
1678
1679 return distsq < maxdist * maxdist;
1680 }
1681
1682 bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
1683 {
1684 if (!IsInMap(obj))
1685 return false;
1686
1687 float x, y, z;
1688 if (obj->GetTypeId() == TYPEID_PLAYER)
1689 obj->GetPosition(x, y, z);
1690 else
1691 obj->GetHitSpherePointFor(GetPosition(), x, y, z);
1692
1693 return IsWithinLOS(x, y, z);
1694 }
1695
1696 float WorldObject::GetDistance(const WorldObject* obj) const
1697 {
1698 float d = GetExactDist(obj) - GetObjectSize() - obj->GetObjectSize();
1699 return d > 0.0f ? d : 0.0f;
1700 }
1701
1702 float WorldObject::GetDistance(const Position &pos) const
1703 {
1704 float d = GetExactDist(&pos) - GetObjectSize();
1705 return d > 0.0f ? d : 0.0f;
1706 }
1707
1708 float WorldObject::GetDistance(float x, float y, float z) const
1709 {
1710 float d = GetExactDist(x, y, z) - GetObjectSize();
1711 return d > 0.0f ? d : 0.0f;
1712 }
1713
1714 float WorldObject::GetDistance2d(const WorldObject* obj) const
1715 {
1716 float d = GetExactDist2d(obj) - GetObjectSize() - obj->GetObjectSize();
1717 return d > 0.0f ? d : 0.0f;
1718 }
1719
1720 float WorldObject::GetDistance2d(float x, float y) const
1721 {
1722 float d = GetExactDist2d(x, y) - GetObjectSize();
1723 return d > 0.0f ? d : 0.0f;
1724 }
1725
1726 bool WorldObject::IsSelfOrInSameMap(const WorldObject* obj) const
1727 {
1728 if (this == obj)
1729 return true;
1730 return IsInMap(obj);
1731 }
1732
1733 bool WorldObject::IsInMap(const WorldObject* obj) const
1734 {
1735 if (obj)
1736 return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap());
1737 return false;
1738 }
1739
1740 bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist) const
1741 {
1742 return IsInDist(x, y, z, dist + GetObjectSize());
1743 }
1744
1745 bool WorldObject::IsWithinDist3d(const Position* pos, float dist) const
1746 {
1747 return IsInDist(pos, dist + GetObjectSize());
1748 }
1749
1750 bool WorldObject::IsWithinDist2d(float x, float y, float dist) const
1751 {
1752 return IsInDist2d(x, y, dist + GetObjectSize());
1753 }
1754
1755 bool WorldObject::IsWithinDist2d(const Position* pos, float dist) const
1756 {
1757 return IsInDist2d(pos, dist + GetObjectSize());
1758 }
1759
1760 bool WorldObject::IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D /*= true*/) const
1761 {
1762 return obj && _IsWithinDist(obj, dist2compare, is3D);
1763 }
1764
1765 bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D /*= true*/) const
1766 {
1767 return obj && IsInMap(obj) && IsInPhase(obj) && _IsWithinDist(obj, dist2compare, is3D);
1768 }
1769
1770 bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
1771 {
1772 /*float x, y, z;
1773 GetPosition(x, y, z);
1774 VMAP::IVMapManager* vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
1775 return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);*/
1776 if (IsInWorld())
1777 {
1778 float x, y, z;
1779 if (GetTypeId() == TYPEID_PLAYER)
1780 GetPosition(x, y, z);
1781 else
1782 GetHitSpherePointFor({ ox, oy, oz }, x, y, z);
1783
1784 return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z + 2.0f, ox, oy, oz + 2.0f);
1785 }
1786
1787 return true;
1788 }
1789
1790 Position WorldObject::GetHitSpherePointFor(Position const& dest) const
1791 {
1792 G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ());
1793 G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
1794 G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * GetObjectSize();
1795
1796 return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAngle(contactPoint.x, contactPoint.y));
1797 }
1798
1799 void WorldObject::GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const
1800 {
1801 Position pos = GetHitSpherePointFor(dest);
1802 x = pos.GetPositionX();
1803 y = pos.GetPositionY();
1804 z = pos.GetPositionZ();
1805 }
1806
1807 bool WorldObject::GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D /* = true */) const
1808 {
1809 float dx1 = GetPositionX() - obj1->GetPositionX();
1810 float dy1 = GetPositionY() - obj1->GetPositionY();
1811 float distsq1 = dx1*dx1 + dy1*dy1;
1812 if (is3D)
1813 {
1814 float dz1 = GetPositionZ() - obj1->GetPositionZ();
1815 distsq1 += dz1*dz1;
1816 }
1817
1818 float dx2 = GetPositionX() - obj2->GetPositionX();
1819 float dy2 = GetPositionY() - obj2->GetPositionY();
1820 float distsq2 = dx2*dx2 + dy2*dy2;
1821 if (is3D)
1822 {
1823 float dz2 = GetPositionZ() - obj2->GetPositionZ();
1824 distsq2 += dz2*dz2;
1825 }
1826
1827 return distsq1 < distsq2;
1828 }
1829
1830 bool WorldObject::IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D /* = true */) const
1831 {
1832 float dx = GetPositionX() - obj->GetPositionX();
1833 float dy = GetPositionY() - obj->GetPositionY();
1834 float distsq = dx*dx + dy*dy;
1835 if (is3D)
1836 {
1837 float dz = GetPositionZ() - obj->GetPositionZ();
1838 distsq += dz*dz;
1839 }
1840
1841 float sizefactor = GetObjectSize() + obj->GetObjectSize();
1842
1843 // check only for real range
1844 if (minRange > 0.0f)
1845 {
1846 float mindist = minRange + sizefactor;
1847 if (distsq < mindist * mindist)
1848 return false;
1849 }
1850
1851 float maxdist = maxRange + sizefactor;
1852 return distsq < maxdist * maxdist;
1853 }
1854
1855 bool WorldObject::IsInRange2d(float x, float y, float minRange, float maxRange) const
1856 {
1857 float dx = GetPositionX() - x;
1858 float dy = GetPositionY() - y;
1859 float distsq = dx*dx + dy*dy;
1860
1861 float sizefactor = GetObjectSize();
1862
1863 // check only for real range
1864 if (minRange > 0.0f)
1865 {
1866 float mindist = minRange + sizefactor;
1867 if (distsq < mindist * mindist)
1868 return false;
1869 }
1870
1871 float maxdist = maxRange + sizefactor;
1872 return distsq < maxdist * maxdist;
1873 }
1874
1875 bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float maxRange) const
1876 {
1877 float dx = GetPositionX() - x;
1878 float dy = GetPositionY() - y;
1879 float dz = GetPositionZ() - z;
1880 float distsq = dx*dx + dy*dy + dz*dz;
1881
1882 float sizefactor = GetObjectSize();
1883
1884 // check only for real range
1885 if (minRange > 0.0f)
1886 {
1887 float mindist = minRange + sizefactor;
1888 if (distsq < mindist * mindist)
1889 return false;
1890 }
1891
1892 float maxdist = maxRange + sizefactor;
1893 return distsq < maxdist * maxdist;
1894 }
1895
1896 bool WorldObject::IsInBetween(Position const& pos1, Position const& pos2, float size) const
1897 {
1898 float dist = GetExactDist2d(pos1);
1899
1900 // not using sqrt() for performance
1901 if ((dist * dist) >= pos1.GetExactDist2dSq(pos2))
1902 return false;
1903
1904 if (!size)
1905 size = GetObjectSize() / 2;
1906
1907 float angle = pos1.GetAngle(pos2);
1908
1909 // not using sqrt() for performance
1910 return (size * size) >= GetExactDist2dSq(pos1.GetPositionX() + std::cos(angle) * dist, pos1.GetPositionY() + std::sin(angle) * dist);
1911 }
1912
1913 bool WorldObject::isInFront(WorldObject const* target, float arc) const
1914 {
1915 return HasInArc(arc, target);
1916 }
1917
1918 bool WorldObject::isInBack(WorldObject const* target, float arc) const
1919 {
1920 return !HasInArc(2 * float(M_PI) - arc, target);
1921 }
1922
1923 void WorldObject::GetRandomPoint(const Position &pos, float distance, float &rand_x, float &rand_y, float &rand_z) const
1924 {
1925 if (!distance)
1926 {
1927 pos.GetPosition(rand_x, rand_y, rand_z);
1928 return;
1929 }
1930
1931 // angle to face `obj` to `this`
1932 float angle = (float)rand_norm()*static_cast<float>(2*M_PI);
1933 float new_dist = (float)rand_norm() + (float)rand_norm();
1934 new_dist = distance * (new_dist > 1 ? new_dist - 2 : new_dist);
1935
1936 rand_x = pos.m_positionX + new_dist * std::cos(angle);
1937 rand_y = pos.m_positionY + new_dist * std::sin(angle);
1938 rand_z = pos.m_positionZ;
1939
1940 Trinity::NormalizeMapCoord(rand_x);
1941 Trinity::NormalizeMapCoord(rand_y);
1942 UpdateGroundPositionZ(rand_x, rand_y, rand_z); // update to LOS height if available
1943 }
1944
1945 Position WorldObject::GetRandomPoint(const Position &srcPos, float distance) const
1946 {
1947 float x, y, z;
1948 GetRandomPoint(srcPos, distance, x, y, z);
1949 return Position(x, y, z, GetOrientation());
1950 }
1951
1952 void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const
1953 {
1954 float new_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z + 2.0f, true);
1955 if (new_z > INVALID_HEIGHT)
1956 z = new_z + 0.05f; // just to be sure that we are not a few pixel under the surface
1957 }
1958
1959 void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
1960 {
1961 // TODO: Allow transports to be part of dynamic vmap tree
1962 if (GetTransport())
1963 return;
1964
1965 switch (GetTypeId())
1966 {
1967 case TYPEID_UNIT:
1968 {
1969 // non fly unit don't must be in air
1970 // non swim unit must be at ground (mostly speedup, because it don't must be in water and water level check less fast
1971 if (!ToCreature()->CanFly())
1972 {
1973 bool canSwim = ToCreature()->CanSwim();
1974 float ground_z = z;
1975 float max_z = canSwim
1976 ? GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK))
1977 : ((ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true)));
1978 if (max_z > INVALID_HEIGHT)
1979 {
1980 if (z > max_z)
1981 z = max_z;
1982 else if (z < ground_z)
1983 z = ground_z;
1984 }
1985 }
1986 else
1987 {
1988 float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true);
1989 if (z < ground_z)
1990 z = ground_z;
1991 }
1992 break;
1993 }
1994 case TYPEID_PLAYER:
1995 {
1996 // for server controlled moves playr work same as creature (but it can always swim)
1997 if (!ToPlayer()->CanFly())
1998 {
1999 float ground_z = z;
2000 float max_z = GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK));
2001 if (max_z > INVALID_HEIGHT)
2002 {
2003 if (z > max_z)
2004 z = max_z;
2005 else if (z < ground_z)
2006 z = ground_z;
2007 }
2008 }
2009 else
2010 {
2011 float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true);
2012 if (z < ground_z)
2013 z = ground_z;
2014 }
2015 break;
2016 }
2017 default:
2018 {
2019 float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true);
2020 if (ground_z > INVALID_HEIGHT)
2021 z = ground_z;
2022 break;
2023 }
2024 }
2025 }
2026
2027 float WorldObject::GetGridActivationRange() const
2028 {
2029 if (ToPlayer())
2030 {
2031 if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
2032 return DEFAULT_VISIBILITY_INSTANCE;
2033 return GetMap()->GetVisibilityRange();
2034 }
2035 else if (ToCreature())
2036 return ToCreature()->m_SightDistance;
2037 else if (ToDynObject())
2038 {
2039 if (isActiveObject())
2040 return GetMap()->GetVisibilityRange();
2041 else
2042 return 0.0f;
2043 }
2044 else
2045 return 0.0f;
2046 }
2047
2048 float WorldObject::GetVisibilityRange() const
2049 {
2050 if (isActiveObject() && !ToPlayer())
2051 return MAX_VISIBILITY_DISTANCE;
2052 else
2053 return GetMap()->GetVisibilityRange();
2054 }
2055
2056 float WorldObject::GetSightRange(const WorldObject* target) const
2057 {
2058 if (ToUnit())
2059 {
2060 if (ToPlayer())
2061 {
2062 if (target && target->isActiveObject() && !target->ToPlayer())
2063 return MAX_VISIBILITY_DISTANCE;
2064 else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
2065 return DEFAULT_VISIBILITY_INSTANCE;
2066 else
2067 return GetMap()->GetVisibilityRange();
2068 }
2069 else if (ToCreature())
2070 return ToCreature()->m_SightDistance;
2071 else
2072 return SIGHT_RANGE_UNIT;
2073 }
2074
2075 if (ToDynObject() && isActiveObject())
2076 {
2077 return GetMap()->GetVisibilityRange();
2078 }
2079
2080 return 0.0f;
2081 }
2082
2083 bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, bool distanceCheck, bool checkAlert) const
2084 {
2085 if (this == obj)
2086 return true;
2087
2088 if (obj->IsNeverVisibleFor(this) || CanNeverSee(obj))
2089 return false;
2090
2091 if (obj->IsAlwaysVisibleFor(this) || CanAlwaysSee(obj))
2092 return true;
2093
2094 bool corpseVisibility = false;
2095 if (distanceCheck)
2096 {
2097 bool corpseCheck = false;
2098 if (Player const* thisPlayer = ToPlayer())
2099 {
2100 if (thisPlayer->isDead() && thisPlayer->GetHealth() > 0 && // Cheap way to check for ghost state
2101 !(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & GHOST_VISIBILITY_GHOST))
2102 {
2103 if (Corpse* corpse = thisPlayer->GetCorpse())
2104 {
2105 corpseCheck = true;
2106 if (corpse->IsWithinDist(thisPlayer, GetSightRange(obj), false))
2107 if (corpse->IsWithinDist(obj, GetSightRange(obj), false))
2108 corpseVisibility = true;
2109 }
2110 }
2111 }
2112
2113 WorldObject const* viewpoint = this;
2114 if (Player const* player = this->ToPlayer())
2115 viewpoint = player->GetViewpoint();
2116
2117 if (!viewpoint)
2118 viewpoint = this;
2119
2120 if (!corpseCheck && !viewpoint->IsWithinDist(obj, GetSightRange(obj), false))
2121 return false;
2122 }
2123
2124 // GM visibility off or hidden NPC
2125 if (!obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM))
2126 {
2127 // Stop checking other things for GMs
2128 if (m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GM))
2129 return true;
2130 }
2131 else
2132 return m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GM) >= obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM);
2133
2134 // Ghost players, Spirit Healers, and some other NPCs
2135 if (!corpseVisibility && !(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GHOST)))
2136 {
2137 // Alive players can see dead players in some cases, but other objects can't do that
2138 if (Player const* thisPlayer = ToPlayer())
2139 {
2140 if (Player const* objPlayer = obj->ToPlayer())
2141 {
2142 if (thisPlayer->GetTeam() != objPlayer->GetTeam() || !thisPlayer->IsGroupVisibleFor(objPlayer))
2143 return false;
2144 }
2145 else
2146 return false;
2147 }
2148 else
2149 return false;
2150 }
2151
2152 if (obj->IsInvisibleDueToDespawn())
2153 return false;
2154
2155 if (!CanDetect(obj, ignoreStealth, checkAlert))
2156 return false;
2157
2158 return true;
2159 }
2160
2161 bool WorldObject::CanNeverSee(WorldObject const* obj) const
2162 {
2163 return GetMap() != obj->GetMap() || !IsInPhase(obj);
2164 }
2165
2166 bool WorldObject::CanDetect(WorldObject const* obj, bool ignoreStealth, bool checkAlert) const
2167 {
2168 const WorldObject* seer = this;
2169
2170 // Pets don't have detection, they use the detection of their masters
2171 if (Unit const* thisUnit = ToUnit())
2172 if (Unit* controller = thisUnit->GetCharmerOrOwner())
2173 seer = controller;
2174
2175 if (obj->IsAlwaysDetectableFor(seer))
2176 return true;
2177
2178 if (!ignoreStealth && !seer->CanDetectInvisibilityOf(obj))
2179 return false;
2180
2181 if (!ignoreStealth && !seer->CanDetectStealthOf(obj, checkAlert))
2182 return false;
2183
2184 return true;
2185 }
2186
2187 bool WorldObject::CanDetectInvisibilityOf(WorldObject const* obj) const
2188 {
2189 uint32 mask = obj->m_invisibility.GetFlags() & m_invisibilityDetect.GetFlags();
2190
2191 // Check for not detected types
2192 if (mask != obj->m_invisibility.GetFlags())
2193 return false;
2194
2195 for (uint32 i = 0; i < TOTAL_INVISIBILITY_TYPES; ++i)
2196 {
2197 if (!(mask & (1 << i)))
2198 continue;
2199
2200 int32 objInvisibilityValue = obj->m_invisibility.GetValue(InvisibilityType(i));
2201 int32 ownInvisibilityDetectValue = m_invisibilityDetect.GetValue(InvisibilityType(i));
2202
2203 // Too low value to detect
2204 if (ownInvisibilityDetectValue < objInvisibilityValue)
2205 return false;
2206 }
2207
2208 return true;
2209 }
2210
2211 bool WorldObject::CanDetectStealthOf(WorldObject const* obj, bool checkAlert) const
2212 {
2213 // Combat reach is the minimal distance (both in front and behind),
2214 // and it is also used in the range calculation.
2215 // One stealth point increases the visibility range by 0.3 yard.
2216
2217 if (!obj->m_stealth.GetFlags())
2218 return true;
2219
2220 float distance = GetExactDist(obj);
2221 float combatReach = 0.0f;
2222
2223 Unit const* unit = ToUnit();
2224 if (unit)
2225 combatReach = unit->GetCombatReach();
2226
2227 if (distance < combatReach)
2228 return true;
2229
2230 if (!HasInArc(float(M_PI), obj))
2231 return false;
2232
2233 GameObject const* go = ToGameObject();
2234 for (uint32 i = 0; i < TOTAL_STEALTH_TYPES; ++i)
2235 {
2236 if (!(obj->m_stealth.GetFlags() & (1 << i)))
2237 continue;
2238
2239 if (unit && unit->HasAuraTypeWithMiscvalue(SPELL_AURA_DETECT_STEALTH, i))
2240 return true;
2241
2242 // Starting points
2243 int32 detectionValue = 30;
2244
2245 // Level difference: 5 point / level, starting from level 1.
2246 // There may be spells for this and the starting points too, but
2247 // not in the DBCs of the client.
2248 detectionValue += int32(GetLevelForTarget(obj) - 1) * 5;
2249
2250 // Apply modifiers
2251 detectionValue += m_stealthDetect.GetValue(StealthType(i));
2252 if (go)
2253 if (Unit* owner = go->GetOwner())
2254 detectionValue -= int32(owner->GetLevelForTarget(this) - 1) * 5;
2255
2256 detectionValue -= obj->m_stealth.GetValue(StealthType(i));
2257
2258 // Calculate max distance
2259 float visibilityRange = float(detectionValue) * 0.3f + combatReach;
2260
2261 // If this unit is an NPC then player detect range doesn't apply
2262 if (unit && unit->GetTypeId() == TYPEID_PLAYER && visibilityRange > MAX_PLAYER_STEALTH_DETECT_RANGE)
2263 visibilityRange = MAX_PLAYER_STEALTH_DETECT_RANGE;
2264
2265 // When checking for alert state, look 8% further, and then 1.5 yards more than that.
2266 if (checkAlert)
2267 visibilityRange += (visibilityRange * 0.08f) + 1.5f;
2268
2269 // If checking for alert, and creature's visibility range is greater than aggro distance, No alert
2270 Unit const* tunit = obj->ToUnit();
2271 if (checkAlert && unit && unit->ToCreature() && visibilityRange >= unit->ToCreature()->GetAttackDistance(tunit) + unit->ToCreature()->m_CombatDistance)
2272 return false;
2273
2274 if (distance > visibilityRange)
2275 return false;
2276 }
2277
2278 return true;
2279 }
2280
2281 void Object::ForceValuesUpdateAtIndex(uint32 i)
2282 {
2283 _changesMask[i] = 1;
2284 AddToObjectUpdateIfNeeded();
2285 }
2286
2287 void WorldObject::SendMessageToSet(WorldPacket const* data, bool self) const
2288 {
2289 if (IsInWorld())
2290 SendMessageToSetInRange(data, GetVisibilityRange(), self);
2291 }
2292
2293 void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/) const
2294 {
2295 Trinity::MessageDistDeliverer notifier(this, data, dist);
2296 Cell::VisitWorldObjects(this, notifier, dist);
2297 }
2298
2299 void WorldObject::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const
2300 {
2301 Trinity::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr);
2302 Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
2303 }
2304
2305 void WorldObject::SetMap(Map* map)
2306 {
2307 ASSERT(map);
2308 ASSERT(!IsInWorld());
2309 if (m_currMap == map) // command add npc: first create, than loadfromdb
2310 return;
2311 if (m_currMap)
2312 {
2313 TC_LOG_FATAL("misc", "WorldObject::SetMap: obj %u new map %u %u, old map %u %u", (uint32)GetTypeId(), map->GetId(), map->GetInstanceId(), m_currMap->GetId(), m_currMap->GetInstanceId());
2314 ABORT();
2315 }
2316 m_currMap = map;
2317 m_mapId = map->GetId();
2318 m_InstanceId = map->GetInstanceId();
2319 if (IsWorldObject())
2320 m_currMap->AddWorldObject(this);
2321 }
2322
2323 void WorldObject::ResetMap()
2324 {
2325 ASSERT(m_currMap);
2326 ASSERT(!IsInWorld());
2327 if (IsWorldObject())
2328 m_currMap->RemoveWorldObject(this);
2329 m_currMap = NULL;
2330 //maybe not for corpse
2331 //m_mapId = 0;
2332 //m_InstanceId = 0;
2333 }
2334
2335 void WorldObject::AddObjectToRemoveList()
2336 {
2337 ASSERT(m_uint32Values);
2338
2339 Map* map = FindMap();
2340 if (!map)
2341 {
2342 TC_LOG_ERROR("misc", "Object (Entry: %u %s) at attempt add to move list not have valid map (Id: %u).", GetEntry(), GetGUID().ToString().c_str(), GetMapId());
2343 return;
2344 }
2345
2346 map->AddObjectToRemoveList(this);
2347 }
2348
2349 TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties /*= NULL*/, uint32 duration /*= 0*/, Unit* summoner /*= NULL*/, uint32 spellId /*= 0*/, uint32 vehId /*= 0*/)
2350 {
2351 uint32 mask = UNIT_MASK_SUMMON;
2352 if (properties)
2353 {
2354 switch (properties->Control)
2355 {
2356 case SUMMON_CATEGORY_PET:
2357 mask = UNIT_MASK_GUARDIAN;
2358 break;
2359 case SUMMON_CATEGORY_PUPPET:
2360 mask = UNIT_MASK_PUPPET;
2361 break;
2362 case SUMMON_CATEGORY_VEHICLE:
2363 mask = UNIT_MASK_MINION;
2364 break;
2365 case SUMMON_CATEGORY_WILD:
2366 case SUMMON_CATEGORY_ALLY:
2367 case SUMMON_CATEGORY_UNK:
2368 {
2369 switch (properties->Title)
2370 {
2371 case SUMMON_TYPE_MINION:
2372 case SUMMON_TYPE_GUARDIAN:
2373 case SUMMON_TYPE_GUARDIAN2:
2374 mask = UNIT_MASK_GUARDIAN;
2375 break;
2376 case SUMMON_TYPE_TOTEM:
2377 case SUMMON_TYPE_LIGHTWELL:
2378 mask = UNIT_MASK_TOTEM;
2379 break;
2380 case SUMMON_TYPE_VEHICLE:
2381 case SUMMON_TYPE_VEHICLE2:
2382 mask = UNIT_MASK_SUMMON;
2383 break;
2384 case SUMMON_TYPE_MINIPET:
2385 mask = UNIT_MASK_MINION;
2386 break;
2387 default:
2388 if (properties->Flags & 512) // Mirror Image, Summon Gargoyle
2389 mask = UNIT_MASK_GUARDIAN;
2390 break;
2391 }
2392 break;
2393 }
2394 default:
2395 return nullptr;
2396 }
2397 }
2398
2399 TempSummon* summon = nullptr;
2400 switch (mask)
2401 {
2402 case UNIT_MASK_SUMMON:
2403 summon = new TempSummon(properties, summoner, false);
2404 break;
2405 case UNIT_MASK_GUARDIAN:
2406 summon = new Guardian(properties, summoner, false);
2407 break;
2408 case UNIT_MASK_PUPPET:
2409 summon = new Puppet(properties, summoner);
2410 break;
2411 case UNIT_MASK_TOTEM:
2412 summon = new Totem(properties, summoner);
2413 break;
2414 case UNIT_MASK_MINION:
2415 summon = new Minion(properties, summoner, false);
2416 break;
2417 }
2418
2419 if (!summon->Create(GenerateLowGuid<HighGuid::Creature>(), this, entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), nullptr, vehId))
2420 {
2421 delete summon;
2422 return nullptr;
2423 }
2424
2425 // Set the summon to the summoner's phase
2426 if (summoner)
2427 PhasingHandler::InheritPhaseShift(summon, summoner);
2428
2429 summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId);
2430
2431 summon->SetHomePosition(pos);
2432
2433 summon->InitStats(duration);
2434 AddToMap(summon->ToCreature());
2435 summon->InitSummon();
2436
2437 // call MoveInLineOfSight for nearby creatures
2438 Trinity::AIRelocationNotifier notifier(*summon);
2439 Cell::VisitAllObjects(summon, notifier, GetVisibilityRange());
2440
2441 return summon;
2442 }
2443
2444 /**
2445 * Summons group of creatures.
2446 *
2447 * @param group Id of group to summon.
2448 * @param list List to store pointers to summoned creatures.
2449 */
2450
2451 void Map::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= NULL*/)
2452 {
2453 std::vector<TempSummonData> const* data = sObjectMgr->GetSummonGroup(GetId(), SUMMONER_TYPE_MAP, group);
2454 if (!data)
2455 return;
2456
2457 for (std::vector<TempSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr)
2458 if (TempSummon* summon = SummonCreature(itr->entry, itr->pos, NULL, itr->time))
2459 if (list)
2460 list->push_back(summon);
2461 }
2462
2463 void WorldObject::SetZoneScript()
2464 {
2465 if (Map* map = FindMap())
2466 {
2467 if (map->IsDungeon())
2468 m_zoneScript = (ZoneScript*)((InstanceMap*)map)->GetInstanceScript();
2469 else if (!map->IsBattlegroundOrArena())
2470 {
2471 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(GetZoneId()))
2472 m_zoneScript = bf;
2473 else
2474 m_zoneScript = sOutdoorPvPMgr->GetZoneScript(GetZoneId());
2475 }
2476 }
2477 }
2478
2479 Scenario* WorldObject::GetScenario() const
2480 {
2481 if (IsInWorld())
2482 if (InstanceMap* instanceMap = GetMap()->ToInstanceMap())
2483 return instanceMap->GetInstanceScenario();
2484
2485 return nullptr;
2486 }
2487
2488 TempSummon* WorldObject::SummonCreature(uint32 entry, Position const& pos, TempSummonType spwtype /*= TEMPSUMMON_MANUAL_DESPAWN*/, uint32 duration /*= 0*/, uint32 /*vehId = 0*/) const
2489 {
2490 if (Map* map = FindMap())
2491 {
2492 if (TempSummon* summon = map->SummonCreature(entry, pos, NULL, duration, isType(TYPEMASK_UNIT) ? (Unit*)this : NULL))
2493 {
2494 summon->SetTempSummonType(spwtype);
2495 return summon;
2496 }
2497 }
2498
2499 return nullptr;
2500 }
2501
2502 TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang /*= 0*/, TempSummonType spwtype /*= TEMPSUMMON_MANUAL_DESPAWN*/, uint32 despwtime /*= 0*/) const
2503 {
2504 if (!x && !y && !z)
2505 {
2506 GetClosePoint(x, y, z, GetObjectSize());
2507 ang = GetOrientation();
2508 }
2509
2510 Position pos;
2511 pos.Relocate(x, y, z, ang);
2512 return SummonCreature(id, pos, spwtype, despwtime, 0);
2513 }
2514
2515 GameObject* WorldObject::SummonGameObject(uint32 entry, Position const& pos, QuaternionData const& rot, uint32 respawnTime)
2516 {
2517 if (!IsInWorld())
2518 return nullptr;
2519
2520 GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
2521 if (!goinfo)
2522 {
2523 TC_LOG_ERROR("sql.sql", "Gameobject template %u not found in database!", entry);
2524 return nullptr;
2525 }
2526
2527 Map* map = GetMap();
2528 GameObject* go = GameObject::CreateGameObject(entry, map, pos, rot, 255, GO_STATE_READY);
2529 if (!go)
2530 return nullptr;
2531
2532 PhasingHandler::InheritPhaseShift(go, this);
2533
2534 go->SetRespawnTime(respawnTime);
2535 if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT) //not sure how to handle this
2536 ToUnit()->AddGameObject(go);
2537 else
2538 go->SetSpawnedByDefault(false);
2539
2540 map->AddToMap(go);
2541 return go;
2542 }
2543
2544 GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, QuaternionData const& rot, uint32 respawnTime)
2545 {
2546 if (!x && !y && !z)
2547 {
2548 GetClosePoint(x, y, z, GetObjectSize());
2549 ang = GetOrientation();
2550 }
2551
2552 Position pos(x, y, z, ang);
2553 return SummonGameObject(entry, pos, rot, respawnTime);
2554 }
2555
2556 Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint32 duration, CreatureAI* (*GetAI)(Creature*))
2557 {
2558 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
2559 Creature* summon = SummonCreature(WORLD_TRIGGER, x, y, z, ang, summonType, duration);
2560 if (!summon)
2561 return NULL;
2562
2563 //summon->SetName(GetName());
2564 if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT)
2565 {
2566 summon->setFaction(((Unit*)this)->getFaction());
2567 summon->SetLevel(((Unit*)this)->getLevel());
2568 }
2569
2570 if (GetAI)
2571 summon->AIM_Initialize(GetAI(summon));
2572 return summon;
2573 }
2574
2575 /**
2576 * Summons group of creatures. Should be called only by instances of Creature and GameObject classes.
2577 *
2578 * @param group Id of group to summon.
2579 * @param list List to store pointers to summoned creatures.
2580 */
2581 void WorldObject::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= NULL*/)
2582 {
2583 ASSERT((GetTypeId() == TYPEID_GAMEOBJECT || GetTypeId() == TYPEID_UNIT) && "Only GOs and creatures can summon npc groups!");
2584
2585 std::vector<TempSummonData> const* data = sObjectMgr->GetSummonGroup(GetEntry(), GetTypeId() == TYPEID_GAMEOBJECT ? SUMMONER_TYPE_GAMEOBJECT : SUMMONER_TYPE_CREATURE, group);
2586 if (!data)
2587 {
2588 TC_LOG_WARN("scripts", "%s (%s) tried to summon non-existing summon group %u.", GetName().c_str(), GetGUID().ToString().c_str(), group);
2589 return;
2590 }
2591
2592 for (std::vector<TempSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr)
2593 if (TempSummon* summon = SummonCreature(itr->entry, itr->pos, itr->type, itr->time))
2594 if (list)
2595 list->push_back(summon);
2596 }
2597
2598 Creature* WorldObject::FindNearestCreature(uint32 entry, float range, bool alive) const
2599 {
2600 Creature* creature = NULL;
2601 Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck checker(*this, entry, alive, range);
2602 Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(this, creature, checker);
2603 Cell::VisitAllObjects(this, searcher, range);
2604 return creature;
2605 }
2606
2607 GameObject* WorldObject::FindNearestGameObject(uint32 entry, float range) const
2608 {
2609 GameObject* go = NULL;
2610 Trinity::NearestGameObjectEntryInObjectRangeCheck checker(*this, entry, range);
2611 Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> searcher(this, go, checker);
2612 Cell::VisitGridObjects(this, searcher, range);
2613 return go;
2614 }
2615
2616 GameObject* WorldObject::FindNearestGameObjectOfType(GameobjectTypes type, float range) const
2617 {
2618 GameObject* go = NULL;
2619 Trinity::NearestGameObjectTypeInObjectRangeCheck checker(*this, type, range);
2620 Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectTypeInObjectRangeCheck> searcher(this, go, checker);
2621 Cell::VisitGridObjects(this, searcher, range);
2622 return go;
2623 }
2624
2625 template <typename Container>
2626 void WorldObject::GetGameObjectListWithEntryInGrid(Container& gameObjectContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const
2627 {
2628 Trinity::AllGameObjectsWithEntryInRange check(this, entry, maxSearchRange);
2629 Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange> searcher(this, gameObjectContainer, check);
2630 Cell::VisitGridObjects(this, searcher, maxSearchRange);
2631 }
2632
2633 template <typename Container>
2634 void WorldObject::GetCreatureListWithEntryInGrid(Container& creatureContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const
2635 {
2636 Trinity::AllCreaturesOfEntryInRange check(this, entry, maxSearchRange);
2637 Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(this, creatureContainer, check);
2638 Cell::VisitGridObjects(this, searcher, maxSearchRange);
2639 }
2640
2641 template <typename Container>
2642 void WorldObject::GetPlayerListInGrid(Container& playerContainer, float maxSearchRange) const
2643 {
2644 Trinity::AnyPlayerInObjectRangeCheck checker(this, maxSearchRange);
2645 Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, playerContainer, checker);
2646 Cell::VisitWorldObjects(this, searcher, maxSearchRange);
2647 }
2648
2649 void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle) const
2650 {
2651 x = GetPositionX() + (GetObjectSize() + distance2d) * std::cos(absAngle);
2652 y = GetPositionY() + (GetObjectSize() + distance2d) * std::sin(absAngle);
2653
2654 Trinity::NormalizeMapCoord(x);
2655 Trinity::NormalizeMapCoord(y);
2656 }
2657
2658 void WorldObject::GetNearPoint(WorldObject const* /*searcher*/, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle) const
2659 {
2660 GetNearPoint2D(x, y, distance2d+searcher_size, absAngle);
2661 z = GetPositionZ();
2662 // Should "searcher" be used instead of "this" when updating z coordinate ?
2663 UpdateAllowedPositionZ(x, y, z);
2664
2665 // if detection disabled, return first point
2666 if (!sWorld->getBoolConfig(CONFIG_DETECT_POS_COLLISION))
2667 return;
2668
2669 // return if the point is already in LoS
2670 if (IsWithinLOS(x, y, z))
2671 return;
2672
2673 // remember first point
2674 float first_x = x;
2675 float first_y = y;
2676 float first_z = z;
2677
2678 // loop in a circle to look for a point in LoS using small steps
2679 for (float angle = float(M_PI) / 8; angle < float(M_PI) * 2; angle += float(M_PI) / 8)
2680 {
2681 GetNearPoint2D(x, y, distance2d + searcher_size, absAngle + angle);
2682 z = GetPositionZ();
2683 UpdateAllowedPositionZ(x, y, z);
2684 if (IsWithinLOS(x, y, z))
2685 return;
2686 }
2687
2688 // still not in LoS, give up and return first position found
2689 x = first_x;
2690 y = first_y;
2691 z = first_z;
2692 }
2693
2694 void WorldObject::GetClosePoint(float &x, float &y, float &z, float size, float distance2d /*= 0*/, float angle /*= 0*/) const
2695 {
2696 // angle calculated from current orientation
2697 GetNearPoint(NULL, x, y, z, size, distance2d, GetOrientation() + angle);
2698 }
2699
2700 Position WorldObject::GetNearPosition(float dist, float angle)
2701 {
2702 Position pos = GetPosition();
2703 MovePosition(pos, dist, angle);
2704 return pos;
2705 }
2706
2707 Position WorldObject::GetFirstCollisionPosition(float dist, float angle)
2708 {
2709 Position pos = GetPosition();
2710 MovePositionToFirstCollision(pos, dist, angle);
2711 return pos;
2712 }
2713
2714 Position WorldObject::GetRandomNearPosition(float radius)
2715 {
2716 Position pos = GetPosition();
2717 MovePosition(pos, radius * (float)rand_norm(), (float)rand_norm() * static_cast<float>(2 * M_PI));
2718 return pos;
2719 }
2720
2721 void WorldObject::GetContactPoint(const WorldObject* obj, float &x, float &y, float &z, float distance2d /*= CONTACT_DISTANCE*/) const
2722 {
2723 // angle to face `obj` to `this` using distance includes size of `obj`
2724 GetNearPoint(obj, x, y, z, obj->GetObjectSize(), distance2d, GetAngle(obj));
2725 }
2726
2727 float WorldObject::GetObjectSize() const
2728 {
2729 return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE;
2730 }
2731
2732 void WorldObject::MovePosition(Position &pos, float dist, float angle)
2733 {
2734 angle += GetOrientation();
2735 float destx, desty, destz, ground, floor;
2736 destx = pos.m_positionX + dist * std::cos(angle);
2737 desty = pos.m_positionY + dist * std::sin(angle);
2738
2739 // Prevent invalid coordinates here, position is unchanged
2740 if (!Trinity::IsValidMapCoord(destx, desty, pos.m_positionZ))
2741 {
2742 TC_LOG_FATAL("misc", "WorldObject::MovePosition: Object (Entry: %u %s) has invalid coordinates X: %f and Y: %f were passed!",
2743 GetEntry(), GetGUID().ToString().c_str(), destx, desty);
2744 return;
2745 }
2746
2747 ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true);
2748 floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true);
2749 destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor;
2750
2751 float step = dist/10.0f;
2752
2753 for (uint8 j = 0; j < 10; ++j)
2754 {
2755 // do not allow too big z changes
2756 if (std::fabs(pos.m_positionZ - destz) > 6)
2757 {
2758 destx -= step * std::cos(angle);
2759 desty -= step * std::sin(angle);
2760 ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true);
2761 floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true);
2762 destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor;
2763 }
2764 // we have correct destz now
2765 else
2766 {
2767 pos.Relocate(destx, desty, destz);
2768 break;
2769 }
2770 }
2771
2772 Trinity::NormalizeMapCoord(pos.m_positionX);
2773 Trinity::NormalizeMapCoord(pos.m_positionY);
2774 UpdateGroundPositionZ(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
2775 pos.SetOrientation(GetOrientation());
2776 }
2777
2778 // @todo: replace with WorldObject::UpdateAllowedPositionZ
2779 float NormalizeZforCollision(WorldObject* obj, float x, float y, float z)
2780 {
2781 float ground = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, MAX_HEIGHT, true);
2782 float floor = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, z + 2.0f, true);
2783 float helper = std::fabs(ground - z) <= std::fabs(floor - z) ? ground : floor;
2784 if (z > helper) // must be above ground
2785 {
2786 if (Unit* unit = obj->ToUnit())
2787 {
2788 if (unit->CanFly())
2789 return z;
2790 }
2791 LiquidData liquid_status;
2792 ZLiquidStatus res = obj->GetMap()->getLiquidStatus(obj->GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
2793 if (res && liquid_status.level > helper) // water must be above ground
2794 {
2795 if (liquid_status.level > z) // z is underwater
2796 return z;
2797 else
2798 return std::fabs(liquid_status.level - z) <= std::fabs(helper - z) ? liquid_status.level : helper;
2799 }
2800 }
2801 return helper;
2802 }
2803
2804 void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float angle)
2805 {
2806 angle += GetOrientation();
2807 float destx, desty, destz;
2808 destx = pos.m_positionX + dist * std::cos(angle);
2809 desty = pos.m_positionY + dist * std::sin(angle);
2810
2811 // Prevent invalid coordinates here, position is unchanged
2812 if (!Trinity::IsValidMapCoord(destx, desty))
2813 {
2814 TC_LOG_FATAL("misc", "WorldObject::MovePositionToFirstCollision invalid coordinates X: %f and Y: %f were passed!", destx, desty);
2815 return;
2816 }
2817
2818 destz = NormalizeZforCollision(this, destx, desty, pos.GetPositionZ());
2819 bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(PhasingHandler::GetTerrainMapId(GetPhaseShift(), GetMap(), pos.m_positionX, pos.m_positionY),
2820 pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.5f, destx, desty, destz + 0.5f, destx, desty, destz, -0.5f);
2821
2822 // collision occured
2823 if (col)
2824 {
2825 // move back a bit
2826 destx -= CONTACT_DISTANCE * std::cos(angle);
2827 desty -= CONTACT_DISTANCE * std::sin(angle);
2828 dist = std::sqrt((pos.m_positionX - destx)*(pos.m_positionX - destx) + (pos.m_positionY - desty)*(pos.m_positionY - desty));
2829 }
2830
2831 // check dynamic collision
2832 col = GetMap()->getObjectHitPos(GetPhaseShift(), pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.5f, destx, desty, destz + 0.5f, destx, desty, destz, -0.5f);
2833
2834 // Collided with a gameobject
2835 if (col)
2836 {
2837 destx -= CONTACT_DISTANCE * std::cos(angle);
2838 desty -= CONTACT_DISTANCE * std::sin(angle);
2839 dist = std::sqrt((pos.m_positionX - destx)*(pos.m_positionX - destx) + (pos.m_positionY - desty)*(pos.m_positionY - desty));
2840 }
2841
2842 float step = dist / 10.0f;
2843
2844 for (uint8 j = 0; j < 10; ++j)
2845 {
2846 // do not allow too big z changes
2847 if (std::fabs(pos.m_positionZ - destz) > 6.0f)
2848 {
2849 destx -= step * std::cos(angle);
2850 desty -= step * std::sin(angle);
2851 destz = NormalizeZforCollision(this, destx, desty, pos.GetPositionZ());
2852 }
2853 // we have correct destz now
2854 else
2855 {
2856 pos.Relocate(destx, desty, destz);
2857 break;
2858 }
2859 }
2860
2861 Trinity::NormalizeMapCoord(pos.m_positionX);
2862 Trinity::NormalizeMapCoord(pos.m_positionY);
2863 pos.m_positionZ = NormalizeZforCollision(this, destx, desty, pos.GetPositionZ());
2864 pos.SetOrientation(GetOrientation());
2865 }
2866
2867 void WorldObject::PlayDistanceSound(uint32 soundId, Player* target /*= nullptr*/)
2868 {
2869 if (target)
2870 target->SendDirectMessage(WorldPackets::Misc::PlaySpeakerbotSound(GetGUID(), soundId).Write());
2871 else
2872 SendMessageToSet(WorldPackets::Misc::PlaySpeakerbotSound(GetGUID(), soundId).Write(), true);
2873 }
2874
2875 void WorldObject::PlayDirectSound(uint32 soundId, Player* target /*= nullptr*/)
2876 {
2877 if (target)
2878 target->SendDirectMessage(WorldPackets::Misc::PlaySound(GetGUID(), soundId).Write());
2879 else
2880 SendMessageToSet(WorldPackets::Misc::PlaySound(GetGUID(), soundId).Write(), true);
2881 }
2882
2883 void WorldObject::PlayDirectMusic(uint32 musicId, Player* target /*= nullptr*/)
2884 {
2885 if (target)
2886 target->SendDirectMessage(WorldPackets::Misc::PlayMusic(musicId).Write());
2887 else
2888 SendMessageToSet(WorldPackets::Misc::PlayMusic(musicId).Write(), true);
2889 }
2890
2891 void WorldObject::DestroyForNearbyPlayers()
2892 {
2893 if (!IsInWorld())
2894 return;
2895
2896 std::list<Player*> targets;
2897 Trinity::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange(), false);
2898 Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, targets, check);
2899 Cell::VisitWorldObjects(this, searcher, GetVisibilityRange());
2900 for (std::list<Player*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
2901 {
2902 Player* player = (*iter);
2903
2904 if (player == this)
2905 continue;
2906
2907 if (!player->HaveAtClient(this))
2908 continue;
2909
2910 if (isType(TYPEMASK_UNIT) && ToUnit()->GetCharmerGUID() == player->GetGUID()) /// @todo this is for puppet
2911 continue;
2912
2913 DestroyForPlayer(player);
2914 player->m_clientGUIDs.erase(GetGUID());
2915 }
2916 }
2917
2918 void WorldObject::UpdateObjectVisibility(bool /*forced*/)
2919 {
2920 //updates object's visibility for nearby players
2921 Trinity::VisibleChangesNotifier notifier(*this);
2922 Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
2923 }
2924
2925 struct WorldObjectChangeAccumulator
2926 {
2927 UpdateDataMapType& i_updateDatas;
2928 WorldObject& i_object;
2929 GuidSet plr_list;
2930 WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) { }
2931 void Visit(PlayerMapType &m)
2932 {
2933 Player* source = NULL;
2934 for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
2935 {
2936 source = iter->GetSource();
2937
2938 BuildPacket(source);
2939
2940 if (!source->GetSharedVisionList().empty())
2941 {
2942 SharedVisionList::const_iterator it = source->GetSharedVisionList().begin();
2943 for (; it != source->GetSharedVisionList().end(); ++it)
2944 BuildPacket(*it);
2945 }
2946 }
2947 }
2948
2949 void Visit(CreatureMapType &m)
2950 {
2951 Creature* source = NULL;
2952 for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
2953 {
2954 source = iter->GetSource();
2955 if (!source->GetSharedVisionList().empty())
2956 {
2957 SharedVisionList::const_iterator it = source->GetSharedVisionList().begin();
2958 for (; it != source->GetSharedVisionList().end(); ++it)
2959 BuildPacket(*it);
2960 }
2961 }
2962 }
2963
2964 void Visit(DynamicObjectMapType &m)
2965 {
2966 DynamicObject* source = NULL;
2967 for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
2968 {
2969 source = iter->GetSource();
2970 ObjectGuid guid = source->GetCasterGUID();
2971
2972 if (guid.IsPlayer())
2973 {
2974 //Caster may be NULL if DynObj is in removelist
2975 if (Player* caster = ObjectAccessor::FindPlayer(guid))
2976 if (caster->GetGuidValue(PLAYER_FARSIGHT) == source->GetGUID())
2977 BuildPacket(caster);
2978 }
2979 }
2980 }
2981
2982 void BuildPacket(Player* player)
2983 {
2984 // Only send update once to a player
2985 if (plr_list.find(player->GetGUID()) == plr_list.end() && player->HaveAtClient(&i_object))
2986 {
2987 i_object.BuildFieldsUpdate(player, i_updateDatas);
2988 plr_list.insert(player->GetGUID());
2989 }
2990 }
2991
2992 template<class SKIP> void Visit(GridRefManager<SKIP> &) { }
2993 };
2994
2995 void WorldObject::BuildUpdate(UpdateDataMapType& data_map)
2996 {
2997 WorldObjectChangeAccumulator notifier(*this, data_map);
2998 //we must build packets for all visible players
2999 Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
3000
3001 ClearUpdateMask(false);
3002 }
3003
3004 void WorldObject::AddToObjectUpdate()
3005 {
3006 GetMap()->AddUpdateObject(this);
3007 }
3008
3009 void WorldObject::RemoveFromObjectUpdate()
3010 {
3011 GetMap()->RemoveUpdateObject(this);
3012 }
3013
3014 ObjectGuid WorldObject::GetTransGUID() const
3015 {
3016 if (GetTransport())
3017 return GetTransport()->GetGUID();
3018 return ObjectGuid::Empty;
3019 }
3020
3021 template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>&, uint32, float) const;
3022 template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque<GameObject*>&, uint32, float) const;
3023 template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector<GameObject*>&, uint32, float) const;
3024
3025 template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>&, uint32, float) const;
3026 template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::deque<Creature*>&, uint32, float) const;
3027 template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::vector<Creature*>&, uint32, float) const;
3028
3029 template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::list<Player*>&, float) const;
3030 template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::deque<Player*>&, float) const;
3031 template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::vector<Player*>&, float) const;