Core/Spells: Implemented personal summons (#19231)
[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 {
2116 viewpoint = player->GetViewpoint();
2117
2118 if (Creature const* creature = obj->ToCreature())
2119 if (TempSummon const* tempSummon = creature->ToTempSummon())
2120 if (tempSummon->IsVisibleBySummonerOnly() && GetGUID() != tempSummon->GetSummonerGUID())
2121 return false;
2122 }
2123
2124 if (!viewpoint)
2125 viewpoint = this;
2126
2127 if (!corpseCheck && !viewpoint->IsWithinDist(obj, GetSightRange(obj), false))
2128 return false;
2129 }
2130
2131 // GM visibility off or hidden NPC
2132 if (!obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM))
2133 {
2134 // Stop checking other things for GMs
2135 if (m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GM))
2136 return true;
2137 }
2138 else
2139 return m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GM) >= obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM);
2140
2141 // Ghost players, Spirit Healers, and some other NPCs
2142 if (!corpseVisibility && !(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GHOST)))
2143 {
2144 // Alive players can see dead players in some cases, but other objects can't do that
2145 if (Player const* thisPlayer = ToPlayer())
2146 {
2147 if (Player const* objPlayer = obj->ToPlayer())
2148 {
2149 if (thisPlayer->GetTeam() != objPlayer->GetTeam() || !thisPlayer->IsGroupVisibleFor(objPlayer))
2150 return false;
2151 }
2152 else
2153 return false;
2154 }
2155 else
2156 return false;
2157 }
2158
2159 if (obj->IsInvisibleDueToDespawn())
2160 return false;
2161
2162 if (!CanDetect(obj, ignoreStealth, checkAlert))
2163 return false;
2164
2165 return true;
2166 }
2167
2168 bool WorldObject::CanNeverSee(WorldObject const* obj) const
2169 {
2170 return GetMap() != obj->GetMap() || !IsInPhase(obj);
2171 }
2172
2173 bool WorldObject::CanDetect(WorldObject const* obj, bool ignoreStealth, bool checkAlert) const
2174 {
2175 const WorldObject* seer = this;
2176
2177 // Pets don't have detection, they use the detection of their masters
2178 if (Unit const* thisUnit = ToUnit())
2179 if (Unit* controller = thisUnit->GetCharmerOrOwner())
2180 seer = controller;
2181
2182 if (obj->IsAlwaysDetectableFor(seer))
2183 return true;
2184
2185 if (!ignoreStealth && !seer->CanDetectInvisibilityOf(obj))
2186 return false;
2187
2188 if (!ignoreStealth && !seer->CanDetectStealthOf(obj, checkAlert))
2189 return false;
2190
2191 return true;
2192 }
2193
2194 bool WorldObject::CanDetectInvisibilityOf(WorldObject const* obj) const
2195 {
2196 uint32 mask = obj->m_invisibility.GetFlags() & m_invisibilityDetect.GetFlags();
2197
2198 // Check for not detected types
2199 if (mask != obj->m_invisibility.GetFlags())
2200 return false;
2201
2202 for (uint32 i = 0; i < TOTAL_INVISIBILITY_TYPES; ++i)
2203 {
2204 if (!(mask & (1 << i)))
2205 continue;
2206
2207 int32 objInvisibilityValue = obj->m_invisibility.GetValue(InvisibilityType(i));
2208 int32 ownInvisibilityDetectValue = m_invisibilityDetect.GetValue(InvisibilityType(i));
2209
2210 // Too low value to detect
2211 if (ownInvisibilityDetectValue < objInvisibilityValue)
2212 return false;
2213 }
2214
2215 return true;
2216 }
2217
2218 bool WorldObject::CanDetectStealthOf(WorldObject const* obj, bool checkAlert) const
2219 {
2220 // Combat reach is the minimal distance (both in front and behind),
2221 // and it is also used in the range calculation.
2222 // One stealth point increases the visibility range by 0.3 yard.
2223
2224 if (!obj->m_stealth.GetFlags())
2225 return true;
2226
2227 float distance = GetExactDist(obj);
2228 float combatReach = 0.0f;
2229
2230 Unit const* unit = ToUnit();
2231 if (unit)
2232 combatReach = unit->GetCombatReach();
2233
2234 if (distance < combatReach)
2235 return true;
2236
2237 if (!HasInArc(float(M_PI), obj))
2238 return false;
2239
2240 GameObject const* go = ToGameObject();
2241 for (uint32 i = 0; i < TOTAL_STEALTH_TYPES; ++i)
2242 {
2243 if (!(obj->m_stealth.GetFlags() & (1 << i)))
2244 continue;
2245
2246 if (unit && unit->HasAuraTypeWithMiscvalue(SPELL_AURA_DETECT_STEALTH, i))
2247 return true;
2248
2249 // Starting points
2250 int32 detectionValue = 30;
2251
2252 // Level difference: 5 point / level, starting from level 1.
2253 // There may be spells for this and the starting points too, but
2254 // not in the DBCs of the client.
2255 detectionValue += int32(GetLevelForTarget(obj) - 1) * 5;
2256
2257 // Apply modifiers
2258 detectionValue += m_stealthDetect.GetValue(StealthType(i));
2259 if (go)
2260 if (Unit* owner = go->GetOwner())
2261 detectionValue -= int32(owner->GetLevelForTarget(this) - 1) * 5;
2262
2263 detectionValue -= obj->m_stealth.GetValue(StealthType(i));
2264
2265 // Calculate max distance
2266 float visibilityRange = float(detectionValue) * 0.3f + combatReach;
2267
2268 // If this unit is an NPC then player detect range doesn't apply
2269 if (unit && unit->GetTypeId() == TYPEID_PLAYER && visibilityRange > MAX_PLAYER_STEALTH_DETECT_RANGE)
2270 visibilityRange = MAX_PLAYER_STEALTH_DETECT_RANGE;
2271
2272 // When checking for alert state, look 8% further, and then 1.5 yards more than that.
2273 if (checkAlert)
2274 visibilityRange += (visibilityRange * 0.08f) + 1.5f;
2275
2276 // If checking for alert, and creature's visibility range is greater than aggro distance, No alert
2277 Unit const* tunit = obj->ToUnit();
2278 if (checkAlert && unit && unit->ToCreature() && visibilityRange >= unit->ToCreature()->GetAttackDistance(tunit) + unit->ToCreature()->m_CombatDistance)
2279 return false;
2280
2281 if (distance > visibilityRange)
2282 return false;
2283 }
2284
2285 return true;
2286 }
2287
2288 void Object::ForceValuesUpdateAtIndex(uint32 i)
2289 {
2290 _changesMask[i] = 1;
2291 AddToObjectUpdateIfNeeded();
2292 }
2293
2294 void WorldObject::SendMessageToSet(WorldPacket const* data, bool self) const
2295 {
2296 if (IsInWorld())
2297 SendMessageToSetInRange(data, GetVisibilityRange(), self);
2298 }
2299
2300 void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/) const
2301 {
2302 Trinity::MessageDistDeliverer notifier(this, data, dist);
2303 Cell::VisitWorldObjects(this, notifier, dist);
2304 }
2305
2306 void WorldObject::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const
2307 {
2308 Trinity::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr);
2309 Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
2310 }
2311
2312 void WorldObject::SetMap(Map* map)
2313 {
2314 ASSERT(map);
2315 ASSERT(!IsInWorld());
2316 if (m_currMap == map) // command add npc: first create, than loadfromdb
2317 return;
2318 if (m_currMap)
2319 {
2320 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());
2321 ABORT();
2322 }
2323 m_currMap = map;
2324 m_mapId = map->GetId();
2325 m_InstanceId = map->GetInstanceId();
2326 if (IsWorldObject())
2327 m_currMap->AddWorldObject(this);
2328 }
2329
2330 void WorldObject::ResetMap()
2331 {
2332 ASSERT(m_currMap);
2333 ASSERT(!IsInWorld());
2334 if (IsWorldObject())
2335 m_currMap->RemoveWorldObject(this);
2336 m_currMap = NULL;
2337 //maybe not for corpse
2338 //m_mapId = 0;
2339 //m_InstanceId = 0;
2340 }
2341
2342 void WorldObject::AddObjectToRemoveList()
2343 {
2344 ASSERT(m_uint32Values);
2345
2346 Map* map = FindMap();
2347 if (!map)
2348 {
2349 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());
2350 return;
2351 }
2352
2353 map->AddObjectToRemoveList(this);
2354 }
2355
2356 TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties /*= NULL*/, uint32 duration /*= 0*/, Unit* summoner /*= NULL*/, uint32 spellId /*= 0*/, uint32 vehId /*= 0*/, bool visibleBySummonerOnly /*= false*/)
2357 {
2358 uint32 mask = UNIT_MASK_SUMMON;
2359 if (properties)
2360 {
2361 switch (properties->Control)
2362 {
2363 case SUMMON_CATEGORY_PET:
2364 mask = UNIT_MASK_GUARDIAN;
2365 break;
2366 case SUMMON_CATEGORY_PUPPET:
2367 mask = UNIT_MASK_PUPPET;
2368 break;
2369 case SUMMON_CATEGORY_VEHICLE:
2370 mask = UNIT_MASK_MINION;
2371 break;
2372 case SUMMON_CATEGORY_WILD:
2373 case SUMMON_CATEGORY_ALLY:
2374 case SUMMON_CATEGORY_UNK:
2375 {
2376 switch (properties->Title)
2377 {
2378 case SUMMON_TYPE_MINION:
2379 case SUMMON_TYPE_GUARDIAN:
2380 case SUMMON_TYPE_GUARDIAN2:
2381 mask = UNIT_MASK_GUARDIAN;
2382 break;
2383 case SUMMON_TYPE_TOTEM:
2384 case SUMMON_TYPE_LIGHTWELL:
2385 mask = UNIT_MASK_TOTEM;
2386 break;
2387 case SUMMON_TYPE_VEHICLE:
2388 case SUMMON_TYPE_VEHICLE2:
2389 mask = UNIT_MASK_SUMMON;
2390 break;
2391 case SUMMON_TYPE_MINIPET:
2392 mask = UNIT_MASK_MINION;
2393 break;
2394 default:
2395 if (properties->Flags & 512) // Mirror Image, Summon Gargoyle
2396 mask = UNIT_MASK_GUARDIAN;
2397 break;
2398 }
2399 break;
2400 }
2401 default:
2402 return nullptr;
2403 }
2404 }
2405
2406 TempSummon* summon = nullptr;
2407 switch (mask)
2408 {
2409 case UNIT_MASK_SUMMON:
2410 summon = new TempSummon(properties, summoner, false);
2411 break;
2412 case UNIT_MASK_GUARDIAN:
2413 summon = new Guardian(properties, summoner, false);
2414 break;
2415 case UNIT_MASK_PUPPET:
2416 summon = new Puppet(properties, summoner);
2417 break;
2418 case UNIT_MASK_TOTEM:
2419 summon = new Totem(properties, summoner);
2420 break;
2421 case UNIT_MASK_MINION:
2422 summon = new Minion(properties, summoner, false);
2423 break;
2424 }
2425
2426 if (!summon->Create(GenerateLowGuid<HighGuid::Creature>(), this, entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), nullptr, vehId))
2427 {
2428 delete summon;
2429 return nullptr;
2430 }
2431
2432 // Set the summon to the summoner's phase
2433 if (summoner)
2434 PhasingHandler::InheritPhaseShift(summon, summoner);
2435
2436 summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId);
2437
2438 summon->SetHomePosition(pos);
2439
2440 summon->InitStats(duration);
2441
2442 summon->SetVisibleBySummonerOnly(visibleBySummonerOnly);
2443
2444 AddToMap(summon->ToCreature());
2445 summon->InitSummon();
2446
2447 // call MoveInLineOfSight for nearby creatures
2448 Trinity::AIRelocationNotifier notifier(*summon);
2449 Cell::VisitAllObjects(summon, notifier, GetVisibilityRange());
2450
2451 return summon;
2452 }
2453
2454 /**
2455 * Summons group of creatures.
2456 *
2457 * @param group Id of group to summon.
2458 * @param list List to store pointers to summoned creatures.
2459 */
2460
2461 void Map::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= NULL*/)
2462 {
2463 std::vector<TempSummonData> const* data = sObjectMgr->GetSummonGroup(GetId(), SUMMONER_TYPE_MAP, group);
2464 if (!data)
2465 return;
2466
2467 for (std::vector<TempSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr)
2468 if (TempSummon* summon = SummonCreature(itr->entry, itr->pos, NULL, itr->time))
2469 if (list)
2470 list->push_back(summon);
2471 }
2472
2473 void WorldObject::SetZoneScript()
2474 {
2475 if (Map* map = FindMap())
2476 {
2477 if (map->IsDungeon())
2478 m_zoneScript = (ZoneScript*)((InstanceMap*)map)->GetInstanceScript();
2479 else if (!map->IsBattlegroundOrArena())
2480 {
2481 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(GetZoneId()))
2482 m_zoneScript = bf;
2483 else
2484 m_zoneScript = sOutdoorPvPMgr->GetZoneScript(GetZoneId());
2485 }
2486 }
2487 }
2488
2489 Scenario* WorldObject::GetScenario() const
2490 {
2491 if (IsInWorld())
2492 if (InstanceMap* instanceMap = GetMap()->ToInstanceMap())
2493 return instanceMap->GetInstanceScenario();
2494
2495 return nullptr;
2496 }
2497
2498 TempSummon* WorldObject::SummonCreature(uint32 entry, Position const& pos, TempSummonType spwtype /*= TEMPSUMMON_MANUAL_DESPAWN*/, uint32 duration /*= 0*/, uint32 vehId /*= 0*/, bool visibleBySummonerOnly /*= false*/)
2499 {
2500 if (Map* map = FindMap())
2501 {
2502 if (TempSummon* summon = map->SummonCreature(entry, pos, nullptr, duration, ToUnit(), 0, vehId, visibleBySummonerOnly))
2503 {
2504 summon->SetTempSummonType(spwtype);
2505 return summon;
2506 }
2507 }
2508
2509 return nullptr;
2510 }
2511
2512 TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang /*= 0*/, TempSummonType spwtype /*= TEMPSUMMON_MANUAL_DESPAWN*/, uint32 despwtime /*= 0*/, bool visibleBySummonerOnly /*= false*/)
2513 {
2514 if (!x && !y && !z)
2515 {
2516 GetClosePoint(x, y, z, GetObjectSize());
2517 ang = GetOrientation();
2518 }
2519
2520 Position pos;
2521 pos.Relocate(x, y, z, ang);
2522 return SummonCreature(id, pos, spwtype, despwtime, 0, visibleBySummonerOnly);
2523 }
2524
2525 GameObject* WorldObject::SummonGameObject(uint32 entry, Position const& pos, QuaternionData const& rot, uint32 respawnTime)
2526 {
2527 if (!IsInWorld())
2528 return nullptr;
2529
2530 GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
2531 if (!goinfo)
2532 {
2533 TC_LOG_ERROR("sql.sql", "Gameobject template %u not found in database!", entry);
2534 return nullptr;
2535 }
2536
2537 Map* map = GetMap();
2538 GameObject* go = GameObject::CreateGameObject(entry, map, pos, rot, 255, GO_STATE_READY);
2539 if (!go)
2540 return nullptr;
2541
2542 PhasingHandler::InheritPhaseShift(go, this);
2543
2544 go->SetRespawnTime(respawnTime);
2545 if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT) //not sure how to handle this
2546 ToUnit()->AddGameObject(go);
2547 else
2548 go->SetSpawnedByDefault(false);
2549
2550 map->AddToMap(go);
2551 return go;
2552 }
2553
2554 GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, QuaternionData const& rot, uint32 respawnTime)
2555 {
2556 if (!x && !y && !z)
2557 {
2558 GetClosePoint(x, y, z, GetObjectSize());
2559 ang = GetOrientation();
2560 }
2561
2562 Position pos(x, y, z, ang);
2563 return SummonGameObject(entry, pos, rot, respawnTime);
2564 }
2565
2566 Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint32 duration, CreatureAI* (*GetAI)(Creature*))
2567 {
2568 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
2569 Creature* summon = SummonCreature(WORLD_TRIGGER, x, y, z, ang, summonType, duration);
2570 if (!summon)
2571 return NULL;
2572
2573 //summon->SetName(GetName());
2574 if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT)
2575 {
2576 summon->setFaction(((Unit*)this)->getFaction());
2577 summon->SetLevel(((Unit*)this)->getLevel());
2578 }
2579
2580 if (GetAI)
2581 summon->AIM_Initialize(GetAI(summon));
2582 return summon;
2583 }
2584
2585 /**
2586 * Summons group of creatures. Should be called only by instances of Creature and GameObject classes.
2587 *
2588 * @param group Id of group to summon.
2589 * @param list List to store pointers to summoned creatures.
2590 */
2591 void WorldObject::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= NULL*/)
2592 {
2593 ASSERT((GetTypeId() == TYPEID_GAMEOBJECT || GetTypeId() == TYPEID_UNIT) && "Only GOs and creatures can summon npc groups!");
2594
2595 std::vector<TempSummonData> const* data = sObjectMgr->GetSummonGroup(GetEntry(), GetTypeId() == TYPEID_GAMEOBJECT ? SUMMONER_TYPE_GAMEOBJECT : SUMMONER_TYPE_CREATURE, group);
2596 if (!data)
2597 {
2598 TC_LOG_WARN("scripts", "%s (%s) tried to summon non-existing summon group %u.", GetName().c_str(), GetGUID().ToString().c_str(), group);
2599 return;
2600 }
2601
2602 for (std::vector<TempSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr)
2603 if (TempSummon* summon = SummonCreature(itr->entry, itr->pos, itr->type, itr->time))
2604 if (list)
2605 list->push_back(summon);
2606 }
2607
2608 Creature* WorldObject::FindNearestCreature(uint32 entry, float range, bool alive) const
2609 {
2610 Creature* creature = NULL;
2611 Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck checker(*this, entry, alive, range);
2612 Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(this, creature, checker);
2613 Cell::VisitAllObjects(this, searcher, range);
2614 return creature;
2615 }
2616
2617 GameObject* WorldObject::FindNearestGameObject(uint32 entry, float range) const
2618 {
2619 GameObject* go = NULL;
2620 Trinity::NearestGameObjectEntryInObjectRangeCheck checker(*this, entry, range);
2621 Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> searcher(this, go, checker);
2622 Cell::VisitGridObjects(this, searcher, range);
2623 return go;
2624 }
2625
2626 GameObject* WorldObject::FindNearestGameObjectOfType(GameobjectTypes type, float range) const
2627 {
2628 GameObject* go = NULL;
2629 Trinity::NearestGameObjectTypeInObjectRangeCheck checker(*this, type, range);
2630 Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectTypeInObjectRangeCheck> searcher(this, go, checker);
2631 Cell::VisitGridObjects(this, searcher, range);
2632 return go;
2633 }
2634
2635 template <typename Container>
2636 void WorldObject::GetGameObjectListWithEntryInGrid(Container& gameObjectContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const
2637 {
2638 Trinity::AllGameObjectsWithEntryInRange check(this, entry, maxSearchRange);
2639 Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange> searcher(this, gameObjectContainer, check);
2640 Cell::VisitGridObjects(this, searcher, maxSearchRange);
2641 }
2642
2643 template <typename Container>
2644 void WorldObject::GetCreatureListWithEntryInGrid(Container& creatureContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const
2645 {
2646 Trinity::AllCreaturesOfEntryInRange check(this, entry, maxSearchRange);
2647 Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(this, creatureContainer, check);
2648 Cell::VisitGridObjects(this, searcher, maxSearchRange);
2649 }
2650
2651 template <typename Container>
2652 void WorldObject::GetPlayerListInGrid(Container& playerContainer, float maxSearchRange) const
2653 {
2654 Trinity::AnyPlayerInObjectRangeCheck checker(this, maxSearchRange);
2655 Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, playerContainer, checker);
2656 Cell::VisitWorldObjects(this, searcher, maxSearchRange);
2657 }
2658
2659 void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle) const
2660 {
2661 x = GetPositionX() + (GetObjectSize() + distance2d) * std::cos(absAngle);
2662 y = GetPositionY() + (GetObjectSize() + distance2d) * std::sin(absAngle);
2663
2664 Trinity::NormalizeMapCoord(x);
2665 Trinity::NormalizeMapCoord(y);
2666 }
2667
2668 void WorldObject::GetNearPoint(WorldObject const* /*searcher*/, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle) const
2669 {
2670 GetNearPoint2D(x, y, distance2d+searcher_size, absAngle);
2671 z = GetPositionZ();
2672 // Should "searcher" be used instead of "this" when updating z coordinate ?
2673 UpdateAllowedPositionZ(x, y, z);
2674
2675 // if detection disabled, return first point
2676 if (!sWorld->getBoolConfig(CONFIG_DETECT_POS_COLLISION))
2677 return;
2678
2679 // return if the point is already in LoS
2680 if (IsWithinLOS(x, y, z))
2681 return;
2682
2683 // remember first point
2684 float first_x = x;
2685 float first_y = y;
2686 float first_z = z;
2687
2688 // loop in a circle to look for a point in LoS using small steps
2689 for (float angle = float(M_PI) / 8; angle < float(M_PI) * 2; angle += float(M_PI) / 8)
2690 {
2691 GetNearPoint2D(x, y, distance2d + searcher_size, absAngle + angle);
2692 z = GetPositionZ();
2693 UpdateAllowedPositionZ(x, y, z);
2694 if (IsWithinLOS(x, y, z))
2695 return;
2696 }
2697
2698 // still not in LoS, give up and return first position found
2699 x = first_x;
2700 y = first_y;
2701 z = first_z;
2702 }
2703
2704 void WorldObject::GetClosePoint(float &x, float &y, float &z, float size, float distance2d /*= 0*/, float angle /*= 0*/) const
2705 {
2706 // angle calculated from current orientation
2707 GetNearPoint(NULL, x, y, z, size, distance2d, GetOrientation() + angle);
2708 }
2709
2710 Position WorldObject::GetNearPosition(float dist, float angle)
2711 {
2712 Position pos = GetPosition();
2713 MovePosition(pos, dist, angle);
2714 return pos;
2715 }
2716
2717 Position WorldObject::GetFirstCollisionPosition(float dist, float angle)
2718 {
2719 Position pos = GetPosition();
2720 MovePositionToFirstCollision(pos, dist, angle);
2721 return pos;
2722 }
2723
2724 Position WorldObject::GetRandomNearPosition(float radius)
2725 {
2726 Position pos = GetPosition();
2727 MovePosition(pos, radius * (float)rand_norm(), (float)rand_norm() * static_cast<float>(2 * M_PI));
2728 return pos;
2729 }
2730
2731 void WorldObject::GetContactPoint(const WorldObject* obj, float &x, float &y, float &z, float distance2d /*= CONTACT_DISTANCE*/) const
2732 {
2733 // angle to face `obj` to `this` using distance includes size of `obj`
2734 GetNearPoint(obj, x, y, z, obj->GetObjectSize(), distance2d, GetAngle(obj));
2735 }
2736
2737 float WorldObject::GetObjectSize() const
2738 {
2739 return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE;
2740 }
2741
2742 void WorldObject::MovePosition(Position &pos, float dist, float angle)
2743 {
2744 angle += GetOrientation();
2745 float destx, desty, destz, ground, floor;
2746 destx = pos.m_positionX + dist * std::cos(angle);
2747 desty = pos.m_positionY + dist * std::sin(angle);
2748
2749 // Prevent invalid coordinates here, position is unchanged
2750 if (!Trinity::IsValidMapCoord(destx, desty, pos.m_positionZ))
2751 {
2752 TC_LOG_FATAL("misc", "WorldObject::MovePosition: Object (Entry: %u %s) has invalid coordinates X: %f and Y: %f were passed!",
2753 GetEntry(), GetGUID().ToString().c_str(), destx, desty);
2754 return;
2755 }
2756
2757 ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true);
2758 floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true);
2759 destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor;
2760
2761 float step = dist/10.0f;
2762
2763 for (uint8 j = 0; j < 10; ++j)
2764 {
2765 // do not allow too big z changes
2766 if (std::fabs(pos.m_positionZ - destz) > 6)
2767 {
2768 destx -= step * std::cos(angle);
2769 desty -= step * std::sin(angle);
2770 ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true);
2771 floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true);
2772 destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor;
2773 }
2774 // we have correct destz now
2775 else
2776 {
2777 pos.Relocate(destx, desty, destz);
2778 break;
2779 }
2780 }
2781
2782 Trinity::NormalizeMapCoord(pos.m_positionX);
2783 Trinity::NormalizeMapCoord(pos.m_positionY);
2784 UpdateGroundPositionZ(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
2785 pos.SetOrientation(GetOrientation());
2786 }
2787
2788 // @todo: replace with WorldObject::UpdateAllowedPositionZ
2789 float NormalizeZforCollision(WorldObject* obj, float x, float y, float z)
2790 {
2791 float ground = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, MAX_HEIGHT, true);
2792 float floor = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, z + 2.0f, true);
2793 float helper = std::fabs(ground - z) <= std::fabs(floor - z) ? ground : floor;
2794 if (z > helper) // must be above ground
2795 {
2796 if (Unit* unit = obj->ToUnit())
2797 {
2798 if (unit->CanFly())
2799 return z;
2800 }
2801 LiquidData liquid_status;
2802 ZLiquidStatus res = obj->GetMap()->getLiquidStatus(obj->GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
2803 if (res && liquid_status.level > helper) // water must be above ground
2804 {
2805 if (liquid_status.level > z) // z is underwater
2806 return z;
2807 else
2808 return std::fabs(liquid_status.level - z) <= std::fabs(helper - z) ? liquid_status.level : helper;
2809 }
2810 }
2811 return helper;
2812 }
2813
2814 void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float angle)
2815 {
2816 angle += GetOrientation();
2817 float destx, desty, destz;
2818 destx = pos.m_positionX + dist * std::cos(angle);
2819 desty = pos.m_positionY + dist * std::sin(angle);
2820
2821 // Prevent invalid coordinates here, position is unchanged
2822 if (!Trinity::IsValidMapCoord(destx, desty))
2823 {
2824 TC_LOG_FATAL("misc", "WorldObject::MovePositionToFirstCollision invalid coordinates X: %f and Y: %f were passed!", destx, desty);
2825 return;
2826 }
2827
2828 destz = NormalizeZforCollision(this, destx, desty, pos.GetPositionZ());
2829 bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(PhasingHandler::GetTerrainMapId(GetPhaseShift(), GetMap(), pos.m_positionX, pos.m_positionY),
2830 pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.5f, destx, desty, destz + 0.5f, destx, desty, destz, -0.5f);
2831
2832 // collision occured
2833 if (col)
2834 {
2835 // move back a bit
2836 destx -= CONTACT_DISTANCE * std::cos(angle);
2837 desty -= CONTACT_DISTANCE * std::sin(angle);
2838 dist = std::sqrt((pos.m_positionX - destx)*(pos.m_positionX - destx) + (pos.m_positionY - desty)*(pos.m_positionY - desty));
2839 }
2840
2841 // check dynamic collision
2842 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);
2843
2844 // Collided with a gameobject
2845 if (col)
2846 {
2847 destx -= CONTACT_DISTANCE * std::cos(angle);
2848 desty -= CONTACT_DISTANCE * std::sin(angle);
2849 dist = std::sqrt((pos.m_positionX - destx)*(pos.m_positionX - destx) + (pos.m_positionY - desty)*(pos.m_positionY - desty));
2850 }
2851
2852 float step = dist / 10.0f;
2853
2854 for (uint8 j = 0; j < 10; ++j)
2855 {
2856 // do not allow too big z changes
2857 if (std::fabs(pos.m_positionZ - destz) > 6.0f)
2858 {
2859 destx -= step * std::cos(angle);
2860 desty -= step * std::sin(angle);
2861 destz = NormalizeZforCollision(this, destx, desty, pos.GetPositionZ());
2862 }
2863 // we have correct destz now
2864 else
2865 {
2866 pos.Relocate(destx, desty, destz);
2867 break;
2868 }
2869 }
2870
2871 Trinity::NormalizeMapCoord(pos.m_positionX);
2872 Trinity::NormalizeMapCoord(pos.m_positionY);
2873 pos.m_positionZ = NormalizeZforCollision(this, destx, desty, pos.GetPositionZ());
2874 pos.SetOrientation(GetOrientation());
2875 }
2876
2877 void WorldObject::PlayDistanceSound(uint32 soundId, Player* target /*= nullptr*/)
2878 {
2879 if (target)
2880 target->SendDirectMessage(WorldPackets::Misc::PlaySpeakerbotSound(GetGUID(), soundId).Write());
2881 else
2882 SendMessageToSet(WorldPackets::Misc::PlaySpeakerbotSound(GetGUID(), soundId).Write(), true);
2883 }
2884
2885 void WorldObject::PlayDirectSound(uint32 soundId, Player* target /*= nullptr*/)
2886 {
2887 if (target)
2888 target->SendDirectMessage(WorldPackets::Misc::PlaySound(GetGUID(), soundId).Write());
2889 else
2890 SendMessageToSet(WorldPackets::Misc::PlaySound(GetGUID(), soundId).Write(), true);
2891 }
2892
2893 void WorldObject::PlayDirectMusic(uint32 musicId, Player* target /*= nullptr*/)
2894 {
2895 if (target)
2896 target->SendDirectMessage(WorldPackets::Misc::PlayMusic(musicId).Write());
2897 else
2898 SendMessageToSet(WorldPackets::Misc::PlayMusic(musicId).Write(), true);
2899 }
2900
2901 void WorldObject::DestroyForNearbyPlayers()
2902 {
2903 if (!IsInWorld())
2904 return;
2905
2906 std::list<Player*> targets;
2907 Trinity::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange(), false);
2908 Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, targets, check);
2909 Cell::VisitWorldObjects(this, searcher, GetVisibilityRange());
2910 for (std::list<Player*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
2911 {
2912 Player* player = (*iter);
2913
2914 if (player == this)
2915 continue;
2916
2917 if (!player->HaveAtClient(this))
2918 continue;
2919
2920 if (isType(TYPEMASK_UNIT) && ToUnit()->GetCharmerGUID() == player->GetGUID()) /// @todo this is for puppet
2921 continue;
2922
2923 DestroyForPlayer(player);
2924 player->m_clientGUIDs.erase(GetGUID());
2925 }
2926 }
2927
2928 void WorldObject::UpdateObjectVisibility(bool /*forced*/)
2929 {
2930 //updates object's visibility for nearby players
2931 Trinity::VisibleChangesNotifier notifier(*this);
2932 Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
2933 }
2934
2935 struct WorldObjectChangeAccumulator
2936 {
2937 UpdateDataMapType& i_updateDatas;
2938 WorldObject& i_object;
2939 GuidSet plr_list;
2940 WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) { }
2941 void Visit(PlayerMapType &m)
2942 {
2943 Player* source = NULL;
2944 for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
2945 {
2946 source = iter->GetSource();
2947
2948 BuildPacket(source);
2949
2950 if (!source->GetSharedVisionList().empty())
2951 {
2952 SharedVisionList::const_iterator it = source->GetSharedVisionList().begin();
2953 for (; it != source->GetSharedVisionList().end(); ++it)
2954 BuildPacket(*it);
2955 }
2956 }
2957 }
2958
2959 void Visit(CreatureMapType &m)
2960 {
2961 Creature* source = NULL;
2962 for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
2963 {
2964 source = iter->GetSource();
2965 if (!source->GetSharedVisionList().empty())
2966 {
2967 SharedVisionList::const_iterator it = source->GetSharedVisionList().begin();
2968 for (; it != source->GetSharedVisionList().end(); ++it)
2969 BuildPacket(*it);
2970 }
2971 }
2972 }
2973
2974 void Visit(DynamicObjectMapType &m)
2975 {
2976 DynamicObject* source = NULL;
2977 for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
2978 {
2979 source = iter->GetSource();
2980 ObjectGuid guid = source->GetCasterGUID();
2981
2982 if (guid.IsPlayer())
2983 {
2984 //Caster may be NULL if DynObj is in removelist
2985 if (Player* caster = ObjectAccessor::FindPlayer(guid))
2986 if (caster->GetGuidValue(PLAYER_FARSIGHT) == source->GetGUID())
2987 BuildPacket(caster);
2988 }
2989 }
2990 }
2991
2992 void BuildPacket(Player* player)
2993 {
2994 // Only send update once to a player
2995 if (plr_list.find(player->GetGUID()) == plr_list.end() && player->HaveAtClient(&i_object))
2996 {
2997 i_object.BuildFieldsUpdate(player, i_updateDatas);
2998 plr_list.insert(player->GetGUID());
2999 }
3000 }
3001
3002 template<class SKIP> void Visit(GridRefManager<SKIP> &) { }
3003 };
3004
3005 void WorldObject::BuildUpdate(UpdateDataMapType& data_map)
3006 {
3007 WorldObjectChangeAccumulator notifier(*this, data_map);
3008 //we must build packets for all visible players
3009 Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
3010
3011 ClearUpdateMask(false);
3012 }
3013
3014 void WorldObject::AddToObjectUpdate()
3015 {
3016 GetMap()->AddUpdateObject(this);
3017 }
3018
3019 void WorldObject::RemoveFromObjectUpdate()
3020 {
3021 GetMap()->RemoveUpdateObject(this);
3022 }
3023
3024 ObjectGuid WorldObject::GetTransGUID() const
3025 {
3026 if (GetTransport())
3027 return GetTransport()->GetGUID();
3028 return ObjectGuid::Empty;
3029 }
3030
3031 template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>&, uint32, float) const;
3032 template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque<GameObject*>&, uint32, float) const;
3033 template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector<GameObject*>&, uint32, float) const;
3034
3035 template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>&, uint32, float) const;
3036 template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::deque<Creature*>&, uint32, float) const;
3037 template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::vector<Creature*>&, uint32, float) const;
3038
3039 template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::list<Player*>&, float) const;
3040 template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::deque<Player*>&, float) const;
3041 template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::vector<Player*>&, float) const;