TrinityCore
Object.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Object.h"
19#include "AreaTriggerPackets.h"
20#include "AreaTriggerTemplate.h"
21#include "BattlefieldMgr.h"
22#include "CellImpl.h"
23#include "CinematicMgr.h"
24#include "CombatLogPackets.h"
25#include "Common.h"
26#include "Creature.h"
27#include "DB2Stores.h"
28#include "GameTime.h"
29#include "GridNotifiersImpl.h"
30#include "G3DPosition.hpp"
31#include "InstanceScenario.h"
32#include "Item.h"
33#include "Log.h"
34#include "MiscPackets.h"
35#include "MovementPackets.h"
36#include "MovementTypedefs.h"
37#include "ObjectAccessor.h"
38#include "ObjectMgr.h"
39#include "OutdoorPvPMgr.h"
40#include "PathGenerator.h"
41#include "PhasingHandler.h"
42#include "Player.h"
43#include "ReputationMgr.h"
44#include "SmoothPhasing.h"
45#include "SpellAuraEffects.h"
46#include "SpellMgr.h"
47#include "SpellPackets.h"
48#include "StringConvert.h"
49#include "TemporarySummon.h"
50#include "Totem.h"
51#include "Transport.h"
52#include "Unit.h"
53#include "UpdateData.h"
54#include "Util.h"
55#include "VMapFactory.h"
56#include "Vehicle.h"
57#include "VMapManager2.h"
58#include "World.h"
59#include <G3D/Vector3.h>
60#include <sstream>
61
63{
70};
71
72Object::Object() : m_values(this)
73{
77
78 m_inWorld = false;
79 m_isNewObject = false;
80 m_isDestroyedObject = false;
81 m_objectUpdated = false;
82}
83
85{
86 if (IsInWorld())
87 {
88 TC_LOG_FATAL("misc", "Object::~Object {} deleted but still in world!!", GetGUID().ToString());
90 TC_LOG_FATAL("misc", "Item slot {}", ((Item*)this)->GetSlot());
91 ABORT();
92 }
93
95 {
96 TC_LOG_FATAL("misc", "Object::~Object {} deleted but still in update list!!", GetGUID().ToString());
97 ABORT();
98 }
99}
100
102{
103 m_objectUpdated = false;
104 m_guid = guid;
105}
106
108{
109 if (m_inWorld)
110 return;
111
112 m_inWorld = true;
113
114 // synchronize values mirror with values array (changes will send in updatecreate opcode any way
116 ClearUpdateMask(false);
117}
118
120{
121 if (!m_inWorld)
122 return;
123
124 m_inWorld = false;
125
126 // if we remove from world then sending changes not required
127 ClearUpdateMask(true);
128}
129
131{
132 if (!target)
133 return;
134
136 uint8 objectType = m_objectTypeId;
138
139 if (target == this) // building packet for yourself
140 {
141 flags.ThisIsYou = true;
142 flags.ActivePlayer = true;
143 objectType = TYPEID_ACTIVE_PLAYER;
144 }
145
146 if (WorldObject const* worldObject = dynamic_cast<WorldObject const*>(this))
147 {
148 if (!flags.MovementUpdate && !worldObject->m_movementInfo.transport.guid.IsEmpty())
149 flags.MovementTransport = true;
150
151 if (worldObject->GetAIAnimKitId() || worldObject->GetMovementAnimKitId() || worldObject->GetMeleeAnimKitId())
152 flags.AnimKit = true;
153
154 if (worldObject->GetSmoothPhasing() && worldObject->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID()))
155 flags.SmoothPhasing = true;
156 }
157
158 if (Unit const* unit = ToUnit())
159 {
160 flags.PlayHoverAnim = unit->IsPlayingHoverAnim();
161
162 if (unit->GetVictim())
163 flags.CombatVictim = true;
164 }
165
166 ByteBuffer& buf = data->GetBuffer();
167 buf << uint8(updateType);
168 buf << GetGUID();
169 buf << uint8(objectType);
170
171 BuildMovementUpdate(&buf, flags, target);
172 BuildValuesCreate(&buf, target);
173 data->AddUpdateBlock();
174}
175
177{
178 // send create update to player
179 UpdateData upd(player->GetMapId());
180 WorldPacket packet;
181
182 if (player->HaveAtClient(this))
184 else
186 upd.BuildPacket(&packet);
187 player->SendDirectMessage(&packet);
188}
189
191{
193
194 BuildValuesUpdate(&buf, target);
195
196 data->AddUpdateBlock();
197}
198
200{
202
203 BuildValuesUpdateWithFlag(&buf, flags, target);
204
205 data->AddUpdateBlock();
206}
207
209{
210 data->AddDestroyObject(GetGUID());
211}
212
214{
215 data->AddOutOfRangeGUID(GetGUID());
216}
217
219{
220 ByteBuffer& buffer = data->GetBuffer();
221 buffer << uint8(UPDATETYPE_VALUES);
222 buffer << GetGUID();
223 return buffer;
224}
225
227{
228 ASSERT(target);
229
230 UpdateData updateData(target->GetMapId());
231 BuildDestroyUpdateBlock(&updateData);
232 WorldPacket packet;
233 updateData.BuildPacket(&packet);
234 target->SendDirectMessage(&packet);
235}
236
238{
239 ASSERT(target);
240
241 UpdateData updateData(target->GetMapId());
242 BuildOutOfRangeUpdateBlock(&updateData);
243 WorldPacket packet;
244 updateData.BuildPacket(&packet);
245 target->SendDirectMessage(&packet);
246}
247
249{
250 std::vector<uint32> const* PauseTimes = nullptr;
251 if (GameObject const* go = ToGameObject())
252 PauseTimes = go->GetPauseTimes();
253
254 data->WriteBit(flags.NoBirthAnim);
255 data->WriteBit(flags.EnablePortals);
256 data->WriteBit(flags.PlayHoverAnim);
257 data->WriteBit(flags.MovementUpdate);
258 data->WriteBit(flags.MovementTransport);
259 data->WriteBit(flags.Stationary);
260 data->WriteBit(flags.CombatVictim);
261 data->WriteBit(flags.ServerTime);
262 data->WriteBit(flags.Vehicle);
263 data->WriteBit(flags.AnimKit);
264 data->WriteBit(flags.Rotation);
265 data->WriteBit(flags.AreaTrigger);
266 data->WriteBit(flags.GameObject);
267 data->WriteBit(flags.SmoothPhasing);
268 data->WriteBit(flags.ThisIsYou);
269 data->WriteBit(flags.SceneObject);
270 data->WriteBit(flags.ActivePlayer);
271 data->WriteBit(flags.Conversation);
272 data->FlushBits();
273
274 if (flags.MovementUpdate)
275 {
276 Unit const* unit = ToUnit();
277 bool HasFallDirection = unit->HasUnitMovementFlag(MOVEMENTFLAG_FALLING);
278 bool HasFall = HasFallDirection || unit->m_movementInfo.jump.fallTime != 0;
279 bool HasSpline = unit->IsSplineEnabled();
280 bool HasInertia = unit->m_movementInfo.inertia.has_value();
281 bool HasAdvFlying = unit->m_movementInfo.advFlying.has_value();
282 bool HasStandingOnGameObjectGUID = unit->m_movementInfo.standingOnGameObjectGUID.has_value();
283
284 *data << GetGUID(); // MoverGUID
285
286 *data << uint32(unit->GetUnitMovementFlags());
287 *data << uint32(unit->GetExtraUnitMovementFlags());
288 *data << uint32(unit->GetExtraUnitMovementFlags2());
289
290 *data << uint32(unit->m_movementInfo.time); // MoveTime
291 *data << float(unit->GetPositionX());
292 *data << float(unit->GetPositionY());
293 *data << float(unit->GetPositionZ());
294 *data << float(unit->GetOrientation());
295
296 *data << float(unit->m_movementInfo.pitch); // Pitch
297 *data << float(unit->m_movementInfo.stepUpStartElevation); // StepUpStartElevation
298
299 *data << uint32(0); // RemoveForcesIDs.size()
300 *data << uint32(0); // MoveIndex
301
302 //for (std::size_t i = 0; i < RemoveForcesIDs.size(); ++i)
303 // *data << ObjectGuid(RemoveForcesIDs);
304
305 data->WriteBit(HasStandingOnGameObjectGUID); // HasStandingOnGameObjectGUID
306 data->WriteBit(!unit->m_movementInfo.transport.guid.IsEmpty()); // HasTransport
307 data->WriteBit(HasFall); // HasFall
308 data->WriteBit(HasSpline); // HasSpline - marks that the unit uses spline movement
309 data->WriteBit(false); // HeightChangeFailed
310 data->WriteBit(false); // RemoteTimeValid
311 data->WriteBit(HasInertia); // HasInertia
312 data->WriteBit(HasAdvFlying); // HasAdvFlying
313
315 *data << unit->m_movementInfo.transport;
316
317 if (HasStandingOnGameObjectGUID)
319
320 if (HasInertia)
321 {
322 *data << unit->m_movementInfo.inertia->id;
323 *data << unit->m_movementInfo.inertia->force.PositionXYZStream();
324 *data << uint32(unit->m_movementInfo.inertia->lifetime);
325 }
326
327 if (HasAdvFlying)
328 {
329 *data << float(unit->m_movementInfo.advFlying->forwardVelocity);
330 *data << float(unit->m_movementInfo.advFlying->upVelocity);
331 }
332
333 if (HasFall)
334 {
335 *data << uint32(unit->m_movementInfo.jump.fallTime); // Time
336 *data << float(unit->m_movementInfo.jump.zspeed); // JumpVelocity
337
338 if (data->WriteBit(HasFallDirection))
339 {
340 *data << float(unit->m_movementInfo.jump.sinAngle); // Direction
341 *data << float(unit->m_movementInfo.jump.cosAngle);
342 *data << float(unit->m_movementInfo.jump.xyspeed); // Speed
343 }
344 }
345
346 *data << float(unit->GetSpeed(MOVE_WALK));
347 *data << float(unit->GetSpeed(MOVE_RUN));
348 *data << float(unit->GetSpeed(MOVE_RUN_BACK));
349 *data << float(unit->GetSpeed(MOVE_SWIM));
350 *data << float(unit->GetSpeed(MOVE_SWIM_BACK));
351 *data << float(unit->GetSpeed(MOVE_FLIGHT));
352 *data << float(unit->GetSpeed(MOVE_FLIGHT_BACK));
353 *data << float(unit->GetSpeed(MOVE_TURN_RATE));
354 *data << float(unit->GetSpeed(MOVE_PITCH_RATE));
355
356 if (MovementForces const* movementForces = unit->GetMovementForces())
357 {
358 *data << uint32(movementForces->GetForces()->size());
359 *data << float(movementForces->GetModMagnitude()); // MovementForcesModMagnitude
360 }
361 else
362 {
363 *data << uint32(0);
364 *data << float(1.0f); // MovementForcesModMagnitude
365 }
366
367 *data << float(2.0f); // advFlyingAirFriction
368 *data << float(65.0f); // advFlyingMaxVel
369 *data << float(1.0f); // advFlyingLiftCoefficient
370 *data << float(3.0f); // advFlyingDoubleJumpVelMod
371 *data << float(10.0f); // advFlyingGlideStartMinHeight
372 *data << float(100.0f); // advFlyingAddImpulseMaxSpeed
373 *data << float(90.0f); // advFlyingMinBankingRate
374 *data << float(140.0f); // advFlyingMaxBankingRate
375 *data << float(180.0f); // advFlyingMinPitchingRateDown
376 *data << float(360.0f); // advFlyingMaxPitchingRateDown
377 *data << float(90.0f); // advFlyingMinPitchingRateUp
378 *data << float(270.0f); // advFlyingMaxPitchingRateUp
379 *data << float(30.0f); // advFlyingMinTurnVelocityThreshold
380 *data << float(80.0f); // advFlyingMaxTurnVelocityThreshold
381 *data << float(2.75f); // advFlyingSurfaceFriction
382 *data << float(7.0f); // advFlyingOverMaxDeceleration
383 *data << float(0.4f); // advFlyingLaunchSpeedCoefficient
384
385 data->WriteBit(HasSpline);
386 data->FlushBits();
387
388 if (MovementForces const* movementForces = unit->GetMovementForces())
389 for (MovementForce const& force : *movementForces->GetForces())
391
392 if (HasSpline)
394 }
395
396 *data << uint32(PauseTimes ? PauseTimes->size() : 0);
397
398 if (flags.Stationary)
399 {
400 WorldObject const* self = static_cast<WorldObject const*>(this);
401 *data << float(self->GetStationaryX());
402 *data << float(self->GetStationaryY());
403 *data << float(self->GetStationaryZ());
404 *data << float(self->GetStationaryO());
405 }
406
407 if (flags.CombatVictim)
408 *data << ToUnit()->GetVictim()->GetGUID(); // CombatVictim
409
410 if (flags.ServerTime)
412
413 if (flags.Vehicle)
414 {
415 Unit const* unit = ToUnit();
416 *data << uint32(unit->GetVehicleKit()->GetVehicleInfo()->ID); // RecID
417 *data << float(unit->GetOrientation()); // InitialRawFacing
418 }
419
420 if (flags.AnimKit)
421 {
422 WorldObject const* self = static_cast<WorldObject const*>(this);
423 *data << uint16(self->GetAIAnimKitId()); // AiID
424 *data << uint16(self->GetMovementAnimKitId()); // MovementID
425 *data << uint16(self->GetMeleeAnimKitId()); // MeleeID
426 }
427
428 if (flags.Rotation)
429 *data << uint64(ToGameObject()->GetPackedLocalRotation()); // Rotation
430
431 if (PauseTimes && !PauseTimes->empty())
432 data->append(PauseTimes->data(), PauseTimes->size());
433
434 if (flags.MovementTransport)
435 {
436 WorldObject const* self = static_cast<WorldObject const*>(this);
437 *data << self->m_movementInfo.transport;
438 }
439
440 if (flags.AreaTrigger)
441 {
442 AreaTrigger const* areaTrigger = ToAreaTrigger();
443 AreaTriggerCreateProperties const* createProperties = areaTrigger->GetCreateProperties();
444 AreaTriggerShapeInfo const& shape = areaTrigger->GetShape();
445
446 *data << uint32(areaTrigger->GetTimeSinceCreated());
447
448 *data << areaTrigger->GetRollPitchYaw().PositionXYZStream();
449
450 bool hasAbsoluteOrientation = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAbsoluteOrientation);
451 bool hasDynamicShape = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasDynamicShape);
452 bool hasAttached = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAttached);
453 bool hasFaceMovementDir = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasFaceMovementDir);
454 bool hasFollowsTerrain = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasFollowsTerrain);
455 bool hasUnk1 = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::Unk1);
456 bool hasUnknown1025 = false;
457 bool hasTargetRollPitchYaw = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasTargetRollPitchYaw);
458 bool hasScaleCurveID = createProperties && createProperties->ScaleCurveId != 0;
459 bool hasMorphCurveID = createProperties && createProperties->MorphCurveId != 0;
460 bool hasFacingCurveID = createProperties && createProperties->FacingCurveId != 0;
461 bool hasMoveCurveID = createProperties && createProperties->MoveCurveId != 0;
462 bool hasAreaTriggerSphere = shape.IsSphere();
463 bool hasAreaTriggerBox = shape.IsBox();
464 bool hasAreaTriggerPolygon = createProperties && shape.IsPolygon();
465 bool hasAreaTriggerCylinder = shape.IsCylinder();
466 bool hasDisk = shape.IsDisk();
467 bool hasBoundedPlane = shape.IsBoundedPlane();
468 bool hasAreaTriggerSpline = areaTrigger->HasSplines();
469 bool hasOrbit = areaTrigger->HasOrbit();
470 bool hasMovementScript = false;
471
472 data->WriteBit(hasAbsoluteOrientation);
473 data->WriteBit(hasDynamicShape);
474 data->WriteBit(hasAttached);
475 data->WriteBit(hasFaceMovementDir);
476 data->WriteBit(hasFollowsTerrain);
477 data->WriteBit(hasUnk1);
478 data->WriteBit(hasUnknown1025);
479 data->WriteBit(hasTargetRollPitchYaw);
480 data->WriteBit(hasScaleCurveID);
481 data->WriteBit(hasMorphCurveID);
482 data->WriteBit(hasFacingCurveID);
483 data->WriteBit(hasMoveCurveID);
484 data->WriteBit(hasAreaTriggerSphere);
485 data->WriteBit(hasAreaTriggerBox);
486 data->WriteBit(hasAreaTriggerPolygon);
487 data->WriteBit(hasAreaTriggerCylinder);
488 data->WriteBit(hasDisk);
489 data->WriteBit(hasBoundedPlane);
490 data->WriteBit(hasAreaTriggerSpline);
491 data->WriteBit(hasOrbit);
492 data->WriteBit(hasMovementScript);
493
494 data->FlushBits();
495
496 if (hasAreaTriggerSpline)
497 {
498 *data << uint32(areaTrigger->GetTimeToTarget());
499 *data << uint32(areaTrigger->GetElapsedTimeForMovement());
500
502 }
503
504 if (hasTargetRollPitchYaw)
505 *data << areaTrigger->GetTargetRollPitchYaw().PositionXYZStream();
506
507 if (hasScaleCurveID)
508 *data << uint32(createProperties->ScaleCurveId);
509
510 if (hasMorphCurveID)
511 *data << uint32(createProperties->MorphCurveId);
512
513 if (hasFacingCurveID)
514 *data << uint32(createProperties->FacingCurveId);
515
516 if (hasMoveCurveID)
517 *data << uint32(createProperties->MoveCurveId);
518
519 if (hasAreaTriggerSphere)
520 {
521 *data << float(shape.SphereDatas.Radius);
522 *data << float(shape.SphereDatas.RadiusTarget);
523 }
524
525 if (hasAreaTriggerBox)
526 {
527 *data << float(shape.BoxDatas.Extents[0]);
528 *data << float(shape.BoxDatas.Extents[1]);
529 *data << float(shape.BoxDatas.Extents[2]);
530 *data << float(shape.BoxDatas.ExtentsTarget[0]);
531 *data << float(shape.BoxDatas.ExtentsTarget[1]);
532 *data << float(shape.BoxDatas.ExtentsTarget[2]);
533 }
534
535 if (hasAreaTriggerPolygon)
536 {
537 *data << int32(shape.PolygonVertices.size());
538 *data << int32(shape.PolygonVerticesTarget.size());
539 *data << float(shape.PolygonDatas.Height);
540 *data << float(shape.PolygonDatas.HeightTarget);
541
542 for (TaggedPosition<Position::XY> const& vertice : shape.PolygonVertices)
543 *data << vertice;
544
545 for (TaggedPosition<Position::XY> const& vertice : shape.PolygonVerticesTarget)
546 *data << vertice;
547 }
548
549 if (hasAreaTriggerCylinder)
550 {
551 *data << float(shape.CylinderDatas.Radius);
552 *data << float(shape.CylinderDatas.RadiusTarget);
553 *data << float(shape.CylinderDatas.Height);
554 *data << float(shape.CylinderDatas.HeightTarget);
555 *data << float(shape.CylinderDatas.LocationZOffset);
557 }
558
559 if (hasDisk)
560 {
561 *data << float(shape.DiskDatas.InnerRadius);
562 *data << float(shape.DiskDatas.InnerRadiusTarget);
563 *data << float(shape.DiskDatas.OuterRadius);
564 *data << float(shape.DiskDatas.OuterRadiusTarget);
565 *data << float(shape.DiskDatas.Height);
566 *data << float(shape.DiskDatas.HeightTarget);
567 *data << float(shape.DiskDatas.LocationZOffset);
568 *data << float(shape.DiskDatas.LocationZOffsetTarget);
569 }
570
571 if (hasBoundedPlane)
572 {
573 *data << float(shape.BoundedPlaneDatas.Extents[0]);
574 *data << float(shape.BoundedPlaneDatas.Extents[1]);
575 *data << float(shape.BoundedPlaneDatas.ExtentsTarget[0]);
576 *data << float(shape.BoundedPlaneDatas.ExtentsTarget[1]);
577 }
578
579 //if (hasMovementScript)
580 // *data << *areaTrigger->GetMovementScript(); // AreaTriggerMovementScriptInfo
581
582 if (hasOrbit)
583 *data << *areaTrigger->GetOrbit();
584 }
585
586 if (flags.GameObject)
587 {
588 bool bit8 = false;
589 uint32 Int1 = 0;
590
591 GameObject const* gameObject = ToGameObject();
592
593 *data << uint32(gameObject->GetWorldEffectID());
594
595 data->WriteBit(bit8);
596 data->FlushBits();
597 if (bit8)
598 *data << uint32(Int1);
599 }
600
601 if (flags.SmoothPhasing)
602 {
603 SmoothPhasingInfo const* smoothPhasingInfo = static_cast<WorldObject const*>(this)->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID());
604 ASSERT(smoothPhasingInfo);
605
606 data->WriteBit(smoothPhasingInfo->ReplaceActive);
607 data->WriteBit(smoothPhasingInfo->StopAnimKits);
608 data->WriteBit(smoothPhasingInfo->ReplaceObject.has_value());
609 data->FlushBits();
610 if (smoothPhasingInfo->ReplaceObject)
611 *data << *smoothPhasingInfo->ReplaceObject;
612 }
613
614 if (flags.SceneObject)
615 {
616 data->WriteBit(false); // HasLocalScriptData
617 data->WriteBit(false); // HasPetBattleFullUpdate
618 data->FlushBits();
619
620 // if (HasLocalScriptData)
621 // {
622 // data->WriteBits(Data.length(), 7);
623 // data->FlushBits();
624 // data->WriteString(Data);
625 // }
626
627 // if (HasPetBattleFullUpdate)
628 // {
629 // for (std::size_t i = 0; i < 2; ++i)
630 // {
631 // *data << ObjectGuid(Players[i].CharacterID);
632 // *data << int32(Players[i].TrapAbilityID);
633 // *data << int32(Players[i].TrapStatus);
634 // *data << uint16(Players[i].RoundTimeSecs);
635 // *data << int8(Players[i].FrontPet);
636 // *data << uint8(Players[i].InputFlags);
637
638 // data->WriteBits(Players[i].Pets.size(), 2);
639 // data->FlushBits();
640 // for (std::size_t j = 0; j < Players[i].Pets.size(); ++j)
641 // {
642 // *data << ObjectGuid(Players[i].Pets[j].BattlePetGUID);
643 // *data << int32(Players[i].Pets[j].SpeciesID);
644 // *data << int32(Players[i].Pets[j].CreatureID);
645 // *data << int32(Players[i].Pets[j].DisplayID);
646 // *data << int16(Players[i].Pets[j].Level);
647 // *data << int16(Players[i].Pets[j].Xp);
648 // *data << int32(Players[i].Pets[j].CurHealth);
649 // *data << int32(Players[i].Pets[j].MaxHealth);
650 // *data << int32(Players[i].Pets[j].Power);
651 // *data << int32(Players[i].Pets[j].Speed);
652 // *data << int32(Players[i].Pets[j].NpcTeamMemberID);
653 // *data << uint16(Players[i].Pets[j].BreedQuality);
654 // *data << uint16(Players[i].Pets[j].StatusFlags);
655 // *data << int8(Players[i].Pets[j].Slot);
656
657 // *data << uint32(Players[i].Pets[j].Abilities.size());
658 // *data << uint32(Players[i].Pets[j].Auras.size());
659 // *data << uint32(Players[i].Pets[j].States.size());
660 // for (std::size_t k = 0; k < Players[i].Pets[j].Abilities.size(); ++k)
661 // {
662 // *data << int32(Players[i].Pets[j].Abilities[k].AbilityID);
663 // *data << int16(Players[i].Pets[j].Abilities[k].CooldownRemaining);
664 // *data << int16(Players[i].Pets[j].Abilities[k].LockdownRemaining);
665 // *data << int8(Players[i].Pets[j].Abilities[k].AbilityIndex);
666 // *data << uint8(Players[i].Pets[j].Abilities[k].Pboid);
667 // }
668
669 // for (std::size_t k = 0; k < Players[i].Pets[j].Auras.size(); ++k)
670 // {
671 // *data << int32(Players[i].Pets[j].Auras[k].AbilityID);
672 // *data << uint32(Players[i].Pets[j].Auras[k].InstanceID);
673 // *data << int32(Players[i].Pets[j].Auras[k].RoundsRemaining);
674 // *data << int32(Players[i].Pets[j].Auras[k].CurrentRound);
675 // *data << uint8(Players[i].Pets[j].Auras[k].CasterPBOID);
676 // }
677
678 // for (std::size_t k = 0; k < Players[i].Pets[j].States.size(); ++k)
679 // {
680 // *data << uint32(Players[i].Pets[j].States[k].StateID);
681 // *data << int32(Players[i].Pets[j].States[k].StateValue);
682 // }
683
684 // data->WriteBits(Players[i].Pets[j].CustomName.length(), 7);
685 // data->FlushBits();
686 // data->WriteString(Players[i].Pets[j].CustomName);
687 // }
688 // }
689
690 // for (std::size_t i = 0; i < 3; ++i)
691 // {
692 // *data << uint32(Enviros[j].Auras.size());
693 // *data << uint32(Enviros[j].States.size());
694 // for (std::size_t j = 0; j < Enviros[j].Auras.size(); ++j)
695 // {
696 // *data << int32(Enviros[j].Auras[j].AbilityID);
697 // *data << uint32(Enviros[j].Auras[j].InstanceID);
698 // *data << int32(Enviros[j].Auras[j].RoundsRemaining);
699 // *data << int32(Enviros[j].Auras[j].CurrentRound);
700 // *data << uint8(Enviros[j].Auras[j].CasterPBOID);
701 // }
702
703 // for (std::size_t j = 0; j < Enviros[j].States.size(); ++j)
704 // {
705 // *data << uint32(Enviros[i].States[j].StateID);
706 // *data << int32(Enviros[i].States[j].StateValue);
707 // }
708 // }
709
710 // *data << uint16(WaitingForFrontPetsMaxSecs);
711 // *data << uint16(PvpMaxRoundTime);
712 // *data << int32(CurRound);
713 // *data << uint32(NpcCreatureID);
714 // *data << uint32(NpcDisplayID);
715 // *data << int8(CurPetBattleState);
716 // *data << uint8(ForfeitPenalty);
717 // *data << ObjectGuid(InitialWildPetGUID);
718 // data->WriteBit(IsPVP);
719 // data->WriteBit(CanAwardXP);
720 // data->FlushBits();
721 // }
722 }
723
724 if (flags.ActivePlayer)
725 {
726 Player const* player = ToPlayer();
727
728 bool HasSceneInstanceIDs = !player->GetSceneMgr().GetSceneTemplateByInstanceMap().empty();
729 bool HasRuneState = ToUnit()->GetPowerIndex(POWER_RUNES) != MAX_POWERS;
730
731 data->WriteBit(HasSceneInstanceIDs);
732 data->WriteBit(HasRuneState);
733 data->FlushBits();
734 if (HasSceneInstanceIDs)
735 {
736 *data << uint32(player->GetSceneMgr().GetSceneTemplateByInstanceMap().size());
737 for (auto const& itr : player->GetSceneMgr().GetSceneTemplateByInstanceMap())
738 *data << uint32(itr.first);
739 }
740 if (HasRuneState)
741 {
742 float baseCd = float(player->GetRuneBaseCooldown());
743 uint32 maxRunes = uint32(player->GetMaxPower(POWER_RUNES));
744
745 *data << uint8((1 << maxRunes) - 1);
746 *data << uint8(player->GetRunesState());
747 *data << uint32(maxRunes);
748 for (uint32 i = 0; i < maxRunes; ++i)
749 *data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255);
750 }
751 }
752
753 if (flags.Conversation)
754 {
755 Conversation const* self = ToConversation();
756 if (data->WriteBit(self->GetTextureKitId() != 0))
757 *data << uint32(self->GetTextureKitId());
758
759 data->FlushBits();
760 }
761}
762
764{
766}
767
768void Object::BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag /*flags*/, Player const* /*target*/) const
769{
770 std::size_t sizePos = data->wpos();
771 *data << uint32(0);
772 *data << uint32(0);
773
774 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
775}
776
778{
781}
782
783void Object::ClearUpdateMask(bool remove)
784{
786
787 if (m_objectUpdated)
788 {
789 if (remove)
791 m_objectUpdated = false;
792 }
793}
794
796{
797 UpdateDataMapType::iterator iter = data_map.find(player);
798
799 if (iter == data_map.end())
800 {
801 std::pair<UpdateDataMapType::iterator, bool> p = data_map.emplace(player, UpdateData(player->GetMapId()));
802 ASSERT(p.second);
803 iter = p.first;
804 }
805
806 BuildValuesUpdateBlockForPlayer(&iter->second, iter->first);
807}
808
809std::string Object::GetDebugInfo() const
810{
811 std::stringstream sstr;
812 sstr << GetGUID().ToString() + " Entry " << GetEntry();
813 return sstr.str();
814}
815
817{
818 TC_LOG_DEBUG("misc", "MOVEMENT INFO");
819 TC_LOG_DEBUG("misc", "{}", guid.ToString());
820 TC_LOG_DEBUG("misc", "flags {} ({})", Movement::MovementFlags_ToString(flags), flags);
822 TC_LOG_DEBUG("misc", "time {} current time {}", time, getMSTime());
823 TC_LOG_DEBUG("misc", "position: `{}`", pos.ToString());
824 if (!transport.guid.IsEmpty())
825 {
826 TC_LOG_DEBUG("misc", "TRANSPORT:");
827 TC_LOG_DEBUG("misc", "{}", transport.guid.ToString());
828 TC_LOG_DEBUG("misc", "position: `{}`", transport.pos.ToString());
829 TC_LOG_DEBUG("misc", "seat: {}", transport.seat);
830 TC_LOG_DEBUG("misc", "time: {}", transport.time);
832 TC_LOG_DEBUG("misc", "prevTime: {}", transport.prevTime);
834 TC_LOG_DEBUG("misc", "vehicleId: {}", transport.vehicleId);
835 }
836
838 TC_LOG_DEBUG("misc", "pitch: {}", pitch);
839
841 {
842 TC_LOG_DEBUG("misc", "fallTime: {} j_zspeed: {}", jump.fallTime, jump.zspeed);
844 TC_LOG_DEBUG("misc", "j_sinAngle: {} j_cosAngle: {} j_xyspeed: {}", jump.sinAngle, jump.cosAngle, jump.xyspeed);
845 }
846
848 TC_LOG_DEBUG("misc", "stepUpStartElevation: {}", stepUpStartElevation);
849
850 if (inertia)
851 {
852 TC_LOG_DEBUG("misc", "inertia->id: {}", inertia->id);
853 TC_LOG_DEBUG("misc", "inertia->force: {}", inertia->force.ToString());
854 TC_LOG_DEBUG("misc", "inertia->lifetime: {}", inertia->lifetime);
855 }
856
857 if (advFlying)
858 {
859 TC_LOG_DEBUG("misc", "advFlying->forwardVelocity: {}", advFlying->forwardVelocity);
860 TC_LOG_DEBUG("misc", "advFlying->upVelocity: {}", advFlying->upVelocity);
861 }
862
864 TC_LOG_DEBUG("misc", "standingOnGameObjectGUID: {}", standingOnGameObjectGUID->ToString());
865}
866
867WorldObject::WorldObject(bool isWorldObject) : Object(), WorldLocation(), LastUsedScriptID(0),
868m_movementInfo(), m_name(), m_isActive(false), m_isFarVisible(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
869m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_outdoors(false), m_liquidStatus(LIQUID_MAP_NO_WATER),
870m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0)
871{
874}
875
877{
878 // this may happen because there are many !create/delete
879 if (IsWorldObject() && m_currMap)
880 {
881 if (GetTypeId() == TYPEID_CORPSE)
882 {
883 TC_LOG_FATAL("misc", "WorldObject::~WorldObject Corpse Type: {} ({}) deleted but still in map!!",
884 ToCorpse()->GetType(), GetGUID().ToString());
885 ABORT();
886 }
887 ResetMap();
888 }
889}
890
892{
893 m_Events.Update(diff);
894}
895
897{
898 if (!IsInWorld())
899 return;
900
901 GetMap()->AddObjectToSwitchList(this, on);
902}
903
905{
906 if (m_isWorldObject)
907 return true;
908
909 if (ToCreature() && ToCreature()->m_isTempWorldObject)
910 return true;
911
912 return false;
913}
914
916{
917 if (m_isActive == on)
918 return;
919
920 if (GetTypeId() == TYPEID_PLAYER)
921 return;
922
923 m_isActive = on;
924
925 if (on && !IsInWorld())
926 return;
927
928 Map* map = FindMap();
929 if (!map)
930 return;
931
932 if (on)
933 map->AddToActive(this);
934 else
935 map->RemoveFromActive(this);
936}
937
939{
941 if (GetTypeId() == TYPEID_PLAYER)
942 return;
943
944 if (Creature* creature = ToCreature())
945 {
947 switch (type)
948 {
950 creature->SetUnitFlag2(UNIT_FLAG2_LARGE_AOI);
951 break;
953 creature->SetUnitFlag2(UNIT_FLAG2_GIGANTIC_AOI);
954 break;
956 creature->SetUnitFlag2(UNIT_FLAG2_INFINITE_AOI);
957 break;
958 default:
959 break;
960 }
961 }
962
964}
965
967{
968 if (GetTypeId() == TYPEID_PLAYER)
969 return;
970
971 m_isFarVisible = on;
972}
973
974void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
975{
976 if (IsInWorld())
978
979 if (TransportBase* transport = GetTransport())
980 transport->RemovePassenger(this);
981
982 m_Events.KillAllEvents(false); // non-delatable (currently cast spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
983}
984
986{
990}
991
993{
994 m_zoneId = m_areaId = data.areaId;
995 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(m_areaId))
996 if (area->ParentAreaID && area->GetFlags().HasFlag(AreaFlags::IsSubzone))
997 m_zoneId = area->ParentAreaID;
998 m_outdoors = data.outdoors;
999 m_staticFloorZ = data.floorZ;
1001}
1002
1004{
1007}
1008
1010{
1011 if (!IsInWorld())
1012 return;
1013
1015
1017}
1018
1020{
1021 switch (GetZoneId())
1022 {
1023 case 4197: // Wintergrasp
1024 case 5095: // Tol Barad
1025 case 6941: // Ashran
1026 return true;
1027 break;
1028 default:
1029 return false;
1030 break;
1031 }
1032}
1033
1035{
1036 Map* map = GetMap();
1037 return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceScript() : nullptr;
1038}
1039
1041{
1042 float dz = std::fabs(GetPositionZ() - obj->GetPositionZ());
1043 float sizefactor = GetCombatReach() + obj->GetCombatReach();
1044 float dist = dz - sizefactor;
1045 return (dist > 0 ? dist : 0);
1046}
1047
1048bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D, bool incOwnRadius, bool incTargetRadius) const
1049{
1050 float sizefactor = 0;
1051 sizefactor += incOwnRadius ? GetCombatReach() : 0.0f;
1052 sizefactor += incTargetRadius ? obj->GetCombatReach() : 0.0f;
1053 float maxdist = dist2compare + sizefactor;
1054
1055 Position const* thisOrTransport = this;
1056 Position const* objOrObjTransport = obj;
1057
1058 if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetTransportGUID() == GetTransport()->GetTransportGUID())
1059 {
1060 thisOrTransport = &m_movementInfo.transport.pos;
1061 objOrObjTransport = &obj->m_movementInfo.transport.pos;
1062 }
1063
1064 if (is3D)
1065 return thisOrTransport->IsInDist(objOrObjTransport, maxdist);
1066 else
1067 return thisOrTransport->IsInDist2d(objOrObjTransport, maxdist);
1068}
1069
1071{
1072 float d = GetExactDist(obj) - GetCombatReach() - obj->GetCombatReach();
1073 return d > 0.0f ? d : 0.0f;
1074}
1075
1076float WorldObject::GetDistance(Position const& pos) const
1077{
1078 float d = GetExactDist(&pos) - GetCombatReach();
1079 return d > 0.0f ? d : 0.0f;
1080}
1081
1082float WorldObject::GetDistance(float x, float y, float z) const
1083{
1084 float d = GetExactDist(x, y, z) - GetCombatReach();
1085 return d > 0.0f ? d : 0.0f;
1086}
1087
1089{
1090 float d = GetExactDist2d(obj) - GetCombatReach() - obj->GetCombatReach();
1091 return d > 0.0f ? d : 0.0f;
1092}
1093
1094float WorldObject::GetDistance2d(float x, float y) const
1095{
1096 float d = GetExactDist2d(x, y) - GetCombatReach();
1097 return d > 0.0f ? d : 0.0f;
1098}
1099
1101{
1102 if (this == obj)
1103 return true;
1104 return IsInMap(obj);
1105}
1106
1107bool WorldObject::IsInMap(WorldObject const* obj) const
1108{
1109 if (obj)
1110 return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap());
1111 return false;
1112}
1113
1114bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist) const
1115{
1116 return IsInDist(x, y, z, dist + GetCombatReach());
1117}
1118
1119bool WorldObject::IsWithinDist3d(Position const* pos, float dist) const
1120{
1121 return IsInDist(pos, dist + GetCombatReach());
1122}
1123
1124bool WorldObject::IsWithinDist2d(float x, float y, float dist) const
1125{
1126 return IsInDist2d(x, y, dist + GetCombatReach());
1127}
1128
1129bool WorldObject::IsWithinDist2d(Position const* pos, float dist) const
1130{
1131 return IsInDist2d(pos, dist + GetCombatReach());
1132}
1133
1134bool WorldObject::IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D /*= true*/, bool incOwnRadius /*= true*/, bool incTargetRadius /*= true*/) const
1135{
1136 return obj && _IsWithinDist(obj, dist2compare, is3D, incOwnRadius, incTargetRadius);
1137}
1138
1139bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D /*= true*/, bool incOwnRadius /*= true*/, bool incTargetRadius /*= true*/) const
1140{
1141 return obj && IsInMap(obj) && InSamePhase(obj) && _IsWithinDist(obj, dist2compare, is3D, incOwnRadius, incTargetRadius);
1142}
1143
1145{
1146 G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ() + GetCollisionHeight());
1147 G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
1148 G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(GetPosition()), GetCombatReach());
1149
1150 return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAbsoluteAngle(contactPoint.x, contactPoint.y));
1151}
1152
1153bool WorldObject::IsWithinLOS(float ox, float oy, float oz, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const
1154{
1155 if (IsInWorld())
1156 {
1157 oz += GetCollisionHeight();
1158 float x, y, z;
1159 if (GetTypeId() == TYPEID_PLAYER)
1160 {
1161 GetPosition(x, y, z);
1162 z += GetCollisionHeight();
1163 }
1164 else
1165 GetHitSpherePointFor({ ox, oy, oz }, x, y, z);
1166
1167 return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z, ox, oy, oz, checks, ignoreFlags);
1168 }
1169
1170 return true;
1171}
1172
1174{
1175 if (!IsInMap(obj))
1176 return false;
1177
1178 float ox, oy, oz;
1179 if (obj->GetTypeId() == TYPEID_PLAYER)
1180 {
1181 obj->GetPosition(ox, oy, oz);
1182 oz += GetCollisionHeight();
1183 }
1184 else
1186
1187 float x, y, z;
1188 if (GetTypeId() == TYPEID_PLAYER)
1189 {
1190 GetPosition(x, y, z);
1191 z += GetCollisionHeight();
1192 }
1193 else
1194 GetHitSpherePointFor({ obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ() + obj->GetCollisionHeight() }, x, y, z);
1195
1196 return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z, ox, oy, oz, checks, ignoreFlags);
1197}
1198
1199void WorldObject::GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const
1200{
1201 Position pos = GetHitSpherePointFor(dest);
1202 x = pos.GetPositionX();
1203 y = pos.GetPositionY();
1204 z = pos.GetPositionZ();
1205}
1206
1207bool WorldObject::GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D /* = true */) const
1208{
1209 float dx1 = GetPositionX() - obj1->GetPositionX();
1210 float dy1 = GetPositionY() - obj1->GetPositionY();
1211 float distsq1 = dx1*dx1 + dy1*dy1;
1212 if (is3D)
1213 {
1214 float dz1 = GetPositionZ() - obj1->GetPositionZ();
1215 distsq1 += dz1*dz1;
1216 }
1217
1218 float dx2 = GetPositionX() - obj2->GetPositionX();
1219 float dy2 = GetPositionY() - obj2->GetPositionY();
1220 float distsq2 = dx2*dx2 + dy2*dy2;
1221 if (is3D)
1222 {
1223 float dz2 = GetPositionZ() - obj2->GetPositionZ();
1224 distsq2 += dz2*dz2;
1225 }
1226
1227 return distsq1 < distsq2;
1228}
1229
1230bool WorldObject::IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D /* = true */) const
1231{
1232 float dx = GetPositionX() - obj->GetPositionX();
1233 float dy = GetPositionY() - obj->GetPositionY();
1234 float distsq = dx*dx + dy*dy;
1235 if (is3D)
1236 {
1237 float dz = GetPositionZ() - obj->GetPositionZ();
1238 distsq += dz*dz;
1239 }
1240
1241 float sizefactor = GetCombatReach() + obj->GetCombatReach();
1242
1243 // check only for real range
1244 if (minRange > 0.0f)
1245 {
1246 float mindist = minRange + sizefactor;
1247 if (distsq < mindist * mindist)
1248 return false;
1249 }
1250
1251 float maxdist = maxRange + sizefactor;
1252 return distsq < maxdist * maxdist;
1253}
1254
1255bool WorldObject::IsInRange2d(float x, float y, float minRange, float maxRange) const
1256{
1257 float dx = GetPositionX() - x;
1258 float dy = GetPositionY() - y;
1259 float distsq = dx*dx + dy*dy;
1260
1261 float sizefactor = GetCombatReach();
1262
1263 // check only for real range
1264 if (minRange > 0.0f)
1265 {
1266 float mindist = minRange + sizefactor;
1267 if (distsq < mindist * mindist)
1268 return false;
1269 }
1270
1271 float maxdist = maxRange + sizefactor;
1272 return distsq < maxdist * maxdist;
1273}
1274
1275bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float maxRange) const
1276{
1277 float dx = GetPositionX() - x;
1278 float dy = GetPositionY() - y;
1279 float dz = GetPositionZ() - z;
1280 float distsq = dx*dx + dy*dy + dz*dz;
1281
1282 float sizefactor = GetCombatReach();
1283
1284 // check only for real range
1285 if (minRange > 0.0f)
1286 {
1287 float mindist = minRange + sizefactor;
1288 if (distsq < mindist * mindist)
1289 return false;
1290 }
1291
1292 float maxdist = maxRange + sizefactor;
1293 return distsq < maxdist * maxdist;
1294}
1295
1296bool WorldObject::IsInBetween(Position const& pos1, Position const& pos2, float size) const
1297{
1298 float dist = GetExactDist2d(pos1);
1299
1300 // not using sqrt() for performance
1301 if ((dist * dist) >= pos1.GetExactDist2dSq(pos2))
1302 return false;
1303
1304 if (!size)
1305 size = GetCombatReach() / 2;
1306
1307 float angle = pos1.GetAbsoluteAngle(pos2);
1308
1309 // not using sqrt() for performance
1310 return (size * size) >= GetExactDist2dSq(pos1.GetPositionX() + std::cos(angle) * dist, pos1.GetPositionY() + std::sin(angle) * dist);
1311}
1312
1313bool WorldObject::isInFront(WorldObject const* target, float arc) const
1314{
1315 return HasInArc(arc, target);
1316}
1317
1318bool WorldObject::isInBack(WorldObject const* target, float arc) const
1319{
1320 return !HasInArc(2 * float(M_PI) - arc, target);
1321}
1322
1323void WorldObject::GetRandomPoint(Position const& pos, float distance, float& rand_x, float& rand_y, float& rand_z) const
1324{
1325 if (!distance)
1326 {
1327 pos.GetPosition(rand_x, rand_y, rand_z);
1328 return;
1329 }
1330
1331 // angle to face `obj` to `this`
1332 float angle = rand_norm() * static_cast<float>(2 * M_PI);
1333 float new_dist = rand_norm() + rand_norm();
1334 new_dist = distance * (new_dist > 1 ? new_dist - 2 : new_dist);
1335
1336 rand_x = pos.m_positionX + new_dist * std::cos(angle);
1337 rand_y = pos.m_positionY + new_dist * std::sin(angle);
1338 rand_z = pos.m_positionZ;
1339
1342 UpdateGroundPositionZ(rand_x, rand_y, rand_z); // update to LOS height if available
1343}
1344
1345Position WorldObject::GetRandomPoint(Position const& srcPos, float distance) const
1346{
1347 float x, y, z;
1348 GetRandomPoint(srcPos, distance, x, y, z);
1349 return Position(x, y, z, GetOrientation());
1350}
1351
1352void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const
1353{
1354 float new_z = GetMapHeight(x, y, z);
1355 if (new_z > INVALID_HEIGHT)
1356 z = new_z + (isType(TYPEMASK_UNIT) ? static_cast<Unit const*>(this)->GetHoverOffset() : 0.0f);
1357}
1358
1359void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z, float* groundZ) const
1360{
1361 // TODO: Allow transports to be part of dynamic vmap tree
1362 if (GetTransport())
1363 {
1364 if (groundZ)
1365 *groundZ = z;
1366
1367 return;
1368 }
1369
1370 if (Unit const* unit = ToUnit())
1371 {
1372 if (!unit->CanFly())
1373 {
1374 bool canSwim = unit->CanSwim();
1375 float ground_z = z;
1376 float max_z;
1377 if (canSwim)
1378 max_z = GetMapWaterOrGroundLevel(x, y, z, &ground_z);
1379 else
1380 max_z = ground_z = GetMapHeight(x, y, z);
1381
1382 if (max_z > INVALID_HEIGHT)
1383 {
1384 // hovering units cannot go below their hover height
1385 float hoverOffset = unit->GetHoverOffset();
1386 max_z += hoverOffset;
1387 ground_z += hoverOffset;
1388
1389 if (z > max_z)
1390 z = max_z;
1391 else if (z < ground_z)
1392 z = ground_z;
1393 }
1394
1395 if (groundZ)
1396 *groundZ = ground_z;
1397 }
1398 else
1399 {
1400 float ground_z = GetMapHeight(x, y, z) + unit->GetHoverOffset();
1401 if (z < ground_z)
1402 z = ground_z;
1403
1404 if (groundZ)
1405 *groundZ = ground_z;
1406 }
1407 }
1408 else
1409 {
1410 float ground_z = GetMapHeight(x, y, z);
1411 if (ground_z > INVALID_HEIGHT)
1412 z = ground_z;
1413
1414 if (groundZ)
1415 *groundZ = ground_z;
1416 }
1417}
1418
1420{
1421 if (isActiveObject())
1422 {
1423 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetCinematicMgr()->IsOnCinematic())
1425
1426 return GetMap()->GetVisibilityRange();
1427 }
1428
1429 if (Creature const* thisCreature = ToCreature())
1430 return thisCreature->m_SightDistance;
1431
1432 return 0.0f;
1433}
1434
1436{
1437 if (IsVisibilityOverridden() && !ToPlayer())
1439 else if (IsFarVisible() && !ToPlayer())
1441 else
1442 return GetMap()->GetVisibilityRange();
1443}
1444
1445float WorldObject::GetSightRange(WorldObject const* target) const
1446{
1447 if (ToUnit())
1448 {
1449 if (ToPlayer())
1450 {
1451 if (target && target->IsVisibilityOverridden() && !target->ToPlayer())
1452 return *target->m_visibilityDistanceOverride;
1453 else if (target && target->IsFarVisible() && !target->ToPlayer())
1455 else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
1457 else
1458 return GetMap()->GetVisibilityRange();
1459 }
1460 else if (ToCreature())
1461 return ToCreature()->m_SightDistance;
1462 else
1463 return SIGHT_RANGE_UNIT;
1464 }
1465
1466 if (ToDynObject() && isActiveObject())
1467 {
1468 return GetMap()->GetVisibilityRange();
1469 }
1470
1471 return 0.0f;
1472}
1473
1475{
1476 if (!IsPrivateObject())
1477 return true;
1478
1479 // Owner of this private object
1480 if (_privateObjectOwner == seer->GetGUID())
1481 return true;
1482
1483 // Another private object of the same owner
1485 return true;
1486
1487 if (Player const* playerSeer = seer->ToPlayer())
1488 if (playerSeer->IsInGroup(_privateObjectOwner))
1489 return true;
1490
1491 return false;
1492}
1493
1495{
1496 if (!_smoothPhasing)
1497 _smoothPhasing = std::make_unique<SmoothPhasing>();
1498
1499 return _smoothPhasing.get();
1500}
1501
1502bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool implicitDetect, bool distanceCheck, bool checkAlert) const
1503{
1504 if (this == obj)
1505 return true;
1506
1507 if (obj->IsNeverVisibleFor(this, implicitDetect) || CanNeverSee(obj))
1508 return false;
1509
1510 if (obj->IsAlwaysVisibleFor(this) || CanAlwaysSee(obj))
1511 return true;
1512
1513 if (!obj->CheckPrivateObjectOwnerVisibility(this))
1514 return false;
1515
1516 if (SmoothPhasing const* smoothPhasing = obj->GetSmoothPhasing())
1517 if (smoothPhasing->IsBeingReplacedForSeer(GetGUID()))
1518 return false;
1519
1520 if (!obj->IsPrivateObject() && !sConditionMgr->IsObjectMeetingVisibilityByObjectIdConditions(obj->GetTypeId(), obj->GetEntry(), this))
1521 return false;
1522
1523 bool corpseVisibility = false;
1524 if (distanceCheck)
1525 {
1526 bool corpseCheck = false;
1527 if (Player const* thisPlayer = ToPlayer())
1528 {
1529 if (thisPlayer->isDead() && thisPlayer->GetHealth() > 0 && // Cheap way to check for ghost state
1531 {
1532 if (Corpse* corpse = thisPlayer->GetCorpse())
1533 {
1534 corpseCheck = true;
1535 if (corpse->IsWithinDist(thisPlayer, GetSightRange(obj), false))
1536 if (corpse->IsWithinDist(obj, GetSightRange(obj), false))
1537 corpseVisibility = true;
1538 }
1539 }
1540
1541 if (Unit const* target = obj->ToUnit())
1542 {
1543 // Don't allow to detect vehicle accessories if you can't see vehicle
1544 if (Unit const* vehicle = target->GetVehicleBase())
1545 if (!thisPlayer->HaveAtClient(vehicle))
1546 return false;
1547 }
1548 }
1549
1550 WorldObject const* viewpoint = this;
1551 if (Player const* player = ToPlayer())
1552 viewpoint = player->GetViewpoint();
1553
1554 if (!viewpoint)
1555 viewpoint = this;
1556
1557 if (!corpseCheck && !viewpoint->IsWithinDist(obj, GetSightRange(obj), false))
1558 return false;
1559 }
1560
1561 // GM visibility off or hidden NPC
1563 {
1564 // Stop checking other things for GMs
1566 return true;
1567 }
1568 else
1570
1571 // Ghost players, Spirit Healers, and some other NPCs
1573 {
1574 // Alive players can see dead players in some cases, but other objects can't do that
1575 if (Player const* thisPlayer = ToPlayer())
1576 {
1577 if (Player const* objPlayer = obj->ToPlayer())
1578 {
1579 if (!thisPlayer->IsGroupVisibleFor(objPlayer))
1580 return false;
1581 }
1582 else
1583 return false;
1584 }
1585 else
1586 return false;
1587 }
1588
1589 if (obj->IsInvisibleDueToDespawn(this))
1590 return false;
1591
1592 if (!CanDetect(obj, implicitDetect, checkAlert))
1593 return false;
1594
1595 return true;
1596}
1597
1599{
1600 return GetMap() != obj->GetMap() || !InSamePhase(obj);
1601}
1602
1603bool WorldObject::CanDetect(WorldObject const* obj, bool implicitDetect, bool checkAlert) const
1604{
1605 WorldObject const* seer = this;
1606
1607 // If a unit is possessing another one, it uses the detection of the latter
1608 // Pets don't have detection, they use the detection of their masters
1609 if (Unit const* thisUnit = ToUnit())
1610 {
1611 if (thisUnit->isPossessing())
1612 {
1613 if (Unit* charmed = thisUnit->GetCharmed())
1614 seer = charmed;
1615 }
1616 else if (Unit* controller = thisUnit->GetCharmerOrOwner())
1617 seer = controller;
1618 }
1619
1620 if (obj->IsAlwaysDetectableFor(seer))
1621 return true;
1622
1623 if (!implicitDetect && !seer->CanDetectInvisibilityOf(obj))
1624 return false;
1625
1626 if (!implicitDetect && !seer->CanDetectStealthOf(obj, checkAlert))
1627 return false;
1628
1629 return true;
1630}
1631
1633{
1635
1636 // Check for not detected types
1637 if (mask != obj->m_invisibility.GetFlags())
1638 return false;
1639
1640 for (uint32 i = 0; i < TOTAL_INVISIBILITY_TYPES; ++i)
1641 {
1642 if (!(mask & (uint64(1) << i)))
1643 continue;
1644
1645 int32 objInvisibilityValue = obj->m_invisibility.GetValue(InvisibilityType(i));
1646 int32 ownInvisibilityDetectValue = m_invisibilityDetect.GetValue(InvisibilityType(i));
1647
1648 // Too low value to detect
1649 if (ownInvisibilityDetectValue < objInvisibilityValue)
1650 return false;
1651 }
1652
1653 return true;
1654}
1655
1656bool WorldObject::CanDetectStealthOf(WorldObject const* obj, bool checkAlert) const
1657{
1658 // Combat reach is the minimal distance (both in front and behind),
1659 // and it is also used in the range calculation.
1660 // One stealth point increases the visibility range by 0.3 yard.
1661
1662 if (!obj->m_stealth.GetFlags())
1663 return true;
1664
1665 float distance = GetExactDist(obj);
1666 float combatReach = 0.0f;
1667
1668 Unit const* unit = ToUnit();
1669 if (unit)
1670 combatReach = unit->GetCombatReach();
1671
1672 if (distance < combatReach)
1673 return true;
1674
1675 // Only check back for units, it does not make sense for gameobjects
1676 if (unit && !HasInArc(float(M_PI), obj))
1677 return false;
1678
1679 // Traps should detect stealth always
1680 if (GameObject const* go = ToGameObject())
1681 if (go->GetGoType() == GAMEOBJECT_TYPE_TRAP)
1682 return true;
1683
1684 GameObject const* go = obj->ToGameObject();
1685 for (uint32 i = 0; i < TOTAL_STEALTH_TYPES; ++i)
1686 {
1687 if (!(obj->m_stealth.GetFlags() & (1 << i)))
1688 continue;
1689
1691 return true;
1692
1693 // Starting points
1694 int32 detectionValue = 30;
1695
1696 // Level difference: 5 point / level, starting from level 1.
1697 // There may be spells for this and the starting points too, but
1698 // not in the DBCs of the client.
1699 detectionValue += int32(GetLevelForTarget(obj) - 1) * 5;
1700
1701 // Apply modifiers
1702 detectionValue += m_stealthDetect.GetValue(StealthType(i));
1703 if (go)
1704 if (Unit* owner = go->GetOwner())
1705 detectionValue -= int32(owner->GetLevelForTarget(this) - 1) * 5;
1706
1707 detectionValue -= obj->m_stealth.GetValue(StealthType(i));
1708
1709 // Calculate max distance
1710 float visibilityRange = float(detectionValue) * 0.3f + combatReach;
1711
1712 // If this unit is an NPC then player detect range doesn't apply
1713 if (unit && unit->GetTypeId() == TYPEID_PLAYER && visibilityRange > MAX_PLAYER_STEALTH_DETECT_RANGE)
1714 visibilityRange = MAX_PLAYER_STEALTH_DETECT_RANGE;
1715
1716 // When checking for alert state, look 8% further, and then 1.5 yards more than that.
1717 if (checkAlert)
1718 visibilityRange += (visibilityRange * 0.08f) + 1.5f;
1719
1720 // If checking for alert, and creature's visibility range is greater than aggro distance, No alert
1721 Unit const* tunit = obj->ToUnit();
1722 if (checkAlert && unit && unit->ToCreature() && visibilityRange >= unit->ToCreature()->GetAttackDistance(tunit) + unit->ToCreature()->m_CombatDistance)
1723 return false;
1724
1725 if (distance > visibilityRange)
1726 return false;
1727 }
1728
1729 return true;
1730}
1731
1732void WorldObject::SendMessageToSet(WorldPacket const* data, bool self) const
1733{
1734 if (IsInWorld())
1736}
1737
1738void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/) const
1739{
1740 Trinity::PacketSenderRef sender(data);
1742 Cell::VisitWorldObjects(this, notifier, dist);
1743}
1744
1745void WorldObject::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const
1746{
1747 Trinity::PacketSenderRef sender(data);
1748 Trinity::MessageDistDeliverer<Trinity::PacketSenderRef> notifier(this, sender, GetVisibilityRange(), false, skipped_rcvr);
1750}
1751
1753{
1755
1757 : i_message(msg)
1758 {
1759 msg->Write();
1760 }
1761
1762 void operator()(Player const* player) const
1763 {
1764 if (player->IsAdvancedCombatLoggingEnabled())
1766 else
1768 }
1769};
1770
1772{
1773 CombatLogSender combatLogSender(combatLog);
1774
1775 if (Player const* self = ToPlayer())
1776 combatLogSender(self);
1777
1778 Trinity::MessageDistDeliverer<CombatLogSender> notifier(this, combatLogSender, GetVisibilityRange());
1780}
1781
1783{
1784 ASSERT(map);
1785 ASSERT(!IsInWorld());
1786 if (m_currMap == map) // command add npc: first create, than loadfromdb
1787 return;
1788 if (m_currMap)
1789 {
1790 TC_LOG_FATAL("misc", "WorldObject::SetMap: obj {} new map {} {}, old map {} {}", (uint32)GetTypeId(), map->GetId(), map->GetInstanceId(), m_currMap->GetId(), m_currMap->GetInstanceId());
1791 ABORT();
1792 }
1793 m_currMap = map;
1794 m_mapId = map->GetId();
1795 m_InstanceId = map->GetInstanceId();
1796 if (IsWorldObject())
1798}
1799
1801{
1803 ASSERT(!IsInWorld());
1804 if (IsWorldObject())
1806 m_currMap = nullptr;
1807 //maybe not for corpse
1808 //m_mapId = 0;
1809 //m_InstanceId = 0;
1810}
1811
1813{
1814 Map* map = FindMap();
1815 if (!map)
1816 {
1817 TC_LOG_ERROR("misc", "Object {} at attempt add to move list not have valid map (Id: {}).", GetGUID().ToString(), GetMapId());
1818 return;
1819 }
1820
1821 map->AddObjectToRemoveList(this);
1822}
1823
1824TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties /*= nullptr*/, Milliseconds duration /*= 0ms*/, WorldObject* summoner /*= nullptr*/, uint32 spellId /*= 0*/, uint32 vehId /*= 0*/, ObjectGuid privateObjectOwner /*= ObjectGuid::Empty*/, SmoothPhasingInfo const* smoothPhasingInfo /* = nullptr*/)
1825{
1826 uint32 mask = UNIT_MASK_SUMMON;
1827 if (properties)
1828 {
1829 switch (properties->Control)
1830 {
1832 mask = UNIT_MASK_GUARDIAN;
1833 break;
1835 mask = UNIT_MASK_PUPPET;
1836 break;
1838 mask = UNIT_MASK_MINION;
1839 break;
1843 {
1844 switch (SummonTitle(properties->Title))
1845 {
1849 mask = UNIT_MASK_GUARDIAN;
1850 break;
1851 case SummonTitle::Totem:
1853 mask = UNIT_MASK_TOTEM;
1854 break;
1856 case SummonTitle::Mount:
1857 mask = UNIT_MASK_SUMMON;
1858 break;
1860 mask = UNIT_MASK_MINION;
1861 break;
1862 default:
1864 mask = UNIT_MASK_GUARDIAN;
1865 break;
1866 }
1867 break;
1868 }
1869 default:
1870 return nullptr;
1871 }
1872 }
1873
1874 Unit* summonerUnit = summoner ? summoner->ToUnit() : nullptr;
1875
1876 TempSummon* summon = nullptr;
1877 switch (mask)
1878 {
1879 case UNIT_MASK_SUMMON:
1880 summon = new TempSummon(properties, summoner, false);
1881 break;
1882 case UNIT_MASK_GUARDIAN:
1883 summon = new Guardian(properties, summonerUnit, false);
1884 break;
1885 case UNIT_MASK_PUPPET:
1886 summon = new Puppet(properties, summonerUnit);
1887 break;
1888 case UNIT_MASK_TOTEM:
1889 summon = new Totem(properties, summonerUnit);
1890 break;
1891 case UNIT_MASK_MINION:
1892 summon = new Minion(properties, summonerUnit, false);
1893 break;
1894 }
1895
1896 if (!summon->Create(GenerateLowGuid<HighGuid::Creature>(), this, entry, pos, nullptr, vehId, true))
1897 {
1898 delete summon;
1899 return nullptr;
1900 }
1901
1902 TransportBase* transport = summoner ? summoner->GetTransport() : nullptr;
1903 if (transport)
1904 {
1905 float x, y, z, o;
1906 pos.GetPosition(x, y, z, o);
1907 transport->CalculatePassengerOffset(x, y, z, &o);
1908 summon->m_movementInfo.transport.pos.Relocate(x, y, z, o);
1909
1910 // This object must be added to transport before adding to map for the client to properly display it
1911 transport->AddPassenger(summon);
1912 }
1913
1914 if (summoner && !(properties && properties->GetFlags().HasFlag(SummonPropertiesFlags::IgnoreSummonerPhase)))
1915 PhasingHandler::InheritPhaseShift(summon, summoner);
1916
1917 summon->SetCreatedBySpell(spellId);
1918
1919 summon->SetHomePosition(pos);
1920
1921 summon->InitStats(summoner, duration);
1922
1923 summon->SetPrivateObjectOwner(privateObjectOwner);
1924
1925 if (smoothPhasingInfo)
1926 {
1927 if (summoner && smoothPhasingInfo->ReplaceObject)
1928 {
1929 if (WorldObject* replacedObject = ObjectAccessor::GetWorldObject(*summoner, *smoothPhasingInfo->ReplaceObject))
1930 {
1931 SmoothPhasingInfo originalSmoothPhasingInfo = *smoothPhasingInfo;
1932 originalSmoothPhasingInfo.ReplaceObject = summon->GetGUID();
1933 replacedObject->GetOrCreateSmoothPhasing()->SetViewerDependentInfo(privateObjectOwner, originalSmoothPhasingInfo);
1934
1935 summon->SetDemonCreatorGUID(privateObjectOwner);
1936 }
1937 }
1938
1939 summon->GetOrCreateSmoothPhasing()->SetSingleInfo(*smoothPhasingInfo);
1940 }
1941
1942 if (!AddToMap(summon->ToCreature()))
1943 {
1944 // Returning false will cause the object to be deleted - remove from transport
1945 if (transport)
1946 transport->RemovePassenger(summon);
1947
1948 delete summon;
1949 return nullptr;
1950 }
1951
1952 summon->InitSummon(summoner);
1953
1954 // call MoveInLineOfSight for nearby creatures
1955 Trinity::AIRelocationNotifier notifier(*summon);
1956 Cell::VisitAllObjects(summon, notifier, GetVisibilityRange());
1957
1958 return summon;
1959}
1960
1968void Map::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= nullptr*/)
1969{
1970 std::vector<TempSummonData> const* data = sObjectMgr->GetSummonGroup(GetId(), SUMMONER_TYPE_MAP, group);
1971 if (!data)
1972 return;
1973
1974 for (std::vector<TempSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr)
1975 if (TempSummon* summon = SummonCreature(itr->entry, itr->pos, nullptr, itr->time))
1976 if (list)
1977 list->push_back(summon);
1978}
1979
1981{
1982 if (Map* map = FindMap())
1983 {
1984 if (InstanceMap* instanceMap = map->ToInstanceMap())
1985 return reinterpret_cast<ZoneScript*>(instanceMap->GetInstanceScript());
1986 if (BattlegroundMap* bgMap = map->ToBattlegroundMap())
1987 return reinterpret_cast<ZoneScript*>(bgMap->GetBG());
1988 if (!map->IsBattlegroundOrArena())
1989 {
1990 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(map, GetZoneId()))
1991 return bf;
1992
1993 return sOutdoorPvPMgr->GetOutdoorPvPToZoneId(map, GetZoneId());
1994 }
1995 }
1996 return nullptr;
1997}
1998
2000{
2002}
2003
2005{
2006 if (IsInWorld())
2007 if (InstanceMap* instanceMap = GetMap()->ToInstanceMap())
2008 return instanceMap->GetInstanceScenario();
2009
2010 return nullptr;
2011}
2012
2013TempSummon* WorldObject::SummonCreature(uint32 entry, Position const& pos, TempSummonType despawnType /*= TEMPSUMMON_MANUAL_DESPAWN*/, Milliseconds despawnTime /*= 0s*/, uint32 vehId /*= 0*/, uint32 spellId /*= 0*/, ObjectGuid privateObjectOwner /* = ObjectGuid::Empty */)
2014{
2015 if (Map* map = FindMap())
2016 {
2017 if (TempSummon* summon = map->SummonCreature(entry, pos, nullptr, despawnTime, this, spellId, vehId, privateObjectOwner))
2018 {
2019 summon->SetTempSummonType(despawnType);
2020 return summon;
2021 }
2022 }
2023
2024 return nullptr;
2025}
2026
2027TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float o /*= 0*/, TempSummonType despawnType /*= TEMPSUMMON_MANUAL_DESPAWN*/, Milliseconds despawnTime /*= 0s*/, ObjectGuid privateObjectOwner /* = ObjectGuid::Empty */)
2028{
2029 if (!x && !y && !z)
2030 GetClosePoint(x, y, z, GetCombatReach());
2031 if (!o)
2032 o = GetOrientation();
2033 return SummonCreature(id, { x,y,z,o }, despawnType, despawnTime, 0, 0, privateObjectOwner);
2034}
2035
2036TempSummon* WorldObject::SummonPersonalClone(Position const& pos, TempSummonType despawnType /*= TEMPSUMMON_MANUAL_DESPAWN*/, Milliseconds despawnTime /*= 0s*/, uint32 vehId /*= 0*/, uint32 spellId /*= 0*/, Player* privateObjectOwner /*= nullptr*/)
2037{
2038 ASSERT(privateObjectOwner);
2039
2040 if (Map* map = FindMap())
2041 {
2042 SmoothPhasingInfo smoothPhasingInfo{GetGUID(), true, true};
2043 if (TempSummon* summon = map->SummonCreature(GetEntry(), pos, nullptr, despawnTime, privateObjectOwner, spellId, vehId, privateObjectOwner->GetGUID(), &smoothPhasingInfo))
2044 {
2045 summon->SetTempSummonType(despawnType);
2046 return summon;
2047 }
2048 }
2049
2050 return nullptr;
2051}
2052
2053GameObject* WorldObject::SummonGameObject(uint32 entry, Position const& pos, QuaternionData const& rot, Seconds respawnTime, GOSummonType summonType)
2054{
2055 if (!IsInWorld())
2056 return nullptr;
2057
2058 GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
2059 if (!goinfo)
2060 {
2061 TC_LOG_ERROR("sql.sql", "Gameobject template {} not found in database!", entry);
2062 return nullptr;
2063 }
2064
2065 Map* map = GetMap();
2066 GameObject* go = GameObject::CreateGameObject(entry, map, pos, rot, 255, GO_STATE_READY);
2067 if (!go)
2068 return nullptr;
2069
2071
2072 go->SetRespawnTime(respawnTime.count());
2073 if (GetTypeId() == TYPEID_PLAYER || (GetTypeId() == TYPEID_UNIT && summonType == GO_SUMMON_TIMED_OR_CORPSE_DESPAWN)) //not sure how to handle this
2074 ToUnit()->AddGameObject(go);
2075 else
2076 go->SetSpawnedByDefault(false);
2077
2078 map->AddToMap(go);
2079 return go;
2080}
2081
2082GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, QuaternionData const& rot, Seconds respawnTime, GOSummonType summonType)
2083{
2084 if (!x && !y && !z)
2085 {
2086 GetClosePoint(x, y, z, GetCombatReach());
2087 ang = GetOrientation();
2088 }
2089
2090 Position pos(x, y, z, ang);
2091 return SummonGameObject(entry, pos, rot, respawnTime, summonType);
2092}
2093
2094Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, Milliseconds despawnTime, CreatureAI* (*GetAI)(Creature*))
2095{
2096 TempSummonType summonType = (despawnTime == 0s) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
2097 Creature* summon = SummonCreature(WORLD_TRIGGER, x, y, z, ang, summonType, despawnTime);
2098 if (!summon)
2099 return nullptr;
2100
2101 //summon->SetName(GetName());
2103 {
2104 summon->SetFaction(((Unit*)this)->GetFaction());
2105 summon->SetLevel(((Unit*)this)->GetLevel());
2106 }
2107
2108 if (GetAI)
2109 summon->AIM_Initialize(GetAI(summon));
2110 return summon;
2111}
2112
2119void WorldObject::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= nullptr*/)
2120{
2121 ASSERT((GetTypeId() == TYPEID_GAMEOBJECT || GetTypeId() == TYPEID_UNIT) && "Only GOs and creatures can summon npc groups!");
2122
2123 std::vector<TempSummonData> const* data = sObjectMgr->GetSummonGroup(GetEntry(), GetTypeId() == TYPEID_GAMEOBJECT ? SUMMONER_TYPE_GAMEOBJECT : SUMMONER_TYPE_CREATURE, group);
2124 if (!data)
2125 {
2126 TC_LOG_WARN("scripts", "{} ({}) tried to summon non-existing summon group {}.", GetName(), GetGUID().ToString(), group);
2127 return;
2128 }
2129
2130 for (std::vector<TempSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr)
2131 if (TempSummon* summon = SummonCreature(itr->entry, itr->pos, itr->type, Milliseconds(itr->time)))
2132 if (list)
2133 list->push_back(summon);
2134}
2135
2136Creature* WorldObject::FindNearestCreature(uint32 entry, float range, bool alive) const
2137{
2138 Creature* creature = nullptr;
2139 Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck checker(*this, entry, alive, range);
2141 Cell::VisitAllObjects(this, searcher, range);
2142 return creature;
2143}
2144
2146{
2147 Creature* creature = nullptr;
2148 Trinity::NearestCheckCustomizer checkCustomizer(*this, range);
2149 Trinity::CreatureWithOptionsInObjectRangeCheck checker(*this, checkCustomizer, options);
2150 Trinity::CreatureLastSearcher searcher(this, creature, checker);
2151 if (options.IgnorePhases)
2153
2154 Cell::VisitAllObjects(this, searcher, range);
2155 return creature;
2156}
2157
2158GameObject* WorldObject::FindNearestGameObject(uint32 entry, float range, bool spawnedOnly) const
2159{
2160 GameObject* go = nullptr;
2161 Trinity::NearestGameObjectEntryInObjectRangeCheck checker(*this, entry, range, spawnedOnly);
2163 Cell::VisitGridObjects(this, searcher, range);
2164 return go;
2165}
2166
2168{
2169 GameObject* go = nullptr;
2170 Trinity::NearestCheckCustomizer checkCustomizer(*this, range);
2171 Trinity::GameObjectWithOptionsInObjectRangeCheck checker(*this, checkCustomizer, options);
2172 Trinity::GameObjectLastSearcher searcher(this, go, checker);
2173 if (options.IgnorePhases)
2175
2176 Cell::VisitGridObjects(this, searcher, range);
2177 return go;
2178}
2179
2181{
2182 GameObject* go = nullptr;
2185 Cell::VisitGridObjects(this, searcher, range);
2186 return go;
2187}
2188
2190{
2191 GameObject* go = nullptr;
2192 Trinity::NearestGameObjectTypeInObjectRangeCheck checker(*this, type, range);
2194 Cell::VisitGridObjects(this, searcher, range);
2195 return go;
2196}
2197
2199{
2200 Player* target = nullptr;
2201
2202 Trinity::NearestPlayerInObjectRangeCheck checker(this, range);
2204 Cell::VisitWorldObjects(this, searcher, range);
2205
2206 return target;
2207}
2208
2210{
2212 if (!guid.IsEmpty())
2213 return guid;
2214 return GetGUID();
2215}
2216
2218{
2219 return ObjectAccessor::GetUnit(*this, GetOwnerGUID());
2220}
2221
2223{
2224 if (Unit const* unit = ToUnit())
2225 return unit->GetCharmerOrOwner();
2226 else if (GameObject const* go = ToGameObject())
2227 return go->GetOwner();
2228
2229 return nullptr;
2230}
2231
2233{
2234 if (Unit* u = GetCharmerOrOwner())
2235 return u;
2236
2237 return const_cast<WorldObject*>(this)->ToUnit();
2238}
2239
2241{
2243 if (guid.IsPlayer())
2244 return ObjectAccessor::GetPlayer(*this, guid);
2245
2246 return const_cast<WorldObject*>(this)->ToPlayer();
2247}
2248
2250{
2251 if (!GetCharmerOrOwnerGUID())
2252 return const_cast<WorldObject*>(this)->ToPlayer();
2253
2254 if (Unit* owner = GetCharmerOrOwner())
2256
2257 return nullptr;
2258}
2259
2261{
2262 if (Player* player = const_cast<WorldObject*>(this)->ToPlayer())
2263 return player;
2264
2265 if (GetTypeId() == TYPEID_UNIT)
2266 {
2267 Creature const* creature = ToCreature();
2268 if (creature->IsPet() || creature->IsTotem())
2269 {
2270 if (Unit* owner = creature->GetOwner())
2271 return owner->ToPlayer();
2272 }
2273 }
2274 else if (GetTypeId() == TYPEID_GAMEOBJECT)
2275 {
2276 GameObject const* go = ToGameObject();
2277 if (Unit* owner = go->GetOwner())
2278 return owner->ToPlayer();
2279 }
2280
2281 return nullptr;
2282}
2283
2284// function uses real base points (typically value - 1)
2285int32 WorldObject::CalculateSpellDamage(Unit const* target, SpellEffectInfo const& spellEffectInfo, int32 const* basePoints /*= nullptr*/, float* variance /*= nullptr*/, uint32 castItemId /*= 0*/, int32 itemLevel /*= -1*/) const
2286{
2287 if (variance)
2288 *variance = 0.0f;
2289
2290 return spellEffectInfo.CalcValue(this, basePoints, target, variance, castItemId, itemLevel);
2291}
2292
2293float WorldObject::GetSpellMaxRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const
2294{
2295 if (!spellInfo->RangeEntry)
2296 return 0.f;
2297
2298 if (spellInfo->RangeEntry->RangeMax[0] == spellInfo->RangeEntry->RangeMax[1])
2299 return spellInfo->GetMaxRange();
2300
2301 if (!target)
2302 return spellInfo->GetMaxRange(true);
2303
2304 return spellInfo->GetMaxRange(!IsHostileTo(target));
2305}
2306
2307float WorldObject::GetSpellMinRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const
2308{
2309 if (!spellInfo->RangeEntry)
2310 return 0.f;
2311
2312 if (spellInfo->RangeEntry->RangeMin[0] == spellInfo->RangeEntry->RangeMin[1])
2313 return spellInfo->GetMinRange();
2314
2315 if (!target)
2316 return spellInfo->GetMinRange(true);
2317
2318 return spellInfo->GetMinRange(!IsHostileTo(target));
2319}
2320
2321double WorldObject::ApplyEffectModifiers(SpellInfo const* spellInfo, uint8 effIndex, double value) const
2322{
2323 if (Player* modOwner = GetSpellModOwner())
2324 {
2325 modOwner->ApplySpellMod(spellInfo, SpellModOp::Points, value);
2326 switch (effIndex)
2327 {
2328 case EFFECT_0:
2329 modOwner->ApplySpellMod(spellInfo, SpellModOp::PointsIndex0, value);
2330 break;
2331 case EFFECT_1:
2332 modOwner->ApplySpellMod(spellInfo, SpellModOp::PointsIndex1, value);
2333 break;
2334 case EFFECT_2:
2335 modOwner->ApplySpellMod(spellInfo, SpellModOp::PointsIndex2, value);
2336 break;
2337 case EFFECT_3:
2338 modOwner->ApplySpellMod(spellInfo, SpellModOp::PointsIndex3, value);
2339 break;
2340 case EFFECT_4:
2341 modOwner->ApplySpellMod(spellInfo, SpellModOp::PointsIndex4, value);
2342 break;
2343 default:
2344 break;
2345 }
2346 }
2347 return value;
2348}
2349
2350int32 WorldObject::CalcSpellDuration(SpellInfo const* spellInfo, std::vector<SpellPowerCost> const* powerCosts) const
2351{
2352 int32 minduration = spellInfo->GetDuration();
2353 if (minduration <= 0)
2354 return minduration;
2355
2356 int32 maxduration = spellInfo->GetMaxDuration();
2357 if (minduration == maxduration)
2358 return minduration;
2359
2360 Unit const* unit = ToUnit();
2361 if (!unit)
2362 return minduration;
2363
2364 if (!powerCosts)
2365 return minduration;
2366
2367 // we want only baseline cost here
2368 auto itr = std::find_if(spellInfo->PowerCosts.begin(), spellInfo->PowerCosts.end(), [=](SpellPowerEntry const* powerEntry)
2369 {
2370 return powerEntry && powerEntry->PowerType == POWER_COMBO_POINTS && (!powerEntry->RequiredAuraSpellID || unit->HasAura(powerEntry->RequiredAuraSpellID));
2371 });
2372
2373 if (itr == spellInfo->PowerCosts.end())
2374 return minduration;
2375
2376 auto consumedItr = std::find_if(powerCosts->begin(), powerCosts->end(),
2377 [](SpellPowerCost const& consumed) { return consumed.Power == POWER_COMBO_POINTS; });
2378 if (consumedItr == powerCosts->end())
2379 return minduration;
2380
2381 int32 baseComboCost = (*itr)->ManaCost + (*itr)->OptionalCost;
2382 if (PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(POWER_COMBO_POINTS))
2383 baseComboCost += int32(CalculatePct(powerTypeEntry->MaxBasePower, (*itr)->PowerCostPct + (*itr)->OptionalCostPct));
2384
2385 float durationPerComboPoint = float(maxduration - minduration) / baseComboCost;
2386 return minduration + int32(durationPerComboPoint * consumedItr->Amount);
2387}
2388
2389int32 WorldObject::ModSpellDuration(SpellInfo const* spellInfo, WorldObject const* target, int32 duration, bool positive, uint32 effectMask) const
2390{
2391 // don't mod permanent auras duration
2392 if (duration < 0)
2393 return duration;
2394
2395 // some auras are not affected by duration modifiers
2397 return duration;
2398
2399 // cut duration only of negative effects
2400 Unit const* unitTarget = target->ToUnit();
2401 if (!unitTarget)
2402 return duration;
2403
2404 if (!positive)
2405 {
2406 uint64 mechanicMask = spellInfo->GetSpellMechanicMaskByEffectMask(effectMask);
2407 auto mechanicCheck = [mechanicMask](AuraEffect const* aurEff) -> bool
2408 {
2409 if (mechanicMask & (UI64LIT(1) << aurEff->GetMiscValue()))
2410 return true;
2411 return false;
2412 };
2413
2414 // Find total mod value (negative bonus)
2415 int32 durationMod_always = unitTarget->GetTotalAuraModifier(SPELL_AURA_MECHANIC_DURATION_MOD, mechanicCheck);
2416 // Find max mod (negative bonus)
2417 int32 durationMod_not_stack = unitTarget->GetMaxNegativeAuraModifier(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanicCheck);
2418
2419 // Select strongest negative mod
2420 int32 durationMod = std::min(durationMod_always, durationMod_not_stack);
2421 if (durationMod != 0)
2422 AddPct(duration, durationMod);
2423
2424 // there are only negative mods currently
2425 durationMod_always = unitTarget->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL, spellInfo->Dispel);
2427
2428 durationMod = std::min(durationMod_always, durationMod_not_stack);
2429 if (durationMod != 0)
2430 AddPct(duration, durationMod);
2431 }
2432 else
2433 {
2434 // else positive mods here, there are no currently
2435 // when there will be, change GetTotalAuraModifierByMiscValue to GetMaxPositiveAuraModifierByMiscValue
2436
2437 // Mixology - duration boost
2438 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
2439 {
2440 if (spellInfo->SpellFamilyName == SPELLFAMILY_POTION && (
2441 sSpellMgr->IsSpellMemberOfSpellGroup(spellInfo->Id, SPELL_GROUP_ELIXIR_BATTLE) ||
2442 sSpellMgr->IsSpellMemberOfSpellGroup(spellInfo->Id, SPELL_GROUP_ELIXIR_GUARDIAN)))
2443 {
2444 SpellEffectInfo const& effect = spellInfo->GetEffect(EFFECT_0);
2445 if (unitTarget->HasAura(53042) && unitTarget->HasSpell(effect.TriggerSpell))
2446 duration *= 2;
2447 }
2448 }
2449 }
2450
2451 return std::max(duration, 0);
2452}
2453
2454void WorldObject::ModSpellCastTime(SpellInfo const* spellInfo, int32& castTime, Spell* spell /*= nullptr*/) const
2455{
2456 if (!spellInfo || castTime < 0)
2457 return;
2458
2459 // called from caster
2460 if (Player* modOwner = GetSpellModOwner())
2461 modOwner->ApplySpellMod(spellInfo, SpellModOp::ChangeCastTime, castTime, spell);
2462
2463 Unit const* unitCaster = ToUnit();
2464 if (!unitCaster)
2465 return;
2466
2467 if (unitCaster->IsPlayer() && unitCaster->ToPlayer()->GetCommandStatus(CHEAT_CASTTIME))
2468 castTime = 0;
2470 ((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
2471 castTime = unitCaster->CanInstantCast() ? 0 : int32(float(castTime) * unitCaster->m_unitData->ModCastingSpeed);
2473 castTime = int32(float(castTime) * unitCaster->m_modAttackSpeedPct[RANGED_ATTACK]);
2474 else if (IsPartOfSkillLine(SKILL_COOKING, spellInfo->Id) && unitCaster->HasAura(67556)) // cooking with Chef Hat.
2475 castTime = 500;
2476}
2477
2478void WorldObject::ModSpellDurationTime(SpellInfo const* spellInfo, int32& duration, Spell* spell /*= nullptr*/) const
2479{
2480 if (!spellInfo || duration < 0)
2481 return;
2482
2483 if (spellInfo->IsChanneled()
2486 return;
2487
2488 // called from caster
2489 if (Player* modOwner = GetSpellModOwner())
2490 modOwner->ApplySpellMod(spellInfo, SpellModOp::ChangeCastTime, duration, spell);
2491
2492 Unit const* unitCaster = ToUnit();
2493 if (!unitCaster)
2494 return;
2495
2497 ((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT))
2498 duration = int32(float(duration) * unitCaster->m_unitData->ModCastingSpeed);
2500 duration = int32(float(duration) * unitCaster->m_modAttackSpeedPct[RANGED_ATTACK]);
2501}
2502
2503float WorldObject::MeleeSpellMissChance(Unit const* /*victim*/, WeaponAttackType /*attType*/, SpellInfo const* /*spellInfo*/) const
2504{
2505 return 0.0f;
2506}
2507
2508SpellMissInfo WorldObject::MeleeSpellHitResult(Unit* /*victim*/, SpellInfo const* /*spellInfo*/) const
2509{
2510 return SPELL_MISS_NONE;
2511}
2512
2514{
2515 // Can`t miss on dead target (on skinning for example)
2516 if (!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER)
2517 return SPELL_MISS_NONE;
2518
2519 if (spellInfo->HasAttribute(SPELL_ATTR3_NO_AVOIDANCE))
2520 return SPELL_MISS_NONE;
2521
2522 float missChance = [&]()
2523 {
2525 return 0.0f;
2526
2527 SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
2528 // PvP - PvE spell misschances per leveldif > 2
2529 int32 lchance = victim->GetTypeId() == TYPEID_PLAYER ? 7 : 11;
2530 int32 thisLevel = GetLevelForTarget(victim);
2531 if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTrigger())
2532 thisLevel = std::max<int32>(thisLevel, spellInfo->SpellLevel);
2533 int32 leveldif = int32(victim->GetLevelForTarget(this)) - thisLevel;
2534 int32 levelBasedHitDiff = leveldif;
2535
2536 // Base hit chance from attacker and victim levels
2537 int32 modHitChance = 100;
2538 if (levelBasedHitDiff >= 0)
2539 {
2540 if (victim->GetTypeId() != TYPEID_PLAYER)
2541 {
2542 modHitChance = 94 - 3 * std::min(levelBasedHitDiff, 3);
2543 levelBasedHitDiff -= 3;
2544 }
2545 else
2546 {
2547 modHitChance = 96 - std::min(levelBasedHitDiff, 2);
2548 levelBasedHitDiff -= 2;
2549 }
2550 if (levelBasedHitDiff > 0)
2551 modHitChance -= lchance * std::min(levelBasedHitDiff, 7);
2552 }
2553 else
2554 modHitChance = 97 - levelBasedHitDiff;
2555
2556 // Spellmod from SpellModOp::HitChance
2557 if (Player* modOwner = GetSpellModOwner())
2558 modOwner->ApplySpellMod(spellInfo, SpellModOp::HitChance, modHitChance);
2559
2560 // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects
2561 if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
2562 {
2563 // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
2565 }
2566
2567 float HitChance = modHitChance;
2568 // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
2569 if (Unit const* unit = ToUnit())
2570 HitChance += unit->m_modSpellHitChance;
2571
2572 RoundToInterval(HitChance, 0.0f, 100.0f);
2573
2574 return 100.0f - HitChance;
2575 }();
2576
2577 int32 tmp = int32(missChance * 100.0f);
2578
2579 int32 rand = irand(0, 9999);
2580 if (tmp > 0 && rand < tmp)
2581 return SPELL_MISS_MISS;
2582
2583 // Chance resist mechanic (select max value from every mechanic spell effect)
2584 int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
2585
2586 // Roll chance
2587 if (resist_chance > 0 && rand < (tmp += resist_chance))
2588 return SPELL_MISS_RESIST;
2589
2590 // cast by caster in front of victim
2591 if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
2592 {
2593 int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
2594 if (deflect_chance > 0 && rand < (tmp += deflect_chance))
2595 return SPELL_MISS_DEFLECT;
2596 }
2597
2598 return SPELL_MISS_NONE;
2599}
2600
2601// Calculate spell hit result can be:
2602// Every spell can: Evade/Immune/Reflect/Sucesful hit
2603// For melee based spells:
2604// Miss
2605// Dodge
2606// Parry
2607// For spells
2608// Resist
2609SpellMissInfo WorldObject::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, bool canReflect /*= false*/) const
2610{
2611 // Check for immune
2612 if (victim->IsImmunedToSpell(spellInfo, this))
2613 return SPELL_MISS_IMMUNE;
2614
2615 // Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
2616 // returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit
2617 if (spellInfo->HasOnlyDamageEffects() && victim->IsImmunedToDamage(spellInfo))
2618 return SPELL_MISS_IMMUNE;
2619
2620 // All positive spells can`t miss
2622 if (spellInfo->IsPositive() && !IsHostileTo(victim)) // prevent from affecting enemy by "positive" spell
2623 return SPELL_MISS_NONE;
2624
2625 if (this == victim)
2626 return SPELL_MISS_NONE;
2627
2628 // Return evade for units in evade mode
2629 if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())
2630 return SPELL_MISS_EVADE;
2631
2632 // Try victim reflect spell
2633 if (canReflect)
2634 {
2635 int32 reflectchance = victim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
2637
2638 if (reflectchance > 0 && roll_chance_i(reflectchance))
2640 }
2641
2642 if (spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
2643 return SPELL_MISS_NONE;
2644
2645 switch (spellInfo->DmgClass)
2646 {
2649 return MeleeSpellHitResult(victim, spellInfo);
2651 return SPELL_MISS_NONE;
2653 return MagicSpellHitResult(victim, spellInfo);
2654 }
2655 return SPELL_MISS_NONE;
2656}
2657
2658void WorldObject::SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo)
2659{
2661 spellMissLog.SpellID = spellID;
2662 spellMissLog.Caster = GetGUID();
2663 spellMissLog.Entries.emplace_back(target->GetGUID(), missInfo);
2664 SendMessageToSet(spellMissLog.Write(), true);
2665}
2666
2668{
2669 uint32 factionId = GetFaction();
2670 FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(factionId);
2671 if (!entry)
2672 {
2673 switch (GetTypeId())
2674 {
2675 case TYPEID_PLAYER:
2676 TC_LOG_ERROR("entities.unit", "Player {} has invalid faction (faction template id) #{}", ToPlayer()->GetName(), factionId);
2677 break;
2678 case TYPEID_UNIT:
2679 TC_LOG_ERROR("entities.unit", "Creature (template id: {}) has invalid faction (faction template Id) #{}", ToCreature()->GetCreatureTemplate()->Entry, factionId);
2680 break;
2681 case TYPEID_GAMEOBJECT:
2682 if (factionId) // Gameobjects may have faction template id = 0
2683 TC_LOG_ERROR("entities.faction", "GameObject (template id: {}) has invalid faction (faction template Id) #{}", ToGameObject()->GetGOInfo()->entry, factionId);
2684 break;
2685 default:
2686 TC_LOG_ERROR("entities.unit", "Object (name={}, type={}) has invalid faction (faction template Id) #{}", GetName(), uint32(GetTypeId()), factionId);
2687 break;
2688 }
2689 }
2690
2691 return entry;
2692}
2693
2694// function based on function Unit::UnitReaction from 13850 client
2696{
2697 // always friendly to self
2698 if (this == target)
2699 return REP_FRIENDLY;
2700
2701 auto isAttackableBySummoner = [&](Unit const* me, ObjectGuid const& targetGuid)
2702 {
2703 if (!me)
2704 return false;
2705
2706 TempSummon const* tempSummon = me->ToTempSummon();
2707 if (!tempSummon || !tempSummon->m_Properties)
2708 return false;
2709
2711 && targetGuid == tempSummon->GetSummonerGUID())
2712 return true;
2713
2714 return false;
2715 };
2716
2717 if (isAttackableBySummoner(ToUnit(), target->GetGUID()) || isAttackableBySummoner(target->ToUnit(), GetGUID()))
2718 return REP_NEUTRAL;
2719
2720 // always friendly to charmer or owner
2722 return REP_FRIENDLY;
2723
2724 Player const* selfPlayerOwner = GetAffectingPlayer();
2725 Player const* targetPlayerOwner = target->GetAffectingPlayer();
2726
2727 // check forced reputation to support SPELL_AURA_FORCE_REACTION
2728 if (selfPlayerOwner)
2729 {
2730 if (FactionTemplateEntry const* targetFactionTemplateEntry = target->GetFactionTemplateEntry())
2731 if (ReputationRank const* repRank = selfPlayerOwner->GetReputationMgr().GetForcedRankIfAny(targetFactionTemplateEntry))
2732 return *repRank;
2733 }
2734 else if (targetPlayerOwner)
2735 {
2736 if (FactionTemplateEntry const* selfFactionTemplateEntry = GetFactionTemplateEntry())
2737 if (ReputationRank const* repRank = targetPlayerOwner->GetReputationMgr().GetForcedRankIfAny(selfFactionTemplateEntry))
2738 return *repRank;
2739 }
2740
2741 Unit const* unit = Coalesce<const Unit>(ToUnit(), selfPlayerOwner);
2742 Unit const* targetUnit = Coalesce<const Unit>(target->ToUnit(), targetPlayerOwner);
2743 if (unit && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
2744 {
2745 if (targetUnit && targetUnit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
2746 {
2747 if (selfPlayerOwner && targetPlayerOwner)
2748 {
2749 // always friendly to other unit controlled by player, or to the player himself
2750 if (selfPlayerOwner == targetPlayerOwner)
2751 return REP_FRIENDLY;
2752
2753 // duel - always hostile to opponent
2754 if (selfPlayerOwner->duel && selfPlayerOwner->duel->Opponent == targetPlayerOwner && selfPlayerOwner->duel->State == DUEL_STATE_IN_PROGRESS)
2755 return REP_HOSTILE;
2756
2757 // same group - checks dependant only on our faction - skip FFA_PVP for example
2758 if (selfPlayerOwner->IsInRaidWith(targetPlayerOwner))
2759 return REP_FRIENDLY; // return true to allow config option AllowTwoSide.Interaction.Group to work
2760 // however client seems to allow mixed group parties, because in 13850 client it works like:
2761 // return GetFactionReactionTo(GetFactionTemplateEntry(), target);
2762 }
2763
2764 // check FFA_PVP
2765 if (unit->IsFFAPvP() && targetUnit->IsFFAPvP())
2766 return REP_HOSTILE;
2767
2768 if (selfPlayerOwner)
2769 {
2770 if (FactionTemplateEntry const* targetFactionTemplateEntry = targetUnit->GetFactionTemplateEntry())
2771 {
2772 if (ReputationRank const* repRank = selfPlayerOwner->GetReputationMgr().GetForcedRankIfAny(targetFactionTemplateEntry))
2773 return *repRank;
2774 if (!selfPlayerOwner->HasUnitFlag2(UNIT_FLAG2_IGNORE_REPUTATION))
2775 {
2776 if (FactionEntry const* targetFactionEntry = sFactionStore.LookupEntry(targetFactionTemplateEntry->Faction))
2777 {
2778 if (targetFactionEntry->CanHaveReputation())
2779 {
2780 // check contested flags
2781 if ((targetFactionTemplateEntry->Flags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD) &&
2782 selfPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP))
2783 return REP_HOSTILE;
2784
2785 // if faction has reputation, hostile state depends only from AtWar state
2786 if (selfPlayerOwner->GetReputationMgr().IsAtWar(targetFactionEntry))
2787 return REP_HOSTILE;
2788 return REP_FRIENDLY;
2789 }
2790 }
2791 }
2792 }
2793 }
2794 }
2795 }
2796
2797 // do checks dependant only on our faction
2799}
2800
2801/*static*/ ReputationRank WorldObject::GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, WorldObject const* target)
2802{
2803 // always neutral when no template entry found
2804 if (!factionTemplateEntry)
2805 return REP_NEUTRAL;
2806
2807 FactionTemplateEntry const* targetFactionTemplateEntry = target->GetFactionTemplateEntry();
2808 if (!targetFactionTemplateEntry)
2809 return REP_NEUTRAL;
2810
2811 if (Player const* targetPlayerOwner = target->GetAffectingPlayer())
2812 {
2813 // check contested flags
2814 if ((factionTemplateEntry->Flags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD) &&
2815 targetPlayerOwner->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP))
2816 return REP_HOSTILE;
2817 if (ReputationRank const* repRank = targetPlayerOwner->GetReputationMgr().GetForcedRankIfAny(factionTemplateEntry))
2818 return *repRank;
2819 if (target->IsUnit() && !target->ToUnit()->HasUnitFlag2(UNIT_FLAG2_IGNORE_REPUTATION))
2820 {
2821 if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplateEntry->Faction))
2822 {
2823 if (factionEntry->CanHaveReputation())
2824 {
2825 // CvP case - check reputation, don't allow state higher than neutral when at war
2826 ReputationRank repRank = targetPlayerOwner->GetReputationMgr().GetRank(factionEntry);
2827 if (targetPlayerOwner->GetReputationMgr().IsAtWar(factionEntry))
2828 repRank = std::min(REP_NEUTRAL, repRank);
2829 return repRank;
2830 }
2831 }
2832 }
2833 }
2834
2835 // common faction based check
2836 if (factionTemplateEntry->IsHostileTo(targetFactionTemplateEntry))
2837 return REP_HOSTILE;
2838 if (factionTemplateEntry->IsFriendlyTo(targetFactionTemplateEntry))
2839 return REP_FRIENDLY;
2840 if (targetFactionTemplateEntry->IsFriendlyTo(factionTemplateEntry))
2841 return REP_FRIENDLY;
2842 if (factionTemplateEntry->Flags & FACTION_TEMPLATE_FLAG_HOSTILE_BY_DEFAULT)
2843 return REP_HOSTILE;
2844 // neutral by default
2845 return REP_NEUTRAL;
2846}
2847
2848bool WorldObject::IsHostileTo(WorldObject const* target) const
2849{
2850 return GetReactionTo(target) <= REP_HOSTILE;
2851}
2852
2854{
2855 return GetReactionTo(target) >= REP_FRIENDLY;
2856}
2857
2859{
2860 FactionTemplateEntry const* my_faction = GetFactionTemplateEntry();
2861 if (!my_faction->Faction)
2862 return false;
2863
2864 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->Faction);
2865 if (raw_faction && raw_faction->ReputationIndex >= 0)
2866 return false;
2867
2868 return my_faction->IsHostileToPlayers();
2869}
2870
2872{
2873 FactionTemplateEntry const* my_faction = GetFactionTemplateEntry();
2874 if (!my_faction->Faction)
2875 return true;
2876
2877 FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->Faction);
2878 if (raw_faction && raw_faction->ReputationIndex >= 0)
2879 return false;
2880
2881 return my_faction->IsNeutralToAll();
2882}
2883
2885{
2886 SpellInfo const* info = sSpellMgr->GetSpellInfo(spellId, args.CastDifficulty != DIFFICULTY_NONE ? args.CastDifficulty : GetMap()->GetDifficultyID());
2887 if (!info)
2888 {
2889 TC_LOG_ERROR("entities.unit", "CastSpell: unknown spell {} by caster {}", spellId, GetGUID().ToString());
2891 }
2892
2893 if (!targets.Targets)
2894 {
2895 TC_LOG_ERROR("entities.unit", "CastSpell: Invalid target passed to spell cast {} by {}", spellId, GetGUID().ToString());
2897 }
2898
2899 Spell* spell = new Spell(this, info, args.TriggerFlags, args.OriginalCaster, args.OriginalCastId);
2900 for (auto const& pair : args.SpellValueOverrides)
2901 spell->SetSpellValue(pair.first, pair.second);
2902
2903 spell->m_CastItem = args.CastItem;
2904 if (args.OriginalCastItemLevel)
2906
2908 {
2909 if (args.TriggeringSpell)
2910 spell->m_CastItem = args.TriggeringSpell->m_CastItem;
2911 else if (args.TriggeringAura && !args.TriggeringAura->GetBase()->GetCastItemGUID().IsEmpty())
2912 if (Player const* triggeringAuraCaster = Object::ToPlayer(args.TriggeringAura->GetCaster()))
2913 spell->m_CastItem = triggeringAuraCaster->GetItemByGuid(args.TriggeringAura->GetBase()->GetCastItemGUID());
2914 }
2915
2916 spell->m_customArg = args.CustomArg;
2917
2918 return spell->prepare(*targets.Targets, args.TriggeringAura);
2919}
2920
2921void WorldObject::SendPlayOrphanSpellVisual(ObjectGuid const& target, uint32 spellVisualId, float travelSpeed, bool speedAsTime /*= false*/, bool withSourceOrientation /*= false*/)
2922{
2923 WorldPackets::Spells::PlayOrphanSpellVisual playOrphanSpellVisual;
2924 playOrphanSpellVisual.SourceLocation = GetPosition();
2925 if (withSourceOrientation)
2926 {
2927 if (IsGameObject())
2928 {
2930 rotation.toEulerAnglesZYX(playOrphanSpellVisual.SourceRotation.Pos.m_positionZ,
2931 playOrphanSpellVisual.SourceRotation.Pos.m_positionY,
2932 playOrphanSpellVisual.SourceRotation.Pos.m_positionX);
2933 }
2934 else
2935 playOrphanSpellVisual.SourceRotation = Position(0.0f, 0.0f, GetOrientation());
2936 }
2937
2938 playOrphanSpellVisual.Target = target; // exclusive with TargetLocation
2939 playOrphanSpellVisual.SpellVisualID = spellVisualId;
2940 playOrphanSpellVisual.TravelSpeed = travelSpeed;
2941 playOrphanSpellVisual.SpeedAsTime = speedAsTime;
2942 playOrphanSpellVisual.LaunchDelay = 0.0f;
2943 SendMessageToSet(playOrphanSpellVisual.Write(), true);
2944}
2945
2946void WorldObject::SendPlayOrphanSpellVisual(Position const& targetLocation, uint32 spellVisualId, float travelSpeed, bool speedAsTime /*= false*/, bool withSourceOrientation /*= false*/)
2947{
2948 WorldPackets::Spells::PlayOrphanSpellVisual playOrphanSpellVisual;
2949 playOrphanSpellVisual.SourceLocation = GetPosition();
2950 if (withSourceOrientation)
2951 {
2952 if (IsGameObject())
2953 {
2955 rotation.toEulerAnglesZYX(playOrphanSpellVisual.SourceRotation.Pos.m_positionZ,
2956 playOrphanSpellVisual.SourceRotation.Pos.m_positionY,
2957 playOrphanSpellVisual.SourceRotation.Pos.m_positionX);
2958 }
2959 else
2960 playOrphanSpellVisual.SourceRotation = Position(0.0f, 0.0f, GetOrientation());
2961 }
2962
2963 playOrphanSpellVisual.TargetLocation = targetLocation; // exclusive with Target
2964 playOrphanSpellVisual.SpellVisualID = spellVisualId;
2965 playOrphanSpellVisual.TravelSpeed = travelSpeed;
2966 playOrphanSpellVisual.SpeedAsTime = speedAsTime;
2967 playOrphanSpellVisual.LaunchDelay = 0.0f;
2968 SendMessageToSet(playOrphanSpellVisual.Write(), true);
2969}
2970
2972{
2973 WorldPackets::Spells::CancelOrphanSpellVisual cancelOrphanSpellVisual;
2974 cancelOrphanSpellVisual.SpellVisualID = id;
2975 SendMessageToSet(cancelOrphanSpellVisual.Write(), true);
2976}
2977
2978// function based on function Unit::CanAttack from 13850 client
2979bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/) const
2980{
2981 ASSERT(target);
2982
2983 // some positive spells can be casted at hostile target
2984 bool isPositiveSpell = bySpell && bySpell->IsPositive();
2985
2986 // can't attack self (spells can, attribute check)
2987 if (!bySpell && this == target)
2988 return false;
2989
2990 // can't attack unattackable units
2991 Unit const* unitTarget = target->ToUnit();
2992 if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
2993 return false;
2994
2995 // can't attack GMs
2996 if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
2997 return false;
2998
2999 Unit const* unit = ToUnit();
3000 // visibility checks (only units)
3001 if (unit)
3002 {
3003 // can't attack invisible
3004 if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_IGNORE_PHASE_SHIFT))
3005 {
3006 if (!unit->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
3007 return false;
3008 }
3009 }
3010
3011 // can't attack dead
3012 if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && unitTarget && !unitTarget->IsAlive())
3013 return false;
3014
3015 // can't attack untargetable
3016 if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE_2))
3017 return false;
3018
3019 if (unitTarget && unitTarget->IsUninteractible())
3020 return false;
3021
3022 if (Player const* playerAttacker = ToPlayer())
3023 {
3024 if (playerAttacker->HasPlayerFlag(PLAYER_FLAGS_UBER))
3025 return false;
3026 }
3027
3028 // check flags
3030 return false;
3031
3032 Unit const* unitOrOwner = unit;
3033 GameObject const* go = ToGameObject();
3034 if (go && go->GetGoType() == GAMEOBJECT_TYPE_TRAP)
3035 unitOrOwner = go->GetOwner();
3036
3037 // ignore immunity flags when assisting
3038 if (unitOrOwner && unitTarget && !(isPositiveSpell && bySpell->HasAttribute(SPELL_ATTR6_CAN_ASSIST_IMMUNE_PC)))
3039 {
3040 if (!unitOrOwner->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && unitTarget->IsImmuneToNPC())
3041 return false;
3042
3043 if (!unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && unitOrOwner->IsImmuneToNPC())
3044 return false;
3045
3047 {
3048 if (unitOrOwner->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && unitTarget->IsImmuneToPC())
3049 return false;
3050
3051 if (unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && unitOrOwner->IsImmuneToPC())
3052 return false;
3053 }
3054 }
3055
3056 // CvC case - can attack each other only when one of them is hostile
3057 if (unit && !unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && unitTarget && !unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3058 return IsHostileTo(unitTarget) || unitTarget->IsHostileTo(this);
3059
3060 // Traps without owner or with NPC owner versus Creature case - can attack to creature only when one of them is hostile
3061 if (go && go->GetGoType() == GAMEOBJECT_TYPE_TRAP)
3062 {
3063 Unit const* goOwner = go->GetOwner();
3064 if (!goOwner || !goOwner->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3065 if (unitTarget && !unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3066 return IsHostileTo(unitTarget) || unitTarget->IsHostileTo(this);
3067 }
3068
3069 // PvP, PvC, CvP case
3070 // can't attack friendly targets
3071 if (IsFriendlyTo(target) || target->IsFriendlyTo(this))
3072 return false;
3073
3074 Player const* playerAffectingAttacker = (unit && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) || go ? GetAffectingPlayer() : nullptr;
3075 Player const* playerAffectingTarget = unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) ? unitTarget->GetAffectingPlayer() : nullptr;
3076
3077 // Pets of mounted players are immune to NPCs
3078 if (!playerAffectingAttacker && unitTarget && unitTarget->IsPet() && playerAffectingTarget && playerAffectingTarget->IsMounted())
3079 return false;
3080
3081 // Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
3082 if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget))
3083 {
3084 Player const* player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
3085
3086 if (Unit const* creature = playerAffectingAttacker ? unitTarget : unit)
3087 {
3088 if (creature->IsContestedGuard() && player->HasPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP))
3089 return true;
3090
3091 if (FactionTemplateEntry const* factionTemplate = creature->GetFactionTemplateEntry())
3092 {
3093 if (!(player->GetReputationMgr().GetForcedRankIfAny(factionTemplate)))
3094 if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionTemplate->Faction))
3095 if (FactionState const* repState = player->GetReputationMgr().GetState(factionEntry))
3096 if (!repState->Flags.HasFlag(ReputationFlags::AtWar))
3097 return false;
3098
3099 }
3100 }
3101 }
3102
3103 if (playerAffectingAttacker && playerAffectingTarget)
3104 if (playerAffectingAttacker->duel && playerAffectingAttacker->duel->Opponent == playerAffectingTarget && playerAffectingAttacker->duel->State == DUEL_STATE_IN_PROGRESS)
3105 return true;
3106
3107 // PvP case - can't attack when attacker or target are in sanctuary
3108 // however, 13850 client doesn't allow to attack when one of the unit's has sanctuary flag and is pvp
3109 if (unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)
3110 && unitOrOwner && unitOrOwner->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)
3111 && (unitTarget->IsInSanctuary() || unitOrOwner->IsInSanctuary())
3112 && (!bySpell || bySpell->HasAttribute(SPELL_ATTR8_IGNORE_SANCTUARY)))
3113 return false;
3114
3115 // additional checks - only PvP case
3116 if (playerAffectingAttacker && playerAffectingTarget)
3117 {
3118 if (playerAffectingTarget->IsPvP() || (bySpell && bySpell->HasAttribute(SPELL_ATTR5_IGNORE_AREA_EFFECT_PVP_CHECK)))
3119 return true;
3120
3121 if (playerAffectingAttacker->IsFFAPvP() && playerAffectingTarget->IsFFAPvP())
3122 return true;
3123
3124 return playerAffectingAttacker->HasPvpFlag(UNIT_BYTE2_FLAG_UNK1) ||
3125 playerAffectingTarget->HasPvpFlag(UNIT_BYTE2_FLAG_UNK1);
3126 }
3127
3128 return true;
3129}
3130
3131// function based on function Unit::CanAssist from 13850 client
3132bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const* bySpell /*= nullptr*/) const
3133{
3134 ASSERT(target);
3135
3136 // some negative spells can be casted at friendly target
3137 bool isNegativeSpell = bySpell && !bySpell->IsPositive();
3138
3139 // can assist to self
3140 if (this == target)
3141 return true;
3142
3143 // can't assist unattackable units
3144 Unit const* unitTarget = target->ToUnit();
3145 if (unitTarget && unitTarget->HasUnitState(UNIT_STATE_UNATTACKABLE))
3146 return false;
3147
3148 // can't assist GMs
3149 if (target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->IsGameMaster())
3150 return false;
3151
3152 // can't assist own vehicle or passenger
3153 Unit const* unit = ToUnit();
3154 if (unit && unitTarget && unit->GetVehicle())
3155 {
3156 if (unit->IsOnVehicle(unitTarget))
3157 return false;
3158
3159 if (unit->GetVehicleBase()->IsOnVehicle(unitTarget))
3160 return false;
3161 }
3162
3163 // can't assist invisible
3164 if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_IGNORE_PHASE_SHIFT)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea()))
3165 return false;
3166
3167 // can't assist dead
3168 if ((!bySpell || !bySpell->IsAllowingDeadTarget()) && unitTarget && !unitTarget->IsAlive())
3169 return false;
3170
3171 // can't assist untargetable
3172 if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_UNTARGETABLE)) && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE_2))
3173 return false;
3174
3175 if (unitTarget && unitTarget->IsUninteractible())
3176 return false;
3177
3178 // check flags for negative spells
3179 if (isNegativeSpell && unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_ON_TAXI | UNIT_FLAG_NOT_ATTACKABLE_1))
3180 return false;
3181
3182 if (isNegativeSpell || !bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_ASSIST_IMMUNE_PC))
3183 {
3184 if (unit && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3185 {
3187 if (unitTarget && unitTarget->IsImmuneToPC())
3188 return false;
3189 }
3190 else
3191 {
3192 if (unitTarget && unitTarget->IsImmuneToNPC())
3193 return false;
3194 }
3195 }
3196
3197 // can't assist non-friendly targets
3199 return false;
3200
3201 // PvP case
3202 if (unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3203 {
3204 if (unit && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3205 {
3206 Player const* selfPlayerOwner = GetAffectingPlayer();
3207 Player const* targetPlayerOwner = unitTarget->GetAffectingPlayer();
3208 if (selfPlayerOwner && targetPlayerOwner)
3209 {
3210 // can't assist player which is dueling someone
3211 if (selfPlayerOwner != targetPlayerOwner && targetPlayerOwner->duel)
3212 return false;
3213 }
3214 // can't assist player in ffa_pvp zone from outside
3215 if (unitTarget->IsFFAPvP() && !unit->IsFFAPvP())
3216 return false;
3217
3218 // can't assist player out of sanctuary from sanctuary if has pvp enabled
3219 if (unitTarget->IsPvP() && (!bySpell || bySpell->HasAttribute(SPELL_ATTR8_IGNORE_SANCTUARY)))
3220 if (unit->IsInSanctuary() && !unitTarget->IsInSanctuary())
3221 return false;
3222 }
3223 }
3224 // PvC case - player can assist creature only if has specific type flags
3225 // !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) &&
3226 else if (unit && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
3227 {
3228 if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_ASSIST_IMMUNE_PC))
3229 if (unitTarget && !unitTarget->IsPvP())
3230 if (Creature const* creatureTarget = target->ToCreature())
3231 return creatureTarget->HasFlag(CREATURE_STATIC_FLAG_4_TREAT_AS_RAID_UNIT_FOR_HELPFUL_SPELLS) || (creatureTarget->GetCreatureDifficulty()->TypeFlags & CREATURE_TYPE_FLAG_CAN_ASSIST);
3232 }
3233
3234 return true;
3235}
3236
3238{
3239 // Patch 1.2 notes: Spell Reflection no longer reflects abilities
3241 return victim;
3242
3244 for (AuraEffect const* aurEff : magnetAuras)
3245 {
3246 if (Unit* magnet = aurEff->GetBase()->GetCaster())
3247 {
3248 if (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK && IsValidAttackTarget(magnet, spellInfo))
3249 {
3251 if (spellInfo->HasHitDelay())
3252 {
3253 // Set up missile speed based delay
3254 float hitDelay = spellInfo->LaunchDelay;
3256 hitDelay += spellInfo->Speed;
3257 else if (spellInfo->Speed > 0.0f)
3258 hitDelay += std::max(victim->GetDistance(this), 5.0f) / spellInfo->Speed;
3259
3260 uint32 delay = uint32(std::floor(hitDelay * 1000.0f));
3261 // Schedule charge drop
3262 aurEff->GetBase()->DropChargeDelayed(delay, AURA_REMOVE_BY_EXPIRE);
3263 }
3264 else
3265 aurEff->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
3266
3267 return magnet;
3268 }
3269 }
3270 }
3271 return victim;
3272}
3273
3275{
3276 return spellInfo->GetSpellXSpellVisualId(this);
3277}
3278
3279template <typename Container>
3280void WorldObject::GetGameObjectListWithEntryInGrid(Container& gameObjectContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const
3281{
3282 Trinity::AllGameObjectsWithEntryInRange check(this, entry, maxSearchRange);
3283 Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange> searcher(this, gameObjectContainer, check);
3284 Cell::VisitGridObjects(this, searcher, maxSearchRange);
3285}
3286
3287template <typename Container>
3288void WorldObject::GetGameObjectListWithOptionsInGrid(Container& gameObjectContainer, float maxSearchRange, FindGameObjectOptions const& options) const
3289{
3290 Trinity::InRangeCheckCustomizer checkCustomizer(*this, maxSearchRange);
3291 Trinity::GameObjectWithOptionsInObjectRangeCheck check(*this, checkCustomizer, options);
3292 Trinity::GameObjectListSearcher searcher(this, gameObjectContainer, check);
3293 if (options.IgnorePhases)
3295
3296 Cell::VisitGridObjects(this, searcher, maxSearchRange);
3297}
3298
3299template <typename Container>
3300void WorldObject::GetCreatureListWithEntryInGrid(Container& creatureContainer, uint32 entry, float maxSearchRange /*= 250.0f*/) const
3301{
3302 Trinity::AllCreaturesOfEntryInRange check(this, entry, maxSearchRange);
3303 Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(this, creatureContainer, check);
3304 Cell::VisitGridObjects(this, searcher, maxSearchRange);
3305}
3306
3307template <typename Container>
3308void WorldObject::GetCreatureListWithOptionsInGrid(Container& creatureContainer, float maxSearchRange, FindCreatureOptions const& options) const
3309{
3310 Trinity::InRangeCheckCustomizer checkCustomizer(*this, maxSearchRange);
3311 Trinity::CreatureWithOptionsInObjectRangeCheck check(*this, checkCustomizer, options);
3312 Trinity::CreatureListSearcher searcher(this, creatureContainer, check);
3313 if (options.IgnorePhases)
3315
3316 Cell::VisitGridObjects(this, searcher, maxSearchRange);
3317}
3318
3319template <typename Container>
3320void WorldObject::GetPlayerListInGrid(Container& playerContainer, float maxSearchRange, bool alive /*= true*/) const
3321{
3322 Trinity::AnyPlayerInObjectRangeCheck checker(this, maxSearchRange, alive);
3323 Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, playerContainer, checker);
3324 Cell::VisitWorldObjects(this, searcher, maxSearchRange);
3325}
3326
3327void WorldObject::GetNearPoint2D(WorldObject const* searcher, float& x, float& y, float distance2d, float absAngle) const
3328{
3329 float effectiveReach = GetCombatReach();
3330
3331 if (searcher)
3332 {
3333 effectiveReach += searcher->GetCombatReach();
3334
3335 if (this != searcher)
3336 {
3337 float myHover = 0.0f, searcherHover = 0.0f;
3338 if (Unit const* unit = ToUnit())
3339 myHover = unit->GetHoverOffset();
3340 if (Unit const* searchUnit = searcher->ToUnit())
3341 searcherHover = searchUnit->GetHoverOffset();
3342
3343 float hoverDelta = myHover - searcherHover;
3344 if (hoverDelta != 0.0f)
3345 effectiveReach = std::sqrt(std::max(effectiveReach * effectiveReach - hoverDelta * hoverDelta, 0.0f));
3346 }
3347 }
3348
3349 x = GetPositionX() + (effectiveReach + distance2d) * std::cos(absAngle);
3350 y = GetPositionY() + (effectiveReach + distance2d) * std::sin(absAngle);
3351
3354}
3355
3356void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y, float& z, float distance2d, float absAngle) const
3357{
3358 GetNearPoint2D(searcher, x, y, distance2d, absAngle);
3359 z = GetPositionZ();
3360 (searcher ? searcher : this)->UpdateAllowedPositionZ(x, y, z);
3361
3362 // if detection disabled, return first point
3363 if (!sWorld->getBoolConfig(CONFIG_DETECT_POS_COLLISION))
3364 return;
3365
3366 // return if the point is already in LoS
3367 if (IsWithinLOS(x, y, z))
3368 return;
3369
3370 // remember first point
3371 float first_x = x;
3372 float first_y = y;
3373 float first_z = z;
3374
3375 // loop in a circle to look for a point in LoS using small steps
3376 for (float angle = float(M_PI) / 8; angle < float(M_PI) * 2; angle += float(M_PI) / 8)
3377 {
3378 GetNearPoint2D(searcher, x, y, distance2d, absAngle + angle);
3379 z = GetPositionZ();
3380 (searcher ? searcher : this)->UpdateAllowedPositionZ(x, y, z);
3381 if (IsWithinLOS(x, y, z))
3382 return;
3383 }
3384
3385 // still not in LoS, give up and return first position found
3386 x = first_x;
3387 y = first_y;
3388 z = first_z;
3389}
3390
3391void WorldObject::GetClosePoint(float& x, float& y, float& z, float size, float distance2d /*= 0*/, float relAngle /*= 0*/) const
3392{
3393 // angle calculated from current orientation
3394 GetNearPoint(nullptr, x, y, z, distance2d + size, GetOrientation() + relAngle);
3395}
3396
3398{
3399 Position pos = GetPosition();
3400 MovePosition(pos, dist, angle);
3401 return pos;
3402}
3403
3405{
3406 Position pos = GetPosition();
3407 MovePositionToFirstCollision(pos, dist, angle);
3408 return pos;
3409}
3410
3412{
3413 Position pos = GetPosition();
3414 MovePosition(pos, radius * rand_norm(), rand_norm() * static_cast<float>(2 * M_PI));
3415 return pos;
3416}
3417
3418void WorldObject::GetContactPoint(WorldObject const* obj, float& x, float& y, float& z, float distance2d /*= CONTACT_DISTANCE*/) const
3419{
3420 // angle to face `obj` to `this` using distance includes size of `obj`
3421 GetNearPoint(obj, x, y, z, distance2d, GetAbsoluteAngle(obj));
3422}
3423
3424void WorldObject::MovePosition(Position &pos, float dist, float angle)
3425{
3426 angle += GetOrientation();
3427 float destx, desty, destz, ground, floor;
3428 destx = pos.m_positionX + dist * std::cos(angle);
3429 desty = pos.m_positionY + dist * std::sin(angle);
3430
3431 // Prevent invalid coordinates here, position is unchanged
3432 if (!Trinity::IsValidMapCoord(destx, desty, pos.m_positionZ))
3433 {
3434 TC_LOG_FATAL("misc", "WorldObject::MovePosition: Object {} has invalid coordinates X: {} and Y: {} were passed!",
3435 GetGUID().ToString(), destx, desty);
3436 return;
3437 }
3438
3439 ground = GetMapHeight(destx, desty, MAX_HEIGHT);
3440 floor = GetMapHeight(destx, desty, pos.m_positionZ);
3441 destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor;
3442
3443 float step = dist/10.0f;
3444
3445 for (uint8 j = 0; j < 10; ++j)
3446 {
3447 // do not allow too big z changes
3448 if (std::fabs(pos.m_positionZ - destz) > 6)
3449 {
3450 destx -= step * std::cos(angle);
3451 desty -= step * std::sin(angle);
3452 ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true);
3453 floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true);
3454 destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor;
3455 }
3456 // we have correct destz now
3457 else
3458 {
3459 pos.Relocate(destx, desty, destz);
3460 break;
3461 }
3462 }
3463
3468}
3469
3470void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float angle)
3471{
3472 angle += GetOrientation();
3473 float destx, desty, destz;
3474 destx = pos.m_positionX + dist * std::cos(angle);
3475 desty = pos.m_positionY + dist * std::sin(angle);
3476 destz = pos.m_positionZ;
3477
3478 // Prevent invalid coordinates here, position is unchanged
3479 if (!Trinity::IsValidMapCoord(destx, desty))
3480 {
3481 TC_LOG_FATAL("misc", "WorldObject::MovePositionToFirstCollision invalid coordinates X: {} and Y: {} were passed!", destx, desty);
3482 return;
3483 }
3484
3485 // Use a detour raycast to get our first collision point
3486 PathGenerator path(this);
3487 path.SetUseRaycast(true);
3488 path.CalculatePath(destx, desty, destz, false);
3489
3490 // Check for valid path types before we proceed
3491 if (!(path.GetPathType() & PATHFIND_NOT_USING_PATH))
3493 return;
3494
3495 G3D::Vector3 result = path.GetPath().back();
3496 destx = result.x;
3497 desty = result.y;
3498 destz = result.z;
3499
3500 // check static LOS
3501 float halfHeight = GetCollisionHeight() * 0.5f;
3502 bool col = false;
3503
3504 // Unit is flying, check for potential collision via vmaps
3506 {
3508 pos.m_positionX, pos.m_positionY, pos.m_positionZ + halfHeight,
3509 destx, desty, destz + halfHeight,
3510 destx, desty, destz, -0.5f);
3511
3512 destz -= halfHeight;
3513
3514 // Collided with static LOS object, move back to collision point
3515 if (col)
3516 {
3517 destx -= CONTACT_DISTANCE * std::cos(angle);
3518 desty -= CONTACT_DISTANCE * std::sin(angle);
3519 dist = std::sqrt((pos.m_positionX - destx) * (pos.m_positionX - destx) + (pos.m_positionY - desty) * (pos.m_positionY - desty));
3520 }
3521 }
3522
3523 // check dynamic collision
3525 pos.m_positionX, pos.m_positionY, pos.m_positionZ + halfHeight,
3526 destx, desty, destz + halfHeight,
3527 destx, desty, destz, -0.5f);
3528
3529 destz -= halfHeight;
3530
3531 // Collided with a gameobject, move back to collision point
3532 if (col)
3533 {
3534 destx -= CONTACT_DISTANCE * std::cos(angle);
3535 desty -= CONTACT_DISTANCE * std::sin(angle);
3536 dist = std::sqrt((pos.m_positionX - destx)*(pos.m_positionX - destx) + (pos.m_positionY - desty) * (pos.m_positionY - desty));
3537 }
3538
3539 float groundZ = VMAP_INVALID_HEIGHT_VALUE;
3542 UpdateAllowedPositionZ(destx, desty, destz, &groundZ);
3543
3545 pos.Relocate(destx, desty, destz);
3546
3547 // position has no ground under it (or is too far away)
3548 if (groundZ <= INVALID_HEIGHT)
3549 {
3550 if (Unit const* unit = ToUnit())
3551 {
3552 // unit can fly, ignore.
3553 if (unit->CanFly())
3554 return;
3555
3556 // fall back to gridHeight if any
3557 float gridHeight = GetMap()->GetGridHeight(GetPhaseShift(), pos.m_positionX, pos.m_positionY);
3558 if (gridHeight > INVALID_HEIGHT)
3559 pos.m_positionZ = gridHeight + unit->GetHoverOffset();
3560 }
3561 }
3562}
3563
3564void WorldObject::PlayDistanceSound(uint32 soundId, Player* target /*= nullptr*/)
3565{
3566 if (target)
3568 else
3570}
3571
3572void WorldObject::PlayDirectSound(uint32 soundId, Player* target /*= nullptr*/, uint32 broadcastTextId /*= 0*/)
3573{
3574 if (target)
3575 target->SendDirectMessage(WorldPackets::Misc::PlaySound(GetGUID(), soundId, broadcastTextId).Write());
3576 else
3577 SendMessageToSet(WorldPackets::Misc::PlaySound(GetGUID(), soundId, broadcastTextId).Write(), true);
3578}
3579
3580void WorldObject::PlayDirectMusic(uint32 musicId, Player* target /*= nullptr*/)
3581{
3582 if (target)
3583 target->SendDirectMessage(WorldPackets::Misc::PlayMusic(musicId).Write());
3584 else
3585 SendMessageToSet(WorldPackets::Misc::PlayMusic(musicId).Write(), true);
3586}
3587
3588void WorldObject::PlayObjectSound(int32 soundKitId, ObjectGuid targetObjectGUID, Player* target /*= nullptr*/, int32 broadcastTextId /*= 0*/)
3589{
3591 pkt.TargetObjectGUID = targetObjectGUID;
3592 pkt.SourceObjectGUID = GetGUID();
3593 pkt.SoundKitID = soundKitId;
3594 pkt.Position = GetPosition();
3595 pkt.BroadcastTextID = broadcastTextId;
3596
3597 if (target)
3598 target->SendDirectMessage(pkt.Write());
3599 else
3600 SendMessageToSet(pkt.Write(), true);
3601}
3602
3604{
3605 if (!IsInWorld())
3606 return;
3607
3608 std::list<Player*> targets;
3612 for (std::list<Player*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
3613 {
3614 Player* player = (*iter);
3615
3616 if (player == this)
3617 continue;
3618
3619 if (!player->HaveAtClient(this))
3620 continue;
3621
3622 if (isType(TYPEMASK_UNIT) && ToUnit()->GetCharmerGUID() == player->GetGUID())
3623 continue;
3624
3625 DestroyForPlayer(player);
3626 player->m_clientGUIDs.erase(GetGUID());
3627 }
3628}
3629
3631{
3632 //updates object's visibility for nearby players
3633 WorldObject* objects[] = { this };
3634 Trinity::VisibleChangesNotifier notifier({ std::begin(objects), std::end(objects) });
3636}
3637
3639{
3645 {
3646 Player* source = nullptr;
3647 for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
3648 {
3649 source = iter->GetSource();
3650
3651 BuildPacket(source);
3652
3653 if (!source->GetSharedVisionList().empty())
3654 {
3655 SharedVisionList::const_iterator it = source->GetSharedVisionList().begin();
3656 for (; it != source->GetSharedVisionList().end(); ++it)
3657 BuildPacket(*it);
3658 }
3659 }
3660 }
3661
3663 {
3664 Creature* source = nullptr;
3665 for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
3666 {
3667 source = iter->GetSource();
3668 if (!source->GetSharedVisionList().empty())
3669 {
3670 SharedVisionList::const_iterator it = source->GetSharedVisionList().begin();
3671 for (; it != source->GetSharedVisionList().end(); ++it)
3672 BuildPacket(*it);
3673 }
3674 }
3675 }
3676
3678 {
3679 DynamicObject* source = nullptr;
3680 for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
3681 {
3682 source = iter->GetSource();
3683 ObjectGuid guid = source->GetCasterGUID();
3684
3685 if (guid.IsPlayer())
3686 {
3687 //Caster may be nullptr if DynObj is in removelist
3688 if (Player* caster = ObjectAccessor::FindPlayer(guid))
3689 if (*caster->m_activePlayerData->FarsightObject == source->GetGUID())
3690 BuildPacket(caster);
3691 }
3692 }
3693 }
3694
3695 void BuildPacket(Player* player)
3696 {
3697 // Only send update once to a player
3698 if (plr_list.find(player->GetGUID()) == plr_list.end() && player->HaveAtClient(&i_object))
3699 {
3701 plr_list.insert(player->GetGUID());
3702 }
3703 }
3704
3705 template<class SKIP> void Visit(GridRefManager<SKIP> &) { }
3706};
3707
3709{
3710 WorldObjectChangeAccumulator notifier(*this, data_map);
3711 //we must build packets for all visible players
3713
3714 ClearUpdateMask(false);
3715}
3716
3718{
3719 GetMap()->AddUpdateObject(this);
3720 return true;
3721}
3722
3724{
3725 GetMap()->RemoveUpdateObject(this);
3726}
3727
3729{
3730 if (GetTransport())
3731 return GetTransport()->GetTransportGUID();
3732 return ObjectGuid::Empty;
3733}
3734
3736{
3737 if (!IsInWorld())
3738 return m_staticFloorZ;
3739 return std::max<float>(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ() + Z_OFFSET_FIND_HEIGHT));
3740}
3741
3742float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const
3743{
3744 return GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ground,
3745 isType(TYPEMASK_UNIT) ? !static_cast<Unit const*>(this)->HasAuraType(SPELL_AURA_WATER_WALK) : false,
3747}
3748
3749float WorldObject::GetMapHeight(float x, float y, float z, bool vmap/* = true*/, float distanceToSearch/* = DEFAULT_HEIGHT_SEARCH*/) const
3750{
3751 if (z != MAX_HEIGHT)
3753
3754 return GetMap()->GetHeight(GetPhaseShift(), x, y, z, vmap, distanceToSearch);
3755}
3756
3757std::string WorldObject::GetDebugInfo() const
3758{
3759 std::stringstream sstr;
3760 sstr << WorldLocation::GetDebugInfo() << "\n"
3761 << Object::GetDebugInfo() << "\n"
3762 << "Name: " << GetName();
3763 return sstr.str();
3764}
3765
3766template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>&, uint32, float) const;
3767template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque<GameObject*>&, uint32, float) const;
3768template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector<GameObject*>&, uint32, float) const;
3769
3770template TC_GAME_API void WorldObject::GetGameObjectListWithOptionsInGrid(std::list<GameObject*>&, float, FindGameObjectOptions const&) const;
3771template TC_GAME_API void WorldObject::GetGameObjectListWithOptionsInGrid(std::deque<GameObject*>&, float, FindGameObjectOptions const&) const;
3772template TC_GAME_API void WorldObject::GetGameObjectListWithOptionsInGrid(std::vector<GameObject*>&, float, FindGameObjectOptions const&) const;
3773
3774template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>&, uint32, float) const;
3775template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::deque<Creature*>&, uint32, float) const;
3776template TC_GAME_API void WorldObject::GetCreatureListWithEntryInGrid(std::vector<Creature*>&, uint32, float) const;
3777
3778template TC_GAME_API void WorldObject::GetCreatureListWithOptionsInGrid(std::list<Creature*>&, float, FindCreatureOptions const&) const;
3779template TC_GAME_API void WorldObject::GetCreatureListWithOptionsInGrid(std::deque<Creature*>&,float, FindCreatureOptions const&) const;
3780template TC_GAME_API void WorldObject::GetCreatureListWithOptionsInGrid(std::vector<Creature*>&, float, FindCreatureOptions const&) const;
3781
3782template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::list<Player*>&, float, bool) const;
3783template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::deque<Player*>&, float, bool) const;
3784template TC_GAME_API void WorldObject::GetPlayerListInGrid(std::vector<Player*>&, float, bool) const;
#define sBattlefieldMgr
#define M_PI
Definition: Common.h:115
#define sConditionMgr
Definition: ConditionMgr.h:365
@ CREATURE_STATIC_FLAG_4_TREAT_AS_RAID_UNIT_FOR_HELPFUL_SPELLS
Definition: CreatureData.h:167
DB2Storage< FactionTemplateEntry > sFactionTemplateStore("FactionTemplate.db2", &FactionTemplateLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
DB2Storage< FactionEntry > sFactionStore("Faction.db2", &FactionLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:537
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
@ FACTION_TEMPLATE_FLAG_HOSTILE_BY_DEFAULT
Definition: DBCEnums.h:944
@ FACTION_TEMPLATE_FLAG_CONTESTED_GUARD
Definition: DBCEnums.h:943
#define TC_GAME_API
Definition: Define.h:124
uint8_t uint8
Definition: Define.h:145
int32_t int32
Definition: Define.h:139
uint64_t uint64
Definition: Define.h:142
#define UI64LIT(N)
Definition: Define.h:128
uint16_t uint16
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:143
uint16 flags
Definition: DisableMgr.cpp:49
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition: Duration.h:32
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
#define ABORT
Definition: Errors.h:74
#define ASSERT
Definition: Errors.h:68
#define MAX_HEIGHT
Definition: GridDefines.h:60
#define INVALID_HEIGHT
Definition: GridDefines.h:61
#define VMAP_INVALID_HEIGHT_VALUE
Definition: IVMapManager.h:44
#define VMAP_INVALID_HEIGHT
Definition: IVMapManager.h:43
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define TC_LOG_FATAL(filterType__,...)
Definition: Log.h:168
@ LIQUID_MAP_NO_WATER
Definition: MapDefines.h:126
#define MAX_VISIBILITY_DISTANCE
Definition: ObjectDefines.h:28
#define DEFAULT_VISIBILITY_DISTANCE
Definition: ObjectDefines.h:35
TempSummonType
Definition: ObjectDefines.h:62
@ TEMPSUMMON_DEAD_DESPAWN
Definition: ObjectDefines.h:69
@ TEMPSUMMON_TIMED_DESPAWN
Definition: ObjectDefines.h:65
#define VISIBILITY_DISTANCE_LARGE
Definition: ObjectDefines.h:31
#define VISIBILITY_DISTANCE_TINY
Definition: ObjectDefines.h:34
GOSummonType
Definition: ObjectDefines.h:82
@ GO_SUMMON_TIMED_OR_CORPSE_DESPAWN
Definition: ObjectDefines.h:83
#define SIGHT_RANGE_UNIT
Definition: ObjectDefines.h:29
#define CONTACT_DISTANCE
Definition: ObjectDefines.h:23
#define DEFAULT_VISIBILITY_INSTANCE
Definition: ObjectDefines.h:36
#define VISIBILITY_DISTANCE_GIGANTIC
Definition: ObjectDefines.h:30
#define VISIBILITY_DISTANCE_SMALL
Definition: ObjectDefines.h:33
VisibilityDistanceType
Definition: ObjectDefines.h:50
@ TYPEID_OBJECT
Definition: ObjectGuid.h:35
@ TYPEID_ACTIVE_PLAYER
Definition: ObjectGuid.h:42
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:43
@ TYPEID_UNIT
Definition: ObjectGuid.h:40
@ TYPEID_CORPSE
Definition: ObjectGuid.h:45
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
std::set< ObjectGuid > GuidSet
Definition: ObjectGuid.h:391
@ TYPEMASK_OBJECT
Definition: ObjectGuid.h:55
@ TYPEMASK_ITEM
Definition: ObjectGuid.h:56
@ TYPEMASK_UNIT
Definition: ObjectGuid.h:60
#define sObjectMgr
Definition: ObjectMgr.h:1945
@ SUMMONER_TYPE_MAP
Definition: ObjectMgr.h:69
@ SUMMONER_TYPE_CREATURE
Definition: ObjectMgr.h:67
@ SUMMONER_TYPE_GAMEOBJECT
Definition: ObjectMgr.h:68
constexpr float VisibilityDistances[AsUnderlyingType(VisibilityDistanceType::Max)]
Definition: Object.cpp:62
std::unordered_map< Player *, UpdateData > UpdateDataMapType
Definition: Object.h:78
#define sOutdoorPvPMgr
@ PATHFIND_FARFROMPOLY_END
Definition: PathGenerator.h:51
@ PATHFIND_NOT_USING_PATH
Definition: PathGenerator.h:48
@ PATHFIND_NORMAL
Definition: PathGenerator.h:44
@ PATHFIND_SHORTCUT
Definition: PathGenerator.h:45
@ PATHFIND_INCOMPLETE
Definition: PathGenerator.h:46
@ DUEL_STATE_IN_PROGRESS
Definition: Player.h:359
@ PLAYER_FLAGS_CONTESTED_PVP
Definition: Player.h:436
@ PLAYER_FLAGS_UBER
Definition: Player.h:447
@ CHEAT_CASTTIME
Definition: Player.h:950
int32 irand(int32 min, int32 max)
Definition: Random.cpp:35
float rand_norm()
Definition: Random.cpp:75
bool roll_chance_i(int chance)
Definition: Random.h:59
@ SERVERSIDE_VISIBILITY_GM
@ SERVERSIDE_VISIBILITY_GHOST
@ EFFECT_3
Definition: SharedDefines.h:33
@ EFFECT_1
Definition: SharedDefines.h:31
@ EFFECT_0
Definition: SharedDefines.h:30
@ EFFECT_4
Definition: SharedDefines.h:34
@ EFFECT_2
Definition: SharedDefines.h:32
@ SPELL_ATTR9_SPECIAL_DELAY_CALCULATION
@ SPELL_ATTR7_REFLECTION_ONLY_DEFENDS
@ SPELL_ATTR7_NO_ATTACK_MISS
@ SPELL_ATTR7_NO_TARGET_DURATION_MOD
StealthType
@ TOTAL_STEALTH_TYPES
GameobjectTypes
@ GAMEOBJECT_TYPE_TRAP
@ SPELL_ATTR5_IGNORE_AREA_EFFECT_PVP_CHECK
@ SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC
SpellMissInfo
@ SPELL_MISS_IMMUNE
@ SPELL_MISS_NONE
@ SPELL_MISS_RESIST
@ SPELL_MISS_MISS
@ SPELL_MISS_EVADE
@ SPELL_MISS_REFLECT
@ SPELL_MISS_DEFLECT
SpellSchoolMask
@ SPELL_ATTR2_AUTO_REPEAT
@ SPELL_ATTR2_RETAIN_ITEM_CAST
SummonTitle
InvisibilityType
@ TOTAL_INVISIBILITY_TYPES
@ SPELL_ATTR1_NO_REDIRECTION
@ SPELL_ATTR3_ALWAYS_HIT
@ SPELL_ATTR3_NO_AVOIDANCE
@ SPELL_ATTR3_IGNORE_CASTER_MODIFIERS
@ SPELL_DAMAGE_CLASS_RANGED
@ SPELL_DAMAGE_CLASS_MAGIC
@ SPELL_DAMAGE_CLASS_NONE
@ SPELL_DAMAGE_CLASS_MELEE
WeaponAttackType
@ RANGED_ATTACK
@ MAX_POWERS
@ POWER_RUNES
@ POWER_COMBO_POINTS
@ SPELL_ATTR0_IS_TRADESKILL
@ SPELL_ATTR0_IS_ABILITY
@ SPELL_ATTR0_NO_IMMUNITIES
@ SPELL_ATTR0_USES_RANGED_SLOT
ReputationRank
@ REP_FRIENDLY
@ REP_NEUTRAL
@ REP_HOSTILE
LineOfSightChecks
SpellCastResult
@ SPELL_FAILED_BAD_TARGETS
@ SPELL_CAST_OK
@ SPELL_FAILED_SPELL_UNAVAILABLE
@ GHOST_VISIBILITY_ALIVE
@ GHOST_VISIBILITY_GHOST
@ SPELLFAMILY_POTION
constexpr float Z_OFFSET_FIND_HEIGHT
Definition: SharedDefines.h:26
@ GO_STATE_READY
@ SUMMON_CATEGORY_PET
@ SUMMON_CATEGORY_VEHICLE
@ SUMMON_CATEGORY_ALLY
@ SUMMON_CATEGORY_PUPPET
@ SUMMON_CATEGORY_WILD
@ SUMMON_CATEGORY_UNK
@ CREATURE_TYPE_FLAG_CAN_ASSIST
@ SPELL_ATTR8_IGNORE_SANCTUARY
@ SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG
@ SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC
@ SKILL_COOKING
@ SPELL_ATTR6_CAN_TARGET_UNTARGETABLE
@ SPELL_ATTR6_IGNORE_PHASE_SHIFT
@ SPELL_ATTR6_CAN_ASSIST_IMMUNE_PC
@ AURA_REMOVE_BY_EXPIRE
@ SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK
@ SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK
@ SPELL_AURA_REFLECT_SPELLS
@ SPELL_AURA_IGNORE_HIT_DIRECTION
@ SPELL_AURA_DEFLECT_SPELLS
@ SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL
@ SPELL_AURA_WATER_WALK
@ SPELL_AURA_MECHANIC_DURATION_MOD
@ SPELL_AURA_DETECT_STEALTH
@ SPELL_AURA_SPELL_MAGNET
@ SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE
@ SPELL_AURA_REFLECT_SPELLS_SCHOOL
bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
Definition: SpellMgr.cpp:118
@ SPELL_GROUP_ELIXIR_BATTLE
Definition: SpellMgr.h:352
@ SPELL_GROUP_ELIXIR_GUARDIAN
Definition: SpellMgr.h:353
#define sSpellMgr
Definition: SpellMgr.h:849
uint32 getMSTime()
Definition: Timer.h:33
@ MOVE_FLIGHT
Definition: UnitDefines.h:123
@ MOVE_SWIM
Definition: UnitDefines.h:120
@ MOVE_TURN_RATE
Definition: UnitDefines.h:122
@ MOVE_FLIGHT_BACK
Definition: UnitDefines.h:124
@ MOVE_SWIM_BACK
Definition: UnitDefines.h:121
@ MOVE_RUN
Definition: UnitDefines.h:118
@ MOVE_PITCH_RATE
Definition: UnitDefines.h:125
@ MOVE_RUN_BACK
Definition: UnitDefines.h:119
@ MOVE_WALK
Definition: UnitDefines.h:117
@ UNIT_FLAG2_IGNORE_REPUTATION
Definition: UnitDefines.h:196
@ UNIT_FLAG2_GIGANTIC_AOI
Definition: UnitDefines.h:216
@ UNIT_FLAG2_INFINITE_AOI
Definition: UnitDefines.h:224
@ UNIT_FLAG2_LARGE_AOI
Definition: UnitDefines.h:215
@ MOVEMENTFLAG_FLYING
Definition: UnitDefines.h:382
@ MOVEMENTFLAG_FALLING
Definition: UnitDefines.h:369
@ MOVEMENTFLAG_SWIMMING
Definition: UnitDefines.h:378
@ MOVEMENTFLAG_SPLINE_ELEVATION
Definition: UnitDefines.h:383
@ MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING
Definition: UnitDefines.h:421
@ UNIT_BYTE2_FLAG_UNK1
Definition: UnitDefines.h:94
@ UNIT_FLAG_NON_ATTACKABLE
Definition: UnitDefines.h:145
@ UNIT_FLAG_NON_ATTACKABLE_2
Definition: UnitDefines.h:160
@ UNIT_FLAG_ON_TAXI
Definition: UnitDefines.h:164
@ UNIT_FLAG_NOT_ATTACKABLE_1
Definition: UnitDefines.h:151
@ UNIT_FLAG_PLAYER_CONTROLLED
Definition: UnitDefines.h:147
@ UNIT_MASK_PUPPET
Definition: Unit.h:351
@ UNIT_MASK_TOTEM
Definition: Unit.h:348
@ UNIT_MASK_SUMMON
Definition: Unit.h:345
@ UNIT_MASK_GUARDIAN
Definition: Unit.h:347
@ UNIT_MASK_MINION
Definition: Unit.h:346
#define WORLD_TRIGGER
Definition: Unit.h:36
#define MAX_PLAYER_STEALTH_DETECT_RANGE
Definition: Unit.h:619
@ UNIT_STATE_UNATTACKABLE
Definition: Unit.h:288
@ UNIT_STATE_CONTROLLED
Definition: Unit.h:290
@ UPDATETYPE_VALUES
Definition: UpdateData.h:30
@ UPDATETYPE_CREATE_OBJECT
Definition: UpdateData.h:31
@ UPDATETYPE_CREATE_OBJECT2
Definition: UpdateData.h:32
T AddPct(T &base, U pct)
Definition: Util.h:85
T RoundToInterval(T &num, T floor, T ceil)
Definition: Util.h:97
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
T CalculatePct(T base, U pct)
Definition: Util.h:72
uint32 const Entry[5]
EnumFlag< AreaTriggerCreatePropertiesFlag > Flags
bool HasSplines() const
uint32 GetTimeSinceCreated() const
Definition: AreaTrigger.h:101
AreaTriggerShapeInfo const & GetShape() const
Definition: AreaTrigger.h:149
uint32 GetTimeToTarget() const
Definition: AreaTrigger.h:118
Optional< AreaTriggerOrbitInfo > const & GetOrbit() const
Definition: AreaTrigger.h:161
uint32 GetElapsedTimeForMovement() const
Definition: AreaTrigger.h:157
::Movement::Spline< int32 > const & GetSpline() const
Definition: AreaTrigger.h:156
Position const & GetTargetRollPitchYaw() const
Definition: AreaTrigger.h:152
Position const & GetRollPitchYaw() const
Definition: AreaTrigger.h:151
bool HasOrbit() const
AreaTriggerCreateProperties const * GetCreateProperties() const
Definition: AreaTrigger.h:137
Unit * GetCaster() const
Aura * GetBase() const
ObjectGuid GetCastItemGUID() const
Definition: SpellAuras.h:139
void append(T value)
Definition: ByteBuffer.h:143
size_t wpos() const
Definition: ByteBuffer.h:412
bool WriteBit(bool bit)
Definition: ByteBuffer.h:175
void put(std::size_t pos, T value)
Definition: ByteBuffer.h:220
void FlushBits()
Definition: ByteBuffer.h:155
uint32 GetTextureKitId() const
Definition: Conversation.h:61
Definition: Corpse.h:53
void SetHomePosition(float x, float y, float z, float o)
Definition: Creature.h:333
float GetAttackDistance(Unit const *player) const
Definition: Creature.cpp:2163
bool IsEvadingAttacks() const
Definition: Creature.h:180
bool AIM_Initialize(CreatureAI *ai=nullptr)
Definition: Creature.cpp:1047
bool Create(ObjectGuid::LowType guidlow, Map *map, uint32 entry, Position const &pos, CreatureData const *data, uint32 vehId, bool dynamic=false)
Definition: Creature.cpp:1074
float m_SightDistance
Definition: Creature.h:374
float m_CombatDistance
Definition: Creature.h:374
ObjectGuid GetCasterGUID() const
Definition: DynamicObject.h:81
constexpr bool HasFlag(T flag) const
Definition: EnumFlag.h:106
void KillAllEvents(bool force)
void Update(uint32 p_time)
T_FLAGS GetFlags() const
Definition: Object.h:422
T_VALUES GetValue(FLAG_TYPE flag) const
Definition: Object.h:427
void SetValue(FLAG_TYPE flag, T_VALUES value)
Definition: Object.h:428
static GameObject * CreateGameObject(uint32 entry, Map *map, Position const &pos, QuaternionData const &rotation, uint32 animProgress, GOState goState, uint32 artKit=0)
void SetRespawnTime(int32 respawn)
void SetSpawnedByDefault(bool b)
Definition: GameObject.h:258
GameobjectTypes GetGoType() const
Definition: GameObject.h:274
QuaternionData GetWorldRotation() const
uint32 GetWorldEffectID() const
Definition: GameObject.h:419
iterator end()
iterator begin()
Definition: Item.h:170
Definition: Map.h:187
void GetFullTerrainStatusForPosition(PhaseShift const &phaseShift, float x, float y, float z, PositionFullTerrainStatus &data, map_liquidHeaderTypeFlags reqLiquidType=map_liquidHeaderTypeFlags::AllLiquids, float collisionHeight=2.03128f)
Definition: Map.cpp:1682
bool IsDungeon() const
Definition: Map.cpp:3205
void AddObjectToRemoveList(WorldObject *obj)
Definition: Map.cpp:2547
void RemoveFromActive(WorldObject *obj)
Definition: Map.cpp:2739
bool AddToMap(T *)
Definition: Map.cpp:530
void RemoveUpdateObject(Object *obj)
Definition: Map.h:533
bool isInLineOfSight(PhaseShift const &phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const
Definition: Map.cpp:1749
TempSummon * SummonCreature(uint32 entry, Position const &pos, SummonPropertiesEntry const *properties=nullptr, Milliseconds duration=0ms, WorldObject *summoner=nullptr, uint32 spellId=0, uint32 vehId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty, SmoothPhasingInfo const *smoothPhasingInfo=nullptr)
Definition: Object.cpp:1824
void GetZoneAndAreaId(PhaseShift const &phaseShift, uint32 &zoneid, uint32 &areaid, float x, float y, float z)
Definition: Map.cpp:1709
bool getObjectHitPos(PhaseShift const &phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, float &rx, float &ry, float &rz, float modifyDist)
Definition: Map.cpp:1760
void AddWorldObject(WorldObject *obj)
Definition: Map.h:357
float GetWaterOrGroundLevel(PhaseShift const &phaseShift, float x, float y, float z, float *ground=nullptr, bool swim=false, float collisionHeight=2.03128f)
Definition: Map.cpp:1744
BattlegroundMap * ToBattlegroundMap()
Definition: Map.h:453
void SummonCreatureGroup(uint8 group, std::list< TempSummon * > *list=nullptr)
Definition: Object.cpp:1968
void RemoveWorldObject(WorldObject *obj)
Definition: Map.h:358
uint32 GetId() const
Definition: Map.cpp:3195
float GetVisibilityRange() const
Definition: Map.h:217
float GetHeight(PhaseShift const &phaseShift, float x, float y, float z, bool vmap=true, float maxSearchDist=DEFAULT_HEIGHT_SEARCH)
Definition: Map.h:289
InstanceMap * ToInstanceMap()
Definition: Map.h:450
float GetGridHeight(PhaseShift const &phaseShift, float x, float y)
Definition: Map.cpp:1719
uint32 GetInstanceId() const
Definition: Map.h:313
void AddToActive(WorldObject *obj)
Definition: Map.cpp:2700
void AddUpdateObject(Object *obj)
Definition: Map.h:528
void AddObjectToSwitchList(WorldObject *obj, bool on)
Definition: Map.cpp:2557
static ObjectGuid const Empty
Definition: ObjectGuid.h:272
bool IsEmpty() const
Definition: ObjectGuid.h:317
bool IsPlayer() const
Definition: ObjectGuid.h:324
std::string ToString() const
Definition: ObjectGuid.cpp:554
Definition: Object.h:149
Corpse * ToCorpse()
Definition: Object.h:226
void BuildFieldsUpdate(Player *, UpdateDataMapType &) const
Definition: Object.cpp:795
void BuildValuesUpdateBlockForPlayer(UpdateData *data, Player const *target) const
Definition: Object.cpp:190
uint16 m_objectType
Definition: Object.h:386
static Creature * ToCreature(Object *o)
Definition: Object.h:206
bool IsPlayer() const
Definition: Object.h:199
bool m_isNewObject
Definition: Object.h:400
DynamicObject * ToDynObject()
Definition: Object.h:232
virtual void BuildValuesUpdateWithFlag(ByteBuffer *data, UF::UpdateFieldFlag flags, Player const *target) const
Definition: Object.cpp:768
static Unit * ToUnit(Object *o)
Definition: Object.h:212
Player * ToPlayer()
Definition: Object.h:202
ObjectGuid m_guid
Definition: Object.h:398
static GameObject * ToGameObject(Object *o)
Definition: Object.h:218
ObjectGuid const & GetGUID() const
Definition: Object.h:159
bool IsInWorld() const
Definition: Object.h:153
UF::UpdateField< UF::ObjectData, 0, TYPEID_OBJECT > m_objectData
Definition: Object.h:254
Object()
Definition: Object.cpp:72
void AddToObjectUpdateIfNeeded()
Definition: Object.cpp:777
void BuildDestroyUpdateBlock(UpdateData *data) const
Definition: Object.cpp:208
void BuildValuesUpdateBlockForPlayerWithFlag(UpdateData *data, UF::UpdateFieldFlag flags, Player const *target) const
Definition: Object.cpp:199
void SendOutOfRangeForPlayer(Player *target) const
Definition: Object.cpp:237
Conversation * ToConversation()
Definition: Object.h:250
bool IsUnit() const
Definition: Object.h:211
TypeID GetTypeId() const
Definition: Object.h:172
virtual void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const
Definition: Object.cpp:130
bool m_isDestroyedObject
Definition: Object.h:401
virtual bool AddToObjectUpdate()=0
virtual void DestroyForPlayer(Player *target) const
Definition: Object.cpp:226
CreateObjectBits m_updateFlag
Definition: Object.h:389
bool isType(uint16 mask) const
Definition: Object.h:173
virtual void BuildValuesCreate(ByteBuffer *data, Player const *target) const =0
bool IsGameObject() const
Definition: Object.h:217
AreaTrigger * ToAreaTrigger()
Definition: Object.h:238
virtual void ClearUpdateMask(bool remove)
Definition: Object.cpp:783
GameObject * ToGameObject()
Definition: Object.h:220
uint32 GetEntry() const
Definition: Object.h:160
UF::UpdateFieldHolder m_values
Definition: Object.h:253
Creature * ToCreature()
Definition: Object.h:208
virtual std::string GetDebugInfo() const
Definition: Object.cpp:809
virtual void BuildValuesUpdate(ByteBuffer *data, Player const *target) const =0
void _Create(ObjectGuid const &guid)
Definition: Object.cpp:101
ByteBuffer & PrepareValuesUpdateBuffer(UpdateData *data) const
Definition: Object.cpp:218
virtual void RemoveFromObjectUpdate()=0
virtual void AddToWorld()
Definition: Object.cpp:107
virtual void RemoveFromWorld()
Definition: Object.cpp:119
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:158
bool m_inWorld
Definition: Object.h:399
void BuildOutOfRangeUpdateBlock(UpdateData *data) const
Definition: Object.cpp:213
void SendUpdateToPlayer(Player *player)
Definition: Object.cpp:176
virtual ~Object()
Definition: Object.cpp:84
virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const
Definition: Object.cpp:763
TypeID m_objectTypeId
Definition: Object.h:388
void BuildMovementUpdate(ByteBuffer *data, CreateObjectBits flags, Player *target) const
Definition: Object.cpp:248
bool m_objectUpdated
Definition: Object.h:395
static Player * ToPlayer(Object *o)
Definition: Object.h:200
Unit * ToUnit()
Definition: Object.h:214
void SetUseRaycast(bool useRaycast)
Definition: PathGenerator.h:74
Movement::PointsArray const & GetPath() const
Definition: PathGenerator.h:81
PathType GetPathType() const
Definition: PathGenerator.h:84
bool CalculatePath(float destX, float destY, float destZ, bool forceDest=false)
static uint32 GetTerrainMapId(PhaseShift const &phaseShift, uint32 mapId, TerrainInfo const *terrain, float x, float y)
static void InheritPhaseShift(WorldObject *target, WorldObject const *source)
static PhaseShift const & GetAlwaysVisiblePhaseShift()
bool HaveAtClient(Object const *u) const
Definition: Player.cpp:23703
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6318
uint32 GetRuneBaseCooldown() const
Definition: Player.cpp:26198
SceneMgr & GetSceneMgr()
Definition: Player.h:2713
GuidUnorderedSet m_clientGUIDs
Definition: Player.h:2510
uint8 GetRunesState() const
Definition: Player.cpp:26193
bool GetCommandStatus(uint32 command) const
Definition: Player.h:1206
WorldObject * GetViewpoint() const
Definition: Player.cpp:26069
uint32 GetRuneCooldown(uint8 index) const
Definition: Player.h:2642
bool IsGameMaster() const
Definition: Player.h:1178
bool IsAdvancedCombatLoggingEnabled() const
Definition: Player.h:2710
bool HasPlayerFlag(PlayerFlags flags) const
Definition: Player.h:2735
std::unique_ptr< DuelInfo > duel
Definition: Player.h:1973
ReputationMgr & GetReputationMgr()
Definition: Player.h:2252
FactionState const * GetState(FactionEntry const *factionEntry) const
bool IsAtWar(uint32 faction_id) const
ReputationRank const * GetForcedRankIfAny(FactionTemplateEntry const *factionTemplateEntry) const
SceneTemplateByInstance const & GetSceneTemplateByInstanceMap() const
Definition: SceneMgr.h:70
void SetSingleInfo(SmoothPhasingInfo const &info)
int32 CalcValue(WorldObject const *caster=nullptr, int32 const *basePoints=nullptr, Unit const *target=nullptr, float *variance=nullptr, uint32 castItemId=0, int32 itemLevel=-1) const
Definition: SpellInfo.cpp:495
uint32 TriggerSpell
Definition: SpellInfo.h:237
std::array< SpellPowerEntry const *, MAX_POWERS_PER_SPELL > PowerCosts
Definition: SpellInfo.h:386
uint32 SpellLevel
Definition: SpellInfo.h:384
uint32 GetSpellXSpellVisualId(WorldObject const *caster=nullptr, WorldObject const *viewer=nullptr) const
Definition: SpellInfo.cpp:4363
float GetMaxRange(bool positive=false, WorldObject *caster=nullptr, Spell *spell=nullptr) const
Definition: SpellInfo.cpp:3768
uint32 const Id
Definition: SpellInfo.h:325
SpellRangeEntry const * RangeEntry
Definition: SpellInfo.h:387
bool HasOnlyDamageEffects() const
Definition: SpellInfo.cpp:1418
uint32 Dispel
Definition: SpellInfo.h:328
bool HasHitDelay() const
Definition: SpellInfo.cpp:1751
float Speed
Definition: SpellInfo.h:388
float GetMinRange(bool positive=false) const
Definition: SpellInfo.cpp:3761
int32 GetMaxDuration() const
Definition: SpellInfo.cpp:3798
bool IsAllowingDeadTarget() const
Definition: SpellInfo.cpp:1668
float LaunchDelay
Definition: SpellInfo.h:389
SpellSchoolMask GetSchoolMask() const
Definition: SpellInfo.cpp:2465
bool IsChanneled() const
Definition: SpellInfo.cpp:1719
bool HasAttribute(SpellAttr0 attribute) const
Definition: SpellInfo.h:449
uint64 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
Definition: SpellInfo.cpp:2495
int32 GetDuration() const
Definition: SpellInfo.cpp:3791
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition: SpellInfo.h:577
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
Definition: SpellInfo.cpp:2359
bool IsAffectingArea() const
Definition: SpellInfo.cpp:1532
bool IsPositive() const
Definition: SpellInfo.cpp:1709
uint32 DmgClass
Definition: SpellInfo.h:410
uint32 SpellFamilyName
Definition: SpellInfo.h:408
Definition: Spell.h:254
void SetSpellValue(SpellValueMod mod, int32 value)
Definition: Spell.cpp:8564
std::any m_customArg
Definition: Spell.h:604
int32 m_castItemLevel
Definition: Spell.h:566
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition: Spell.cpp:3419
Item * m_CastItem
Definition: Spell.h:563
virtual void InitStats(WorldObject *summoner, Milliseconds duration)
ObjectGuid GetSummonerGUID() const
void SetTempSummonType(TempSummonType type)
virtual void InitSummon(WorldObject *summoner)
SummonPropertiesEntry const *const m_Properties
virtual ObjectGuid GetTransportGUID() const =0
virtual TransportBase * RemovePassenger(WorldObject *passenger)=0
virtual void CalculatePassengerOffset(float &x, float &y, float &z, float *o=nullptr) const =0
This method transforms supplied global coordinates into local offsets.
virtual void AddPassenger(WorldObject *passenger)=0
void ClearChangesMask(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UpdateField.h:690
Definition: Unit.h:622
Unit * GetCharmed() const
Definition: Unit.h:1177
Vehicle * GetVehicle() const
Definition: Unit.h:1697
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition: Unit.h:1307
bool HasPvpFlag(UnitPVPStateFlags flags) const
Definition: Unit.h:862
uint32 GetUnitMovementFlags() const
Definition: Unit.h:1649
float GetSpeed(UnitMoveType mtype) const
Definition: Unit.cpp:8488
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition: Unit.cpp:4668
UF::UpdateField< UF::UnitData, 0, TYPEID_UNIT > m_unitData
Definition: Unit.h:1791
void SetFaction(uint32 faction) override
Definition: Unit.h:854
std::forward_list< AuraEffect * > AuraEffectList
Definition: Unit.h:639
bool IsImmunedToSpell(SpellInfo const *spellInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7405
bool IsPvP() const
Definition: Unit.h:868
Unit * GetVehicleBase() const
Definition: Unit.cpp:11403
bool IsPet() const
Definition: Unit.h:735
bool HasUnitFlag(UnitFlags flags) const
Definition: Unit.h:827
void SetCreatedBySpell(int32 spellId)
Definition: Unit.h:842
bool CanInstantCast() const
Definition: Unit.h:1750
MovementForces const * GetMovementForces() const
Definition: Unit.h:1139
int32 GetMaxNegativeAuraModifier(AuraType auraType) const
Definition: Unit.cpp:4925
bool HasUnitFlag2(UnitFlags2 flags) const
Definition: Unit.h:832