2 * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
3 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
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.
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
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/>.
20 #include "AreaTriggerTemplate.h"
21 #include "BattlefieldMgr.h"
23 #include "CinematicMgr.h"
26 #include "GridNotifiersImpl.h"
27 #include "InstanceScenario.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"
38 #include "SharedDefines.h"
39 #include "SpellAuraEffects.h"
40 #include "TemporarySummon.h"
42 #include "Transport.h"
44 #include "UpdateData.h"
45 #include "UpdateFieldFlags.h"
47 #include "VMapFactory.h"
50 #include "WorldSession.h"
51 #include <G3D/Vector3.h>
55 m_objectTypeId
= TYPEID_OBJECT
;
56 m_objectType
= TYPEMASK_OBJECT
;
57 m_updateFlag
= UPDATEFLAG_NONE
;
59 m_uint32Values
= nullptr;
60 _dynamicValues
= nullptr;
61 _dynamicChangesArrayMask
= nullptr;
63 _dynamicValuesCount
= 0;
64 _fieldNotifyFlags
= UF_FLAG_DYNAMIC
;
67 m_objectUpdated
= false;
70 WorldObject::~WorldObject()
72 // this may happen because there are many !create/delete
73 if (IsWorldObject() && m_currMap
)
75 if (GetTypeId() == TYPEID_CORPSE
)
77 TC_LOG_FATAL("misc", "WorldObject::~WorldObject Corpse Type: %d (%s) deleted but still in map!!",
78 ToCorpse()->GetType(), GetGUID().ToString().c_str());
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());
97 TC_LOG_FATAL("misc", "Object::~Object %s deleted but still in update list!!", GetGUID().ToString().c_str());
101 delete[] m_uint32Values
;
102 m_uint32Values
= nullptr;
104 delete[] _dynamicValues
;
105 _dynamicValues
= nullptr;
107 delete[] _dynamicChangesArrayMask
;
108 _dynamicChangesArrayMask
= nullptr;
111 void Object::_InitValues()
113 m_uint32Values
= new uint32
[m_valuesCount
];
114 memset(m_uint32Values
, 0, m_valuesCount
* sizeof(uint32
));
116 _changesMask
.resize(m_valuesCount
);
117 _dynamicChangesMask
.resize(_dynamicValuesCount
);
118 if (_dynamicValuesCount
)
120 _dynamicValues
= new std::vector
<uint32
>[_dynamicValuesCount
];
121 _dynamicChangesArrayMask
= new std::vector
<uint8
>[_dynamicValuesCount
];
124 m_objectUpdated
= false;
127 void Object::_Create(ObjectGuid
const& guid
)
129 if (!m_uint32Values
) _InitValues();
131 SetGuidValue(OBJECT_FIELD_GUID
, guid
);
132 SetUInt16Value(OBJECT_FIELD_TYPE
, 0, m_objectType
);
135 std::string
Object::_ConcatFields(uint16 startIndex
, uint16 size
) const
137 std::ostringstream ss
;
138 for (uint16 index
= 0; index
< size
; ++index
)
139 ss
<< GetUInt32Value(index
+ startIndex
) << ' ';
143 void Object::AddToWorld()
148 ASSERT(m_uint32Values
);
152 // synchronize values mirror with values array (changes will send in updatecreate opcode any way
153 ASSERT(!m_objectUpdated
);
154 ClearUpdateMask(false);
157 void Object::RemoveFromWorld()
164 // if we remove from world then sending changes not required
165 ClearUpdateMask(true);
168 void Object::BuildCreateUpdateBlockForPlayer(UpdateData
* data
, Player
* target
) const
173 uint8 updateType
= UPDATETYPE_CREATE_OBJECT
;
174 uint32 flags
= m_updateFlag
;
177 if (target
== this) // building packet for yourself
178 flags
|= UPDATEFLAG_SELF
;
180 switch (GetGUID().GetHigh())
182 case HighGuid::Player
:
184 case HighGuid::Corpse
:
185 case HighGuid::DynamicObject
:
186 case HighGuid::AreaTrigger
:
187 case HighGuid::Conversation
:
188 updateType
= UPDATETYPE_CREATE_OBJECT2
;
190 case HighGuid::Creature
:
191 case HighGuid::Vehicle
:
193 if (TempSummon
const* summon
= ToUnit()->ToTempSummon())
194 if (summon
->GetSummonerGUID().IsPlayer())
195 updateType
= UPDATETYPE_CREATE_OBJECT2
;
199 case HighGuid::GameObject
:
201 if (ToGameObject()->GetOwnerGUID().IsPlayer())
202 updateType
= UPDATETYPE_CREATE_OBJECT2
;
209 if (WorldObject
const* worldObject
= dynamic_cast<WorldObject
const*>(this))
211 if (!(flags
& UPDATEFLAG_LIVING
))
212 if (!worldObject
->m_movementInfo
.transport
.guid
.IsEmpty())
213 flags
|= UPDATEFLAG_TRANSPORT_POSITION
;
215 if (worldObject
->GetAIAnimKitId() || worldObject
->GetMovementAnimKitId() || worldObject
->GetMeleeAnimKitId())
216 flags
|= UPDATEFLAG_ANIMKITS
;
219 if (flags
& UPDATEFLAG_STATIONARY_POSITION
)
221 // UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
222 if (isType(TYPEMASK_GAMEOBJECT
))
224 switch (ToGameObject()->GetGoType())
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
;
238 if (Unit
const* unit
= ToUnit())
239 if (unit
->GetVictim())
240 flags
|= UPDATEFLAG_HAS_TARGET
;
242 ByteBuffer
buf(0x400);
243 buf
<< uint8(updateType
);
245 buf
<< uint8(m_objectTypeId
);
247 BuildMovementUpdate(&buf
, flags
);
248 BuildValuesUpdate(updateType
, &buf
, target
);
249 BuildDynamicValuesUpdate(updateType
, &buf
, target
);
250 data
->AddUpdateBlock(buf
);
253 void Object::SendUpdateToPlayer(Player
* player
)
255 // send create update to player
256 UpdateData
upd(player
->GetMapId());
259 if (player
->HaveAtClient(this))
260 BuildValuesUpdateBlockForPlayer(&upd
, player
);
262 BuildCreateUpdateBlockForPlayer(&upd
, player
);
263 upd
.BuildPacket(&packet
);
264 player
->SendDirectMessage(&packet
);
267 void Object::BuildValuesUpdateBlockForPlayer(UpdateData
* data
, Player
* target
) const
271 buf
<< uint8(UPDATETYPE_VALUES
);
274 BuildValuesUpdate(UPDATETYPE_VALUES
, &buf
, target
);
275 BuildDynamicValuesUpdate(UPDATETYPE_VALUES
, &buf
, target
);
277 data
->AddUpdateBlock(buf
);
280 void Object::BuildOutOfRangeUpdateBlock(UpdateData
* data
) const
282 data
->AddOutOfRangeGUID(GetGUID());
285 void Object::DestroyForPlayer(Player
* target
) const
289 UpdateData
updateData(target
->GetMapId());
290 BuildOutOfRangeUpdateBlock(&updateData
);
292 updateData
.BuildPacket(&packet
);
293 target
->SendDirectMessage(&packet
);
296 int32
Object::GetInt32Value(uint16 index
) const
298 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, false));
299 return m_int32Values
[index
];
302 uint32
Object::GetUInt32Value(uint16 index
) const
304 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, false));
305 return m_uint32Values
[index
];
308 uint64
Object::GetUInt64Value(uint16 index
) const
310 ASSERT(index
+ 1 < m_valuesCount
|| PrintIndexError(index
, false));
311 return *((uint64
*)&(m_uint32Values
[index
]));
314 float Object::GetFloatValue(uint16 index
) const
316 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, false));
317 return m_floatValues
[index
];
320 uint8
Object::GetByteValue(uint16 index
, uint8 offset
) const
322 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, false));
324 return *(((uint8
*)&m_uint32Values
[index
])+offset
);
327 uint16
Object::GetUInt16Value(uint16 index
, uint8 offset
) const
329 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, false));
331 return *(((uint16
*)&m_uint32Values
[index
])+offset
);
334 ObjectGuid
const& Object::GetGuidValue(uint16 index
) const
336 ASSERT(index
+ 1 < m_valuesCount
|| PrintIndexError(index
, false));
337 return *((ObjectGuid
*)&(m_uint32Values
[index
]));
340 void Object::BuildMovementUpdate(ByteBuffer
* data
, uint32 flags
) const
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())
363 if (go
->GetGoType() == GAMEOBJECT_TYPE_TRANSPORT
)
365 PauseTimes
= go
->GetGOValue()->Transport
.StopFrames
;
366 PauseTimesCount
= PauseTimes
->size();
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
);
389 if (HasMovementUpdate
)
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();
396 *data
<< GetGUID(); // MoverGUID
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());
404 *data
<< float(unit
->m_movementInfo
.pitch
); // Pitch
405 *data
<< float(unit
->m_movementInfo
.splineElevation
); // StepUpStartElevation
407 *data
<< uint32(0); // RemoveForcesIDs.size()
408 *data
<< uint32(0); // MoveIndex
410 //for (std::size_t i = 0; i < RemoveForcesIDs.size(); ++i)
411 // *data << ObjectGuid(RemoveForcesIDs);
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
421 if (!unit
->m_movementInfo
.transport
.guid
.IsEmpty())
422 *data
<< unit
->m_movementInfo
.transport
;
426 *data
<< uint32(unit
->m_movementInfo
.jump
.fallTime
); // Time
427 *data
<< float(unit
->m_movementInfo
.jump
.zspeed
); // JumpVelocity
429 if (data
->WriteBit(HasFallDirection
))
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
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
));
447 *data
<< uint32(0); // unit->m_movementInfo.forces.size()
449 data
->WriteBit(HasSpline
);
452 //for (std::size_t i = 0; i < unit->m_movementInfo.forces.size(); ++i)
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);
463 WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(*unit
->movespline
, *data
);
466 *data
<< uint32(PauseTimesCount
);
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());
478 *data
<< ToUnit()->GetVictim()->GetGUID(); // CombatVictim
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
488 if (go
&& go
->ToTransport()) // ServerTime
489 *data
<< uint32(go
->GetGOValue()->Transport
.PathProgress
);
491 *data
<< uint32(getMSTime());
496 Unit
const* unit
= ToUnit();
497 *data
<< uint32(unit
->GetVehicleKit()->GetVehicleInfo()->ID
); // RecID
498 *data
<< float(unit
->GetOrientation()); // InitialRawFacing
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
510 *data
<< uint64(ToGameObject()->GetPackedWorldRotation()); // Rotation
513 data
->append(PauseTimes
->data(), PauseTimes
->size());
515 if (HasMovementTransport
)
517 WorldObject
const* self
= static_cast<WorldObject
const*>(this);
518 *data
<< self
->m_movementInfo
.transport
;
523 AreaTrigger
const* areaTrigger
= ToAreaTrigger();
524 AreaTriggerMiscTemplate
const* areaTriggerMiscTemplate
= areaTrigger
->GetMiscTemplate();
525 AreaTriggerTemplate
const* areaTriggerTemplate
= areaTrigger
->GetTemplate();
527 *data
<< uint32(areaTrigger
->GetTimeSinceCreated());
529 *data
<< areaTrigger
->GetRollPitchYaw().PositionXYZStream();
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);
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
);
578 if (hasAreaTriggerSpline
)
580 *data
<< uint32(areaTrigger
->GetTimeToTarget());
581 *data
<< uint32(areaTrigger
->GetElapsedTimeForMovement());
583 WorldPackets::Movement::CommonMovement::WriteCreateObjectAreaTriggerSpline(areaTrigger
->GetSpline(), *data
);
586 if (hasTargetRollPitchYaw
)
587 *data
<< areaTrigger
->GetTargetRollPitchYaw().PositionXYZStream();
590 *data
<< uint32(areaTriggerMiscTemplate
->ScaleCurveId
);
593 *data
<< uint32(areaTriggerMiscTemplate
->MorphCurveId
);
595 if (hasFacingCurveID
)
596 *data
<< uint32(areaTriggerMiscTemplate
->FacingCurveId
);
599 *data
<< uint32(areaTriggerMiscTemplate
->MoveCurveId
);
607 if (hasAreaTriggerSphere
)
609 *data
<< float(areaTriggerTemplate
->SphereDatas
.Radius
);
610 *data
<< float(areaTriggerTemplate
->SphereDatas
.RadiusTarget
);
613 if (hasAreaTriggerBox
)
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]);
623 if (hasAreaTriggerPolygon
)
625 *data
<< int32(areaTriggerTemplate
->PolygonVertices
.size());
626 *data
<< int32(areaTriggerTemplate
->PolygonVerticesTarget
.size());
627 *data
<< float(areaTriggerTemplate
->PolygonDatas
.Height
);
628 *data
<< float(areaTriggerTemplate
->PolygonDatas
.HeightTarget
);
630 for (TaggedPosition
<Position::XY
> const& vertice
: areaTriggerTemplate
->PolygonVertices
)
633 for (TaggedPosition
<Position::XY
> const& vertice
: areaTriggerTemplate
->PolygonVerticesTarget
)
637 if (hasAreaTriggerCylinder
)
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
);
647 if (hasAreaTriggerUnkType
)
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);
658 packet.ReadSingle("Radius", index);
659 packet.ReadSingle("BlendFromRadius", index);
660 packet.ReadSingle("InitialAngel", index);
661 packet.ReadSingle("ZOffset", index);
664 packet.ReadPackedGuid128("AreaTriggerUnkGUID", index);
667 packet.ReadVector3("Center", index);*/
676 GameObject
const* gameObject
= ToGameObject();
678 *data
<< uint32(gameObject
->GetWorldEffectID());
680 data
->WriteBit(bit8
);
683 *data
<< uint32(Int1
);
688 // data->WriteBit(ReplaceActive);
689 // data->WriteBit(HasReplaceObject);
690 // data->FlushBits();
691 // if (HasReplaceObject)
692 // *data << ObjectGuid(ReplaceObject);
695 //if (SceneObjCreate)
697 // data->WriteBit(HasLocalScriptData);
698 // data->WriteBit(HasPetBattleFullUpdate);
699 // data->FlushBits();
701 // if (HasLocalScriptData)
703 // data->WriteBits(Data.length(), 7);
704 // data->FlushBits();
705 // data->WriteString(Data);
708 // if (HasPetBattleFullUpdate)
710 // for (std::size_t i = 0; i < 2; ++i)
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);
719 // data->WriteBits(Players[i].Pets.size(), 2);
720 // data->FlushBits();
721 // for (std::size_t j = 0; j < Players[i].Pets.size(); ++j)
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);
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)
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);
750 // for (std::size_t k = 0; k < Players[i].Pets[j].Auras.size(); ++k)
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);
759 // for (std::size_t k = 0; k < Players[i].Pets[j].States.size(); ++k)
761 // *data << uint32(Players[i].Pets[j].States[k].StateID);
762 // *data << int32(Players[i].Pets[j].States[k].StateValue);
765 // data->WriteBits(Players[i].Pets[j].CustomName.length(), 7);
766 // data->FlushBits();
767 // data->WriteString(Players[i].Pets[j].CustomName);
771 // for (std::size_t i = 0; i < 3; ++i)
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)
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);
784 // for (std::size_t j = 0; j < Enviros[j].States.size(); ++j)
786 // *data << uint32(Enviros[i].States[j].StateID);
787 // *data << int32(Enviros[i].States[j].StateValue);
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();
805 if (PlayerCreateData
)
807 bool HasSceneInstanceIDs
= false;
808 bool HasRuneState
= ToUnit()->GetPowerIndex(POWER_RUNES
) != MAX_POWERS
;
810 data
->WriteBit(HasSceneInstanceIDs
);
811 data
->WriteBit(HasRuneState
);
813 //if (HasSceneInstanceIDs)
815 // *data << uint32(SceneInstanceIDs.size());
816 // for (std::size_t i = 0; i < SceneInstanceIDs.size(); ++i)
817 // *data << uint32(SceneInstanceIDs[i]);
821 Player
const* player
= ToPlayer();
822 float baseCd
= float(player
->GetRuneBaseCooldown());
823 uint32 maxRunes
= uint32(player
->GetMaxPower(POWER_RUNES
));
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);
834 void Object::BuildValuesUpdate(uint8 updateType
, ByteBuffer
* data
, Player
* target
) const
839 std::size_t blockCount
= UpdateMask::GetBlockCount(m_valuesCount
);
841 uint32
* flags
= NULL
;
842 uint32 visibleFlag
= GetUpdateFieldData(target
, flags
);
845 *data
<< uint8(blockCount
);
846 std::size_t maskPos
= data
->wpos();
847 data
->resize(data
->size() + blockCount
* sizeof(UpdateMask::BlockType
));
849 for (uint16 index
= 0; index
< m_valuesCount
; ++index
)
851 if (_fieldNotifyFlags
& flags
[index
] ||
852 ((updateType
== UPDATETYPE_VALUES
? _changesMask
[index
] : m_uint32Values
[index
]) && (flags
[index
] & visibleFlag
)))
854 UpdateMask::SetUpdateBit(data
->contents() + maskPos
, index
);
855 *data
<< m_uint32Values
[index
];
860 void Object::BuildDynamicValuesUpdate(uint8 updateType
, ByteBuffer
* data
, Player
* target
) const
865 std::size_t blockCount
= UpdateMask::GetBlockCount(_dynamicValuesCount
);
867 uint32
* flags
= nullptr;
868 uint32 visibleFlag
= GetDynamicUpdateFieldData(target
, flags
);
870 *data
<< uint8(blockCount
);
871 std::size_t maskPos
= data
->wpos();
872 data
->resize(data
->size() + blockCount
* sizeof(UpdateMask::BlockType
));
874 for (uint16 index
= 0; index
< _dynamicValuesCount
; ++index
)
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
)))
880 UpdateMask::SetUpdateBit(data
->contents() + maskPos
, index
);
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());
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
)
891 if (updateType
!= UPDATETYPE_VALUES
|| _dynamicChangesArrayMask
[index
][v
])
893 UpdateMask::SetUpdateBit(data
->contents() + arrayMaskPos
, v
);
894 *data
<< uint32(values
[v
]);
901 void Object::AddToObjectUpdateIfNeeded()
903 if (m_inWorld
&& !m_objectUpdated
)
906 m_objectUpdated
= true;
910 void Object::ClearUpdateMask(bool remove
)
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());
920 RemoveFromObjectUpdate();
921 m_objectUpdated
= false;
925 void Object::BuildFieldsUpdate(Player
* player
, UpdateDataMapType
& data_map
) const
927 UpdateDataMapType::iterator iter
= data_map
.find(player
);
929 if (iter
== data_map
.end())
931 std::pair
<UpdateDataMapType::iterator
, bool> p
= data_map
.emplace(player
, UpdateData(player
->GetMapId()));
936 BuildValuesUpdateBlockForPlayer(&iter
->second
, iter
->first
);
939 uint32
Object::GetUpdateFieldData(Player
const* target
, uint32
*& flags
) const
941 uint32 visibleFlag
= UF_FLAG_PUBLIC
;
944 visibleFlag
|= UF_FLAG_PRIVATE
;
949 case TYPEID_CONTAINER
:
950 flags
= ItemUpdateFieldFlags
;
951 if (((Item
const*)this)->GetOwnerGUID() == target
->GetGUID())
952 visibleFlag
|= UF_FLAG_OWNER
| UF_FLAG_ITEM_OWNER
;
957 Player
* plr
= ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself();
958 flags
= UnitUpdateFieldFlags
;
959 if (ToUnit()->GetOwnerGUID() == target
->GetGUID())
960 visibleFlag
|= UF_FLAG_OWNER
;
962 if (HasFlag(OBJECT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_SPECIALINFO
))
963 if (ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY
, target
->GetGUID()))
964 visibleFlag
|= UF_FLAG_SPECIAL_INFO
;
966 if (plr
&& plr
->IsInSameRaidWith(target
))
967 visibleFlag
|= UF_FLAG_PARTY_MEMBER
;
970 case TYPEID_GAMEOBJECT
:
971 flags
= GameObjectUpdateFieldFlags
;
972 if (ToGameObject()->GetOwnerGUID() == target
->GetGUID())
973 visibleFlag
|= UF_FLAG_OWNER
;
975 case TYPEID_DYNAMICOBJECT
:
976 flags
= DynamicObjectUpdateFieldFlags
;
977 if (ToDynObject()->GetCasterGUID() == target
->GetGUID())
978 visibleFlag
|= UF_FLAG_OWNER
;
981 flags
= CorpseUpdateFieldFlags
;
982 if (ToCorpse()->GetOwnerGUID() == target
->GetGUID())
983 visibleFlag
|= UF_FLAG_OWNER
;
985 case TYPEID_AREATRIGGER
:
986 flags
= AreaTriggerUpdateFieldFlags
;
988 case TYPEID_SCENEOBJECT
:
989 flags
= SceneObjectUpdateFieldFlags
;
991 case TYPEID_CONVERSATION
:
992 flags
= ConversationUpdateFieldFlags
;
1002 uint32
Object::GetDynamicUpdateFieldData(Player
const* target
, uint32
*& flags
) const
1004 uint32 visibleFlag
= UF_FLAG_PUBLIC
;
1007 visibleFlag
|= UF_FLAG_PRIVATE
;
1009 switch (GetTypeId())
1012 case TYPEID_CONTAINER
:
1013 flags
= ItemDynamicUpdateFieldFlags
;
1014 if (((Item
const*)this)->GetOwnerGUID() == target
->GetGUID())
1015 visibleFlag
|= UF_FLAG_OWNER
| UF_FLAG_ITEM_OWNER
;
1020 Player
* plr
= ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself();
1021 flags
= UnitDynamicUpdateFieldFlags
;
1022 if (ToUnit()->GetOwnerGUID() == target
->GetGUID())
1023 visibleFlag
|= UF_FLAG_OWNER
;
1025 if (HasFlag(OBJECT_DYNAMIC_FLAGS
, UNIT_DYNFLAG_SPECIALINFO
))
1026 if (ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY
, target
->GetGUID()))
1027 visibleFlag
|= UF_FLAG_SPECIAL_INFO
;
1029 if (plr
&& plr
->IsInSameRaidWith(target
))
1030 visibleFlag
|= UF_FLAG_PARTY_MEMBER
;
1033 case TYPEID_GAMEOBJECT
:
1034 flags
= GameObjectDynamicUpdateFieldFlags
;
1036 case TYPEID_CONVERSATION
:
1037 flags
= ConversationDynamicUpdateFieldFlags
;
1039 if (ToConversation()->GetCreatorGuid() == target
->GetGUID())
1040 visibleFlag
|= UF_FLAG_0x100
;
1050 void Object::_LoadIntoDataField(std::string
const& data
, uint32 startOffset
, uint32 count
)
1055 Tokenizer
tokens(data
, ' ', count
);
1057 if (tokens
.size() != count
)
1060 for (uint32 index
= 0; index
< count
; ++index
)
1062 m_uint32Values
[startOffset
+ index
] = atoul(tokens
[index
]);
1063 _changesMask
[startOffset
+ index
] = 1;
1067 void Object::SetInt32Value(uint16 index
, int32 value
)
1069 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1071 if (m_int32Values
[index
] != value
)
1073 m_int32Values
[index
] = value
;
1074 _changesMask
[index
] = 1;
1076 AddToObjectUpdateIfNeeded();
1080 void Object::SetUInt32Value(uint16 index
, uint32 value
)
1082 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1084 if (m_uint32Values
[index
] != value
)
1086 m_uint32Values
[index
] = value
;
1087 _changesMask
[index
] = 1;
1089 AddToObjectUpdateIfNeeded();
1093 void Object::UpdateUInt32Value(uint16 index
, uint32 value
)
1095 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1097 m_uint32Values
[index
] = value
;
1098 _changesMask
[index
] = 1;
1101 void Object::SetUInt64Value(uint16 index
, uint64 value
)
1103 ASSERT(index
+ 1 < m_valuesCount
|| PrintIndexError(index
, true));
1104 if (*((uint64
*)&(m_uint32Values
[index
])) != value
)
1106 m_uint32Values
[index
] = PAIR64_LOPART(value
);
1107 m_uint32Values
[index
+ 1] = PAIR64_HIPART(value
);
1108 _changesMask
[index
] = 1;
1109 _changesMask
[index
+ 1] = 1;
1111 AddToObjectUpdateIfNeeded();
1115 bool Object::AddGuidValue(uint16 index
, ObjectGuid
const& value
)
1117 ASSERT(index
+ 3 < m_valuesCount
|| PrintIndexError(index
, true));
1118 if (!value
.IsEmpty() && ((ObjectGuid
*)&(m_uint32Values
[index
]))->IsEmpty())
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;
1126 AddToObjectUpdateIfNeeded();
1133 bool Object::RemoveGuidValue(uint16 index
, ObjectGuid
const& value
)
1135 ASSERT(index
+ 3 < m_valuesCount
|| PrintIndexError(index
, true));
1136 if (!value
.IsEmpty() && *((ObjectGuid
*)&(m_uint32Values
[index
])) == value
)
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;
1144 AddToObjectUpdateIfNeeded();
1151 void Object::SetFloatValue(uint16 index
, float value
)
1153 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1155 if (m_floatValues
[index
] != value
)
1157 m_floatValues
[index
] = value
;
1158 _changesMask
[index
] = 1;
1160 AddToObjectUpdateIfNeeded();
1164 void Object::SetByteValue(uint16 index
, uint8 offset
, uint8 value
)
1166 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1170 TC_LOG_ERROR("misc", "Object::SetByteValue: wrong offset %u", offset
);
1174 if (uint8(m_uint32Values
[index
] >> (offset
* 8)) != value
)
1176 m_uint32Values
[index
] &= ~uint32(uint32(0xFF) << (offset
* 8));
1177 m_uint32Values
[index
] |= uint32(uint32(value
) << (offset
* 8));
1178 _changesMask
[index
] = 1;
1180 AddToObjectUpdateIfNeeded();
1184 void Object::SetUInt16Value(uint16 index
, uint8 offset
, uint16 value
)
1186 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1190 TC_LOG_ERROR("misc", "Object::SetUInt16Value: wrong offset %u", offset
);
1194 if (uint16(m_uint32Values
[index
] >> (offset
* 16)) != value
)
1196 m_uint32Values
[index
] &= ~uint32(uint32(0xFFFF) << (offset
* 16));
1197 m_uint32Values
[index
] |= uint32(uint32(value
) << (offset
* 16));
1198 _changesMask
[index
] = 1;
1200 AddToObjectUpdateIfNeeded();
1204 void Object::SetGuidValue(uint16 index
, ObjectGuid
const& value
)
1206 ASSERT(index
+ 3 < m_valuesCount
|| PrintIndexError(index
, true));
1207 if (*((ObjectGuid
*)&(m_uint32Values
[index
])) != value
)
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;
1215 AddToObjectUpdateIfNeeded();
1219 void Object::SetStatFloatValue(uint16 index
, float value
)
1224 SetFloatValue(index
, value
);
1227 void Object::SetStatInt32Value(uint16 index
, int32 value
)
1232 SetUInt32Value(index
, uint32(value
));
1235 void Object::ApplyModUInt32Value(uint16 index
, int32 val
, bool apply
)
1237 int32 cur
= GetUInt32Value(index
);
1238 cur
+= (apply
? val
: -val
);
1241 SetUInt32Value(index
, cur
);
1244 void Object::ApplyModInt32Value(uint16 index
, int32 val
, bool apply
)
1246 int32 cur
= GetInt32Value(index
);
1247 cur
+= (apply
? val
: -val
);
1248 SetInt32Value(index
, cur
);
1251 void Object::ApplyModUInt16Value(uint16 index
, uint8 offset
, int16 val
, bool apply
)
1253 int16 cur
= GetUInt16Value(index
, offset
);
1254 cur
+= (apply
? val
: -val
);
1257 SetUInt16Value(index
, offset
, cur
);
1260 void Object::ApplyModSignedFloatValue(uint16 index
, float val
, bool apply
)
1262 float cur
= GetFloatValue(index
);
1263 cur
+= (apply
? val
: -val
);
1264 SetFloatValue(index
, cur
);
1267 void Object::ApplyPercentModFloatValue(uint16 index
, float val
, bool apply
)
1269 float value
= GetFloatValue(index
);
1270 ApplyPercentModFloatVar(value
, val
, apply
);
1271 SetFloatValue(index
, value
);
1274 void Object::ApplyModPositiveFloatValue(uint16 index
, float val
, bool apply
)
1276 float cur
= GetFloatValue(index
);
1277 cur
+= (apply
? val
: -val
);
1280 SetFloatValue(index
, cur
);
1283 void Object::SetFlag(uint16 index
, uint32 newFlag
)
1285 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1286 uint32 oldval
= m_uint32Values
[index
];
1287 uint32 newval
= oldval
| newFlag
;
1289 if (oldval
!= newval
)
1291 m_uint32Values
[index
] = newval
;
1292 _changesMask
[index
] = 1;
1294 AddToObjectUpdateIfNeeded();
1298 void Object::RemoveFlag(uint16 index
, uint32 oldFlag
)
1300 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1301 ASSERT(m_uint32Values
);
1303 uint32 oldval
= m_uint32Values
[index
];
1304 uint32 newval
= oldval
& ~oldFlag
;
1306 if (oldval
!= newval
)
1308 m_uint32Values
[index
] = newval
;
1309 _changesMask
[index
] = 1;
1311 AddToObjectUpdateIfNeeded();
1315 void Object::ToggleFlag(uint16 index
, uint32 flag
)
1317 if (HasFlag(index
, flag
))
1318 RemoveFlag(index
, flag
);
1320 SetFlag(index
, flag
);
1323 bool Object::HasFlag(uint16 index
, uint32 flag
) const
1325 if (index
>= m_valuesCount
&& !PrintIndexError(index
, false))
1328 return (m_uint32Values
[index
] & flag
) != 0;
1331 void Object::ApplyModFlag(uint16 index
, uint32 flag
, bool apply
)
1333 if (apply
) SetFlag(index
, flag
); else RemoveFlag(index
, flag
);
1336 void Object::SetByteFlag(uint16 index
, uint8 offset
, uint8 newFlag
)
1338 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1342 TC_LOG_ERROR("misc", "Object::SetByteFlag: wrong offset %u", offset
);
1346 if (!(uint8(m_uint32Values
[index
] >> (offset
* 8)) & newFlag
))
1348 m_uint32Values
[index
] |= uint32(uint32(newFlag
) << (offset
* 8));
1349 _changesMask
[index
] = 1;
1351 AddToObjectUpdateIfNeeded();
1355 void Object::RemoveByteFlag(uint16 index
, uint8 offset
, uint8 oldFlag
)
1357 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, true));
1361 TC_LOG_ERROR("misc", "Object::RemoveByteFlag: wrong offset %u", offset
);
1365 if (uint8(m_uint32Values
[index
] >> (offset
* 8)) & oldFlag
)
1367 m_uint32Values
[index
] &= ~uint32(uint32(oldFlag
) << (offset
* 8));
1368 _changesMask
[index
] = 1;
1370 AddToObjectUpdateIfNeeded();
1374 void Object::ToggleByteFlag(uint16 index
, uint8 offset
, uint8 flag
)
1376 if (HasByteFlag(index
, offset
, flag
))
1377 RemoveByteFlag(index
, offset
, flag
);
1379 SetByteFlag(index
, offset
, flag
);
1382 bool Object::HasByteFlag(uint16 index
, uint8 offset
, uint8 flag
) const
1384 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, false));
1386 return (((uint8
*)&m_uint32Values
[index
])[offset
] & flag
) != 0;
1389 void Object::SetFlag64(uint16 index
, uint64 newFlag
)
1391 uint64 oldval
= GetUInt64Value(index
);
1392 uint64 newval
= oldval
| newFlag
;
1393 SetUInt64Value(index
, newval
);
1396 void Object::RemoveFlag64(uint16 index
, uint64 oldFlag
)
1398 uint64 oldval
= GetUInt64Value(index
);
1399 uint64 newval
= oldval
& ~oldFlag
;
1400 SetUInt64Value(index
, newval
);
1403 void Object::ToggleFlag64(uint16 index
, uint64 flag
)
1405 if (HasFlag64(index
, flag
))
1406 RemoveFlag64(index
, flag
);
1408 SetFlag64(index
, flag
);
1411 bool Object::HasFlag64(uint16 index
, uint64 flag
) const
1413 ASSERT(index
< m_valuesCount
|| PrintIndexError(index
, false));
1414 return (GetUInt64Value(index
) & flag
) != 0;
1417 void Object::ApplyModFlag64(uint16 index
, uint64 flag
, bool apply
)
1419 if (apply
) SetFlag64(index
, flag
); else RemoveFlag64(index
, flag
);
1422 std::vector
<uint32
> const& Object::GetDynamicValues(uint16 index
) const
1424 ASSERT(index
< _dynamicValuesCount
|| PrintIndexError(index
, false));
1425 return _dynamicValues
[index
];
1428 uint32
Object::GetDynamicValue(uint16 index
, uint16 offset
) const
1430 ASSERT(index
< _dynamicValuesCount
|| PrintIndexError(index
, false));
1431 if (offset
>= _dynamicValues
[index
].size())
1433 return _dynamicValues
[index
][offset
];
1436 void Object::AddDynamicValue(uint16 index
, uint32 value
)
1438 ASSERT(index
< _dynamicValuesCount
|| PrintIndexError(index
, false));
1439 SetDynamicValue(index
, _dynamicValues
[index
].size(), value
);
1442 void Object::RemoveDynamicValue(uint16 index
, uint32 value
)
1444 ASSERT(index
< _dynamicValuesCount
|| PrintIndexError(index
, false));
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
)
1450 if (values
[i
] == value
)
1453 _dynamicChangesMask
[index
] = UpdateMask::VALUE_CHANGED
;
1454 _dynamicChangesArrayMask
[index
][i
] = 1;
1456 AddToObjectUpdateIfNeeded();
1461 void Object::ClearDynamicValue(uint16 index
)
1463 ASSERT(index
< _dynamicValuesCount
|| PrintIndexError(index
, false));
1465 if (!_dynamicValues
[index
].empty())
1467 _dynamicValues
[index
].clear();
1468 _dynamicChangesMask
[index
] = UpdateMask::VALUE_AND_SIZE_CHANGED
;
1469 _dynamicChangesArrayMask
[index
].clear();
1471 AddToObjectUpdateIfNeeded();
1475 void Object::SetDynamicValue(uint16 index
, uint16 offset
, uint32 value
)
1477 ASSERT(index
< _dynamicValuesCount
|| PrintIndexError(index
, false));
1479 UpdateMask::DynamicFieldChangeType changeType
= UpdateMask::VALUE_CHANGED
;
1480 std::vector
<uint32
>& values
= _dynamicValues
[index
];
1481 if (values
.size() <= offset
)
1483 values
.resize(offset
+ 1);
1484 changeType
= UpdateMask::VALUE_AND_SIZE_CHANGED
;
1487 if (_dynamicChangesArrayMask
[index
].size() <= offset
)
1488 _dynamicChangesArrayMask
[index
].resize((offset
/ 32 + 1) * 32);
1490 if (values
[offset
] != value
|| changeType
== UpdateMask::VALUE_AND_SIZE_CHANGED
)
1492 values
[offset
] = value
;
1493 _dynamicChangesMask
[index
] = changeType
;
1494 _dynamicChangesArrayMask
[index
][offset
] = 1;
1496 AddToObjectUpdateIfNeeded();
1500 bool Object::PrintIndexError(uint32 index
, bool set
) const
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
);
1504 // ASSERT must fail after function call
1508 void MovementInfo::OutDebug()
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())
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
);
1529 if ((flags
& (MOVEMENTFLAG_SWIMMING
| MOVEMENTFLAG_FLYING
)) || (flags2
& MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING
))
1530 TC_LOG_DEBUG("misc", "pitch: %f", pitch
);
1532 if (flags
& MOVEMENTFLAG_FALLING
|| jump
.fallTime
)
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
);
1539 if (flags
& MOVEMENTFLAG_SPLINE_ELEVATION
)
1540 TC_LOG_DEBUG("misc", "splineElevation: %f", splineElevation
);
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)
1548 m_serverSideVisibility
.SetValue(SERVERSIDE_VISIBILITY_GHOST
, GHOST_VISIBILITY_ALIVE
| GHOST_VISIBILITY_GHOST
);
1549 m_serverSideVisibilityDetect
.SetValue(SERVERSIDE_VISIBILITY_GHOST
, GHOST_VISIBILITY_ALIVE
);
1552 void WorldObject::SetWorldObject(bool on
)
1557 GetMap()->AddObjectToSwitchList(this, on
);
1560 bool WorldObject::IsWorldObject() const
1562 if (m_isWorldObject
)
1565 if (ToCreature() && ToCreature()->m_isTempWorldObject
)
1571 void WorldObject::setActive(bool on
)
1573 if (m_isActive
== on
)
1576 if (GetTypeId() == TYPEID_PLAYER
)
1584 Map
* map
= FindMap();
1590 if (GetTypeId() == TYPEID_UNIT
)
1591 map
->AddToActive(this->ToCreature());
1592 else if (GetTypeId() == TYPEID_DYNAMICOBJECT
)
1593 map
->AddToActive((DynamicObject
*)this);
1597 if (GetTypeId() == TYPEID_UNIT
)
1598 map
->RemoveFromActive(this->ToCreature());
1599 else if (GetTypeId() == TYPEID_DYNAMICOBJECT
)
1600 map
->RemoveFromActive((DynamicObject
*)this);
1604 void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
1609 if (Transport
* transport
= GetTransport())
1610 transport
->RemovePassenger(this);
1613 void WorldObject::RemoveFromWorld()
1618 DestroyForNearbyPlayers();
1620 Object::RemoveFromWorld();
1623 uint32
WorldObject::GetZoneId() const
1625 return GetMap()->GetZoneId(GetPhaseShift(), m_positionX
, m_positionY
, m_positionZ
);
1628 uint32
WorldObject::GetAreaId() const
1630 return GetMap()->GetAreaId(GetPhaseShift(), m_positionX
, m_positionY
, m_positionZ
);
1633 void WorldObject::GetZoneAndAreaId(uint32
& zoneid
, uint32
& areaid
) const
1635 GetMap()->GetZoneAndAreaId(GetPhaseShift(), zoneid
, areaid
, m_positionX
, m_positionY
, m_positionZ
);
1638 InstanceScript
* WorldObject::GetInstanceScript()
1640 Map
* map
= GetMap();
1641 return map
->IsDungeon() ? ((InstanceMap
*)map
)->GetInstanceScript() : NULL
;
1644 float WorldObject::GetDistanceZ(const WorldObject
* obj
) const
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);
1652 bool WorldObject::_IsWithinDist(WorldObject
const* obj
, float dist2compare
, bool is3D
) const
1654 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
1655 float maxdist
= dist2compare
+ sizefactor
;
1657 if (GetTransport() && obj
->GetTransport() && obj
->GetTransport()->GetGUID() == GetTransport()->GetGUID())
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
;
1664 float dtz
= m_movementInfo
.transport
.pos
.m_positionZ
- obj
->m_movementInfo
.transport
.pos
.m_positionZ
;
1665 disttsq
+= dtz
* dtz
;
1667 return disttsq
< (maxdist
* maxdist
);
1670 float dx
= GetPositionX() - obj
->GetPositionX();
1671 float dy
= GetPositionY() - obj
->GetPositionY();
1672 float distsq
= dx
*dx
+ dy
*dy
;
1675 float dz
= GetPositionZ() - obj
->GetPositionZ();
1679 return distsq
< maxdist
* maxdist
;
1682 bool WorldObject::IsWithinLOSInMap(const WorldObject
* obj
) const
1688 if (obj
->GetTypeId() == TYPEID_PLAYER
)
1689 obj
->GetPosition(x
, y
, z
);
1691 obj
->GetHitSpherePointFor(GetPosition(), x
, y
, z
);
1693 return IsWithinLOS(x
, y
, z
);
1696 float WorldObject::GetDistance(const WorldObject
* obj
) const
1698 float d
= GetExactDist(obj
) - GetObjectSize() - obj
->GetObjectSize();
1699 return d
> 0.0f
? d
: 0.0f
;
1702 float WorldObject::GetDistance(const Position
&pos
) const
1704 float d
= GetExactDist(&pos
) - GetObjectSize();
1705 return d
> 0.0f
? d
: 0.0f
;
1708 float WorldObject::GetDistance(float x
, float y
, float z
) const
1710 float d
= GetExactDist(x
, y
, z
) - GetObjectSize();
1711 return d
> 0.0f
? d
: 0.0f
;
1714 float WorldObject::GetDistance2d(const WorldObject
* obj
) const
1716 float d
= GetExactDist2d(obj
) - GetObjectSize() - obj
->GetObjectSize();
1717 return d
> 0.0f
? d
: 0.0f
;
1720 float WorldObject::GetDistance2d(float x
, float y
) const
1722 float d
= GetExactDist2d(x
, y
) - GetObjectSize();
1723 return d
> 0.0f
? d
: 0.0f
;
1726 bool WorldObject::IsSelfOrInSameMap(const WorldObject
* obj
) const
1730 return IsInMap(obj
);
1733 bool WorldObject::IsInMap(const WorldObject
* obj
) const
1736 return IsInWorld() && obj
->IsInWorld() && (GetMap() == obj
->GetMap());
1740 bool WorldObject::IsWithinDist3d(float x
, float y
, float z
, float dist
) const
1742 return IsInDist(x
, y
, z
, dist
+ GetObjectSize());
1745 bool WorldObject::IsWithinDist3d(const Position
* pos
, float dist
) const
1747 return IsInDist(pos
, dist
+ GetObjectSize());
1750 bool WorldObject::IsWithinDist2d(float x
, float y
, float dist
) const
1752 return IsInDist2d(x
, y
, dist
+ GetObjectSize());
1755 bool WorldObject::IsWithinDist2d(const Position
* pos
, float dist
) const
1757 return IsInDist2d(pos
, dist
+ GetObjectSize());
1760 bool WorldObject::IsWithinDist(WorldObject
const* obj
, float dist2compare
, bool is3D
/*= true*/) const
1762 return obj
&& _IsWithinDist(obj
, dist2compare
, is3D
);
1765 bool WorldObject::IsWithinDistInMap(WorldObject
const* obj
, float dist2compare
, bool is3D
/*= true*/) const
1767 return obj
&& IsInMap(obj
) && IsInPhase(obj
) && _IsWithinDist(obj
, dist2compare
, is3D
);
1770 bool WorldObject::IsWithinLOS(float ox
, float oy
, float oz
) const
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);*/
1779 if (GetTypeId() == TYPEID_PLAYER
)
1780 GetPosition(x
, y
, z
);
1782 GetHitSpherePointFor({ ox
, oy
, oz
}, x
, y
, z
);
1784 return GetMap()->isInLineOfSight(GetPhaseShift(), x
, y
, z
+ 2.0f
, ox
, oy
, oz
+ 2.0f
);
1790 Position
WorldObject::GetHitSpherePointFor(Position
const& dest
) const
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();
1796 return Position(contactPoint
.x
, contactPoint
.y
, contactPoint
.z
, GetAngle(contactPoint
.x
, contactPoint
.y
));
1799 void WorldObject::GetHitSpherePointFor(Position
const& dest
, float& x
, float& y
, float& z
) const
1801 Position pos
= GetHitSpherePointFor(dest
);
1802 x
= pos
.GetPositionX();
1803 y
= pos
.GetPositionY();
1804 z
= pos
.GetPositionZ();
1807 bool WorldObject::GetDistanceOrder(WorldObject
const* obj1
, WorldObject
const* obj2
, bool is3D
/* = true */) const
1809 float dx1
= GetPositionX() - obj1
->GetPositionX();
1810 float dy1
= GetPositionY() - obj1
->GetPositionY();
1811 float distsq1
= dx1
*dx1
+ dy1
*dy1
;
1814 float dz1
= GetPositionZ() - obj1
->GetPositionZ();
1818 float dx2
= GetPositionX() - obj2
->GetPositionX();
1819 float dy2
= GetPositionY() - obj2
->GetPositionY();
1820 float distsq2
= dx2
*dx2
+ dy2
*dy2
;
1823 float dz2
= GetPositionZ() - obj2
->GetPositionZ();
1827 return distsq1
< distsq2
;
1830 bool WorldObject::IsInRange(WorldObject
const* obj
, float minRange
, float maxRange
, bool is3D
/* = true */) const
1832 float dx
= GetPositionX() - obj
->GetPositionX();
1833 float dy
= GetPositionY() - obj
->GetPositionY();
1834 float distsq
= dx
*dx
+ dy
*dy
;
1837 float dz
= GetPositionZ() - obj
->GetPositionZ();
1841 float sizefactor
= GetObjectSize() + obj
->GetObjectSize();
1843 // check only for real range
1844 if (minRange
> 0.0f
)
1846 float mindist
= minRange
+ sizefactor
;
1847 if (distsq
< mindist
* mindist
)
1851 float maxdist
= maxRange
+ sizefactor
;
1852 return distsq
< maxdist
* maxdist
;
1855 bool WorldObject::IsInRange2d(float x
, float y
, float minRange
, float maxRange
) const
1857 float dx
= GetPositionX() - x
;
1858 float dy
= GetPositionY() - y
;
1859 float distsq
= dx
*dx
+ dy
*dy
;
1861 float sizefactor
= GetObjectSize();
1863 // check only for real range
1864 if (minRange
> 0.0f
)
1866 float mindist
= minRange
+ sizefactor
;
1867 if (distsq
< mindist
* mindist
)
1871 float maxdist
= maxRange
+ sizefactor
;
1872 return distsq
< maxdist
* maxdist
;
1875 bool WorldObject::IsInRange3d(float x
, float y
, float z
, float minRange
, float maxRange
) const
1877 float dx
= GetPositionX() - x
;
1878 float dy
= GetPositionY() - y
;
1879 float dz
= GetPositionZ() - z
;
1880 float distsq
= dx
*dx
+ dy
*dy
+ dz
*dz
;
1882 float sizefactor
= GetObjectSize();
1884 // check only for real range
1885 if (minRange
> 0.0f
)
1887 float mindist
= minRange
+ sizefactor
;
1888 if (distsq
< mindist
* mindist
)
1892 float maxdist
= maxRange
+ sizefactor
;
1893 return distsq
< maxdist
* maxdist
;
1896 bool WorldObject::IsInBetween(Position
const& pos1
, Position
const& pos2
, float size
) const
1898 float dist
= GetExactDist2d(pos1
);
1900 // not using sqrt() for performance
1901 if ((dist
* dist
) >= pos1
.GetExactDist2dSq(pos2
))
1905 size
= GetObjectSize() / 2;
1907 float angle
= pos1
.GetAngle(pos2
);
1909 // not using sqrt() for performance
1910 return (size
* size
) >= GetExactDist2dSq(pos1
.GetPositionX() + std::cos(angle
) * dist
, pos1
.GetPositionY() + std::sin(angle
) * dist
);
1913 bool WorldObject::isInFront(WorldObject
const* target
, float arc
) const
1915 return HasInArc(arc
, target
);
1918 bool WorldObject::isInBack(WorldObject
const* target
, float arc
) const
1920 return !HasInArc(2 * float(M_PI
) - arc
, target
);
1923 void WorldObject::GetRandomPoint(const Position
&pos
, float distance
, float &rand_x
, float &rand_y
, float &rand_z
) const
1927 pos
.GetPosition(rand_x
, rand_y
, rand_z
);
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
);
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
;
1940 Trinity::NormalizeMapCoord(rand_x
);
1941 Trinity::NormalizeMapCoord(rand_y
);
1942 UpdateGroundPositionZ(rand_x
, rand_y
, rand_z
); // update to LOS height if available
1945 Position
WorldObject::GetRandomPoint(const Position
&srcPos
, float distance
) const
1948 GetRandomPoint(srcPos
, distance
, x
, y
, z
);
1949 return Position(x
, y
, z
, GetOrientation());
1952 void WorldObject::UpdateGroundPositionZ(float x
, float y
, float &z
) const
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
1959 void WorldObject::UpdateAllowedPositionZ(float x
, float y
, float &z
) const
1961 // TODO: Allow transports to be part of dynamic vmap tree
1965 switch (GetTypeId())
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())
1973 bool canSwim
= ToCreature()->CanSwim();
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
)
1982 else if (z
< ground_z
)
1988 float ground_z
= GetMap()->GetHeight(GetPhaseShift(), x
, y
, z
, true);
1996 // for server controlled moves playr work same as creature (but it can always swim)
1997 if (!ToPlayer()->CanFly())
2000 float max_z
= GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x
, y
, z
, &ground_z
, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK
));
2001 if (max_z
> INVALID_HEIGHT
)
2005 else if (z
< ground_z
)
2011 float ground_z
= GetMap()->GetHeight(GetPhaseShift(), x
, y
, z
, true);
2019 float ground_z
= GetMap()->GetHeight(GetPhaseShift(), x
, y
, z
, true);
2020 if (ground_z
> INVALID_HEIGHT
)
2027 float WorldObject::GetGridActivationRange() const
2031 if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
2032 return DEFAULT_VISIBILITY_INSTANCE
;
2033 return GetMap()->GetVisibilityRange();
2035 else if (ToCreature())
2036 return ToCreature()->m_SightDistance
;
2037 else if (ToDynObject())
2039 if (isActiveObject())
2040 return GetMap()->GetVisibilityRange();
2048 float WorldObject::GetVisibilityRange() const
2050 if (isActiveObject() && !ToPlayer())
2051 return MAX_VISIBILITY_DISTANCE
;
2053 return GetMap()->GetVisibilityRange();
2056 float WorldObject::GetSightRange(const WorldObject
* target
) const
2062 if (target
&& target
->isActiveObject() && !target
->ToPlayer())
2063 return MAX_VISIBILITY_DISTANCE
;
2064 else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
2065 return DEFAULT_VISIBILITY_INSTANCE
;
2067 return GetMap()->GetVisibilityRange();
2069 else if (ToCreature())
2070 return ToCreature()->m_SightDistance
;
2072 return SIGHT_RANGE_UNIT
;
2075 if (ToDynObject() && isActiveObject())
2077 return GetMap()->GetVisibilityRange();
2083 bool WorldObject::CanSeeOrDetect(WorldObject
const* obj
, bool ignoreStealth
, bool distanceCheck
, bool checkAlert
) const
2088 if (obj
->IsNeverVisibleFor(this) || CanNeverSee(obj
))
2091 if (obj
->IsAlwaysVisibleFor(this) || CanAlwaysSee(obj
))
2094 bool corpseVisibility
= false;
2097 bool corpseCheck
= false;
2098 if (Player
const* thisPlayer
= ToPlayer())
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
))
2103 if (Corpse
* corpse
= thisPlayer
->GetCorpse())
2106 if (corpse
->IsWithinDist(thisPlayer
, GetSightRange(obj
), false))
2107 if (corpse
->IsWithinDist(obj
, GetSightRange(obj
), false))
2108 corpseVisibility
= true;
2113 WorldObject
const* viewpoint
= this;
2114 if (Player
const* player
= this->ToPlayer())
2115 viewpoint
= player
->GetViewpoint();
2120 if (!corpseCheck
&& !viewpoint
->IsWithinDist(obj
, GetSightRange(obj
), false))
2124 // GM visibility off or hidden NPC
2125 if (!obj
->m_serverSideVisibility
.GetValue(SERVERSIDE_VISIBILITY_GM
))
2127 // Stop checking other things for GMs
2128 if (m_serverSideVisibilityDetect
.GetValue(SERVERSIDE_VISIBILITY_GM
))
2132 return m_serverSideVisibilityDetect
.GetValue(SERVERSIDE_VISIBILITY_GM
) >= obj
->m_serverSideVisibility
.GetValue(SERVERSIDE_VISIBILITY_GM
);
2134 // Ghost players, Spirit Healers, and some other NPCs
2135 if (!corpseVisibility
&& !(obj
->m_serverSideVisibility
.GetValue(SERVERSIDE_VISIBILITY_GHOST
) & m_serverSideVisibilityDetect
.GetValue(SERVERSIDE_VISIBILITY_GHOST
)))
2137 // Alive players can see dead players in some cases, but other objects can't do that
2138 if (Player
const* thisPlayer
= ToPlayer())
2140 if (Player
const* objPlayer
= obj
->ToPlayer())
2142 if (thisPlayer
->GetTeam() != objPlayer
->GetTeam() || !thisPlayer
->IsGroupVisibleFor(objPlayer
))
2152 if (obj
->IsInvisibleDueToDespawn())
2155 if (!CanDetect(obj
, ignoreStealth
, checkAlert
))
2161 bool WorldObject::CanNeverSee(WorldObject
const* obj
) const
2163 return GetMap() != obj
->GetMap() || !IsInPhase(obj
);
2166 bool WorldObject::CanDetect(WorldObject
const* obj
, bool ignoreStealth
, bool checkAlert
) const
2168 const WorldObject
* seer
= this;
2170 // Pets don't have detection, they use the detection of their masters
2171 if (Unit
const* thisUnit
= ToUnit())
2172 if (Unit
* controller
= thisUnit
->GetCharmerOrOwner())
2175 if (obj
->IsAlwaysDetectableFor(seer
))
2178 if (!ignoreStealth
&& !seer
->CanDetectInvisibilityOf(obj
))
2181 if (!ignoreStealth
&& !seer
->CanDetectStealthOf(obj
, checkAlert
))
2187 bool WorldObject::CanDetectInvisibilityOf(WorldObject
const* obj
) const
2189 uint32 mask
= obj
->m_invisibility
.GetFlags() & m_invisibilityDetect
.GetFlags();
2191 // Check for not detected types
2192 if (mask
!= obj
->m_invisibility
.GetFlags())
2195 for (uint32 i
= 0; i
< TOTAL_INVISIBILITY_TYPES
; ++i
)
2197 if (!(mask
& (1 << i
)))
2200 int32 objInvisibilityValue
= obj
->m_invisibility
.GetValue(InvisibilityType(i
));
2201 int32 ownInvisibilityDetectValue
= m_invisibilityDetect
.GetValue(InvisibilityType(i
));
2203 // Too low value to detect
2204 if (ownInvisibilityDetectValue
< objInvisibilityValue
)
2211 bool WorldObject::CanDetectStealthOf(WorldObject
const* obj
, bool checkAlert
) const
2213 // Combat reach is the minimal distance (both in front and behind),
2214 // and it is also used in the range calculation.
2215 // One stealth point increases the visibility range by 0.3 yard.
2217 if (!obj
->m_stealth
.GetFlags())
2220 float distance
= GetExactDist(obj
);
2221 float combatReach
= 0.0f
;
2223 Unit
const* unit
= ToUnit();
2225 combatReach
= unit
->GetCombatReach();
2227 if (distance
< combatReach
)
2230 if (!HasInArc(float(M_PI
), obj
))
2233 GameObject
const* go
= ToGameObject();
2234 for (uint32 i
= 0; i
< TOTAL_STEALTH_TYPES
; ++i
)
2236 if (!(obj
->m_stealth
.GetFlags() & (1 << i
)))
2239 if (unit
&& unit
->HasAuraTypeWithMiscvalue(SPELL_AURA_DETECT_STEALTH
, i
))
2243 int32 detectionValue
= 30;
2245 // Level difference: 5 point / level, starting from level 1.
2246 // There may be spells for this and the starting points too, but
2247 // not in the DBCs of the client.
2248 detectionValue
+= int32(GetLevelForTarget(obj
) - 1) * 5;
2251 detectionValue
+= m_stealthDetect
.GetValue(StealthType(i
));
2253 if (Unit
* owner
= go
->GetOwner())
2254 detectionValue
-= int32(owner
->GetLevelForTarget(this) - 1) * 5;
2256 detectionValue
-= obj
->m_stealth
.GetValue(StealthType(i
));
2258 // Calculate max distance
2259 float visibilityRange
= float(detectionValue
) * 0.3f
+ combatReach
;
2261 // If this unit is an NPC then player detect range doesn't apply
2262 if (unit
&& unit
->GetTypeId() == TYPEID_PLAYER
&& visibilityRange
> MAX_PLAYER_STEALTH_DETECT_RANGE
)
2263 visibilityRange
= MAX_PLAYER_STEALTH_DETECT_RANGE
;
2265 // When checking for alert state, look 8% further, and then 1.5 yards more than that.
2267 visibilityRange
+= (visibilityRange
* 0.08f
) + 1.5f
;
2269 // If checking for alert, and creature's visibility range is greater than aggro distance, No alert
2270 Unit
const* tunit
= obj
->ToUnit();
2271 if (checkAlert
&& unit
&& unit
->ToCreature() && visibilityRange
>= unit
->ToCreature()->GetAttackDistance(tunit
) + unit
->ToCreature()->m_CombatDistance
)
2274 if (distance
> visibilityRange
)
2281 void Object::ForceValuesUpdateAtIndex(uint32 i
)
2283 _changesMask
[i
] = 1;
2284 AddToObjectUpdateIfNeeded();
2287 void WorldObject::SendMessageToSet(WorldPacket
const* data
, bool self
) const
2290 SendMessageToSetInRange(data
, GetVisibilityRange(), self
);
2293 void WorldObject::SendMessageToSetInRange(WorldPacket
const* data
, float dist
, bool /*self*/) const
2295 Trinity::MessageDistDeliverer
notifier(this, data
, dist
);
2296 Cell::VisitWorldObjects(this, notifier
, dist
);
2299 void WorldObject::SendMessageToSet(WorldPacket
const* data
, Player
const* skipped_rcvr
) const
2301 Trinity::MessageDistDeliverer
notifier(this, data
, GetVisibilityRange(), false, skipped_rcvr
);
2302 Cell::VisitWorldObjects(this, notifier
, GetVisibilityRange());
2305 void WorldObject::SetMap(Map
* map
)
2308 ASSERT(!IsInWorld());
2309 if (m_currMap
== map
) // command add npc: first create, than loadfromdb
2313 TC_LOG_FATAL("misc", "WorldObject::SetMap: obj %u new map %u %u, old map %u %u", (uint32
)GetTypeId(), map
->GetId(), map
->GetInstanceId(), m_currMap
->GetId(), m_currMap
->GetInstanceId());
2317 m_mapId
= map
->GetId();
2318 m_InstanceId
= map
->GetInstanceId();
2319 if (IsWorldObject())
2320 m_currMap
->AddWorldObject(this);
2323 void WorldObject::ResetMap()
2326 ASSERT(!IsInWorld());
2327 if (IsWorldObject())
2328 m_currMap
->RemoveWorldObject(this);
2330 //maybe not for corpse
2335 void WorldObject::AddObjectToRemoveList()
2337 ASSERT(m_uint32Values
);
2339 Map
* map
= FindMap();
2342 TC_LOG_ERROR("misc", "Object (Entry: %u %s) at attempt add to move list not have valid map (Id: %u).", GetEntry(), GetGUID().ToString().c_str(), GetMapId());
2346 map
->AddObjectToRemoveList(this);
2349 TempSummon
* Map::SummonCreature(uint32 entry
, Position
const& pos
, SummonPropertiesEntry
const* properties
/*= NULL*/, uint32 duration
/*= 0*/, Unit
* summoner
/*= NULL*/, uint32 spellId
/*= 0*/, uint32 vehId
/*= 0*/)
2351 uint32 mask
= UNIT_MASK_SUMMON
;
2354 switch (properties
->Control
)
2356 case SUMMON_CATEGORY_PET
:
2357 mask
= UNIT_MASK_GUARDIAN
;
2359 case SUMMON_CATEGORY_PUPPET
:
2360 mask
= UNIT_MASK_PUPPET
;
2362 case SUMMON_CATEGORY_VEHICLE
:
2363 mask
= UNIT_MASK_MINION
;
2365 case SUMMON_CATEGORY_WILD
:
2366 case SUMMON_CATEGORY_ALLY
:
2367 case SUMMON_CATEGORY_UNK
:
2369 switch (properties
->Title
)
2371 case SUMMON_TYPE_MINION
:
2372 case SUMMON_TYPE_GUARDIAN
:
2373 case SUMMON_TYPE_GUARDIAN2
:
2374 mask
= UNIT_MASK_GUARDIAN
;
2376 case SUMMON_TYPE_TOTEM
:
2377 case SUMMON_TYPE_LIGHTWELL
:
2378 mask
= UNIT_MASK_TOTEM
;
2380 case SUMMON_TYPE_VEHICLE
:
2381 case SUMMON_TYPE_VEHICLE2
:
2382 mask
= UNIT_MASK_SUMMON
;
2384 case SUMMON_TYPE_MINIPET
:
2385 mask
= UNIT_MASK_MINION
;
2388 if (properties
->Flags
& 512) // Mirror Image, Summon Gargoyle
2389 mask
= UNIT_MASK_GUARDIAN
;
2399 TempSummon
* summon
= nullptr;
2402 case UNIT_MASK_SUMMON
:
2403 summon
= new TempSummon(properties
, summoner
, false);
2405 case UNIT_MASK_GUARDIAN
:
2406 summon
= new Guardian(properties
, summoner
, false);
2408 case UNIT_MASK_PUPPET
:
2409 summon
= new Puppet(properties
, summoner
);
2411 case UNIT_MASK_TOTEM
:
2412 summon
= new Totem(properties
, summoner
);
2414 case UNIT_MASK_MINION
:
2415 summon
= new Minion(properties
, summoner
, false);
2419 if (!summon
->Create(GenerateLowGuid
<HighGuid::Creature
>(), this, entry
, pos
.GetPositionX(), pos
.GetPositionY(), pos
.GetPositionZ(), pos
.GetOrientation(), nullptr, vehId
))
2425 // Set the summon to the summoner's phase
2427 PhasingHandler::InheritPhaseShift(summon
, summoner
);
2429 summon
->SetUInt32Value(UNIT_CREATED_BY_SPELL
, spellId
);
2431 summon
->SetHomePosition(pos
);
2433 summon
->InitStats(duration
);
2434 AddToMap(summon
->ToCreature());
2435 summon
->InitSummon();
2437 // call MoveInLineOfSight for nearby creatures
2438 Trinity::AIRelocationNotifier
notifier(*summon
);
2439 Cell::VisitAllObjects(summon
, notifier
, GetVisibilityRange());
2445 * Summons group of creatures.
2447 * @param group Id of group to summon.
2448 * @param list List to store pointers to summoned creatures.
2451 void Map::SummonCreatureGroup(uint8 group
, std::list
<TempSummon
*>* list
/*= NULL*/)
2453 std::vector
<TempSummonData
> const* data
= sObjectMgr
->GetSummonGroup(GetId(), SUMMONER_TYPE_MAP
, group
);
2457 for (std::vector
<TempSummonData
>::const_iterator itr
= data
->begin(); itr
!= data
->end(); ++itr
)
2458 if (TempSummon
* summon
= SummonCreature(itr
->entry
, itr
->pos
, NULL
, itr
->time
))
2460 list
->push_back(summon
);
2463 void WorldObject::SetZoneScript()
2465 if (Map
* map
= FindMap())
2467 if (map
->IsDungeon())
2468 m_zoneScript
= (ZoneScript
*)((InstanceMap
*)map
)->GetInstanceScript();
2469 else if (!map
->IsBattlegroundOrArena())
2471 if (Battlefield
* bf
= sBattlefieldMgr
->GetBattlefieldToZoneId(GetZoneId()))
2474 m_zoneScript
= sOutdoorPvPMgr
->GetZoneScript(GetZoneId());
2479 Scenario
* WorldObject::GetScenario() const
2482 if (InstanceMap
* instanceMap
= GetMap()->ToInstanceMap())
2483 return instanceMap
->GetInstanceScenario();
2488 TempSummon
* WorldObject::SummonCreature(uint32 entry
, Position
const& pos
, TempSummonType spwtype
/*= TEMPSUMMON_MANUAL_DESPAWN*/, uint32 duration
/*= 0*/, uint32
/*vehId = 0*/) const
2490 if (Map
* map
= FindMap())
2492 if (TempSummon
* summon
= map
->SummonCreature(entry
, pos
, NULL
, duration
, isType(TYPEMASK_UNIT
) ? (Unit
*)this : NULL
))
2494 summon
->SetTempSummonType(spwtype
);
2502 TempSummon
* WorldObject::SummonCreature(uint32 id
, float x
, float y
, float z
, float ang
/*= 0*/, TempSummonType spwtype
/*= TEMPSUMMON_MANUAL_DESPAWN*/, uint32 despwtime
/*= 0*/) const
2506 GetClosePoint(x
, y
, z
, GetObjectSize());
2507 ang
= GetOrientation();
2511 pos
.Relocate(x
, y
, z
, ang
);
2512 return SummonCreature(id
, pos
, spwtype
, despwtime
, 0);
2515 GameObject
* WorldObject::SummonGameObject(uint32 entry
, Position
const& pos
, QuaternionData
const& rot
, uint32 respawnTime
)
2520 GameObjectTemplate
const* goinfo
= sObjectMgr
->GetGameObjectTemplate(entry
);
2523 TC_LOG_ERROR("sql.sql", "Gameobject template %u not found in database!", entry
);
2527 Map
* map
= GetMap();
2528 GameObject
* go
= GameObject::CreateGameObject(entry
, map
, pos
, rot
, 255, GO_STATE_READY
);
2532 PhasingHandler::InheritPhaseShift(go
, this);
2534 go
->SetRespawnTime(respawnTime
);
2535 if (GetTypeId() == TYPEID_PLAYER
|| GetTypeId() == TYPEID_UNIT
) //not sure how to handle this
2536 ToUnit()->AddGameObject(go
);
2538 go
->SetSpawnedByDefault(false);
2544 GameObject
* WorldObject::SummonGameObject(uint32 entry
, float x
, float y
, float z
, float ang
, QuaternionData
const& rot
, uint32 respawnTime
)
2548 GetClosePoint(x
, y
, z
, GetObjectSize());
2549 ang
= GetOrientation();
2552 Position
pos(x
, y
, z
, ang
);
2553 return SummonGameObject(entry
, pos
, rot
, respawnTime
);
2556 Creature
* WorldObject::SummonTrigger(float x
, float y
, float z
, float ang
, uint32 duration
, CreatureAI
* (*GetAI
)(Creature
*))
2558 TempSummonType summonType
= (duration
== 0) ? TEMPSUMMON_DEAD_DESPAWN
: TEMPSUMMON_TIMED_DESPAWN
;
2559 Creature
* summon
= SummonCreature(WORLD_TRIGGER
, x
, y
, z
, ang
, summonType
, duration
);
2563 //summon->SetName(GetName());
2564 if (GetTypeId() == TYPEID_PLAYER
|| GetTypeId() == TYPEID_UNIT
)
2566 summon
->setFaction(((Unit
*)this)->getFaction());
2567 summon
->SetLevel(((Unit
*)this)->getLevel());
2571 summon
->AIM_Initialize(GetAI(summon
));
2576 * Summons group of creatures. Should be called only by instances of Creature and GameObject classes.
2578 * @param group Id of group to summon.
2579 * @param list List to store pointers to summoned creatures.
2581 void WorldObject::SummonCreatureGroup(uint8 group
, std::list
<TempSummon
*>* list
/*= NULL*/)
2583 ASSERT((GetTypeId() == TYPEID_GAMEOBJECT
|| GetTypeId() == TYPEID_UNIT
) && "Only GOs and creatures can summon npc groups!");
2585 std::vector
<TempSummonData
> const* data
= sObjectMgr
->GetSummonGroup(GetEntry(), GetTypeId() == TYPEID_GAMEOBJECT
? SUMMONER_TYPE_GAMEOBJECT
: SUMMONER_TYPE_CREATURE
, group
);
2588 TC_LOG_WARN("scripts", "%s (%s) tried to summon non-existing summon group %u.", GetName().c_str(), GetGUID().ToString().c_str(), group
);
2592 for (std::vector
<TempSummonData
>::const_iterator itr
= data
->begin(); itr
!= data
->end(); ++itr
)
2593 if (TempSummon
* summon
= SummonCreature(itr
->entry
, itr
->pos
, itr
->type
, itr
->time
))
2595 list
->push_back(summon
);
2598 Creature
* WorldObject::FindNearestCreature(uint32 entry
, float range
, bool alive
) const
2600 Creature
* creature
= NULL
;
2601 Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck
checker(*this, entry
, alive
, range
);
2602 Trinity::CreatureLastSearcher
<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck
> searcher(this, creature
, checker
);
2603 Cell::VisitAllObjects(this, searcher
, range
);
2607 GameObject
* WorldObject::FindNearestGameObject(uint32 entry
, float range
) const
2609 GameObject
* go
= NULL
;
2610 Trinity::NearestGameObjectEntryInObjectRangeCheck
checker(*this, entry
, range
);
2611 Trinity::GameObjectLastSearcher
<Trinity::NearestGameObjectEntryInObjectRangeCheck
> searcher(this, go
, checker
);
2612 Cell::VisitGridObjects(this, searcher
, range
);
2616 GameObject
* WorldObject::FindNearestGameObjectOfType(GameobjectTypes type
, float range
) const
2618 GameObject
* go
= NULL
;
2619 Trinity::NearestGameObjectTypeInObjectRangeCheck
checker(*this, type
, range
);
2620 Trinity::GameObjectLastSearcher
<Trinity::NearestGameObjectTypeInObjectRangeCheck
> searcher(this, go
, checker
);
2621 Cell::VisitGridObjects(this, searcher
, range
);
2625 template <typename Container
>
2626 void WorldObject::GetGameObjectListWithEntryInGrid(Container
& gameObjectContainer
, uint32 entry
, float maxSearchRange
/*= 250.0f*/) const
2628 Trinity::AllGameObjectsWithEntryInRange
check(this, entry
, maxSearchRange
);
2629 Trinity::GameObjectListSearcher
<Trinity::AllGameObjectsWithEntryInRange
> searcher(this, gameObjectContainer
, check
);
2630 Cell::VisitGridObjects(this, searcher
, maxSearchRange
);
2633 template <typename Container
>
2634 void WorldObject::GetCreatureListWithEntryInGrid(Container
& creatureContainer
, uint32 entry
, float maxSearchRange
/*= 250.0f*/) const
2636 Trinity::AllCreaturesOfEntryInRange
check(this, entry
, maxSearchRange
);
2637 Trinity::CreatureListSearcher
<Trinity::AllCreaturesOfEntryInRange
> searcher(this, creatureContainer
, check
);
2638 Cell::VisitGridObjects(this, searcher
, maxSearchRange
);
2641 template <typename Container
>
2642 void WorldObject::GetPlayerListInGrid(Container
& playerContainer
, float maxSearchRange
) const
2644 Trinity::AnyPlayerInObjectRangeCheck
checker(this, maxSearchRange
);
2645 Trinity::PlayerListSearcher
<Trinity::AnyPlayerInObjectRangeCheck
> searcher(this, playerContainer
, checker
);
2646 Cell::VisitWorldObjects(this, searcher
, maxSearchRange
);
2649 void WorldObject::GetNearPoint2D(float &x
, float &y
, float distance2d
, float absAngle
) const
2651 x
= GetPositionX() + (GetObjectSize() + distance2d
) * std::cos(absAngle
);
2652 y
= GetPositionY() + (GetObjectSize() + distance2d
) * std::sin(absAngle
);
2654 Trinity::NormalizeMapCoord(x
);
2655 Trinity::NormalizeMapCoord(y
);
2658 void WorldObject::GetNearPoint(WorldObject
const* /*searcher*/, float &x
, float &y
, float &z
, float searcher_size
, float distance2d
, float absAngle
) const
2660 GetNearPoint2D(x
, y
, distance2d
+searcher_size
, absAngle
);
2662 // Should "searcher" be used instead of "this" when updating z coordinate ?
2663 UpdateAllowedPositionZ(x
, y
, z
);
2665 // if detection disabled, return first point
2666 if (!sWorld
->getBoolConfig(CONFIG_DETECT_POS_COLLISION
))
2669 // return if the point is already in LoS
2670 if (IsWithinLOS(x
, y
, z
))
2673 // remember first point
2678 // loop in a circle to look for a point in LoS using small steps
2679 for (float angle
= float(M_PI
) / 8; angle
< float(M_PI
) * 2; angle
+= float(M_PI
) / 8)
2681 GetNearPoint2D(x
, y
, distance2d
+ searcher_size
, absAngle
+ angle
);
2683 UpdateAllowedPositionZ(x
, y
, z
);
2684 if (IsWithinLOS(x
, y
, z
))
2688 // still not in LoS, give up and return first position found
2694 void WorldObject::GetClosePoint(float &x
, float &y
, float &z
, float size
, float distance2d
/*= 0*/, float angle
/*= 0*/) const
2696 // angle calculated from current orientation
2697 GetNearPoint(NULL
, x
, y
, z
, size
, distance2d
, GetOrientation() + angle
);
2700 Position
WorldObject::GetNearPosition(float dist
, float angle
)
2702 Position pos
= GetPosition();
2703 MovePosition(pos
, dist
, angle
);
2707 Position
WorldObject::GetFirstCollisionPosition(float dist
, float angle
)
2709 Position pos
= GetPosition();
2710 MovePositionToFirstCollision(pos
, dist
, angle
);
2714 Position
WorldObject::GetRandomNearPosition(float radius
)
2716 Position pos
= GetPosition();
2717 MovePosition(pos
, radius
* (float)rand_norm(), (float)rand_norm() * static_cast<float>(2 * M_PI
));
2721 void WorldObject::GetContactPoint(const WorldObject
* obj
, float &x
, float &y
, float &z
, float distance2d
/*= CONTACT_DISTANCE*/) const
2723 // angle to face `obj` to `this` using distance includes size of `obj`
2724 GetNearPoint(obj
, x
, y
, z
, obj
->GetObjectSize(), distance2d
, GetAngle(obj
));
2727 float WorldObject::GetObjectSize() const
2729 return (m_valuesCount
> UNIT_FIELD_COMBATREACH
) ? m_floatValues
[UNIT_FIELD_COMBATREACH
] : DEFAULT_WORLD_OBJECT_SIZE
;
2732 void WorldObject::MovePosition(Position
&pos
, float dist
, float angle
)
2734 angle
+= GetOrientation();
2735 float destx
, desty
, destz
, ground
, floor
;
2736 destx
= pos
.m_positionX
+ dist
* std::cos(angle
);
2737 desty
= pos
.m_positionY
+ dist
* std::sin(angle
);
2739 // Prevent invalid coordinates here, position is unchanged
2740 if (!Trinity::IsValidMapCoord(destx
, desty
, pos
.m_positionZ
))
2742 TC_LOG_FATAL("misc", "WorldObject::MovePosition: Object (Entry: %u %s) has invalid coordinates X: %f and Y: %f were passed!",
2743 GetEntry(), GetGUID().ToString().c_str(), destx
, desty
);
2747 ground
= GetMap()->GetHeight(GetPhaseShift(), destx
, desty
, MAX_HEIGHT
, true);
2748 floor
= GetMap()->GetHeight(GetPhaseShift(), destx
, desty
, pos
.m_positionZ
, true);
2749 destz
= std::fabs(ground
- pos
.m_positionZ
) <= std::fabs(floor
- pos
.m_positionZ
) ? ground
: floor
;
2751 float step
= dist
/10.0f
;
2753 for (uint8 j
= 0; j
< 10; ++j
)
2755 // do not allow too big z changes
2756 if (std::fabs(pos
.m_positionZ
- destz
) > 6)
2758 destx
-= step
* std::cos(angle
);
2759 desty
-= step
* std::sin(angle
);
2760 ground
= GetMap()->GetHeight(GetPhaseShift(), destx
, desty
, MAX_HEIGHT
, true);
2761 floor
= GetMap()->GetHeight(GetPhaseShift(), destx
, desty
, pos
.m_positionZ
, true);
2762 destz
= std::fabs(ground
- pos
.m_positionZ
) <= std::fabs(floor
- pos
.m_positionZ
) ? ground
: floor
;
2764 // we have correct destz now
2767 pos
.Relocate(destx
, desty
, destz
);
2772 Trinity::NormalizeMapCoord(pos
.m_positionX
);
2773 Trinity::NormalizeMapCoord(pos
.m_positionY
);
2774 UpdateGroundPositionZ(pos
.m_positionX
, pos
.m_positionY
, pos
.m_positionZ
);
2775 pos
.SetOrientation(GetOrientation());
2778 // @todo: replace with WorldObject::UpdateAllowedPositionZ
2779 float NormalizeZforCollision(WorldObject
* obj
, float x
, float y
, float z
)
2781 float ground
= obj
->GetMap()->GetHeight(obj
->GetPhaseShift(), x
, y
, MAX_HEIGHT
, true);
2782 float floor
= obj
->GetMap()->GetHeight(obj
->GetPhaseShift(), x
, y
, z
+ 2.0f
, true);
2783 float helper
= std::fabs(ground
- z
) <= std::fabs(floor
- z
) ? ground
: floor
;
2784 if (z
> helper
) // must be above ground
2786 if (Unit
* unit
= obj
->ToUnit())
2791 LiquidData liquid_status
;
2792 ZLiquidStatus res
= obj
->GetMap()->getLiquidStatus(obj
->GetPhaseShift(), x
, y
, z
, MAP_ALL_LIQUIDS
, &liquid_status
);
2793 if (res
&& liquid_status
.level
> helper
) // water must be above ground
2795 if (liquid_status
.level
> z
) // z is underwater
2798 return std::fabs(liquid_status
.level
- z
) <= std::fabs(helper
- z
) ? liquid_status
.level
: helper
;
2804 void WorldObject::MovePositionToFirstCollision(Position
&pos
, float dist
, float angle
)
2806 angle
+= GetOrientation();
2807 float destx
, desty
, destz
;
2808 destx
= pos
.m_positionX
+ dist
* std::cos(angle
);
2809 desty
= pos
.m_positionY
+ dist
* std::sin(angle
);
2811 // Prevent invalid coordinates here, position is unchanged
2812 if (!Trinity::IsValidMapCoord(destx
, desty
))
2814 TC_LOG_FATAL("misc", "WorldObject::MovePositionToFirstCollision invalid coordinates X: %f and Y: %f were passed!", destx
, desty
);
2818 destz
= NormalizeZforCollision(this, destx
, desty
, pos
.GetPositionZ());
2819 bool col
= VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(PhasingHandler::GetTerrainMapId(GetPhaseShift(), GetMap(), pos
.m_positionX
, pos
.m_positionY
),
2820 pos
.m_positionX
, pos
.m_positionY
, pos
.m_positionZ
+ 0.5f
, destx
, desty
, destz
+ 0.5f
, destx
, desty
, destz
, -0.5f
);
2822 // collision occured
2826 destx
-= CONTACT_DISTANCE
* std::cos(angle
);
2827 desty
-= CONTACT_DISTANCE
* std::sin(angle
);
2828 dist
= std::sqrt((pos
.m_positionX
- destx
)*(pos
.m_positionX
- destx
) + (pos
.m_positionY
- desty
)*(pos
.m_positionY
- desty
));
2831 // check dynamic collision
2832 col
= GetMap()->getObjectHitPos(GetPhaseShift(), pos
.m_positionX
, pos
.m_positionY
, pos
.m_positionZ
+ 0.5f
, destx
, desty
, destz
+ 0.5f
, destx
, desty
, destz
, -0.5f
);
2834 // Collided with a gameobject
2837 destx
-= CONTACT_DISTANCE
* std::cos(angle
);
2838 desty
-= CONTACT_DISTANCE
* std::sin(angle
);
2839 dist
= std::sqrt((pos
.m_positionX
- destx
)*(pos
.m_positionX
- destx
) + (pos
.m_positionY
- desty
)*(pos
.m_positionY
- desty
));
2842 float step
= dist
/ 10.0f
;
2844 for (uint8 j
= 0; j
< 10; ++j
)
2846 // do not allow too big z changes
2847 if (std::fabs(pos
.m_positionZ
- destz
) > 6.0f
)
2849 destx
-= step
* std::cos(angle
);
2850 desty
-= step
* std::sin(angle
);
2851 destz
= NormalizeZforCollision(this, destx
, desty
, pos
.GetPositionZ());
2853 // we have correct destz now
2856 pos
.Relocate(destx
, desty
, destz
);
2861 Trinity::NormalizeMapCoord(pos
.m_positionX
);
2862 Trinity::NormalizeMapCoord(pos
.m_positionY
);
2863 pos
.m_positionZ
= NormalizeZforCollision(this, destx
, desty
, pos
.GetPositionZ());
2864 pos
.SetOrientation(GetOrientation());
2867 void WorldObject::PlayDistanceSound(uint32 soundId
, Player
* target
/*= nullptr*/)
2870 target
->SendDirectMessage(WorldPackets::Misc::PlaySpeakerbotSound(GetGUID(), soundId
).Write());
2872 SendMessageToSet(WorldPackets::Misc::PlaySpeakerbotSound(GetGUID(), soundId
).Write(), true);
2875 void WorldObject::PlayDirectSound(uint32 soundId
, Player
* target
/*= nullptr*/)
2878 target
->SendDirectMessage(WorldPackets::Misc::PlaySound(GetGUID(), soundId
).Write());
2880 SendMessageToSet(WorldPackets::Misc::PlaySound(GetGUID(), soundId
).Write(), true);
2883 void WorldObject::PlayDirectMusic(uint32 musicId
, Player
* target
/*= nullptr*/)
2886 target
->SendDirectMessage(WorldPackets::Misc::PlayMusic(musicId
).Write());
2888 SendMessageToSet(WorldPackets::Misc::PlayMusic(musicId
).Write(), true);
2891 void WorldObject::DestroyForNearbyPlayers()
2896 std::list
<Player
*> targets
;
2897 Trinity::AnyPlayerInObjectRangeCheck
check(this, GetVisibilityRange(), false);
2898 Trinity::PlayerListSearcher
<Trinity::AnyPlayerInObjectRangeCheck
> searcher(this, targets
, check
);
2899 Cell::VisitWorldObjects(this, searcher
, GetVisibilityRange());
2900 for (std::list
<Player
*>::const_iterator iter
= targets
.begin(); iter
!= targets
.end(); ++iter
)
2902 Player
* player
= (*iter
);
2907 if (!player
->HaveAtClient(this))
2910 if (isType(TYPEMASK_UNIT
) && ToUnit()->GetCharmerGUID() == player
->GetGUID()) /// @todo this is for puppet
2913 DestroyForPlayer(player
);
2914 player
->m_clientGUIDs
.erase(GetGUID());
2918 void WorldObject::UpdateObjectVisibility(bool /*forced*/)
2920 //updates object's visibility for nearby players
2921 Trinity::VisibleChangesNotifier
notifier(*this);
2922 Cell::VisitWorldObjects(this, notifier
, GetVisibilityRange());
2925 struct WorldObjectChangeAccumulator
2927 UpdateDataMapType
& i_updateDatas
;
2928 WorldObject
& i_object
;
2930 WorldObjectChangeAccumulator(WorldObject
&obj
, UpdateDataMapType
&d
) : i_updateDatas(d
), i_object(obj
) { }
2931 void Visit(PlayerMapType
&m
)
2933 Player
* source
= NULL
;
2934 for (PlayerMapType::iterator iter
= m
.begin(); iter
!= m
.end(); ++iter
)
2936 source
= iter
->GetSource();
2938 BuildPacket(source
);
2940 if (!source
->GetSharedVisionList().empty())
2942 SharedVisionList::const_iterator it
= source
->GetSharedVisionList().begin();
2943 for (; it
!= source
->GetSharedVisionList().end(); ++it
)
2949 void Visit(CreatureMapType
&m
)
2951 Creature
* source
= NULL
;
2952 for (CreatureMapType::iterator iter
= m
.begin(); iter
!= m
.end(); ++iter
)
2954 source
= iter
->GetSource();
2955 if (!source
->GetSharedVisionList().empty())
2957 SharedVisionList::const_iterator it
= source
->GetSharedVisionList().begin();
2958 for (; it
!= source
->GetSharedVisionList().end(); ++it
)
2964 void Visit(DynamicObjectMapType
&m
)
2966 DynamicObject
* source
= NULL
;
2967 for (DynamicObjectMapType::iterator iter
= m
.begin(); iter
!= m
.end(); ++iter
)
2969 source
= iter
->GetSource();
2970 ObjectGuid guid
= source
->GetCasterGUID();
2972 if (guid
.IsPlayer())
2974 //Caster may be NULL if DynObj is in removelist
2975 if (Player
* caster
= ObjectAccessor::FindPlayer(guid
))
2976 if (caster
->GetGuidValue(PLAYER_FARSIGHT
) == source
->GetGUID())
2977 BuildPacket(caster
);
2982 void BuildPacket(Player
* player
)
2984 // Only send update once to a player
2985 if (plr_list
.find(player
->GetGUID()) == plr_list
.end() && player
->HaveAtClient(&i_object
))
2987 i_object
.BuildFieldsUpdate(player
, i_updateDatas
);
2988 plr_list
.insert(player
->GetGUID());
2992 template<class SKIP
> void Visit(GridRefManager
<SKIP
> &) { }
2995 void WorldObject::BuildUpdate(UpdateDataMapType
& data_map
)
2997 WorldObjectChangeAccumulator
notifier(*this, data_map
);
2998 //we must build packets for all visible players
2999 Cell::VisitWorldObjects(this, notifier
, GetVisibilityRange());
3001 ClearUpdateMask(false);
3004 void WorldObject::AddToObjectUpdate()
3006 GetMap()->AddUpdateObject(this);
3009 void WorldObject::RemoveFromObjectUpdate()
3011 GetMap()->RemoveUpdateObject(this);
3014 ObjectGuid
WorldObject::GetTransGUID() const
3017 return GetTransport()->GetGUID();
3018 return ObjectGuid::Empty
;
3021 template TC_GAME_API
void WorldObject::GetGameObjectListWithEntryInGrid(std::list
<GameObject
*>&, uint32
, float) const;
3022 template TC_GAME_API
void WorldObject::GetGameObjectListWithEntryInGrid(std::deque
<GameObject
*>&, uint32
, float) const;
3023 template TC_GAME_API
void WorldObject::GetGameObjectListWithEntryInGrid(std::vector
<GameObject
*>&, uint32
, float) const;
3025 template TC_GAME_API
void WorldObject::GetCreatureListWithEntryInGrid(std::list
<Creature
*>&, uint32
, float) const;
3026 template TC_GAME_API
void WorldObject::GetCreatureListWithEntryInGrid(std::deque
<Creature
*>&, uint32
, float) const;
3027 template TC_GAME_API
void WorldObject::GetCreatureListWithEntryInGrid(std::vector
<Creature
*>&, uint32
, float) const;
3029 template TC_GAME_API
void WorldObject::GetPlayerListInGrid(std::list
<Player
*>&, float) const;
3030 template TC_GAME_API
void WorldObject::GetPlayerListInGrid(std::deque
<Player
*>&, float) const;
3031 template TC_GAME_API
void WorldObject::GetPlayerListInGrid(std::vector
<Player
*>&, float) const;