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