TrinityCore
GameObject.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 "GameObject.h"
19#include "ArtifactPackets.h"
20#include "AzeriteItem.h"
21#include "AzeritePackets.h"
22#include "Battleground.h"
23#include "BattlegroundPackets.h"
24#include "CellImpl.h"
25#include "Containers.h"
26#include "CreatureAISelector.h"
27#include "DatabaseEnv.h"
28#include "DB2Stores.h"
29#include "G3DPosition.hpp"
30#include "GameEventSender.h"
31#include "GameObjectAI.h"
32#include "GameObjectModel.h"
33#include "GameObjectPackets.h"
34#include "GameTime.h"
35#include "GossipDef.h"
36#include "GridNotifiersImpl.h"
37#include "Group.h"
38#include "Item.h"
39#include "ItemBonusMgr.h"
40#include "Log.h"
41#include "Loot.h"
42#include "LootMgr.h"
43#include "Map.h"
44#include "MapManager.h"
45#include "MiscPackets.h"
46#include "ObjectAccessor.h"
47#include "ObjectMgr.h"
48#include "OutdoorPvPMgr.h"
49#include "PhasingHandler.h"
50#include "PoolMgr.h"
51#include "QueryPackets.h"
52#include "Util.h"
53#include "SpellAuras.h"
54#include "SpellMgr.h"
55#include "Transport.h"
56#include "Vignette.h"
57#include "World.h"
58#include <G3D/Box.h>
59#include <G3D/CoordinateFrame.h>
60#include <G3D/Quat.h>
61#include <sstream>
62
64{
65 for (uint8 loc = LOCALE_enUS; loc < TOTAL_LOCALES; ++loc)
66 QueryData[loc] = BuildQueryData(static_cast<LocaleConstant>(loc));
67}
68
70{
72
73 queryTemp.GameObjectID = entry;
74
75 queryTemp.Allow = true;
77
78 stats.Type = type;
79 stats.DisplayID = displayId;
80
81 stats.Name[0] = name;
82 stats.IconName = IconName;
84 stats.UnkString = unk1;
85
86 if (loc != LOCALE_enUS)
87 if (GameObjectLocale const* gameObjectLocale = sObjectMgr->GetGameObjectLocale(entry))
88 {
89 ObjectMgr::GetLocaleString(gameObjectLocale->Name, loc, stats.Name[0]);
90 ObjectMgr::GetLocaleString(gameObjectLocale->CastBarCaption, loc, stats.CastBarCaption);
91 ObjectMgr::GetLocaleString(gameObjectLocale->Unk1, loc, stats.UnkString);
92 }
93
94 stats.Size = size;
95
96 if (std::vector<uint32> const* items = sObjectMgr->GetGameObjectQuestItemList(entry))
97 for (int32 item : *items)
98 stats.QuestItems.push_back(item);
99
100 memcpy(stats.Data.data(), raw.data, MAX_GAMEOBJECT_DATA * sizeof(int32));
102
103 queryTemp.Write();
104 queryTemp.ShrinkToFit();
105 return queryTemp.Move();
106}
107
109{
110 return fabs(x * x + y * y + z * z + w * w - 1.0f) < 1e-5f;
111}
112
113void QuaternionData::toEulerAnglesZYX(float& Z, float& Y, float& X) const
114{
115 G3D::Matrix3(G3D::Quat(x, y, z, w)).toEulerAnglesZYX(Z, Y, X);
116}
117
119{
120 G3D::Quat quat(G3D::Matrix3::fromEulerAnglesZYX(Z, Y, X));
121 return QuaternionData(quat.x, quat.y, quat.z, quat.w);
122}
123
125
127{
128//11 GAMEOBJECT_TYPE_TRANSPORT
130{
131public:
132 static constexpr Milliseconds PositionUpdateInterval = 50ms;
133
134 explicit Transport(GameObject& owner) : GameObjectTypeBase(owner), _animationInfo(sTransportMgr->GetTransportAnimInfo(owner.GetGOInfo()->entry)),
137 {
138 GameObjectTemplate const* goInfo = _owner.GetGOInfo();
139 if (goInfo->transport.Timeto2ndfloor > 0)
140 {
141 _stopFrames.push_back(goInfo->transport.Timeto2ndfloor);
142 if (goInfo->transport.Timeto3rdfloor > 0)
143 {
144 _stopFrames.push_back(goInfo->transport.Timeto3rdfloor);
145 if (goInfo->transport.Timeto4thfloor > 0)
146 {
147 _stopFrames.push_back(goInfo->transport.Timeto4thfloor);
148 if (goInfo->transport.Timeto5thfloor > 0)
149 {
150 _stopFrames.push_back(goInfo->transport.Timeto5thfloor);
151 if (goInfo->transport.Timeto6thfloor > 0)
152 {
153 _stopFrames.push_back(goInfo->transport.Timeto6thfloor);
154 if (goInfo->transport.Timeto7thfloor > 0)
155 {
156 _stopFrames.push_back(goInfo->transport.Timeto7thfloor);
157 if (goInfo->transport.Timeto8thfloor > 0)
158 {
159 _stopFrames.push_back(goInfo->transport.Timeto8thfloor);
160 if (goInfo->transport.Timeto9thfloor > 0)
161 {
162 _stopFrames.push_back(goInfo->transport.Timeto9thfloor);
163 if (goInfo->transport.Timeto10thfloor > 0)
164 _stopFrames.push_back(goInfo->transport.Timeto10thfloor);
165 }
166 }
167 }
168 }
169 }
170 }
171 }
172 }
173
174 if (!_stopFrames.empty())
175 {
176 _pathProgress = 0;
178 }
179
181 }
182
183 void Update(uint32 diff) override
184 {
185 if (!_animationInfo)
186 return;
187
190 return;
191
193
195 uint32 period = GetTransportPeriod();
196 uint32 newProgress = 0;
197 if (_stopFrames.empty())
198 newProgress = now % period;
199 else
200 {
201 int32 stopTargetTime = 0;
203 stopTargetTime = 0;
204 else
206
207 if (now < uint32(*_owner.m_gameObjectData->Level))
208 {
209 int32 timeToStop = _owner.m_gameObjectData->Level - _stateChangeTime;
210 float stopSourcePathPct = float(_stateChangeProgress) / float(period);
211 float stopTargetPathPct = float(stopTargetTime) / float(period);
212 float timeSinceStopProgressPct = float(now - _stateChangeTime) / float(timeToStop);
213
214 float progressPct;
216 {
218 stopTargetPathPct = 1.0f;
219
220 float pathPctBetweenStops = stopTargetPathPct - stopSourcePathPct;
221 if (pathPctBetweenStops < 0.0f)
222 pathPctBetweenStops += 1.0f;
223
224 progressPct = pathPctBetweenStops * timeSinceStopProgressPct + stopSourcePathPct;
225 if (progressPct > 1.0f)
226 progressPct = progressPct - 1.0f;
227 }
228 else
229 {
230 float pathPctBetweenStops = stopSourcePathPct - stopTargetPathPct;
231 if (pathPctBetweenStops < 0.0f)
232 pathPctBetweenStops += 1.0f;
233
234 progressPct = stopSourcePathPct - pathPctBetweenStops * timeSinceStopProgressPct;
235 if (progressPct < 0.0f)
236 progressPct += 1.0f;
237 }
238
239 newProgress = uint32(float(period) * progressPct) % period;
240 }
241 else
242 newProgress = stopTargetTime;
243
244 if (int32(newProgress) == stopTargetTime && newProgress != _pathProgress)
245 {
246 uint32 eventId = [&]()
247 {
249 {
250 case 0:
252 case 1:
254 case 2:
256 case 3:
258 case 4:
260 case 5:
262 case 6:
264 case 7:
266 case 8:
268 case 9:
270 default:
271 return 0u;
272 }
273 }();
274 if (eventId)
275 GameEvents::Trigger(eventId, &_owner, &_owner);
276
278 {
279 GOState currentState = _owner.GetGoState();
280 GOState newState;
281 if (currentState == GO_STATE_TRANSPORT_ACTIVE)
283 else if (currentState - GO_STATE_TRANSPORT_ACTIVE == int32(_stopFrames.size()))
284 newState = GOState(currentState - 1);
286 newState = GOState(currentState - 1);
287 else
288 newState = GOState(currentState + 1);
289
290 _owner.SetGoState(newState);
291 }
292 }
293 }
294
295 if (_pathProgress == newProgress)
296 return;
297
298 _pathProgress = newProgress;
299
300 TransportAnimationEntry const* oldAnimation = _animationInfo->GetPrevAnimNode(newProgress);
301 TransportAnimationEntry const* newAnimation = _animationInfo->GetNextAnimNode(newProgress);
302 if (oldAnimation && newAnimation)
303 {
304 G3D::Matrix3 pathRotation = G3D::Quat(_owner.m_gameObjectData->ParentRotation->x, _owner.m_gameObjectData->ParentRotation->y,
305 _owner.m_gameObjectData->ParentRotation->z, _owner.m_gameObjectData->ParentRotation->w).toRotationMatrix();
306
307 G3D::Vector3 prev(oldAnimation->Pos.X, oldAnimation->Pos.Y, oldAnimation->Pos.Z);
308 G3D::Vector3 next(newAnimation->Pos.X, newAnimation->Pos.Y, newAnimation->Pos.Z);
309
310 G3D::Vector3 dst = next;
311 if (prev != next)
312 {
313 float animProgress = float(newProgress - oldAnimation->TimeIndex) / float(newAnimation->TimeIndex - oldAnimation->TimeIndex);
314
315 dst = prev.lerp(next, animProgress);
316 }
317
318 dst = dst * pathRotation;
319 dst += PositionToVector3(&_owner.GetStationaryPosition());
320
321 _owner.GetMap()->GameObjectRelocation(&_owner, dst.x, dst.y, dst.z, _owner.GetOrientation());
322 }
323
324 TransportRotationEntry const* oldRotation = _animationInfo->GetPrevAnimRotation(newProgress);
325 TransportRotationEntry const* newRotation = _animationInfo->GetNextAnimRotation(newProgress);
326 if (oldRotation && newRotation)
327 {
328 G3D::Quat prev(oldRotation->Rot[0], oldRotation->Rot[1], oldRotation->Rot[2], oldRotation->Rot[3]);
329 G3D::Quat next(newRotation->Rot[0], newRotation->Rot[1], newRotation->Rot[2], newRotation->Rot[3]);
330
331 G3D::Quat rotation = next;
332
333 if (prev != next)
334 {
335 float animProgress = float(newProgress - oldRotation->TimeIndex) / float(newRotation->TimeIndex - oldRotation->TimeIndex);
336
337 rotation = prev.slerp(next, animProgress);
338 }
339
340 _owner.SetLocalRotation(rotation.x, rotation.y, rotation.z, rotation.w);
342 }
343
344 // update progress marker for client
345 _owner.SetPathProgressForClient(float(_pathProgress) / float(period));
346 }
347
348 void OnStateChanged(GOState oldState, GOState newState) override
349 {
351
352 // transports without stop frames just keep animating in state 24
353 if (_stopFrames.empty())
354 {
355 if (newState != GO_STATE_TRANSPORT_ACTIVE)
357 return;
358 }
359
360 int32 stopPathProgress = 0;
361
362 if (newState != GO_STATE_TRANSPORT_ACTIVE)
363 {
365 uint32 stopFrame = newState - GO_STATE_TRANSPORT_STOPPED;
366 ASSERT(stopFrame < _stopFrames.size());
367 stopPathProgress = _stopFrames[stopFrame];
368 }
369
372 uint32 timeToStop = std::abs(int32(_pathProgress) - stopPathProgress);
375
376 if (oldState == GO_STATE_ACTIVE || oldState == newState)
377 {
378 // initialization
379 if (int32(_pathProgress) > stopPathProgress)
381 else
383
384 return;
385 }
386
387 int32 pauseTimesCount = _stopFrames.size();
388 int32 newToOldStateDelta = newState - oldState;
389 if (newToOldStateDelta < 0)
390 newToOldStateDelta += pauseTimesCount + 1;
391
392 int32 oldToNewStateDelta = oldState - newState;
393 if (oldToNewStateDelta < 0)
394 oldToNewStateDelta += pauseTimesCount + 1;
395
396 // this additional check is neccessary because client doesn't check dynamic flags on progress update
397 // instead it multiplies progress from dynamicflags field by -1 and then compares that against 0
398 // when calculating path progress while we simply check the flag if (!_owner.HasDynamicFlag(GO_DYNFLAG_LO_INVERTED_MOVEMENT))
399 bool isAtStartOfPath = _stateChangeProgress == 0;
400
401 if (oldToNewStateDelta < newToOldStateDelta && !isAtStartOfPath)
403 else
405 }
406
407 void OnRelocated() override
408 {
410 }
411
413 {
414 for (WorldObject* passenger : _passengers)
415 {
416 float x, y, z, o;
417 passenger->m_movementInfo.transport.pos.GetPosition(x, y, z, o);
418 CalculatePassengerPosition(x, y, z, &o);
419 UpdatePassengerPosition(_owner.GetMap(), passenger, x, y, z, o, true);
420 }
421 }
422
424 {
425 if (_animationInfo)
427
428 return 1;
429 }
430
431 std::vector<uint32> const* GetPauseTimes() const
432 {
433 return &_stopFrames;
434 }
435
436 ObjectGuid GetTransportGUID() const override { return _owner.GetGUID(); }
437
438 float GetTransportOrientation() const override { return _owner.GetOrientation(); }
439
440 void AddPassenger(WorldObject* passenger) override
441 {
442 if (!_owner.IsInWorld())
443 return;
444
445 if (_passengers.insert(passenger).second)
446 {
447 passenger->SetTransport(this);
449 TC_LOG_DEBUG("entities.transport", "Object {} boarded transport {}.", passenger->GetName(), _owner.GetName());
450 }
451 }
452
454 {
455 if (_passengers.erase(passenger) > 0)
456 {
457 passenger->SetTransport(nullptr);
458 passenger->m_movementInfo.transport.Reset();
459 TC_LOG_DEBUG("entities.transport", "Object {} removed from transport {}.", passenger->GetName(), _owner.GetName());
460
461 if (Player* plr = passenger->ToPlayer())
462 plr->SetFallInformation(0, plr->GetPositionZ());
463 }
464
465 return this;
466 }
467
468 void CalculatePassengerPosition(float& x, float& y, float& z, float* o) const override
469 {
471 }
472
473 void CalculatePassengerOffset(float& x, float& y, float& z, float* o) const override
474 {
476 }
477
478 int32 GetMapIdForSpawning() const override
479 {
481 }
482
484 {
486 }
487
488private:
493 std::vector<uint32> _stopFrames;
496 std::unordered_set<WorldObject*> _passengers;
497};
498
500{
501}
502
504{
505 if (Transport* transport = dynamic_cast<Transport*>(&type))
506 transport->SetAutoCycleBetweenStopFrames(_on);
507}
508
510{
511public:
513
514 void SetState(FlagState newState, Player* player)
515 {
516 if (_state == newState)
517 return;
518
519 FlagState oldState = _state;
520 _state = newState;
521
522 if (player && newState == FlagState::Taken)
523 _carrierGUID = player->GetGUID();
524 else
526
527 if (newState == FlagState::Taken && oldState == FlagState::InBase)
529 else if (newState == FlagState::InBase || newState == FlagState::Respawning)
531
533
534 if (newState == FlagState::Respawning)
536 else
537 _respawnTime = 0;
538
539 if (ZoneScript* zoneScript = _owner.GetZoneScript())
540 zoneScript->OnFlagStateChange(&_owner, oldState, _state, player);
541 }
542
543 void Update([[maybe_unused]] uint32 diff) override
544 {
546 SetState(FlagState::InBase, nullptr);
547 }
548
549 bool IsNeverVisibleFor([[maybe_unused]] WorldObject const* seer, [[maybe_unused]] bool allowServersideObjects) const override
550 {
551 return _state != FlagState::InBase;
552 }
553
554 FlagState GetState() const { return _state; }
555 ObjectGuid const& GetCarrierGUID() const { return _carrierGUID; }
556 time_t GetTakenFromBaseTime() const { return _takenFromBaseTime; }
557
558private:
563};
564
565SetNewFlagState::SetNewFlagState(FlagState state, Player* player) : _state(state), _player(player)
566{
567}
568
570{
571 if (NewFlag* newFlag = dynamic_cast<NewFlag*>(&type))
572 newFlag->SetState(_state, _player);
573}
574
576{
577public:
578 explicit ControlZone(GameObject& owner) : GameObjectTypeBase(owner), _value(static_cast<float>(owner.GetGOInfo()->controlZone.startingValue))
579 {
580 if (owner.GetMap()->Instanceable())
581 _heartbeatRate = 1s;
582 else if (owner.GetGOInfo()->controlZone.FrequentHeartbeat)
583 _heartbeatRate = 2500ms;
584 else
585 _heartbeatRate = 5s;
586
589 _contestedTriggered = false;
590 }
591
592 void Update(uint32 diff) override
593 {
595 return;
596
599 {
602 }
603 }
604
606 {
607 if (_value < GetMaxHordeValue())
608 return TEAM_HORDE;
609
611 return TEAM_ALLIANCE;
612
613 return TEAM_NEUTRAL;
614 }
615
617
618 void ActivateObject(GameObjectActions action, int32 /*param*/, WorldObject* /*spellCaster*/, uint32 /*spellId*/, int32 /*effectIndex*/) override
619 {
620 switch (action)
621 {
623 for (ObjectGuid const& guid : _insidePlayers)
624 if (Player* player = ObjectAccessor::GetPlayer(_owner, guid))
625 player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldState1, 0);
626
627 _insidePlayers.clear();
628 break;
629 default:
630 break;
631 }
632 }
633
634 void SetValue(float value)
635 {
636 _value = RoundToInterval<float>(value, 0.0f, 100.0f);
637 }
638
640 {
641 // update player list inside control zone
642 std::vector<Player*> targetList;
643 SearchTargets(targetList);
644
645 TeamId oldControllingTeam = GetControllingTeam();
646 float pointsGained = CalculatePointsPerSecond(targetList) * _heartbeatRate.count() / 1000.0f;
647 if (pointsGained == 0)
648 return;
649
650 int32 oldRoundedValue = static_cast<int32>(_value);
651 SetValue(_value + pointsGained);
652 int32 roundedValue = static_cast<int32>(_value);
653 if (oldRoundedValue == roundedValue)
654 return;
655
656 TeamId newControllingTeam = GetControllingTeam();
657 TeamId assaultingTeam = pointsGained > 0 ? TEAM_ALLIANCE : TEAM_HORDE;
658
659 if (oldControllingTeam != newControllingTeam)
660 _contestedTriggered = false;
661
662 if (oldControllingTeam != TEAM_ALLIANCE && newControllingTeam == TEAM_ALLIANCE)
664 else if (oldControllingTeam != TEAM_HORDE && newControllingTeam == TEAM_HORDE)
666 else if (oldControllingTeam == TEAM_HORDE && newControllingTeam == TEAM_NEUTRAL)
668 else if (oldControllingTeam == TEAM_ALLIANCE && newControllingTeam == TEAM_NEUTRAL)
670
671 if (roundedValue == 100 && newControllingTeam == TEAM_ALLIANCE && assaultingTeam == TEAM_ALLIANCE)
673 else if (roundedValue == 0 && newControllingTeam == TEAM_HORDE && assaultingTeam == TEAM_HORDE)
675
676 if (oldRoundedValue == 100 && assaultingTeam == TEAM_HORDE && !_contestedTriggered)
677 {
679 _contestedTriggered = true;
680 }
681 else if (oldRoundedValue == 0 && assaultingTeam == TEAM_ALLIANCE && !_contestedTriggered)
682 {
684 _contestedTriggered = true;
685 }
686
687 for (Player* player : targetList)
688 player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldstate2, roundedValue);
689 }
690
691 void SearchTargets(std::vector<Player*>& targetList)
692 {
696 HandleUnitEnterExit(targetList);
697 }
698
699 float CalculatePointsPerSecond(std::vector<Player*> const& targetList)
700 {
701 int32 delta = 0;
702
703 for (Player* player : targetList)
704 {
705 if (!player->IsOutdoorPvPActive())
706 continue;
707
708 if (player->GetTeamId() == TEAM_HORDE)
709 delta--;
710 else
711 delta++;
712 }
713
718
719 if (static_cast<uint32>(std::abs(delta)) < minSuperiority)
720 return 0;
721
722 float slope = (static_cast<float>(minTime) - maxTime) / (maxSuperiority - minSuperiority);
723 float intercept = maxTime - slope * minSuperiority;
724 float timeNeeded = slope * std::abs(delta) + intercept;
725 float percentageIncrease = 100.0f / timeNeeded;
726
727 if (delta < 0)
728 percentageIncrease *= -1;
729
730 return percentageIncrease;
731 }
732
733 void HandleUnitEnterExit(std::vector<Player*> const& newTargetList)
734 {
735 GuidUnorderedSet exitPlayers(std::move(_insidePlayers));
736
737 std::vector<Player*> enteringPlayers;
738
739 for (Player* unit : newTargetList)
740 {
741 if (exitPlayers.erase(unit->GetGUID()) == 0) // erase(key_type) returns number of elements erased
742 enteringPlayers.push_back(unit);
743
744 _insidePlayers.insert(unit->GetGUID());
745 }
746
747 for (Player* player : enteringPlayers)
748 {
749 player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldState1, 1);
750 player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldstate2, static_cast<int32>(_value));
752 }
753
754 for (ObjectGuid const& exitPlayerGuid : exitPlayers)
755 {
756 if (Player* player = ObjectAccessor::GetPlayer(_owner, exitPlayerGuid))
757 {
758 player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldState1, 0);
759 }
760 }
761 }
762
763 float GetMaxHordeValue() const
764 {
765 // ex: if neutralPercent is 40; then 0 - 30 is Horde Controlled
766 return 50.0f - _owner.GetGOInfo()->controlZone.neutralPercent / 2.0f;
767 }
768
770 {
771 // ex: if neutralPercent is 40; then 70 - 100 is Alliance Controlled
772 return 50.0f + _owner.GetGOInfo()->controlZone.neutralPercent / 2.0f;
773 }
774
775 void TriggerEvent(uint32 eventId) const
776 {
777 if (eventId <= 0)
778 return;
779
781 GameEvents::Trigger(eventId, &_owner, nullptr);
782 }
783
785 {
787 }
788
789private:
794 float _value;
796};
797
799{
800}
801
803{
804 if (ControlZone* controlZone = dynamic_cast<ControlZone*>(&type))
805 {
806 uint32 value = controlZone->GetStartingValue();
807 if (_value.has_value())
808 value = *_value;
809
810 controlZone->SetValue(value);
811 }
812}
813}
814
816 m_model(nullptr), m_goValue(), m_AI(nullptr), m_respawnCompatibilityMode(false), _animKitId(0), _worldEffectID(0)
817{
820
822 m_updateFlag.Rotation = true;
823
824 m_respawnTime = 0;
825 m_respawnDelayTime = 300;
826 m_despawnDelay = 0;
828 m_restockTime = 0;
830 m_spawnedByDefault = true;
831 m_usetimes = 0;
832 m_spellId = 0;
833 m_cooldownTime = 0;
835 m_goInfo = nullptr;
836 m_goData = nullptr;
838 m_goTemplateAddon = nullptr;
839
840 m_spawnId = UI64LIT(0);
841
842 ResetLootMode(); // restore default loot mode
843 m_stationaryPosition.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
844}
845
847{
848 delete m_AI;
849 delete m_model;
850}
851
853{
854 delete m_AI;
855 m_AI = nullptr;
856}
857
859{
860 AIM_Destroy();
861
863
864 if (!m_AI)
865 return false;
866
868 return true;
869}
870
871std::string const& GameObject::GetAIName() const
872{
873 return sObjectMgr->GetGameObjectTemplate(GetEntry())->AIName;
874}
875
876void GameObject::CleanupsBeforeDelete(bool finalCleanup)
877{
878 SetVignette(0);
879
881
883}
884
886{
887 ObjectGuid ownerGUID = GetOwnerGUID();
888 if (!ownerGUID)
889 return;
890
891 if (Unit* owner = ObjectAccessor::GetUnit(*this, ownerGUID))
892 {
893 owner->RemoveGameObject(this, false);
895 return;
896 }
897
898 // This happens when a mage portal is despawned after the caster changes map (for example using the portal)
899 TC_LOG_DEBUG("misc", "Removed GameObject ({} Entry: {} SpellId: {} LinkedGO: {}) that just lost any reference to the owner ({}) GO list",
900 GetGUID().ToString(), GetGOInfo()->entry, m_spellId, GetGOInfo()->GetLinkedGameObjectEntry(), ownerGUID.ToString());
902}
903
905{
907 if (!IsInWorld())
908 {
909 if (m_zoneScript)
911
913 if (m_spawnId)
914 GetMap()->GetGameObjectBySpawnIdStore().insert(std::make_pair(m_spawnId, this));
915
916 // The state can be changed after GameObject::Create but before GameObject::AddToWorld
917 bool toggledState = GetGoType() == GAMEOBJECT_TYPE_CHEST ? getLootState() == GO_READY : (GetGoState() == GO_STATE_READY || IsTransport());
918 if (m_model)
919 {
920 if (Transport* trans = ToTransport())
921 trans->SetDelayedAddModelToMap();
922 else
924 }
925
926 EnableCollision(toggledState);
928 }
929}
930
932{
934 if (IsInWorld())
935 {
936 if (m_zoneScript)
938
940 if (m_model)
941 if (GetMap()->ContainsGameObjectModel(*m_model))
943
944 // If linked trap exists, despawn it
945 if (GameObject* linkedTrap = GetLinkedTrap())
946 linkedTrap->DespawnOrUnsummon();
947
949
950 if (m_spawnId)
951 Trinity::Containers::MultimapErasePair(GetMap()->GetGameObjectBySpawnIdStore(), m_spawnId, this);
953 }
954}
955
956bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionData const& rotation, uint32 animProgress, GOState goState, uint32 artKit, bool dynamic, ObjectGuid::LowType spawnid)
957{
958 ASSERT(map);
959 SetMap(map);
960
961 Relocate(pos);
963 if (!IsPositionValid())
964 {
965 TC_LOG_ERROR("misc", "Gameobject (Spawn id: {} Entry: {}) not created. Suggested coordinates isn't valid (X: {} Y: {})", GetSpawnId(), entry, pos.GetPositionX(), pos.GetPositionY());
966 return false;
967 }
968
969 // Set if this object can handle dynamic spawns
970 if (!dynamic)
972
974
976 if (m_zoneScript)
977 {
979 if (!entry)
980 return false;
981 }
982
983 GameObjectTemplate const* goInfo = sObjectMgr->GetGameObjectTemplate(entry);
984 if (!goInfo)
985 {
986 TC_LOG_ERROR("sql.sql", "Gameobject (Spawn id: {} Entry: {}) not created: non-existing entry in `gameobject_template`. Map: {} (X: {} Y: {} Z: {})", GetSpawnId(), entry, map->GetId(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
987 return false;
988 }
989
991 {
992 TC_LOG_ERROR("sql.sql", "Gameobject (Spawn id: {} Entry: {}) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.", GetSpawnId(), entry);
993 return false;
994 }
995
996 ObjectGuid guid;
997 if (goInfo->type != GAMEOBJECT_TYPE_TRANSPORT)
998 guid = ObjectGuid::Create<HighGuid::GameObject>(map->GetId(), goInfo->entry, map->GenerateLowGuid<HighGuid::GameObject>());
999 else
1000 {
1001 guid = ObjectGuid::Create<HighGuid::Transport>(map->GenerateLowGuid<HighGuid::Transport>());
1002 m_updateFlag.ServerTime = true;
1003 }
1004
1005 Object::_Create(guid);
1006
1007 m_goInfo = goInfo;
1008 m_goTemplateAddon = sObjectMgr->GetGameObjectTemplateAddon(entry);
1009
1010 if (goInfo->type >= MAX_GAMEOBJECT_TYPE)
1011 {
1012 TC_LOG_ERROR("sql.sql", "Gameobject ({} Spawn id: {} Entry: {}) not created: non-existing GO type '{}' in `gameobject_template`. It will crash client if created.", guid.ToString(), GetSpawnId(), entry, goInfo->type);
1013 return false;
1014 }
1015
1016 SetLocalRotation(rotation.x, rotation.y, rotation.z, rotation.w);
1017 GameObjectAddon const* gameObjectAddon = sObjectMgr->GetGameObjectAddon(GetSpawnId());
1018
1019 // For most of gameobjects is (0, 0, 0, 1) quaternion, there are only some transports with not standard rotation
1020 QuaternionData parentRotation;
1021 if (gameObjectAddon)
1022 parentRotation = gameObjectAddon->ParentRotation;
1023
1024 SetParentRotation(parentRotation);
1025
1026 SetObjectScale(goInfo->size);
1027
1028 if (GameObjectOverride const* goOverride = GetGameObjectOverride())
1029 {
1030 SetFaction(goOverride->Faction);
1031 ReplaceAllFlags(GameObjectFlags(goOverride->Flags));
1032 }
1033
1035 {
1037 {
1038 m_updateFlag.GameObject = true;
1040 }
1041
1044 }
1045
1046 SetEntry(goInfo->entry);
1047
1048 // set name for logs usage, doesn't affect anything ingame
1049 SetName(goInfo->name);
1050
1051 SetDisplayId(goInfo->displayId);
1052
1053 CreateModel();
1054 // GAMEOBJECT_BYTES_1, index at 0, 1, 2 and 3
1055 SetGoType(GameobjectTypes(goInfo->type));
1056 m_prevGoState = goState;
1057 SetGoState(goState);
1058 SetGoArtKit(artKit);
1059
1061
1062 switch (goInfo->type)
1063 {
1065 SetGoAnimProgress(animProgress);
1066 m_goValue.FishingHole.MaxOpens = urand(GetGOInfo()->fishingHole.minRestock, GetGOInfo()->fishingHole.maxRestock);
1067 break;
1069 {
1070 // TODO: Get the values somehow, no longer in gameobject_template
1071 m_goValue.Building.Health = 20000/*goinfo->destructibleBuilding.intactNumHits + goinfo->destructibleBuilding.damagedNumHits*/;
1073 SetGoAnimProgress(255);
1074 // yes, even after the updatefield rewrite this garbage hack is still in client
1075 QuaternionData reinterpretId;
1076 memcpy(&reinterpretId.x, &m_goInfo->destructibleBuilding.DestructibleModelRec, sizeof(float));
1078 break;
1079 }
1081 {
1082 m_goTypeImpl = std::make_unique<GameObjectType::Transport>(*this);
1083 if (goInfo->transport.startOpen)
1085 else
1087
1088 SetGoAnimProgress(animProgress);
1089 setActive(true);
1090 break;
1091 }
1093 SetLevel(0);
1094 SetGoAnimProgress(255);
1095 break;
1097 if (GetGOInfo()->trap.stealthed)
1098 {
1101 }
1102
1103 if (GetGOInfo()->trap.stealthAffected)
1104 {
1107 }
1108 break;
1110 m_goTypeImpl = std::make_unique<GameObjectType::ControlZone>(*this);
1111 setActive(true);
1112 break;
1114 m_goTypeImpl = std::make_unique<GameObjectType::NewFlag>(*this);
1115 if (map->Instanceable())
1116 setActive(true);
1117 break;
1119 if (map->Instanceable())
1120 setActive(true);
1121 break;
1125 break;
1132 if (map->Instanceable())
1133 setActive(true);
1134 break;
1135 default:
1136 SetGoAnimProgress(animProgress);
1137 break;
1138 }
1139
1140 if (gameObjectAddon)
1141 {
1142 if (gameObjectAddon->InvisibilityValue)
1143 {
1144 m_invisibility.AddFlag(gameObjectAddon->invisibilityType);
1145 m_invisibility.AddValue(gameObjectAddon->invisibilityType, gameObjectAddon->InvisibilityValue);
1146 }
1147
1148 if (gameObjectAddon->WorldEffectID)
1149 {
1150 m_updateFlag.GameObject = true;
1151 SetWorldEffectID(gameObjectAddon->WorldEffectID);
1152 }
1153
1154 if (gameObjectAddon->AIAnimKitID)
1155 _animKitId = gameObjectAddon->AIAnimKitID;
1156 }
1157
1158 if (uint32 vignetteId = GetGOInfo()->GetSpawnVignette())
1159 SetVignette(vignetteId);
1160
1162
1163 m_stringIds[0] = goInfo->StringId;
1164
1166
1167 if (spawnid)
1168 m_spawnId = spawnid;
1169
1170 if (uint32 linkedEntry = GetGOInfo()->GetLinkedGameObjectEntry())
1171 {
1172 if (GameObject* linkedGo = GameObject::CreateGameObject(linkedEntry, map, pos, rotation, 255, GO_STATE_READY))
1173 {
1174 SetLinkedTrap(linkedGo);
1175 if (!map->AddToMap(linkedGo))
1176 delete linkedGo;
1177 }
1178 }
1179
1180 // Check if GameObject is Infinite
1181 if (goInfo->IsInfiniteGameObject())
1183
1184 // Check if GameObject is Gigantic
1185 if (goInfo->IsGiganticGameObject())
1187
1188 // Check if GameObject is Large
1189 if (goInfo->IsLargeGameObject())
1191
1192 return true;
1193}
1194
1195GameObject* GameObject::CreateGameObject(uint32 entry, Map* map, Position const& pos, QuaternionData const& rotation, uint32 animProgress, GOState goState, uint32 artKit /*= 0*/)
1196{
1197 GameObjectTemplate const* goInfo = sObjectMgr->GetGameObjectTemplate(entry);
1198 if (!goInfo)
1199 return nullptr;
1200
1201 GameObject* go = new GameObject();
1202 if (!go->Create(entry, map, pos, rotation, animProgress, goState, artKit, false, 0))
1203 {
1204 delete go;
1205 return nullptr;
1206 }
1207
1208 return go;
1209}
1210
1212{
1213 GameObject* go = new GameObject();
1214 if (!go->LoadFromDB(spawnId, map, addToMap))
1215 {
1216 delete go;
1217 return nullptr;
1218 }
1219
1220 return go;
1221}
1222
1224{
1225 WorldObject::Update(diff);
1226
1227 if (AI())
1228 AI()->UpdateAI(diff);
1229 else if (!AIM_Initialize())
1230 TC_LOG_ERROR("misc", "Could not initialize GameObjectAI");
1231
1232 if (m_despawnDelay)
1233 {
1234 if (m_despawnDelay > diff)
1235 m_despawnDelay -= diff;
1236 else
1237 {
1238 m_despawnDelay = 0;
1240 }
1241 }
1242
1243 if (m_goTypeImpl)
1244 m_goTypeImpl->Update(diff);
1245
1246 if (m_perPlayerState)
1247 {
1248 for (auto itr = m_perPlayerState->begin(); itr != m_perPlayerState->end(); )
1249 {
1250 if (itr->second.ValidUntil > GameTime::GetSystemTime())
1251 {
1252 ++itr;
1253 continue;
1254 }
1255
1256 Player* seer = ObjectAccessor::GetPlayer(*this, itr->first);
1257 bool needsStateUpdate = itr->second.State != GetGoState();
1258 bool despawned = itr->second.Despawned;
1259
1260 itr = m_perPlayerState->erase(itr);
1261
1262 if (seer)
1263 {
1264 if (despawned)
1265 {
1266 seer->UpdateVisibilityOf(this);
1267 }
1268 else if (needsStateUpdate)
1269 {
1270 UF::ObjectData::Base objMask;
1273
1274 UpdateData udata(GetMapId());
1275 BuildValuesUpdateForPlayerWithMask(&udata, objMask.GetChangesMask(), goMask.GetChangesMask(), seer);
1276 WorldPacket packet;
1277 udata.BuildPacket(&packet);
1278 seer->SendDirectMessage(&packet);
1279 }
1280 }
1281 }
1282 }
1283
1284 switch (m_lootState)
1285 {
1286 case GO_NOT_READY:
1287 {
1288 switch (GetGoType())
1289 {
1291 {
1292 // Arming Time for GAMEOBJECT_TYPE_TRAP (6)
1293 GameObjectTemplate const* goInfo = GetGOInfo();
1294 // Bombs
1295 if (goInfo->trap.charges == 2)
1296 // Hardcoded tooltip value
1298 else if (Unit* owner = GetOwner())
1299 if (owner->IsInCombat())
1301
1303 break;
1304 }
1306 {
1307 // fishing code (bobber ready)
1309 {
1310 // splash bobber (bobber ready now)
1311 Unit* caster = GetOwner();
1312 if (caster && caster->GetTypeId() == TYPEID_PLAYER)
1313 SendCustomAnim(0);
1314
1315 m_lootState = GO_READY; // can be successfully open with some chance
1316 }
1317 return;
1318 }
1321 return;
1322 // If there is no restock timer, or if the restock timer passed, the chest becomes ready to loot
1323 m_restockTime = 0;
1325 ClearLoot();
1327 break;
1328 default:
1329 m_lootState = GO_READY; // for other GOis same switched without delay to GO_READY
1330 break;
1331 }
1332 [[fallthrough]];
1333 }
1334 case GO_READY:
1335 {
1337 {
1338 if (m_respawnTime > 0) // timer on
1339 {
1340 time_t now = GameTime::GetGameTime();
1341 if (m_respawnTime <= now) // timer expired
1342 {
1343 ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::GameObject>(GetMapId(), GetEntry(), m_spawnId);
1344 time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid);
1345 if (linkedRespawntime) // Can't respawn, the master is dead
1346 {
1347 ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid);
1348 if (targetGuid == dbtableHighGuid) // if linking self, never respawn
1350 else
1351 m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + urand(5, MINUTE); // else copy time from master and add a little
1353 return;
1354 }
1355
1356 m_respawnTime = 0;
1357 m_SkillupList.clear();
1358 m_usetimes = 0;
1359
1360 switch (GetGoType())
1361 {
1362 case GAMEOBJECT_TYPE_FISHINGNODE: // can't fish now
1363 {
1364 Unit* caster = GetOwner();
1365 if (caster && caster->GetTypeId() == TYPEID_PLAYER)
1366 {
1367 caster->ToPlayer()->RemoveGameObject(this, false);
1368
1370 }
1371 // can be delete
1373 return;
1374 }
1377 // We need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for battlegrounds)
1378 if (GetGoState() != GO_STATE_READY)
1380 break;
1382 // Initialize a new max fish count on respawn
1383 m_goValue.FishingHole.MaxOpens = urand(GetGOInfo()->fishingHole.minRestock, GetGOInfo()->fishingHole.maxRestock);
1384 break;
1385 default:
1386 break;
1387 }
1388
1389 // Despawn timer
1390 if (!m_spawnedByDefault)
1391 {
1392 // Can be despawned or destroyed
1394 return;
1395 }
1396
1397 // Call AI Reset (required for example in SmartAI to clear one time events)
1398 if (AI())
1399 AI()->Reset();
1400
1401 // Respawn timer
1403 if (poolid)
1404 sPoolMgr->UpdatePool<GameObject>(GetMap()->GetPoolData(), poolid, GetSpawnId());
1405 else
1406 GetMap()->AddToMap(this);
1407 }
1408 }
1409 }
1410
1411 // Set respawn timer
1414
1415 if (isSpawned())
1416 {
1417 GameObjectTemplate const* goInfo = GetGOInfo();
1418 if (goInfo->type == GAMEOBJECT_TYPE_TRAP)
1419 {
1421 break;
1422
1423 // Type 2 (bomb) does not need to be triggered by a unit and despawns after casting its spell.
1424 if (goInfo->trap.charges == 2)
1425 {
1427 break;
1428 }
1429
1430 // Type 0 despawns after being triggered, type 1 does not.
1432 float radius = goInfo->trap.radius / 2.f; // this division seems to date back to when the field was called diameter, don't think it is still relevant.
1433 if (!radius)
1434 break;
1435
1436 // Pointer to appropriate target if found any
1437 Unit* target = nullptr;
1438
1439 if (GetOwner() || goInfo->trap.Checkallunits)
1440 {
1441 // Hunter trap: Search units which are unfriendly to the trap's owner
1444 Cell::VisitAllObjects(this, searcher, radius);
1445 }
1446 else
1447 {
1448 // Environmental trap: Any player
1449 Player* player = nullptr;
1450 Trinity::AnyPlayerInObjectRangeCheck checker(this, radius);
1452 Cell::VisitWorldObjects(this, searcher, radius);
1453 target = player;
1454 }
1455
1456 if (target)
1457 SetLootState(GO_ACTIVATED, target);
1458
1459 }
1460 else if (goInfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
1461 {
1464 if (hordeCapturing || allianceCapturing)
1465 {
1467 {
1469 if (hordeCapturing)
1470 {
1472 if (BattlegroundMap* map = GetMap()->ToBattlegroundMap())
1473 {
1474 if (Battleground* bg = map->GetBG())
1475 {
1476 if (goInfo->capturePoint.CaptureEventHorde)
1478 bg->SendBroadcastText(goInfo->capturePoint.CaptureBroadcastHorde, CHAT_MSG_BG_SYSTEM_HORDE);
1479 }
1480 }
1481 }
1482 else
1483 {
1485 if (BattlegroundMap* map = GetMap()->ToBattlegroundMap())
1486 {
1487 if (Battleground* bg = map->GetBG())
1488 {
1492 }
1493 }
1494 }
1495
1498 }
1499 else
1501 }
1502 }
1503 else if (uint32 max_charges = goInfo->GetCharges())
1504 {
1505 if (m_usetimes >= max_charges)
1506 {
1507 m_usetimes = 0;
1508 SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed
1509 }
1510 }
1511 }
1512
1513 break;
1514 }
1515 case GO_ACTIVATED:
1516 {
1517 switch (GetGoType())
1518 {
1523 break;
1526 {
1528
1530 m_cooldownTime = 0;
1531 }
1532 break;
1534 if (m_loot)
1535 {
1536 m_loot->Update();
1537
1538 // Non-consumable chest was partially looted and restock time passed, restock all loot now
1540 {
1541 m_restockTime = 0;
1543 ClearLoot();
1545 }
1546 }
1547
1548 for (auto&& [playerOwner, loot] : m_personalLoot)
1549 loot->Update();
1550 break;
1552 {
1553 GameObjectTemplate const* goInfo = GetGOInfo();
1554 if (goInfo->trap.charges == 2 && goInfo->trap.spell)
1555 {
1557 CastSpell(nullptr, goInfo->trap.spell);
1559 }
1560 else if (Unit* target = ObjectAccessor::GetUnit(*this, m_lootStateUnitGUID))
1561 {
1562 // Some traps do not have a spell but should be triggered
1563 CastSpellExtraArgs args;
1565 if (goInfo->trap.spell)
1566 CastSpell(target, goInfo->trap.spell, args);
1567
1568 // Template value or 4 seconds
1570
1571 if (goInfo->trap.charges == 1)
1573 else if (!goInfo->trap.charges)
1575 }
1576 break;
1577 }
1578 default:
1579 break;
1580 }
1581 break;
1582 }
1584 {
1585 // If nearby linked trap exists, despawn it
1586 if (GameObject* linkedTrap = GetLinkedTrap())
1587 linkedTrap->DespawnOrUnsummon();
1588
1589 //if Gameobject should cast spell, then this, but some GOs (type = 10) should be destroyed
1591 {
1592 uint32 spellId = GetGOInfo()->goober.spell;
1593
1594 if (spellId)
1595 {
1596 for (GuidSet::const_iterator it = m_unique_users.begin(); it != m_unique_users.end(); ++it)
1597 // m_unique_users can contain only player GUIDs
1598 if (Player* owner = ObjectAccessor::GetPlayer(*this, *it))
1599 owner->CastSpell(owner, spellId, false);
1600
1601 m_unique_users.clear();
1602 m_usetimes = 0;
1603 }
1604
1605 // Only goobers with a lock id or a reset time may reset their go state
1606 if (GetGOInfo()->GetLockId() || GetGOInfo()->GetAutoCloseTime())
1608
1609 //any return here in case battleground traps
1610 if (GameObjectOverride const* goOverride = GetGameObjectOverride())
1611 if (goOverride->Flags & GO_FLAG_NODESPAWN)
1612 return;
1613 }
1614
1615 ClearLoot();
1616
1617 // Do not delete chests or goobers that are not consumed on loot, while still allowing them to despawn when they expire if summoned
1618 bool isSummonedAndExpired = (GetOwner() || GetSpellId()) && m_respawnTime == 0;
1619 if ((GetGoType() == GAMEOBJECT_TYPE_CHEST || GetGoType() == GAMEOBJECT_TYPE_GOOBER) && !GetGOInfo()->IsDespawnAtAction() && !isSummonedAndExpired)
1620 {
1622 {
1623 // Start restock timer when the chest is fully looted
1627 }
1628 else
1631 return;
1632 }
1633 else if (!GetOwnerGUID().IsEmpty() || GetSpellId())
1634 {
1635 SetRespawnTime(0);
1636
1638 {
1640 go->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::InBase, nullptr));
1641 }
1642
1643 Delete();
1644 return;
1645 }
1646
1648
1649 //burning flags in some battlegrounds, if you find better condition, just add it
1650 if (GetGOInfo()->IsDespawnAtAction() || GetGoAnimProgress() > 0)
1651 {
1653 //reset flags
1654 if (GameObjectOverride const* goOverride = GetGameObjectOverride())
1655 ReplaceAllFlags(GameObjectFlags(goOverride->Flags));
1656 }
1657
1658 if (!m_respawnDelayTime)
1659 return;
1660
1661 if (!m_spawnedByDefault)
1662 {
1663 m_respawnTime = 0;
1664
1665 if (m_spawnId)
1667 else
1668 Delete();
1669
1670 return;
1671 }
1672
1673 uint32 respawnDelay = m_respawnDelayTime;
1674 if (uint32 scalingMode = sWorld->getIntConfig(CONFIG_RESPAWN_DYNAMICMODE))
1675 GetMap()->ApplyDynamicModeRespawnScaling(this, this->m_spawnId, respawnDelay, scalingMode);
1676 m_respawnTime = GameTime::GetGameTime() + respawnDelay;
1677
1678 // if option not set then object will be saved at grid unload
1679 // Otherwise just save respawn time to map object memory
1681
1684 else
1686
1687 break;
1688 }
1689 }
1690}
1691
1693{
1694 if (m_spawnId)
1695 {
1696 if (GameObjectOverride const* goOverride = sObjectMgr->GetGameObjectOverride(m_spawnId))
1697 return goOverride;
1698 }
1699
1700 return m_goTemplateAddon;
1701}
1702
1704{
1705 // Do not refresh despawned GO from spellcast (GO's from spellcast are destroyed after despawn)
1707 return;
1708
1709 if (isSpawned())
1710 GetMap()->AddToMap(this);
1711}
1712
1714{
1715 AddUse();
1716 m_unique_users.insert(player->GetGUID());
1717}
1718
1720{
1721 if (delay > 0ms)
1722 {
1723 if (!m_despawnDelay || m_despawnDelay > delay.count())
1724 {
1725 m_despawnDelay = delay.count();
1726 m_despawnRespawnTime = forceRespawnTime;
1727 }
1728 }
1729 else
1730 {
1731 if (m_goData)
1732 {
1733 uint32 const respawnDelay = (forceRespawnTime > 0s) ? forceRespawnTime.count() : m_goData->spawntimesecs;
1734 SaveRespawnTime(respawnDelay);
1735 }
1736 Delete();
1737 }
1738}
1739
1741{
1742 PerPlayerState& perPlayerState = GetOrCreatePerPlayerStates()[seer->GetGUID()];
1743 perPlayerState.ValidUntil = GameTime::GetSystemTime() + respawnTime;
1744 perPlayerState.Despawned = true;
1745 seer->UpdateVisibilityOf(this);
1746}
1747
1749{
1752
1754 {
1756 SendMessageToSet(packet.Write(), true);
1757 }
1758
1760
1763
1764 if (GameObjectOverride const* goOverride = GetGameObjectOverride())
1765 ReplaceAllFlags(GameObjectFlags(goOverride->Flags));
1766
1768 if (m_respawnCompatibilityMode && poolid)
1769 sPoolMgr->UpdatePool<GameObject>(GetMap()->GetPoolData(), poolid, GetSpawnId());
1770 else
1772}
1773
1775{
1777 packet.ObjectGUID = GetGUID();
1778 SendMessageToSet(packet.Write(), true);
1779}
1780
1782{
1783 uint32 defaultzone = 1;
1784
1785 Loot* fishLoot = new Loot(GetMap(), GetGUID(), LOOT_FISHING, nullptr);
1786
1787 uint32 areaId = GetAreaId();
1788 ItemContext itemContext = ItemBonusMgr::GetContextForPlayer(GetMap()->GetMapDifficulty(), lootOwner);
1789 while (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId))
1790 {
1791 fishLoot->FillLoot(areaId, LootTemplates_Fishing, lootOwner, true, true, LOOT_MODE_DEFAULT, itemContext);
1792 if (!fishLoot->isLooted())
1793 break;
1794
1795 areaId = areaEntry->ParentAreaID;
1796 }
1797
1798 if (fishLoot->isLooted())
1799 fishLoot->FillLoot(defaultzone, LootTemplates_Fishing, lootOwner, true, true, LOOT_MODE_DEFAULT, itemContext);
1800
1801 return fishLoot;
1802}
1803
1805{
1806 uint32 defaultzone = 1;
1807
1808 Loot* fishLoot = new Loot(GetMap(), GetGUID(), LOOT_FISHING_JUNK, nullptr);
1809
1810 uint32 areaId = GetAreaId();
1811 ItemContext itemContext = ItemBonusMgr::GetContextForPlayer(GetMap()->GetMapDifficulty(), lootOwner);
1812 while (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId))
1813 {
1814 fishLoot->FillLoot(areaId, LootTemplates_Fishing, lootOwner, true, true, LOOT_MODE_JUNK_FISH, itemContext);
1815 if (!fishLoot->isLooted())
1816 break;
1817
1818 areaId = areaEntry->ParentAreaID;
1819 }
1820
1821 if (fishLoot->isLooted())
1822 fishLoot->FillLoot(defaultzone, LootTemplates_Fishing, lootOwner, true, true, LOOT_MODE_JUNK_FISH, itemContext);
1823
1824 return fishLoot;
1825}
1826
1828{
1829 // this should only be used when the gameobject has already been loaded
1830 // preferably after adding to map, because mapid may not be valid otherwise
1831 GameObjectData const* data = sObjectMgr->GetGameObjectData(m_spawnId);
1832 if (!data)
1833 {
1834 TC_LOG_ERROR("misc", "GameObject::SaveToDB failed, cannot get gameobject data!");
1835 return;
1836 }
1837
1838 uint32 mapId = GetMapId();
1839 if (TransportBase* transport = GetTransport())
1840 if (transport->GetMapIdForSpawning() >= 0)
1841 mapId = transport->GetMapIdForSpawning();
1842
1843 SaveToDB(mapId, data->spawnDifficulties);
1844}
1845
1846void GameObject::SaveToDB(uint32 mapid, std::vector<Difficulty> const& spawnDifficulties)
1847{
1848 GameObjectTemplate const* goI = GetGOInfo();
1849 if (!goI)
1850 return;
1851
1852 if (!m_spawnId)
1853 m_spawnId = sObjectMgr->GenerateGameObjectSpawnId();
1854
1855 // update in loaded data (changing data only in this place)
1856 GameObjectData& data = sObjectMgr->NewOrExistGameObjectData(m_spawnId);
1857
1858 if (!data.spawnId)
1859 data.spawnId = m_spawnId;
1860 ASSERT(data.spawnId == m_spawnId);
1861 data.id = GetEntry();
1862 data.mapId = GetMapId();
1863 data.spawnPoint.Relocate(this);
1867 data.goState = GetGoState();
1868 data.spawnDifficulties = spawnDifficulties;
1869 data.artKit = GetGoArtKit();
1870 if (!data.spawnGroupData)
1871 data.spawnGroupData = sObjectMgr->GetDefaultSpawnGroup();
1872
1873 data.phaseId = GetDBPhase() > 0 ? GetDBPhase() : data.phaseId;
1874 data.phaseGroup = GetDBPhase() < 0 ? -GetDBPhase() : data.phaseGroup;
1875
1876 // Update in DB
1877 WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction();
1878
1879 uint8 index = 0;
1880
1882 stmt->setUInt64(0, m_spawnId);
1883 trans->Append(stmt);
1884
1885 stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_GAMEOBJECT);
1886 stmt->setUInt64(index++, m_spawnId);
1887 stmt->setUInt32(index++, GetEntry());
1888 stmt->setUInt16(index++, uint16(mapid));
1889 stmt->setString(index++, [&data]() -> std::string
1890 {
1891 if (data.spawnDifficulties.empty())
1892 return "";
1893
1894 std::ostringstream os;
1895 auto itr = data.spawnDifficulties.begin();
1896 os << int32(*itr++);
1897
1898 for (; itr != data.spawnDifficulties.end(); ++itr)
1899 os << ',' << int32(*itr);
1900
1901 return os.str();
1902 }());
1903 stmt->setUInt32(index++, data.phaseId);
1904 stmt->setUInt32(index++, data.phaseGroup);
1905 stmt->setFloat(index++, GetPositionX());
1906 stmt->setFloat(index++, GetPositionY());
1907 stmt->setFloat(index++, GetPositionZ());
1908 stmt->setFloat(index++, GetOrientation());
1909 stmt->setFloat(index++, m_localRotation.x);
1910 stmt->setFloat(index++, m_localRotation.y);
1911 stmt->setFloat(index++, m_localRotation.z);
1912 stmt->setFloat(index++, m_localRotation.w);
1913 stmt->setInt32(index++, int32(m_respawnDelayTime));
1914 stmt->setUInt8(index++, GetGoAnimProgress());
1915 stmt->setUInt8(index++, uint8(GetGoState()));
1916 trans->Append(stmt);
1917
1918 WorldDatabase.CommitTransaction(trans);
1919}
1920
1921bool GameObject::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, bool)
1922{
1923 GameObjectData const* data = sObjectMgr->GetGameObjectData(spawnId);
1924 if (!data)
1925 {
1926 TC_LOG_ERROR("sql.sql", "Gameobject (GUID: {}) not found in table `gameobject`, can't load. ", spawnId);
1927 return false;
1928 }
1929
1930 uint32 entry = data->id;
1931 //uint32 map_id = data->mapid; // already used before call
1932
1933 uint32 animprogress = data->animprogress;
1934 GOState go_state = data->goState;
1935 uint32 artKit = data->artKit;
1936
1937 m_spawnId = spawnId;
1939 if (!Create(entry, map, data->spawnPoint, data->rotation, animprogress, go_state, artKit, !m_respawnCompatibilityMode, spawnId))
1940 return false;
1941
1944
1945 if (data->spawntimesecs >= 0)
1946 {
1947 m_spawnedByDefault = true;
1948
1949 if (!GetGOInfo()->GetDespawnPossibility() && !GetGOInfo()->IsDespawnAtAction())
1950 {
1953 m_respawnTime = 0;
1954 }
1955 else
1956 {
1959
1960 // ready to respawn
1962 {
1963 m_respawnTime = 0;
1965 }
1966 }
1967 }
1968 else
1969 {
1971 {
1972 TC_LOG_WARN("sql.sql", "GameObject {} (SpawnID {}) is not spawned by default, but tries to use a non-hack spawn system. This will not work. Defaulting to compatibility mode.", entry, spawnId);
1974 }
1975
1976 m_spawnedByDefault = false;
1978 m_respawnTime = 0;
1979 }
1980
1981 m_goData = data;
1982
1983 m_stringIds[1] = data->StringId;
1984
1985 if (addToMap && !GetMap()->AddToMap(this))
1986 return false;
1987
1988 return true;
1989}
1990
1992{
1993 GameObjectData const* data = sObjectMgr->GetGameObjectData(spawnId);
1994 if (!data)
1995 return false;
1996
1997 CharacterDatabaseTransaction charTrans = CharacterDatabase.BeginTransaction();
1998
1999 sMapMgr->DoForAllMapsWithMapId(data->mapId,
2000 [spawnId, charTrans](Map* map) -> void
2001 {
2002 // despawn all active objects, and remove their respawns
2003 std::vector<GameObject*> toUnload;
2004 for (auto const& pair : Trinity::Containers::MapEqualRange(map->GetGameObjectBySpawnIdStore(), spawnId))
2005 toUnload.push_back(pair.second);
2006 for (GameObject* obj : toUnload)
2007 map->AddObjectToRemoveList(obj);
2008 map->RemoveRespawnTime(SPAWN_TYPE_GAMEOBJECT, spawnId, charTrans);
2009 }
2010 );
2011
2012 // delete data from memory
2013 sObjectMgr->DeleteGameObjectData(spawnId);
2014
2015 CharacterDatabase.CommitTransaction(charTrans);
2016
2017 WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction();
2018
2019 // ... and the database
2021 stmt->setUInt64(0, spawnId);
2022 trans->Append(stmt);
2023
2024 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_SPAWNGROUP_MEMBER);
2026 stmt->setUInt64(1, spawnId);
2027 trans->Append(stmt);
2028
2029 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_EVENT_GAMEOBJECT);
2030 stmt->setUInt64(0, spawnId);
2031 trans->Append(stmt);
2032
2033 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_LINKED_RESPAWN);
2034 stmt->setUInt64(0, spawnId);
2036 trans->Append(stmt);
2037
2038 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_LINKED_RESPAWN);
2039 stmt->setUInt64(0, spawnId);
2041 trans->Append(stmt);
2042
2043 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_LINKED_RESPAWN_MASTER);
2044 stmt->setUInt64(0, spawnId);
2046 trans->Append(stmt);
2047
2048 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_LINKED_RESPAWN_MASTER);
2049 stmt->setUInt64(0, spawnId);
2051 trans->Append(stmt);
2052
2053 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAMEOBJECT_ADDON);
2054 stmt->setUInt64(0, spawnId);
2055 trans->Append(stmt);
2056
2057 WorldDatabase.CommitTransaction(trans);
2058
2059 return true;
2060}
2061
2062/*********************************************************/
2063/*** QUEST SYSTEM ***/
2064/*********************************************************/
2065bool GameObject::hasQuest(uint32 quest_id) const
2066{
2067 return sObjectMgr->GetGOQuestRelations(GetEntry()).HasQuest(quest_id);
2068}
2069
2071{
2072 return sObjectMgr->GetGOQuestInvolvedRelations(GetEntry()).HasQuest(quest_id);
2073}
2074
2076{
2077 // If something is marked as a transport, don't transmit an out of range packet for it.
2078 GameObjectTemplate const* gInfo = GetGOInfo();
2079 if (!gInfo)
2080 return false;
2081
2083}
2084
2085// is Dynamic transport = non-stop Transport
2087{
2088 // If something is marked as a transport, don't transmit an out of range packet for it.
2089 GameObjectTemplate const* gInfo = GetGOInfo();
2090 if (!gInfo)
2091 return false;
2092
2094}
2095
2097{
2098 GameObjectTemplate const* gInfo = GetGOInfo();
2099 if (!gInfo)
2100 return false;
2101
2103}
2104
2106{
2107 if (m_goData && (forceDelay || m_respawnTime > GameTime::GetGameTime()) && m_spawnedByDefault)
2108 {
2110 {
2111 RespawnInfo ri;
2113 ri.spawnId = m_spawnId;
2116 return;
2117 }
2118
2119 uint32 thisRespawnTime = forceDelay ? GameTime::GetGameTime() + forceDelay : m_respawnTime;
2121 }
2122}
2123
2124bool GameObject::IsNeverVisibleFor(WorldObject const* seer, bool allowServersideObjects) const
2125{
2127 return true;
2128
2129 if (GetGOInfo()->GetServerOnly() && !allowServersideObjects)
2130 return true;
2131
2132 if (!GetDisplayId() && GetGOInfo()->IsDisplayMandatory())
2133 return true;
2134
2135 if (m_goTypeImpl)
2136 return m_goTypeImpl->IsNeverVisibleFor(seer, allowServersideObjects);
2137
2138 return false;
2139}
2140
2142{
2144 return true;
2145
2147 return true;
2148
2149 if (!seer)
2150 return false;
2151
2152 // Always seen by owner and friendly units
2153 if (!GetOwnerGUID().IsEmpty())
2154 {
2155 if (seer->GetGUID() == GetOwnerGUID())
2156 return true;
2157
2158 Unit* owner = GetOwner();
2159 if (Unit const* unitSeer = seer->ToUnit())
2160 if (owner && owner->IsFriendlyTo(unitSeer))
2161 return true;
2162 }
2163
2164 return false;
2165}
2166
2168{
2170 return true;
2171
2172 // Despawned
2173 if (!isSpawned())
2174 return true;
2175
2176 if (m_perPlayerState)
2178 if (state->Despawned)
2179 return true;
2180
2181 return false;
2182}
2183
2185{
2186 if (Unit* owner = GetOwner())
2187 return owner->GetLevelForTarget(target);
2188
2190 {
2191 if (Player const* player = target->ToPlayer())
2192 if (Optional<ContentTuningLevels> userLevels = sDB2Manager.GetContentTuningData(GetGOInfo()->ContentTuningId, player->m_playerData->CtrOptions->ContentTuningConditionMask))
2193 return uint8(std::clamp<int16>(player->GetLevel(), userLevels->MinLevel, userLevels->MaxLevel));
2194
2195 if (Unit const* targetUnit = target->ToUnit())
2196 return targetUnit->GetLevel();
2197 }
2198
2199 return 1;
2200}
2201
2203{
2204 time_t now = GameTime::GetGameTime();
2205 if (m_respawnTime > now)
2206 return m_respawnTime;
2207 else
2208 return now;
2209}
2210
2212{
2213 m_respawnTime = respawn > 0 ? GameTime::GetGameTime() + respawn : 0;
2214 m_respawnDelayTime = respawn > 0 ? respawn : 0;
2215 if (respawn && !m_spawnedByDefault)
2217}
2218
2220{
2222 {
2225 }
2226}
2227
2228bool GameObject::ActivateToQuest(Player const* target) const
2229{
2230 if (target->HasQuestForGO(GetEntry()))
2231 return true;
2232
2233 if (!sObjectMgr->IsGameObjectForQuests(GetEntry()))
2234 return false;
2235
2236 switch (GetGoType())
2237 {
2239 {
2240 GameObject* go = const_cast<GameObject*>(this);
2241 QuestGiverStatus questStatus = const_cast<Player*>(target)->GetQuestDialogStatus(go);
2242 if (questStatus != QuestGiverStatus::None && questStatus != QuestGiverStatus::Future)
2243 return true;
2244 break;
2245 }
2247 {
2248 // Chests become inactive while not ready to be looted
2249 if (getLootState() == GO_NOT_READY)
2250 return false;
2251
2252 // scan GO chest with loot including quest items
2257 {
2258 if (Battleground const* bg = target->GetBattleground())
2259 return bg->CanActivateGO(GetEntry(), bg->GetPlayerTeam(target->GetGUID()));
2260 return true;
2261 }
2262 break;
2263 }
2265 {
2267 return true;
2268 break;
2269 }
2271 {
2273 return true;
2274 break;
2275 }
2276 default:
2277 break;
2278 }
2279
2280 return false;
2281}
2282
2284{
2285 GameObjectTemplate const* trapInfo = sObjectMgr->GetGameObjectTemplate(trapEntry);
2286 if (!trapInfo || trapInfo->type != GAMEOBJECT_TYPE_TRAP)
2287 return;
2288
2289 SpellInfo const* trapSpell = sSpellMgr->GetSpellInfo(trapInfo->trap.spell, GetMap()->GetDifficultyID());
2290 if (!trapSpell) // checked at load already
2291 return;
2292
2293 if (GameObject* trapGO = GetLinkedTrap())
2294 trapGO->CastSpell(target, trapSpell->Id);
2295}
2296
2298{
2299 GameObject* ok = nullptr;
2300 Trinity::NearestGameObjectFishingHole u_check(*this, range);
2302 Cell::VisitGridObjects(this, checker, range);
2303 return ok;
2304}
2305
2307{
2309 return;
2310
2313
2315 m_cooldownTime = 0;
2316}
2317
2318void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */, Unit* user /*=nullptr*/)
2319{
2320 if (m_lootState != GO_READY)
2321 return;
2322
2323 if (!time_to_restore)
2324 time_to_restore = GetGOInfo()->GetAutoCloseTime();
2325
2326 SwitchDoorOrButton(true, alternative);
2328
2329 m_cooldownTime = time_to_restore ? (GameTime::GetGameTimeMS() + time_to_restore) : 0;
2330}
2331
2332void GameObject::ActivateObject(GameObjectActions action, int32 param, WorldObject* spellCaster /*= nullptr*/, uint32 spellId /*= 0*/, int32 effectIndex /*= -1*/)
2333{
2334 Unit* unitCaster = spellCaster ? spellCaster->ToUnit() : nullptr;
2335
2336 switch (action)
2337 {
2339 TC_LOG_FATAL("spell", "Spell {} has action type NONE in effect {}", spellId, effectIndex);
2340 break;
2346 break;
2347 case GameObjectActions::Disturb: // What's the difference with Open?
2348 if (unitCaster)
2349 Use(unitCaster);
2350 break;
2353 break;
2356 break;
2358 if (unitCaster)
2359 Use(unitCaster);
2360 break;
2362 if (unitCaster)
2363 UseDoorOrButton(0, false, unitCaster);
2365 break;
2368 break;
2370 // No use cases, implementation unknown
2371 break;
2373 if (unitCaster)
2374 UseDoorOrButton(0, true, unitCaster);
2375 break;
2378 break;
2380 // No use cases, implementation unknown
2381 break;
2384 break;
2387 break;
2390 break;
2394 break;
2400 {
2401 GameObjectTemplateAddon const* templateAddon = GetTemplateAddon();
2402
2403 uint32 artKitIndex = action != GameObjectActions::UseArtKit4 ? uint32(action) - uint32(GameObjectActions::UseArtKit0) : 4;
2404
2405 uint32 artKitValue = 0;
2406 if (templateAddon != nullptr)
2407 artKitValue = templateAddon->ArtKits[artKitIndex];
2408
2409 if (artKitValue == 0)
2410 TC_LOG_ERROR("sql.sql", "GameObject {} hit by spell {} needs `artkit{}` in `gameobject_template_addon`", GetEntry(), spellId, artKitIndex);
2411 else
2412 SetGoArtKit(artKitValue);
2413
2414 break;
2415 }
2428 SetGoState(GOState(action));
2429 else
2430 TC_LOG_ERROR("spell", "Spell {} targeted non-transport gameobject for transport only action \"Go to Floor\" {} in effect {}", spellId, int32(action), effectIndex);
2431 break;
2433 SetAnimKitId(param, false);
2434 break;
2436 if (unitCaster)
2437 UseDoorOrButton(0, false, unitCaster);
2438 SetAnimKitId(param, false);
2439 break;
2442 SetAnimKitId(param, false);
2443 break;
2445 SetAnimKitId(param, true);
2446 break;
2448 SetAnimKitId(0, false);
2449 break;
2451 if (unitCaster)
2452 UseDoorOrButton(0, false, unitCaster);
2453 SetAnimKitId(0, false);
2454 break;
2457 SetAnimKitId(0, false);
2458 break;
2460 SetSpellVisualId(param, Object::GetGUID(spellCaster));
2461 break;
2464 break;
2465 default:
2466 TC_LOG_ERROR("spell", "Spell {} has unhandled action {} in effect {}", spellId, int32(action), effectIndex);
2467 break;
2468 }
2469
2470 // Apply side effects of type
2471 if (m_goTypeImpl)
2472 m_goTypeImpl->ActivateObject(action, param, spellCaster, spellId, effectIndex);
2473}
2474
2476{
2478 GameObjectData* data = const_cast<GameObjectData*>(sObjectMgr->GetGameObjectData(m_spawnId));
2479 if (data)
2480 data->artKit = kit;
2481}
2482
2484{
2485 GameObjectData const* data = nullptr;
2486 if (go)
2487 {
2488 go->SetGoArtKit(artkit);
2489 data = go->GetGameObjectData();
2490 }
2491 else if (lowguid)
2492 data = sObjectMgr->GetGameObjectData(lowguid);
2493
2494 if (data)
2495 const_cast<GameObjectData*>(data)->artKit = artkit;
2496}
2497
2498void GameObject::SwitchDoorOrButton(bool activate, bool alternative /* = false */)
2499{
2500 if (activate)
2502 else
2504
2505 if (GetGoState() == GO_STATE_READY) //if closed -> open
2507 else //if open -> close
2509}
2510
2512{
2513 // by default spell caster is user
2514 Unit* spellCaster = user;
2515 uint32 spellId = 0;
2516 bool triggered = false;
2517
2518 if (Player* playerUser = user->ToPlayer())
2519 {
2520 if (m_goInfo->GetNoDamageImmune() && playerUser->HasUnitFlag(UNIT_FLAG_IMMUNE))
2521 return;
2522
2523 if (!m_goInfo->IsUsableMounted())
2525
2526 playerUser->PlayerTalkClass->ClearMenus();
2527 if (AI()->OnGossipHello(playerUser))
2528 return;
2529 }
2530
2531 // If cooldown data present in template
2532 if (uint32 cooldown = GetGOInfo()->GetCooldown())
2533 {
2535 return;
2536
2538 }
2539
2540 switch (GetGoType())
2541 {
2542 case GAMEOBJECT_TYPE_DOOR: //0
2543 case GAMEOBJECT_TYPE_BUTTON: //1
2544 //doors/buttons never really despawn, only reset to default state/flags
2545 UseDoorOrButton(0, false, user);
2546 return;
2548 {
2549 if (user->GetTypeId() != TYPEID_PLAYER)
2550 return;
2551
2552 Player* player = user->ToPlayer();
2553
2554 player->PrepareGossipMenu(this, GetGOInfo()->questgiver.gossipID, true);
2555 player->SendPreparedGossip(this);
2556 return;
2557 }
2558 case GAMEOBJECT_TYPE_CHEST: //3
2559 {
2560 Player* player = user->ToPlayer();
2561 if (!player)
2562 return;
2563
2564 if (Battleground* bg = player->GetBattleground())
2565 if (!bg->CanActivateGO(GetEntry(), bg->GetPlayerTeam(user->GetGUID())))
2566 return;
2567
2568 GameObjectTemplate const* info = GetGOInfo();
2569 if (!m_loot && info->GetLootId())
2570 {
2571 if (info->GetLootId())
2572 {
2573 Group const* group = player->GetGroup();
2574 bool groupRules = group && info->chest.usegrouplootrules;
2575
2576 Loot* loot = new Loot(GetMap(), GetGUID(), LOOT_CHEST, groupRules ? group : nullptr);
2577 m_loot.reset(loot);
2578
2580 loot->FillLoot(info->GetLootId(), LootTemplates_Gameobject, player, !groupRules, false, GetLootMode(), ItemBonusMgr::GetContextForPlayer(GetMap()->GetMapDifficulty(), player));
2581
2582 if (GetLootMode() > 0)
2583 if (GameObjectTemplateAddon const* addon = GetTemplateAddon())
2584 loot->generateMoneyLoot(addon->Mingold, addon->Maxgold);
2585 }
2586
2587 if (info->chest.triggeredEvent)
2588 GameEvents::Trigger(info->chest.triggeredEvent, player, this);
2589
2590 // triggering linked GO
2591 if (uint32 trapEntry = info->chest.linkedTrap)
2592 TriggeringLinkedGameObject(trapEntry, player);
2593 }
2594 else if (!m_personalLoot.count(player->GetGUID()))
2595 {
2596 if (info->chest.chestPersonalLoot)
2597 {
2599 if (info->chest.DungeonEncounter)
2600 {
2601 std::vector<Player*> tappers;
2602 for (ObjectGuid tapperGuid : GetTapList())
2603 if (Player* tapper = ObjectAccessor::GetPlayer(*this, tapperGuid))
2604 tappers.push_back(tapper);
2605
2606 if (tappers.empty())
2607 tappers.push_back(player);
2608
2610 LootTemplates_Gameobject, LOOT_CHEST, this, addon ? addon->Mingold : 0, addon ? addon->Maxgold : 0,
2611 GetLootMode(), GetMap()->GetMapDifficulty(), tappers);
2612 }
2613 else
2614 {
2615 Loot* loot = new Loot(GetMap(), GetGUID(), LOOT_CHEST, nullptr);
2616 m_personalLoot[player->GetGUID()].reset(loot);
2617
2619 loot->FillLoot(info->chest.chestPersonalLoot, LootTemplates_Gameobject, player, true, false, GetLootMode(), ItemBonusMgr::GetContextForPlayer(GetMap()->GetMapDifficulty(), player));
2620
2621 if (GetLootMode() > 0 && addon)
2622 loot->generateMoneyLoot(addon->Mingold, addon->Maxgold);
2623 }
2624 }
2625 }
2626
2627 if (!m_unique_users.count(player->GetGUID()) && !info->GetLootId())
2628 {
2629 if (info->chest.chestPushLoot)
2630 {
2631 Loot pushLoot(GetMap(), GetGUID(), LOOT_CHEST, nullptr);
2632 pushLoot.FillLoot(info->chest.chestPushLoot, LootTemplates_Gameobject, player, true, false, GetLootMode(), ItemBonusMgr::GetContextForPlayer(GetMap()->GetMapDifficulty(), player));
2633 pushLoot.AutoStore(player, NULL_BAG, NULL_SLOT);
2634 }
2635
2636 if (info->chest.triggeredEvent)
2637 GameEvents::Trigger(info->chest.triggeredEvent, player, this);
2638
2639 // triggering linked GO
2640 if (uint32 trapEntry = info->chest.linkedTrap)
2641 TriggeringLinkedGameObject(trapEntry, player);
2642
2643 AddUniqueUse(player);
2644 }
2645
2646 if (getLootState() != GO_ACTIVATED)
2647 SetLootState(GO_ACTIVATED, player);
2648
2649 // Send loot
2650 if (Loot* loot = GetLootForPlayer(player))
2651 player->SendLoot(*loot);
2652 break;
2653 }
2654 case GAMEOBJECT_TYPE_TRAP: //6
2655 {
2656 GameObjectTemplate const* goInfo = GetGOInfo();
2657 if (goInfo->trap.spell)
2658 CastSpell(user, goInfo->trap.spell);
2659
2660 m_cooldownTime = GameTime::GetGameTimeMS() + (goInfo->trap.cooldown ? goInfo->trap.cooldown : uint32(4)) * IN_MILLISECONDS; // template or 4 seconds
2661
2662 if (goInfo->trap.charges == 1) // Deactivate after trigger
2664
2665 return;
2666 }
2667 //Sitting: Wooden bench, chairs enzz
2668 case GAMEOBJECT_TYPE_CHAIR: //7
2669 {
2670 GameObjectTemplate const* info = GetGOInfo();
2671 if (ChairListSlots.empty()) // this is called once at first chair use to make list of available slots
2672 {
2673 if (info->chair.chairslots > 0) // sometimes chairs in DB have error in fields and we dont know number of slots
2674 for (uint32 i = 0; i < info->chair.chairslots; ++i)
2675 ChairListSlots[i].Clear(); // Last user of current slot set to 0 (none sit here yet)
2676 else
2677 ChairListSlots[0].Clear(); // error in DB, make one default slot
2678 }
2679
2680 // a chair may have n slots. we have to calculate their positions and teleport the player to the nearest one
2681
2682 float lowestDist = DEFAULT_VISIBILITY_DISTANCE;
2683
2684 uint32 nearest_slot = 0;
2685 float x_lowest = GetPositionX();
2686 float y_lowest = GetPositionY();
2687
2688 // the object orientation + 1/2 pi
2689 // every slot will be on that straight line
2690 float orthogonalOrientation = GetOrientation() + float(M_PI) * 0.5f;
2691 // find nearest slot
2692 bool found_free_slot = false;
2693 for (auto& [slot, sittingUnit] : ChairListSlots)
2694 {
2695 // the distance between this slot and the center of the go - imagine a 1D space
2696 float relativeDistance = (info->size * slot) - (info->size * (info->chair.chairslots - 1) / 2.0f);
2697
2698 float x_i = GetPositionX() + relativeDistance * std::cos(orthogonalOrientation);
2699 float y_i = GetPositionY() + relativeDistance * std::sin(orthogonalOrientation);
2700
2701 if (!sittingUnit.IsEmpty())
2702 {
2703 if (Unit* chairUser = ObjectAccessor::GetUnit(*this, sittingUnit))
2704 {
2705 if (chairUser->IsSitState() && chairUser->GetStandState() != UNIT_STAND_STATE_SIT && chairUser->GetExactDist2d(x_i, y_i) < 0.1f)
2706 continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->GetStandState() != UNIT_STAND_STATE_SIT check is required.
2707
2708 sittingUnit.Clear(); // This seat is unoccupied.
2709 }
2710 else
2711 sittingUnit.Clear(); // The seat may of had an occupant, but they're offline.
2712 }
2713
2714 found_free_slot = true;
2715
2716 // calculate the distance between the player and this slot
2717 float thisDistance = user->GetDistance2d(x_i, y_i);
2718
2719 if (thisDistance <= lowestDist)
2720 {
2721 nearest_slot = slot;
2722 lowestDist = thisDistance;
2723 x_lowest = x_i;
2724 y_lowest = y_i;
2725 }
2726 }
2727
2728 if (found_free_slot)
2729 {
2730 auto itr = ChairListSlots.find(nearest_slot);
2731 if (itr != ChairListSlots.end())
2732 {
2733 itr->second = user->GetGUID(); //this slot in now used by player
2734 user->NearTeleportTo(x_lowest, y_lowest, GetPositionZ(), GetOrientation());
2736 if (info->chair.triggeredEvent)
2737 GameEvents::Trigger(info->chair.triggeredEvent, user, this);
2738 return;
2739 }
2740 }
2741
2742 return;
2743 }
2745 // triggering linked GO
2746 if (uint32 trapEntry = GetGOInfo()->spellFocus.linkedTrap)
2747 TriggeringLinkedGameObject(trapEntry, user);
2748 break;
2749 //big gun, its a spell/aura
2750 case GAMEOBJECT_TYPE_GOOBER: //10
2751 {
2752 GameObjectTemplate const* info = GetGOInfo();
2753 Player* player = user->ToPlayer();
2754
2755 if (player)
2756 {
2757 if (info->goober.pageID) // show page...
2758 {
2760 data.GameObjectGUID = GetGUID();
2761 player->SendDirectMessage(data.Write());
2762 }
2763 else if (info->goober.gossipID)
2764 {
2765 player->PrepareGossipMenu(this, info->goober.gossipID);
2766 player->SendPreparedGossip(this);
2767 }
2768
2769 if (info->goober.eventID)
2770 {
2771 TC_LOG_DEBUG("maps.script", "Goober ScriptStart id {} for GO entry {} (GUID {}).", info->goober.eventID, GetEntry(), GetSpawnId());
2772 GameEvents::Trigger(info->goober.eventID, player, this);
2773 }
2774
2775 // possible quest objective for active quests
2776 if (info->goober.questID && sObjectMgr->GetQuestTemplate(info->goober.questID))
2777 {
2778 //Quest require to be active for GO using
2780 break;
2781 }
2782
2783 if (Group* group = player->GetGroup())
2784 {
2785 for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
2786 if (Player* member = itr->GetSource())
2787 if (member->IsAtGroupRewardDistance(this))
2788 member->KillCreditGO(info->entry, GetGUID());
2789 }
2790 else
2791 player->KillCreditGO(info->entry, GetGUID());
2792 }
2793
2794 if (uint32 trapEntry = info->goober.linkedTrap)
2795 TriggeringLinkedGameObject(trapEntry, user);
2796
2797 if (info->goober.AllowMultiInteract && player)
2798 {
2799 if (info->IsDespawnAtAction())
2801 else
2803 }
2804 else
2805 {
2808
2809 // this appear to be ok, however others exist in addition to this that should have custom (ex: 190510, 188692, 187389)
2810 if (info->goober.customAnim)
2812 else
2814
2816 }
2817
2818 // cast this spell later if provided
2819 spellId = info->goober.spell;
2820 if (!info->goober.playerCast)
2821 spellCaster = nullptr;
2822
2823 break;
2824 }
2825 case GAMEOBJECT_TYPE_CAMERA: //13
2826 {
2827 GameObjectTemplate const* info = GetGOInfo();
2828 if (!info)
2829 return;
2830
2831 if (user->GetTypeId() != TYPEID_PLAYER)
2832 return;
2833
2834 Player* player = user->ToPlayer();
2835
2836 if (info->camera.camera)
2837 player->SendCinematicStart(info->camera.camera);
2838
2839 if (info->camera.eventID)
2840 GameEvents::Trigger(info->camera.eventID, player, this);
2841
2842 return;
2843 }
2844 //fishing bobber
2846 {
2847 Player* player = user->ToPlayer();
2848 if (!player)
2849 return;
2850
2851 if (player->GetGUID() != GetOwnerGUID())
2852 return;
2853
2854 switch (getLootState())
2855 {
2856 case GO_READY: // ready for loot
2857 {
2858 SetLootState(GO_ACTIVATED, player);
2859
2862
2863 SendUpdateToPlayer(player);
2864
2865 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(GetAreaId());
2866 if (!areaEntry)
2867 {
2868 TC_LOG_ERROR("entities.gameobject", "Gameobject '{}' ({}) spawned in unknown area (x: {} y: {} z: {} map: {})",
2870 break;
2871 }
2872
2873 // Update the correct fishing skill according to the area's ContentTuning
2874 ContentTuningEntry const* areaContentTuning = DB2Manager::GetContentTuningForArea(areaEntry);
2875 if (!areaContentTuning)
2876 break;
2877
2878 player->UpdateFishingSkill(areaContentTuning->ExpansionID);
2879
2880 // Send loot
2881 int32 areaFishingLevel = sObjectMgr->GetFishingBaseSkillLevel(areaEntry);
2882
2883 uint32 playerFishingSkill = player->GetProfessionSkillForExp(SKILL_FISHING, areaContentTuning->ExpansionID);
2884 int32 playerFishingLevel = player->GetSkillValue(playerFishingSkill);
2885
2886 int32 roll = irand(1, 100);
2887 int32 chance = 100;
2888 if (playerFishingLevel < areaFishingLevel)
2889 {
2890 chance = int32(pow((double)playerFishingLevel / areaFishingLevel, 2) * 100);
2891 if (chance < 1)
2892 chance = 1;
2893 }
2894
2895 TC_LOG_DEBUG("misc", "Fishing check (skill {} level: {} area skill level: {} chance {} roll: {}", playerFishingSkill, playerFishingLevel, areaFishingLevel, chance, roll);
2896
2898 GameObject* fishingPool = LookupFishingHoleAround(20.0f + CONTACT_DISTANCE);
2899
2900 // If fishing skill is high enough, or if fishing on a pool, send correct loot.
2901 // Fishing pools have no skill requirement as of patch 3.3.0 (undocumented change).
2902 if (chance >= roll || fishingPool)
2903 {
2905 // prevent removing GO at spell cancel
2907 SetOwnerGUID(player->GetGUID());
2908 SetSpellId(0); // prevent removing unintended auras at Unit::RemoveGameObject
2909
2910 if (fishingPool)
2911 {
2912 fishingPool->Use(player);
2914 }
2915 else
2916 {
2917 m_loot.reset(GetFishLoot(player));
2918 player->SendLoot(*m_loot);
2919 }
2920 }
2921 else // If fishing skill is too low, send junk loot.
2922 {
2923 m_loot.reset(GetFishLootJunk(player));
2924 player->SendLoot(*m_loot);
2925 }
2926 break;
2927 }
2928 case GO_JUST_DEACTIVATED: // nothing to do, will be deleted at next update
2929 break;
2930 default:
2931 {
2934 break;
2935 }
2936 }
2937
2939 return;
2940 }
2941
2942 case GAMEOBJECT_TYPE_RITUAL: //18
2943 {
2944 if (user->GetTypeId() != TYPEID_PLAYER)
2945 return;
2946
2947 Player* player = user->ToPlayer();
2948
2949 Unit* owner = GetOwner();
2950
2951 GameObjectTemplate const* info = GetGOInfo();
2952
2953 Player* m_ritualOwner = nullptr;
2956
2957 // ritual owner is set for GO's without owner (not summoned)
2958 if (!m_ritualOwner && !owner)
2959 {
2960 m_ritualOwnerGUID = player->GetGUID();
2961 m_ritualOwner = player;
2962 }
2963
2964 if (owner)
2965 {
2966 if (owner->GetTypeId() != TYPEID_PLAYER)
2967 return;
2968
2969 // accept only use by player from same group as owner, excluding owner itself (unique use already added in spell effect)
2970 if (player == owner->ToPlayer() || (info->ritual.castersGrouped && !player->IsInSameRaidWith(owner->ToPlayer())))
2971 return;
2972
2973 // expect owner to already be channeling, so if not...
2975 return;
2976
2977 // in case summoning ritual caster is GO creator
2978 spellCaster = owner;
2979 }
2980 else
2981 {
2982 if (player != m_ritualOwner && (info->ritual.castersGrouped && !player->IsInSameRaidWith(m_ritualOwner)))
2983 return;
2984
2985 spellCaster = player;
2986 }
2987
2988 AddUniqueUse(player);
2989
2990 if (info->ritual.animSpell)
2991 {
2992 player->CastSpell(player, info->ritual.animSpell, true);
2993
2994 // for this case, summoningRitual.spellId is always triggered
2995 triggered = true;
2996 }
2997
2998 // full amount unique participants including original summoner
2999 if (GetUniqueUseCount() == info->ritual.casters)
3000 {
3001 if (m_ritualOwner)
3002 spellCaster = m_ritualOwner;
3003
3004 spellId = info->ritual.spell;
3005
3006 if (spellId == 62330) // GO store nonexistent spell, replace by expected
3007 {
3008 // spell have reagent and mana cost but it not expected use its
3009 // it triggered spell in fact cast at currently channeled GO
3010 spellId = 61993;
3011 triggered = true;
3012 }
3013
3014 // Cast casterTargetSpell at a random GO user
3015 // on the current DB there is only one gameobject that uses this (Ritual of Doom)
3016 // and its required target number is 1 (outter for loop will run once)
3017 if (info->ritual.casterTargetSpell && info->ritual.casterTargetSpell != 1) // No idea why this field is a bool in some cases
3018 for (uint32 i = 0; i < info->ritual.casterTargetSpellTargets; i++)
3019 // m_unique_users can contain only player GUIDs
3021 spellCaster->CastSpell(target, info->ritual.casterTargetSpell, true);
3022
3023 // finish owners spell
3024 if (owner)
3026
3027 // can be deleted now, if
3028 if (!info->ritual.ritualPersistent)
3030 else
3031 {
3032 // reset ritual for this GO
3034 m_unique_users.clear();
3035 m_usetimes = 0;
3036 }
3037 }
3038 else
3039 return;
3040
3041 // go to end function to spell casting
3042 break;
3043 }
3045 {
3046 GameObjectTemplate const* info = GetGOInfo();
3047 if (!info)
3048 return;
3049
3050 if (info->spellCaster.partyOnly)
3051 {
3052 Unit* caster = GetOwner();
3053 if (!caster || caster->GetTypeId() != TYPEID_PLAYER)
3054 return;
3055
3056 if (user->GetTypeId() != TYPEID_PLAYER || !user->ToPlayer()->IsInSameRaidWith(caster->ToPlayer()))
3057 return;
3058 }
3059
3061 spellId = info->spellCaster.spell;
3062
3063 AddUse();
3064 break;
3065 }
3067 {
3068 GameObjectTemplate const* info = GetGOInfo();
3069
3070 if (user->GetTypeId() != TYPEID_PLAYER)
3071 return;
3072
3073 Player* player = user->ToPlayer();
3074
3075 Player* targetPlayer = ObjectAccessor::FindPlayer(player->GetTarget());
3076
3077 // accept only use by player from same raid as caster, except caster itself
3078 if (!targetPlayer || targetPlayer == player || !targetPlayer->IsInSameRaidWith(player))
3079 return;
3080
3081 //required lvl checks!
3082 if (Optional<ContentTuningLevels> userLevels = sDB2Manager.GetContentTuningData(info->ContentTuningId, player->m_playerData->CtrOptions->ContentTuningConditionMask))
3083 if (player->GetLevel() < userLevels->MaxLevel)
3084 return;
3085
3086 if (Optional<ContentTuningLevels> targetLevels = sDB2Manager.GetContentTuningData(info->ContentTuningId, targetPlayer->m_playerData->CtrOptions->ContentTuningConditionMask))
3087 if (targetPlayer->GetLevel() < targetLevels->MaxLevel)
3088 return;
3089
3090 if (info->entry == 194097)
3091 spellId = 61994; // Ritual of Summoning
3092 else
3093 spellId = 59782; // Summoning Stone Effect
3094
3095 break;
3096 }
3097
3098 case GAMEOBJECT_TYPE_FLAGSTAND: // 24
3099 {
3100 if (user->GetTypeId() != TYPEID_PLAYER)
3101 return;
3102
3103 Player* player = user->ToPlayer();
3104
3105 if (player->CanUseBattlegroundObject(this))
3106 {
3107 // in battleground check
3108 Battleground* bg = player->GetBattleground();
3109 if (!bg)
3110 return;
3111
3112 if (player->GetVehicle())
3113 return;
3114
3117 // BG flag click
3118 // AB:
3119 // 15001
3120 // 15002
3121 // 15003
3122 // 15004
3123 // 15005
3124 bg->EventPlayerClickedOnFlag(player, this);
3125 return; //we don;t need to delete flag ... it is despawned!
3126 }
3127 break;
3128 }
3129
3130 case GAMEOBJECT_TYPE_FISHINGHOLE: // 25
3131 {
3132 if (user->GetTypeId() != TYPEID_PLAYER)
3133 return;
3134
3135 Player* player = user->ToPlayer();
3136
3137 Loot* loot = new Loot(GetMap(), GetGUID(), LOOT_FISHINGHOLE, nullptr);
3138 loot->FillLoot(GetGOInfo()->GetLootId(), LootTemplates_Gameobject, player, true, false, LOOT_MODE_DEFAULT, ItemBonusMgr::GetContextForPlayer(GetMap()->GetMapDifficulty(), player));
3139 m_personalLoot[player->GetGUID()].reset(loot);
3140
3141 player->SendLoot(*loot);
3143 return;
3144 }
3145
3146 case GAMEOBJECT_TYPE_FLAGDROP: // 26
3147 {
3148 if (user->GetTypeId() != TYPEID_PLAYER)
3149 return;
3150
3151 Player* player = user->ToPlayer();
3152
3153 if (player->CanUseBattlegroundObject(this))
3154 {
3155 // in battleground check
3156 Battleground* bg = player->GetBattleground();
3157 if (!bg)
3158 return;
3159
3160 if (player->GetVehicle())
3161 return;
3162
3165 // BG flag dropped
3166 // WS:
3167 // 179785 - Silverwing Flag
3168 // 179786 - Warsong Flag
3169 // EotS:
3170 // 184142 - Netherstorm Flag
3171 GameObjectTemplate const* info = GetGOInfo();
3172 if (info)
3173 {
3174 switch (info->entry)
3175 {
3176 case 179785: // Silverwing Flag
3177 case 179786: // Warsong Flag
3178 if (bg->GetTypeID() == BATTLEGROUND_WS)
3179 bg->EventPlayerClickedOnFlag(player, this);
3180 break;
3181 case 184142: // Netherstorm Flag
3182 if (bg->GetTypeID() == BATTLEGROUND_EY)
3183 bg->EventPlayerClickedOnFlag(player, this);
3184 break;
3185 }
3186
3187 if (info->flagDrop.eventID)
3188 GameEvents::Trigger(info->flagDrop.eventID, player, this);
3189 }
3190 //this cause to call return, all flags must be deleted here!!
3191 spellId = 0;
3192 Delete();
3193 }
3194 break;
3195 }
3197 {
3198 GameObjectTemplate const* info = GetGOInfo();
3199 if (!info)
3200 return;
3201
3202 if (user->GetTypeId() != TYPEID_PLAYER)
3203 return;
3204
3205 Player* player = user->ToPlayer();
3206
3207 WorldPackets::Misc::EnableBarberShop enableBarberShop;
3208 enableBarberShop.CustomizationScope = info->barberChair.CustomizationScope;
3209 player->SendDirectMessage(enableBarberShop.Write());
3210
3211 // fallback, will always work
3213
3215 return;
3216 }
3218 {
3219 GameObjectTemplate const* info = GetGOInfo();
3220 if (!info)
3221 return;
3222
3223 Player* player = user->ToPlayer();
3224 if (!player)
3225 return;
3226
3227 if (!player->CanUseBattlegroundObject(this))
3228 return;
3229
3230 GameObjectType::NewFlag const* newFlag = dynamic_cast<GameObjectType::NewFlag const*>(m_goTypeImpl.get());
3231 if (!newFlag)
3232 return;
3233
3234 if (newFlag->GetState() != FlagState::InBase)
3235 return;
3236
3237 spellId = info->newflag.pickupSpell;
3238 spellCaster = nullptr;
3239 break;
3240 }
3242 {
3243 GameObjectTemplate const* info = GetGOInfo();
3244 if (!info)
3245 return;
3246
3247 if (user->GetTypeId() != TYPEID_PLAYER)
3248 return;
3249
3250 if (!user->IsAlive())
3251 return;
3252
3253 if (GameObject* owner = GetMap()->GetGameObject(GetOwnerGUID()))
3254 {
3255 if (owner->GetGoType() == GAMEOBJECT_TYPE_NEW_FLAG)
3256 {
3257 GameObjectType::NewFlag const* newFlag = dynamic_cast<GameObjectType::NewFlag const*>(owner->m_goTypeImpl.get());
3258 if (!newFlag)
3259 return;
3260
3261 if (newFlag->GetState() != FlagState::Dropped)
3262 return;
3263
3264 // friendly with enemy flag means you're taking it
3265 bool defenderInteract = !owner->IsFriendlyTo(user);
3266 if (defenderInteract && owner->GetGOInfo()->newflag.ReturnonDefenderInteract)
3267 {
3268 Delete();
3269 owner->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::InBase, user->ToPlayer()));
3270 return;
3271 }
3272 else
3273 {
3274 // we let the owner cast the spell for now
3275 // so that caster guid is set correctly
3276 SpellCastResult result = owner->CastSpell(user, owner->GetGOInfo()->newflag.pickupSpell, CastSpellExtraArgs(TRIGGERED_FULL_MASK));
3277 if (result == SPELL_CAST_OK)
3278 {
3279 Delete();
3280 owner->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Taken, user->ToPlayer()));
3281 return;
3282 }
3283 }
3284 }
3285 }
3286
3287 Delete();
3288 return;
3289 }
3291 {
3292 Player* player = user->ToPlayer();
3293 if (!player)
3294 return;
3295
3296 AssaultCapturePoint(player);
3297 return;
3298 }
3300 {
3301 GameObjectTemplate const* info = GetGOInfo();
3302 if (!info)
3303 return;
3304
3305 if (user->GetTypeId() != TYPEID_PLAYER)
3306 return;
3307
3308 Player* player = user->ToPlayer();
3309 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(info->itemForge.conditionID1))
3310 if (!sConditionMgr->IsPlayerMeetingCondition(player, playerCondition))
3311 return;
3312
3313 switch (info->itemForge.ForgeType)
3314 {
3315 case 0: // Artifact Forge
3316 case 1: // Relic Forge
3317 {
3319 Item const* item = artifactAura ? player->GetItemByGuid(artifactAura->GetCastItemGUID()) : nullptr;
3320 if (!item)
3321 {
3323 return;
3324 }
3325
3327 openArtifactForge.ArtifactGUID = item->GetGUID();
3328 openArtifactForge.ForgeGUID = GetGUID();
3329 player->SendDirectMessage(openArtifactForge.Write());
3330 break;
3331 }
3332 case 2: // Heart Forge
3333 {
3335 if (!item)
3336 return;
3337
3339 openHeartForge.ObjectGUID = GetGUID();
3341 player->SendDirectMessage(openHeartForge.Write());
3342 break;
3343 }
3344 default:
3345 break;
3346 }
3347 return;
3348 }
3350 {
3351 Player* player = user->ToPlayer();
3352 if (!player)
3353 return;
3354
3356 gameObjectUILink.ObjectGUID = GetGUID();
3357 switch (GetGOInfo()->UILink.UILinkType)
3358 {
3359 case 0:
3361 break;
3362 case 1:
3364 break;
3365 case 2:
3367 break;
3368 case 3:
3370 break;
3371 default:
3372 break;
3373 }
3374 player->SendDirectMessage(gameObjectUILink.Write());
3375 return;
3376 }
3378 {
3379 Player* player = user->ToPlayer();
3380 if (!player)
3381 return;
3382
3383 GameObjectTemplate const* info = GetGOInfo();
3384 if (!m_personalLoot.count(player->GetGUID()))
3385 {
3386 if (info->gatheringNode.chestLoot)
3387 {
3388 Loot* loot = new Loot(GetMap(), GetGUID(), LOOT_CHEST, nullptr);
3389 m_personalLoot[player->GetGUID()].reset(loot);
3390
3391 loot->FillLoot(info->gatheringNode.chestLoot, LootTemplates_Gameobject, player, true, false, GetLootMode(), ItemBonusMgr::GetContextForPlayer(GetMap()->GetMapDifficulty(), player));
3392 }
3393
3394 if (info->gatheringNode.triggeredEvent)
3396
3397 // triggering linked GO
3398 if (uint32 trapEntry = info->gatheringNode.linkedTrap)
3399 TriggeringLinkedGameObject(trapEntry, player);
3400
3401 if (info->gatheringNode.xpDifficulty && info->gatheringNode.xpDifficulty < 10)
3402 if (QuestXPEntry const* questXp = sQuestXPStore.LookupEntry(player->GetLevel()))
3403 if (uint32 xp = Quest::RoundXPValue(questXp->Difficulty[info->gatheringNode.xpDifficulty]))
3404 player->GiveXP(xp, nullptr);
3405
3406 spellId = info->gatheringNode.spell;
3407 }
3408
3409 if (m_personalLoot.size() >= info->gatheringNode.MaxNumberofLoots)
3410 {
3413 }
3414
3415 if (getLootState() != GO_ACTIVATED)
3416 {
3417 SetLootState(GO_ACTIVATED, player);
3420 }
3421
3422 // Send loot
3423 if (Loot* loot = GetLootForPlayer(player))
3424 player->SendLoot(*loot);
3425 break;
3426 }
3427 default:
3429 TC_LOG_ERROR("misc", "GameObject::Use(): unit ({}, name: {}) tries to use object ({}, name: {}) of unknown type ({})",
3430 user->GetGUID().ToString(), user->GetName(), GetGUID().ToString(), GetGOInfo()->name, GetGoType());
3431 break;
3432 }
3433
3434 if (m_vignette)
3435 {
3436 if (Player* player = user->ToPlayer())
3437 {
3438 if (Quest const* reward = sObjectMgr->GetQuestTemplate(m_vignette->Data->RewardQuestID))
3439 if (!player->GetQuestRewardStatus(m_vignette->Data->RewardQuestID))
3440 player->RewardQuest(reward, LootItemType::Item, 0, this, false);
3441
3442 if (m_vignette->Data->VisibleTrackingQuestID)
3443 player->SetRewardedQuest(m_vignette->Data->VisibleTrackingQuestID);
3444 }
3445
3446 // only unregister it from visibility (need to keep vignette for other gameobject users in case its usable by multiple players
3447 // to flag their quest completion
3448 if (GetGOInfo()->ClearObjectVignetteonOpening())
3450 }
3451
3452 if (!spellId)
3453 return;
3454
3455 if (!sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()))
3456 {
3457 if (user->GetTypeId() != TYPEID_PLAYER || !sOutdoorPvPMgr->HandleCustomSpell(user->ToPlayer(), spellId, this))
3458 TC_LOG_ERROR("misc", "WORLD: unknown spell id {} at use action for gameobject (Entry: {} GoType: {})", spellId, GetEntry(), GetGoType());
3459 else
3460 TC_LOG_DEBUG("outdoorpvp", "WORLD: {} non-dbc spell was handled by OutdoorPvP", spellId);
3461 return;
3462 }
3463
3464 if (Player* player = user->ToPlayer())
3465 sOutdoorPvPMgr->HandleCustomSpell(player, spellId, this);
3466
3467 if (spellCaster)
3468 spellCaster->CastSpell(user, spellId, triggered);
3469 else
3470 {
3471 SpellCastResult castResult = CastSpell(user, spellId);
3472 if (castResult == SPELL_FAILED_SUCCESS)
3473 {
3476 }
3477 }
3478}
3479
3481{
3483 customAnim.ObjectGUID = GetGUID();
3484 customAnim.CustomAnim = anim;
3485 SendMessageToSet(customAnim.Write(), true);
3486}
3487
3488bool GameObject::IsInRange(float x, float y, float z, float radius) const
3489{
3491 if (!info)
3492 return IsWithinDist3d(x, y, z, radius);
3493
3494 float sinA = std::sin(GetOrientation());
3495 float cosA = std::cos(GetOrientation());
3496 float dx = x - GetPositionX();
3497 float dy = y - GetPositionY();
3498 float dz = z - GetPositionZ();
3499 float dist = std::sqrt(dx*dx + dy*dy);
3502 if (G3D::fuzzyEq(dist, 0.0f))
3503 return true;
3504
3505 float sinB = dx / dist;
3506 float cosB = dy / dist;
3507 dx = dist * (cosA * cosB + sinA * sinB);
3508 dy = dist * (cosA * sinB - sinA * cosB);
3509 return dx < info->GeoBoxMax.X + radius && dx > info->GeoBoxMin.X - radius
3510 && dy < info->GeoBoxMax.Y + radius && dy > info->GeoBoxMin.Y - radius
3511 && dz < info->GeoBoxMax.Z + radius && dz > info->GeoBoxMin.Z - radius;
3512}
3513
3515{
3517 if (uint32 scriptId = gameObjectData->scriptId)
3518 return scriptId;
3519
3520 return GetGOInfo()->ScriptId;
3521}
3522
3523bool GameObject::HasStringId(std::string_view id) const
3524{
3525 return std::find(m_stringIds.begin(), m_stringIds.end(), id) != m_stringIds.end();
3526}
3527
3529{
3530 if (!id.empty())
3531 {
3532 m_scriptStringId.emplace(std::move(id));
3534 }
3535 else
3536 {
3537 m_scriptStringId.reset();
3538 m_stringIds[2] = {};
3539 }
3540}
3541
3542// overwrite WorldObject function for proper name localization
3544{
3545 if (locale != DEFAULT_LOCALE)
3546 if (GameObjectLocale const* cl = sObjectMgr->GetGameObjectLocale(GetEntry()))
3547 if (cl->Name.size() > locale && !cl->Name[locale].empty())
3548 return cl->Name[locale];
3549
3550 return GetName();
3551}
3552
3554{
3555 static const int32 PACK_YZ = 1 << 20;
3556 static const int32 PACK_X = PACK_YZ << 1;
3557
3558 static const int32 PACK_YZ_MASK = (PACK_YZ << 1) - 1;
3559 static const int32 PACK_X_MASK = (PACK_X << 1) - 1;
3560
3561 int8 w_sign = (m_localRotation.w >= 0.f ? 1 : -1);
3562 int64 x = int32(m_localRotation.x * PACK_X) * w_sign & PACK_X_MASK;
3563 int64 y = int32(m_localRotation.y * PACK_YZ) * w_sign & PACK_YZ_MASK;
3564 int64 z = int32(m_localRotation.z * PACK_YZ) * w_sign & PACK_YZ_MASK;
3565 m_packedRotation = z | (y << 21) | (x << 42);
3566}
3567
3568void GameObject::SetLocalRotation(float qx, float qy, float qz, float qw)
3569{
3570 G3D::Quat rotation(qx, qy, qz, qw);
3571 rotation.unitize();
3572 m_localRotation.x = rotation.x;
3573 m_localRotation.y = rotation.y;
3574 m_localRotation.z = rotation.z;
3575 m_localRotation.w = rotation.w;
3577}
3578
3580{
3582}
3583
3584void GameObject::SetLocalRotationAngles(float z_rot, float y_rot, float x_rot)
3585{
3586 G3D::Quat quat(G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot));
3587 SetLocalRotation(quat.x, quat.y, quat.z, quat.w);
3588}
3589
3591{
3592 QuaternionData localRotation = GetLocalRotation();
3593 if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
3594 {
3595 QuaternionData worldRotation = transport->GetWorldRotation();
3596
3597 G3D::Quat worldRotationQuat(worldRotation.x, worldRotation.y, worldRotation.z, worldRotation.w);
3598 G3D::Quat localRotationQuat(localRotation.x, localRotation.y, localRotation.z, localRotation.w);
3599
3600 G3D::Quat resultRotation = localRotationQuat * worldRotationQuat;
3601
3602 return QuaternionData(resultRotation.x, resultRotation.y, resultRotation.z, resultRotation.w);
3603 }
3604 return localRotation;
3605}
3606
3607void GameObject::ModifyHealth(int32 change, WorldObject* attackerOrHealer /*= nullptr*/, uint32 spellId /*= 0*/)
3608{
3609 if (!m_goValue.Building.MaxHealth || !change)
3610 return;
3611
3612 // prevent double destructions of the same object
3613 if (change < 0 && !m_goValue.Building.Health)
3614 return;
3615
3616 if (int32(m_goValue.Building.Health) + change <= 0)
3620 else
3621 m_goValue.Building.Health += change;
3622
3623 // Set the health bar, value = 255 * healthPct;
3625
3626 // dealing damage, send packet
3627 if (Player* player = attackerOrHealer ? attackerOrHealer->GetCharmerOrOwnerPlayerOrPlayerItself() : nullptr)
3628 {
3630 packet.Caster = attackerOrHealer->GetGUID(); // todo: this can be a GameObject
3631 packet.Target = GetGUID();
3632 packet.Damage = -change;
3633 packet.Owner = player->GetGUID();
3634 packet.SpellID = spellId;
3635 player->SendDirectMessage(packet.Write());
3636 }
3637
3638 if (change < 0 && GetGOInfo()->destructibleBuilding.DamageEvent)
3639 GameEvents::Trigger(GetGOInfo()->destructibleBuilding.DamageEvent, attackerOrHealer, this);
3640
3642
3644 newState = GO_DESTRUCTIBLE_DESTROYED;
3645 else if (m_goValue.Building.Health <= 10000/*GetGOInfo()->destructibleBuilding.damagedNumHits*/) // TODO: Get health somewhere
3646 newState = GO_DESTRUCTIBLE_DAMAGED;
3648 newState = GO_DESTRUCTIBLE_INTACT;
3649
3650 if (newState == GetDestructibleState())
3651 return;
3652
3653 SetDestructibleState(newState, attackerOrHealer, false);
3654}
3655
3656void GameObject::SetDestructibleState(GameObjectDestructibleState state, WorldObject* attackerOrHealer /*= nullptr*/, bool setHealth /*= false*/)
3657{
3658 // the user calling this must know he is already operating on destructible gameobject
3660
3661 switch (state)
3662 {
3666 if (setHealth)
3667 {
3669 SetGoAnimProgress(255);
3670 }
3671 EnableCollision(true);
3672 break;
3674 {
3675 if (GetGOInfo()->destructibleBuilding.DamagedEvent && attackerOrHealer)
3676 GameEvents::Trigger(GetGOInfo()->destructibleBuilding.DamagedEvent, attackerOrHealer, this);
3677 AI()->Damaged(attackerOrHealer, m_goInfo->destructibleBuilding.DamagedEvent);
3678
3681
3682 uint32 modelId = m_goInfo->displayId;
3684 if (modelData->State1Wmo)
3685 modelId = modelData->State1Wmo;
3686 SetDisplayId(modelId);
3687
3688 if (setHealth)
3689 {
3690 m_goValue.Building.Health = 10000/*m_goInfo->destructibleBuilding.damagedNumHits*/;
3691 uint32 maxHealth = m_goValue.Building.MaxHealth;
3692 // in this case current health is 0 anyway so just prevent crashing here
3693 if (!maxHealth)
3694 maxHealth = 1;
3695 SetGoAnimProgress(m_goValue.Building.Health * 255 / maxHealth);
3696 }
3697 break;
3698 }
3700 {
3701 if (GetGOInfo()->destructibleBuilding.DestroyedEvent && attackerOrHealer)
3702 GameEvents::Trigger(GetGOInfo()->destructibleBuilding.DestroyedEvent, attackerOrHealer, this);
3704
3705 if (Player* player = attackerOrHealer ? attackerOrHealer->GetCharmerOrOwnerPlayerOrPlayerItself() : nullptr)
3706 if (Battleground* bg = player->GetBattleground())
3707 bg->DestroyGate(player, this);
3708
3711
3712 uint32 modelId = m_goInfo->displayId;
3714 if (modelData->State2Wmo)
3715 modelId = modelData->State2Wmo;
3716 SetDisplayId(modelId);
3717
3718 if (setHealth)
3719 {
3722 }
3723 EnableCollision(false);
3724 break;
3725 }
3727 {
3728 if (GetGOInfo()->destructibleBuilding.RebuildingEvent && attackerOrHealer)
3729 GameEvents::Trigger(GetGOInfo()->destructibleBuilding.RebuildingEvent, attackerOrHealer, this);
3731
3732 uint32 modelId = m_goInfo->displayId;
3734 if (modelData->State3Wmo)
3735 modelId = modelData->State3Wmo;
3736 SetDisplayId(modelId);
3737
3738 // restores to full health
3739 if (setHealth)
3740 {
3742 SetGoAnimProgress(255);
3743 }
3744 EnableCollision(true);
3745 break;
3746 }
3747 }
3748}
3749
3751{
3752 m_lootState = state;
3753 if (unit)
3754 m_lootStateUnitGUID = unit->GetGUID();
3755 else
3757
3758 AI()->OnLootStateChanged(state, unit);
3759
3760 // Start restock timer if the chest is partially looted or not looted at all
3761 if (GetGoType() == GAMEOBJECT_TYPE_CHEST && state == GO_ACTIVATED && GetGOInfo()->chest.chestRestockTime > 0 && m_restockTime == 0 && m_loot && m_loot->IsChanged())
3763
3764 if (GetGoType() == GAMEOBJECT_TYPE_DOOR) // only set collision for doors on SetGoState
3765 return;
3766
3767 if (m_model)
3768 {
3769 bool collision = false;
3770 // Use the current go state
3771 if ((GetGoState() != GO_STATE_READY && (state == GO_ACTIVATED || state == GO_JUST_DEACTIVATED)) || state == GO_READY)
3772 collision = !collision;
3773
3774 EnableCollision(collision);
3775 }
3776}
3777
3779{
3780 // Unlink loot objects from this GameObject before destroying to avoid accessing freed memory from Loot destructor
3781 std::unique_ptr<Loot> loot(std::move(m_loot));
3782 std::unordered_map<ObjectGuid, std::unique_ptr<Loot>> personalLoot(std::move(m_personalLoot));
3783
3784 loot.reset();
3785 personalLoot.clear();
3786 m_unique_users.clear();
3787 m_usetimes = 0;
3788}
3789
3791{
3792 if (m_loot && !m_loot->isLooted())
3793 return false;
3794
3795 for (auto const& [_, loot] : m_personalLoot)
3796 if (!loot->isLooted())
3797 return false;
3798
3799 return true;
3800}
3801
3803{
3804 switch (GetGoType())
3805 {
3807 {
3808 GameObjectTemplate const* goInfo = GetGOInfo();
3809 if (!goInfo->chest.consumable && goInfo->chest.chestPersonalLoot)
3810 {
3812 ? Seconds(goInfo->chest.chestRestockTime)
3813 : Seconds(m_respawnDelayTime)); // not hiding this object permanently to prevent infinite growth of m_perPlayerState
3814 // while also maintaining some sort of cheater protection (not getting rid of entries on logout)
3815 }
3816 break;
3817 }
3819 {
3821
3822 UF::ObjectData::Base objMask;
3825
3826 UpdateData udata(GetMapId());
3827 BuildValuesUpdateForPlayerWithMask(&udata, objMask.GetChangesMask(), goMask.GetChangesMask(), looter);
3828 WorldPacket packet;
3829 udata.BuildPacket(&packet);
3830 looter->SendDirectMessage(&packet);
3831 break;
3832 }
3833 default:
3834 break;
3835 }
3836}
3837
3839{
3840 GOState oldState = GetGoState();
3842 if (AI())
3843 AI()->OnStateChanged(state);
3844
3845 if (m_goTypeImpl)
3846 m_goTypeImpl->OnStateChanged(oldState, state);
3847
3848 if (m_model && !IsTransport())
3849 {
3850 if (!IsInWorld())
3851 return;
3852
3853 // startOpen determines whether we are going to add or remove the LoS on activation
3854 bool collision = false;
3855 if (state == GO_STATE_READY)
3856 collision = !collision;
3857
3858 EnableCollision(collision);
3859 }
3860}
3861
3863{
3864 if (m_perPlayerState)
3866 if (state->State)
3867 return *state->State;
3868
3869 return GetGoState();
3870}
3871
3872void GameObject::SetGoStateFor(GOState state, Player const* viewer)
3873{
3874 PerPlayerState& perPlayerState = GetOrCreatePerPlayerStates()[viewer->GetGUID()];
3876 perPlayerState.State = state;
3877
3879 setStateLocal.ObjectGUID = GetGUID();
3880 setStateLocal.State = state;
3881 viewer->SendDirectMessage(setStateLocal.Write());
3882}
3883
3885{
3887 UpdateModel();
3888}
3889
3891{
3892 switch (GetGoType())
3893 {
3896 {
3897 switch (GetDestructibleState())
3898 {
3900 return modelData->State0NameSet;
3902 return modelData->State1NameSet;
3904 return modelData->State2NameSet;
3906 return modelData->State3NameSet;
3907 default:
3908 break;
3909 }
3910 }
3911 break;
3915 return ((*m_gameObjectData->Flags) >> 8) & 0xF;
3916 default:
3917 break;
3918 }
3919
3920 return 0;
3921}
3922
3924{
3925 if (!m_model)
3926 return;
3927
3928 /*if (enable && !GetMap()->ContainsGameObjectModel(*m_model))
3929 GetMap()->InsertGameObjectModel(*m_model);*/
3930
3931 m_model->enableCollision(enable);
3932}
3933
3935{
3936 if (!IsInWorld())
3937 return;
3938 if (m_model)
3939 if (GetMap()->ContainsGameObjectModel(*m_model))
3942 delete m_model;
3943 m_model = nullptr;
3944 CreateModel();
3945 if (m_model)
3947}
3948
3949bool GameObject::IsLootAllowedFor(Player const* player) const
3950{
3951 if (Loot const* loot = GetLootForPlayer(player)) // check only if loot was already generated
3952 {
3953 if (loot->isLooted()) // nothing to loot or everything looted.
3954 return false;
3955 if (!loot->HasAllowedLooter(GetGUID()) || (!loot->hasItemForAll() && !loot->hasItemFor(player))) // no loot in chest for this player
3956 return false;
3957 }
3958
3959 if (HasLootRecipient())
3960 return m_tapList.find(player->GetGUID()) != m_tapList.end();
3961
3962 return true;
3963}
3964
3966{
3967 if (m_personalLoot.empty())
3968 return m_loot.get();
3969
3970 if (std::unique_ptr<Loot> const* loot = Trinity::Containers::MapGetValuePtr(m_personalLoot, player->GetGUID()))
3971 return loot->get();
3972
3973 return nullptr;
3974}
3975
3977{
3979}
3980
3981void GameObject::BuildValuesCreate(ByteBuffer* data, Player const* target) const
3982{
3984 std::size_t sizePos = data->wpos();
3985 *data << uint32(0);
3986 *data << uint8(flags);
3987 m_objectData->WriteCreate(*data, flags, this, target);
3988 m_gameObjectData->WriteCreate(*data, flags, this, target);
3989 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
3990}
3991
3992void GameObject::BuildValuesUpdate(ByteBuffer* data, Player const* target) const
3993{
3995 std::size_t sizePos = data->wpos();
3996 *data << uint32(0);
3998
4000 m_objectData->WriteUpdate(*data, flags, this, target);
4001
4003 m_gameObjectData->WriteUpdate(*data, flags, this, target);
4004
4005 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
4006}
4007
4009 UF::GameObjectData::Mask const& requestedGameObjectMask, Player const* target) const
4010{
4012 if (requestedObjectMask.IsAnySet())
4013 valuesMask.Set(TYPEID_OBJECT);
4014
4015 if (requestedGameObjectMask.IsAnySet())
4016 valuesMask.Set(TYPEID_GAMEOBJECT);
4017
4018 ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
4019 std::size_t sizePos = buffer.wpos();
4020 buffer << uint32(0);
4021 buffer << uint32(valuesMask.GetBlock(0));
4022
4023 if (valuesMask[TYPEID_OBJECT])
4024 m_objectData->WriteUpdate(buffer, requestedObjectMask, true, this, target);
4025
4026 if (valuesMask[TYPEID_GAMEOBJECT])
4027 m_gameObjectData->WriteUpdate(buffer, requestedGameObjectMask, true, this, target);
4028
4029 buffer.put<uint32>(sizePos, buffer.wpos() - sizePos - 4);
4030
4031 data->AddUpdateBlock();
4032}
4033
4035{
4036 UpdateData udata(Owner->GetMapId());
4037 WorldPacket packet;
4038
4040
4041 udata.BuildPacket(&packet);
4042 player->SendDirectMessage(&packet);
4043}
4044
4046{
4049}
4050
4051std::vector<uint32> const* GameObject::GetPauseTimes() const
4052{
4053 if (GameObjectType::Transport const* transport = dynamic_cast<GameObjectType::Transport const*>(m_goTypeImpl.get()))
4054 return transport->GetPauseTimes();
4055
4056 return nullptr;
4057}
4058
4060{
4062 {
4063 UF::ObjectData::Base dynflagMask;
4065 bool marked = (m_objectData->GetChangesMask() & dynflagMask.GetChangesMask()).IsAnySet();
4066
4067 uint32 dynamicFlags = GetDynamicFlags();
4068 dynamicFlags &= 0xFFFF; // remove high bits
4069 dynamicFlags |= uint32(progress * 65535.0f) << 16;
4070 ReplaceAllDynamicFlags(dynamicFlags);
4071
4072 if (!marked)
4073 const_cast<UF::ObjectData&>(*m_objectData).ClearChanged(&UF::ObjectData::DynamicFlags);
4074 });
4075}
4076
4077void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = nullptr*/) const
4078{
4079 if (m_goData)
4080 {
4081 if (ori)
4082 m_goData->spawnPoint.GetPosition(x, y, z, *ori);
4083 else
4085 }
4086 else
4087 {
4088 if (ori)
4089 GetPosition(x, y, z, *ori);
4090 else
4091 GetPosition(x, y, z);
4092 }
4093}
4094
4096{
4097 switch (GetGoType())
4098 {
4100 return static_cast<GameObjectType::Transport const*>(m_goTypeImpl.get());
4102 return static_cast<Transport const*>(this);
4103 default:
4104 break;
4105 }
4106
4107 return nullptr;
4108}
4109
4111{
4114 if (m_goTypeImpl)
4115 m_goTypeImpl->OnRelocated();
4116
4117 // TODO: on heartbeat
4118 if (m_vignette)
4120
4122}
4123
4125{
4126 if (GetGOInfo()->GetInteractRadiusOverride())
4127 return float(GetGOInfo()->GetInteractRadiusOverride()) / 100.0f;
4128
4129 switch (GetGoType())
4130 {
4132 return 0.0f;
4138 return 5.5555553f;
4140 return 10.0f;
4143 return 3.0f;
4145 return 100.0f;
4147 return 20.0f + CONTACT_DISTANCE; // max spell range
4153 return 5.0f;
4154 // Following values are not blizzlike
4157 // Successful mailbox interaction is rather critical to the client, failing it will start a minute-long cooldown until the next mail query may be executed.
4158 // And since movement info update is not sent with mailbox interaction query, server may find the player outside of interaction range. Thus we increase it.
4159 return 10.0f; // 5.0f is blizzlike
4160 default:
4161 return INTERACTION_DISTANCE;
4162 }
4163}
4164
4166{
4167 if (!m_model)
4168 return;
4169
4170 if (GetMap()->ContainsGameObjectModel(*m_model))
4171 {
4175 }
4176}
4177
4178void GameObject::SetAnimKitId(uint16 animKitId, bool oneshot)
4179{
4180 if (_animKitId == animKitId)
4181 return;
4182
4183 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
4184 return;
4185
4186 if (!oneshot)
4187 _animKitId = animKitId;
4188 else
4189 _animKitId = 0;
4190
4192 activateAnimKit.ObjectGUID = GetGUID();
4193 activateAnimKit.AnimKitID = animKitId;
4194 activateAnimKit.Maintain = !oneshot;
4195 SendMessageToSet(activateAnimKit.Write(), true);
4196}
4197
4199{
4200 if (m_vignette)
4201 {
4202 if (m_vignette->Data->ID == vignetteId)
4203 return;
4204
4206 m_vignette = nullptr;
4207 }
4208
4209 if (VignetteEntry const* vignette = sVignetteStore.LookupEntry(vignetteId))
4210 m_vignette = Vignettes::Create(vignette, this);
4211}
4212
4213void GameObject::SetSpellVisualId(int32 spellVisualId, ObjectGuid activatorGuid)
4214{
4216
4218 packet.ObjectGUID = GetGUID();
4219 packet.ActivatorGUID = activatorGuid;
4220 packet.SpellVisualID = spellVisualId;
4221 SendMessageToSet(packet.Write(), true);
4222}
4223
4225{
4226 if (!CanInteractWithCapturePoint(player))
4227 return;
4228
4229 if (GameObjectAI* ai = AI())
4230 if (ai->OnCapturePointAssaulted(player))
4231 return;
4232
4233 // only supported in battlegrounds
4234 Battleground* battleground = nullptr;
4235 if (BattlegroundMap* map = GetMap()->ToBattlegroundMap())
4236 if (Battleground* bg = map->GetBG())
4237 battleground = bg;
4238
4239 if (!battleground)
4240 return;
4241
4242 // Cancel current timer
4244
4245 if (player->GetBGTeam() == HORDE)
4246 {
4248 {
4249 // defended. capture instantly.
4251 battleground->SendBroadcastText(GetGOInfo()->capturePoint.DefendedBroadcastHorde, CHAT_MSG_BG_SYSTEM_HORDE, player);
4253 if (GetGOInfo()->capturePoint.DefendedEventHorde)
4254 GameEvents::Trigger(GetGOInfo()->capturePoint.DefendedEventHorde, player, this);
4255 return;
4256 }
4257
4259 {
4264 battleground->SendBroadcastText(GetGOInfo()->capturePoint.AssaultBroadcastHorde, CHAT_MSG_BG_SYSTEM_HORDE, player);
4266 if (GetGOInfo()->capturePoint.ContestedEventHorde)
4267 GameEvents::Trigger(GetGOInfo()->capturePoint.ContestedEventHorde, player, this);
4269 break;
4270 default:
4271 break;
4272 }
4273 }
4274 else
4275 {
4277 {
4278 // defended. capture instantly.
4282 if (GetGOInfo()->capturePoint.DefendedEventAlliance)
4283 GameEvents::Trigger(GetGOInfo()->capturePoint.DefendedEventAlliance, player, this);
4284 return;
4285 }
4286
4288 {
4295 if (GetGOInfo()->capturePoint.ContestedEventAlliance)
4296 GameEvents::Trigger(GetGOInfo()->capturePoint.ContestedEventAlliance, player, this);
4298 break;
4299 default:
4300 break;
4301 }
4302 }
4303}
4304
4306{
4308 return;
4309
4310 if (GameObjectAI* ai = AI())
4311 if (ai->OnCapturePointUpdated(m_goValue.CapturePoint.State))
4312 return;
4313
4314 uint32 spellVisualId = 0;
4315 uint32 customAnim = 0;
4316
4318 {
4320 spellVisualId = GetGOInfo()->capturePoint.SpellVisual1;
4321 break;
4323 customAnim = 1;
4324 spellVisualId = GetGOInfo()->capturePoint.SpellVisual2;
4325 break;
4327 customAnim = 2;
4328 spellVisualId = GetGOInfo()->capturePoint.SpellVisual3;
4329 break;
4331 customAnim = 3;
4332 spellVisualId = GetGOInfo()->capturePoint.SpellVisual4;
4333 break;
4335 customAnim = 4;
4336 spellVisualId = GetGOInfo()->capturePoint.SpellVisual5;
4337 break;
4338 default:
4339 break;
4340 }
4341
4342 if (customAnim != 0)
4343 SendCustomAnim(customAnim);
4344
4345 SetSpellVisualId(spellVisualId);
4347
4348 if (BattlegroundMap* map = GetMap()->ToBattlegroundMap())
4349 {
4350 if (Battleground* bg = map->GetBG())
4351 {
4354 packet.CapturePointInfo.Pos = GetPosition();
4355 packet.CapturePointInfo.Guid = GetGUID();
4358 bg->SendPacketToAll(packet.Write());
4359 bg->UpdateWorldState(GetGOInfo()->capturePoint.worldState1, AsUnderlyingType(m_goValue.CapturePoint.State));
4360 }
4361 }
4362
4364}
4365
4367{
4369 return false;
4370
4372 return true;
4373
4374 if (target->GetBGTeam() == HORDE)
4375 {
4378 }
4379
4380 // For Alliance players
4383}
4384
4386{
4388 return FlagState(0);
4389
4390 GameObjectType::NewFlag const* newFlag = dynamic_cast<GameObjectType::NewFlag const*>(m_goTypeImpl.get());
4391 if (!newFlag)
4392 return FlagState(0);
4393
4394 return newFlag->GetState();
4395}
4396
4398{
4400 return ObjectGuid::Empty;
4401
4402 GameObjectType::NewFlag const* newFlag = dynamic_cast<GameObjectType::NewFlag const*>(m_goTypeImpl.get());
4403 if (!newFlag)
4404 return ObjectGuid::Empty;
4405
4406 return newFlag->GetCarrierGUID();
4407}
4408
4410{
4412 return time_t(0);
4413
4414 GameObjectType::NewFlag const* newFlag = dynamic_cast<GameObjectType::NewFlag const*>(m_goTypeImpl.get());
4415 if (!newFlag)
4416 return time_t(0);
4417
4418 return newFlag->GetTakenFromBaseTime();
4419}
4420
4422{
4423 if (GameObjectType::ControlZone const* controlZone = dynamic_cast<GameObjectType::ControlZone const*>(m_goTypeImpl.get()))
4424 return controlZone->GetInsidePlayers();
4425
4426 return nullptr;
4427}
4428
4430{
4431 if (!m_goInfo->GetConditionID1())
4432 return true;
4433
4434 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(m_goInfo->GetConditionID1()))
4435 if (!ConditionMgr::IsPlayerMeetingCondition(user, playerCondition))
4436 return false;
4437
4438 return true;
4439}
4440
4441std::unordered_map<ObjectGuid, GameObject::PerPlayerState>& GameObject::GetOrCreatePerPlayerStates()
4442{
4443 if (!m_perPlayerState)
4444 m_perPlayerState = std::make_unique<std::unordered_map<ObjectGuid, PerPlayerState>>();
4445
4446 return *m_perPlayerState;
4447}
4448
4450{
4451public:
4452 explicit GameObjectModelOwnerImpl(GameObject* owner) : _owner(owner) { }
4453 virtual ~GameObjectModelOwnerImpl() = default;
4454
4455 bool IsSpawned() const override { return _owner->isSpawned(); }
4456 uint32 GetDisplayId() const override { return _owner->GetDisplayId(); }
4457 uint8 GetNameSetId() const override { return _owner->GetNameSetId(); }
4458 bool IsInPhase(PhaseShift const& phaseShift) const override { return _owner->GetPhaseShift().CanSee(phaseShift); }
4459 G3D::Vector3 GetPosition() const override { return G3D::Vector3(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); }
4460 G3D::Quat GetRotation() const override { return G3D::Quat(_owner->GetLocalRotation().x, _owner->GetLocalRotation().y, _owner->GetLocalRotation().z, _owner->GetLocalRotation().w); }
4461 float GetScale() const override { return _owner->GetObjectScale(); }
4462 void DebugVisualizeCorner(G3D::Vector3 const& corner) const override { _owner->SummonCreature(1, corner.x, corner.y, corner.z, 0, TEMPSUMMON_MANUAL_DESPAWN); }
4463
4464private:
4466};
4467
4469{
4472}
4473
4475{
4476 if (m_goTypeImpl)
4477 command.Execute(*m_goTypeImpl);
4478}
4479
4481{
4482 m_model = GameObjectModel::Create(std::make_unique<GameObjectModelOwnerImpl>(this), sWorld->GetDataPath());
4483 if (m_model && m_model->isMapObject())
4485}
4486
4487std::string GameObject::GetDebugInfo() const
4488{
4489 std::stringstream sstr;
4490 sstr << WorldObject::GetDebugInfo() << "\n"
4491 << "SpawnId: " << GetSpawnId() << " GoState: " << std::to_string(GetGoState()) << " ScriptId: " << GetScriptId() << " AIName: " << GetAIName();
4492 return sstr.str();
4493}
4494
4495bool GameObject::IsAtInteractDistance(Player const* player, SpellInfo const* spell) const
4496{
4497 if (spell || (spell = GetSpellForLock(player)))
4498 {
4499 float maxRange = spell->GetMaxRange(spell->IsPositive());
4500
4502 return maxRange * maxRange >= GetExactDistSq(player);
4503
4504 if (sGameObjectDisplayInfoStore.LookupEntry(GetGOInfo()->displayId))
4505 return IsAtInteractDistance(*player, maxRange);
4506 }
4507
4509}
4510
4511bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const
4512{
4513 if (GameObjectDisplayInfoEntry const* displayInfo = sGameObjectDisplayInfoStore.LookupEntry(GetGOInfo()->displayId))
4514 {
4515 float scale = GetObjectScale();
4516
4517 float minX = displayInfo->GeoBoxMin.X * scale - radius;
4518 float minY = displayInfo->GeoBoxMin.Y * scale - radius;
4519 float minZ = displayInfo->GeoBoxMin.Z * scale - radius;
4520 float maxX = displayInfo->GeoBoxMax.X * scale + radius;
4521 float maxY = displayInfo->GeoBoxMax.Y * scale + radius;
4522 float maxZ = displayInfo->GeoBoxMax.Z * scale + radius;
4523
4524 QuaternionData worldRotation = GetWorldRotation();
4525 G3D::Quat worldRotationQuat(worldRotation.x, worldRotation.y, worldRotation.z, worldRotation.w);
4526
4527 return G3D::CoordinateFrame { { worldRotationQuat }, { GetPositionX(), GetPositionY(), GetPositionZ() } }
4528 .toWorldSpace(G3D::Box { { minX, minY, minZ }, { maxX, maxY, maxZ } })
4529 .contains({ pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() });
4530 }
4531
4532 return GetExactDist(&pos) <= radius;
4533}
4534
4535bool GameObject::IsWithinDistInMap(Player const* player) const
4536{
4537 return IsInMap(player) && InSamePhase(player) && IsAtInteractDistance(player);
4538}
4539
4541{
4542 if (!player)
4543 return nullptr;
4544
4545 uint32 lockId = GetGOInfo()->GetLockId();
4546 if (!lockId)
4547 return nullptr;
4548
4549 LockEntry const* lock = sLockStore.LookupEntry(lockId);
4550 if (!lock)
4551 return nullptr;
4552
4553 for (uint8 i = 0; i < MAX_LOCK_CASE; ++i)
4554 {
4555 if (!lock->Type[i])
4556 continue;
4557
4558 if (lock->Type[i] == LOCK_KEY_SPELL)
4559 if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(lock->Index[i], GetMap()->GetDifficultyID()))
4560 return spell;
4561
4562 if (lock->Type[i] != LOCK_KEY_SKILL)
4563 break;
4564
4565 for (auto&& playerSpell : player->GetSpellMap())
4566 if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(playerSpell.first, GetMap()->GetDifficultyID()))
4567 for (auto&& effect : spell->GetEffects())
4568 if (effect.Effect == SPELL_EFFECT_OPEN_LOCK && effect.MiscValue == lock->Index[i])
4569 if (effect.CalcValue(player) >= int32(lock->Skill[i]))
4570 return spell;
4571 }
4572
4573 return nullptr;
4574}
constexpr uint32 ITEM_ID_HEART_OF_AZEROTH
Definition: AzeriteItem.h:23
LocaleConstant
Definition: Common.h:48
@ TOTAL_LOCALES
Definition: Common.h:62
@ LOCALE_enUS
Definition: Common.h:49
#define DEFAULT_LOCALE
Definition: Common.h:66
@ IN_MILLISECONDS
Definition: Common.h:35
@ MINUTE
Definition: Common.h:29
@ WEEK
Definition: Common.h:32
#define M_PI
Definition: Common.h:115
#define sConditionMgr
Definition: ConditionMgr.h:365
DB2Storage< GameObjectDisplayInfoEntry > sGameObjectDisplayInfoStore("GameObjectDisplayInfo.db2", &GameobjectDisplayInfoLoadInfo::Instance)
DB2Storage< AnimKitEntry > sAnimKitStore("AnimKit.db2", &AnimKitLoadInfo::Instance)
DB2Storage< DestructibleModelDataEntry > sDestructibleModelDataStore("DestructibleModelData.db2", &DestructibleModelDataLoadInfo::Instance)
DB2Storage< LockEntry > sLockStore("Lock.db2", &LockLoadInfo::Instance)
DB2Storage< VignetteEntry > sVignetteStore("Vignette.db2", &VignetteLoadInfo::Instance)
DB2Storage< QuestXPEntry > sQuestXPStore("QuestXP.db2", &QuestXpLoadInfo::Instance)
DB2Storage< PlayerConditionEntry > sPlayerConditionStore("PlayerCondition.db2", &PlayerConditionLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:538
#define MAX_LOCK_CASE
ItemContext
Definition: DBCEnums.h:1063
@ CatchFishInFishingHole
SQLTransaction< WorldDatabaseConnection > WorldDatabaseTransaction
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
#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 ASSERT
Definition: Errors.h:68
GameObjectActions
LootState
Definition: GameObject.h:155
@ GO_ACTIVATED
Definition: GameObject.h:158
@ GO_READY
Definition: GameObject.h:157
@ GO_NOT_READY
Definition: GameObject.h:156
@ GO_JUST_DEACTIVATED
Definition: GameObject.h:159
FlagState
Definition: GameObject.h:46
#define FISHING_BOBBER_READY_TIME
Definition: GameObject.h:163
#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
LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true)
std::unordered_map< ObjectGuid, std::unique_ptr< Loot > > GenerateDungeonEncounterPersonalLoot(uint32 dungeonEncounterId, uint32 lootId, LootStore const &store, LootType type, WorldObject const *lootOwner, uint32 minMoney, uint32 maxMoney, uint16 lootMode, MapDifficultyEntry const *mapDifficulty, std::vector< Player * > const &tappers)
Definition: LootMgr.cpp:914
LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true)
@ LOOT_FISHING_JUNK
Definition: Loot.h:113
@ LOOT_CHEST
Definition: Loot.h:108
@ LOOT_FISHING
Definition: Loot.h:103
@ LOOT_FISHINGHOLE
Definition: Loot.h:111
#define sMapMgr
Definition: MapManager.h:184
#define DEFAULT_VISIBILITY_DISTANCE
Definition: ObjectDefines.h:35
@ TEMPSUMMON_MANUAL_DESPAWN
Definition: ObjectDefines.h:70
#define INTERACTION_DISTANCE
Definition: ObjectDefines.h:24
#define CONTACT_DISTANCE
Definition: ObjectDefines.h:23
std::unordered_set< ObjectGuid > GuidUnorderedSet
Definition: ObjectGuid.h:396
@ TYPEID_OBJECT
Definition: ObjectGuid.h:35
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:43
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
@ TYPEMASK_GAMEOBJECT
Definition: ObjectGuid.h:63
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
#define sOutdoorPvPMgr
@ TELE_TO_NOT_LEAVE_COMBAT
Definition: Player.h:804
@ TELE_TO_NOT_UNSUMMON_PET
Definition: Player.h:805
@ TELE_TO_NOT_LEAVE_TRANSPORT
Definition: Player.h:803
#define sPoolMgr
Definition: PoolMgr.h:179
QuestGiverStatus
Definition: QuestDef.h:153
@ QUEST_STATUS_INCOMPLETE
Definition: QuestDef.h:145
int32 irand(int32 min, int32 max)
Definition: Random.cpp:35
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
@ STEALTH_TRAP
#define MAX_GO_STATE_TRANSPORT_STOP_FRAMES
GameobjectTypes
@ GAMEOBJECT_TYPE_GUILD_BANK
@ GAMEOBJECT_TYPE_MINI_GAME
@ GAMEOBJECT_TYPE_CAMERA
@ GAMEOBJECT_TYPE_CAPTURE_POINT
@ GAMEOBJECT_TYPE_BUTTON
@ GAMEOBJECT_TYPE_MAP_OBJECT
@ GAMEOBJECT_TYPE_SPELL_FOCUS
@ GAMEOBJECT_TYPE_TRANSPORT
@ GAMEOBJECT_TYPE_MEETINGSTONE
@ GAMEOBJECT_TYPE_TRAP
@ GAMEOBJECT_TYPE_GENERIC
@ GAMEOBJECT_TYPE_CHEST
@ GAMEOBJECT_TYPE_FISHINGHOLE
@ GAMEOBJECT_TYPE_GARRISON_PLOT
@ GAMEOBJECT_TYPE_CONTROL_ZONE
@ GAMEOBJECT_TYPE_NEW_FLAG_DROP
@ GAMEOBJECT_TYPE_FLAGDROP
@ GAMEOBJECT_TYPE_QUESTGIVER
@ GAMEOBJECT_TYPE_MAILBOX
@ GAMEOBJECT_TYPE_SPELLCASTER
@ GAMEOBJECT_TYPE_FLAGSTAND
@ GAMEOBJECT_TYPE_CHAIR
@ GAMEOBJECT_TYPE_TEXT
@ GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY
@ GAMEOBJECT_TYPE_AREADAMAGE
@ GAMEOBJECT_TYPE_ITEM_FORGE
@ GAMEOBJECT_TYPE_PHASEABLE_MO
@ GAMEOBJECT_TYPE_NEW_FLAG
@ GAMEOBJECT_TYPE_GOOBER
@ GAMEOBJECT_TYPE_FISHINGNODE
@ GAMEOBJECT_TYPE_BARBER_CHAIR
@ GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT
@ GAMEOBJECT_TYPE_DOOR
@ GAMEOBJECT_TYPE_GARRISON_BUILDING
@ GAMEOBJECT_TYPE_RITUAL
@ GAMEOBJECT_TYPE_UI_LINK
@ GAMEOBJECT_TYPE_GATHERING_NODE
@ GAMEOBJECT_TYPE_BINDER
@ GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
@ INVISIBILITY_TRAP
#define MAX_GAMEOBJECT_TYPE
TeamId
@ TEAM_NEUTRAL
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ LOCK_KEY_SKILL
@ LOCK_KEY_SPELL
@ SPELL_EFFECT_OPEN_LOCK
@ ERR_MUST_EQUIP_ARTIFACT
@ GO_DYNFLAG_LO_INVERTED_MOVEMENT
@ GO_DYNFLAG_LO_NO_INTERACT
#define MAX_GAMEOBJECT_DATA
GameObjectDestructibleState
@ GO_DESTRUCTIBLE_DESTROYED
@ GO_DESTRUCTIBLE_REBUILDING
@ GO_DESTRUCTIBLE_INTACT
@ GO_DESTRUCTIBLE_DAMAGED
@ HORDE
@ LOOT_MODE_DEFAULT
Definition: SharedDefines.h:77
@ LOOT_MODE_JUNK_FISH
Definition: SharedDefines.h:82
@ BATTLEGROUND_WS
@ BATTLEGROUND_EY
SpellCastResult
@ SPELL_FAILED_SUCCESS
@ SPELL_CAST_OK
GameObjectFlags
@ GO_FLAG_NODESPAWN
@ GO_FLAG_NOT_SELECTABLE
@ GO_FLAG_IN_MULTI_USE
@ GO_FLAG_MAP_OBJECT
@ GO_FLAG_IN_USE
@ GO_FLAG_DESTROYED
@ GO_FLAG_LOCKED
@ GO_FLAG_DAMAGED
@ CHAT_MSG_BG_SYSTEM_ALLIANCE
@ CHAT_MSG_BG_SYSTEM_HORDE
GOState
@ GO_STATE_TRANSPORT_STOPPED
@ GO_STATE_TRANSPORT_ACTIVE
@ GO_STATE_READY
@ GO_STATE_DESTROYED
@ GO_STATE_ACTIVE
@ SKILL_FISHING
@ SPAWNGROUP_FLAG_COMPATIBILITY_MODE
Definition: SpawnData.h:55
@ LINKED_RESPAWN_CREATURE_TO_GO
Definition: SpawnData.h:123
@ LINKED_RESPAWN_GO_TO_GO
Definition: SpawnData.h:124
@ LINKED_RESPAWN_GO_TO_CREATURE
Definition: SpawnData.h:125
@ SPAWN_TYPE_GAMEOBJECT
Definition: SpawnData.h:35
@ SPELL_AURA_MOD_INVISIBILITY
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_MOD_STEALTH
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
Definition: SpellDefines.h:266
#define sSpellMgr
Definition: SpellMgr.h:849
#define sTransportMgr
Definition: TransportMgr.h:183
UnitStandStateType
Definition: UnitDefines.h:41
@ UNIT_STAND_STATE_SIT_LOW_CHAIR
Definition: UnitDefines.h:46
@ UNIT_STAND_STATE_SIT
Definition: UnitDefines.h:43
@ UNIT_FLAG_IMMUNE
Definition: UnitDefines.h:175
@ CURRENT_CHANNELED_SPELL
Definition: Unit.h:591
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
#define ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE
Definition: Unit.h:37
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
@ WORLD_DEL_EVENT_GAMEOBJECT
Definition: WorldDatabase.h:37
@ WORLD_DEL_SPAWNGROUP_MEMBER
Definition: WorldDatabase.h:84
@ WORLD_DEL_GAMEOBJECT
Definition: WorldDatabase.h:36
@ WORLD_DEL_LINKED_RESPAWN
Definition: WorldDatabase.h:31
@ WORLD_INS_GAMEOBJECT
Definition: WorldDatabase.h:78
@ WORLD_DEL_GAMEOBJECT_ADDON
Definition: WorldDatabase.h:85
@ WORLD_DEL_LINKED_RESPAWN_MASTER
Definition: WorldDatabase.h:32
ObjectGuid GetCastItemGUID() const
Definition: SpellAuras.h:140
virtual void EventPlayerClickedOnFlag(Player *, GameObject *)
Definition: Battleground.h:421
BattlegroundTypeId GetTypeID() const
void SendBroadcastText(uint32 id, ChatMsg msgType, WorldObject const *target=nullptr)
size_t wpos() const
Definition: ByteBuffer.h:412
void put(std::size_t pos, T value)
Definition: ByteBuffer.h:220
static bool IsPlayerMeetingCondition(Player const *player, PlayerConditionEntry const *condition)
static ContentTuningEntry const * GetContentTuningForArea(AreaTableEntry const *areaEntry)
Definition: DB2Stores.cpp:1924
void AddFlag(FLAG_TYPE flag)
Definition: Object.h:442
void AddValue(FLAG_TYPE flag, T_VALUES value)
Definition: Object.h:447
virtual void Damaged(WorldObject *, uint32)
Definition: GameObjectAI.h:95
virtual void OnStateChanged(uint32)
Definition: GameObjectAI.h:104
virtual void InitializeAI()
Definition: GameObjectAI.h:61
virtual void UpdateAI(uint32)
Definition: GameObjectAI.h:59
virtual void Destroyed(WorldObject *, uint32)
Definition: GameObjectAI.h:94
virtual void Reset()
Definition: GameObjectAI.h:63
virtual void OnLootStateChanged(uint32, Unit *)
Definition: GameObjectAI.h:103
float GetScale() const override
uint32 GetDisplayId() const override
bool IsInPhase(PhaseShift const &phaseShift) const override
uint8 GetNameSetId() const override
G3D::Vector3 GetPosition() const override
virtual ~GameObjectModelOwnerImpl()=default
G3D::Quat GetRotation() const override
GameObjectModelOwnerImpl(GameObject *owner)
bool IsSpawned() const override
void DebugVisualizeCorner(G3D::Vector3 const &corner) const override
void enableCollision(bool enable)
static GameObjectModel * Create(std::unique_ptr< GameObjectModelOwnerBase > modelOwner, std::string const &dataPath)
bool isMapObject() const
virtual void Execute(GameObjectTypeBase &type) const =0
GameObject & _owner
Definition: GameObject.h:82
void SetValue(float value)
Definition: GameObject.cpp:634
uint32 GetStartingValue() const
Definition: GameObject.cpp:784
TeamId GetControllingTeam() const
Definition: GameObject.cpp:605
void Update(uint32 diff) override
Definition: GameObject.cpp:592
ControlZone(GameObject &owner)
Definition: GameObject.cpp:578
GuidUnorderedSet const * GetInsidePlayers() const
Definition: GameObject.cpp:616
void SearchTargets(std::vector< Player * > &targetList)
Definition: GameObject.cpp:691
float GetMaxHordeValue() const
Definition: GameObject.cpp:763
float CalculatePointsPerSecond(std::vector< Player * > const &targetList)
Definition: GameObject.cpp:699
GuidUnorderedSet _insidePlayers
Definition: GameObject.cpp:792
void ActivateObject(GameObjectActions action, int32, WorldObject *, uint32, int32) override
Definition: GameObject.cpp:618
void HandleUnitEnterExit(std::vector< Player * > const &newTargetList)
Definition: GameObject.cpp:733
float GetMinAllianceValue() const
Definition: GameObject.cpp:769
void TriggerEvent(uint32 eventId) const
Definition: GameObject.cpp:775
time_t GetTakenFromBaseTime() const
Definition: GameObject.cpp:556
ObjectGuid const & GetCarrierGUID() const
Definition: GameObject.cpp:555
bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects) const override
Definition: GameObject.cpp:549
void Update(uint32 diff) override
Definition: GameObject.cpp:543
FlagState GetState() const
Definition: GameObject.cpp:554
NewFlag(GameObject &owner)
Definition: GameObject.cpp:512
void SetState(FlagState newState, Player *player)
Definition: GameObject.cpp:514
SetControlZoneValue(Optional< uint32 > value={ })
Definition: GameObject.cpp:798
void Execute(GameObjectTypeBase &type) const override
Definition: GameObject.cpp:802
SetNewFlagState(FlagState state, Player *player)
Definition: GameObject.cpp:565
void Execute(GameObjectTypeBase &type) const override
Definition: GameObject.cpp:569
void Execute(GameObjectTypeBase &type) const override
Definition: GameObject.cpp:503
TransportBase * RemovePassenger(WorldObject *passenger) override
Definition: GameObject.cpp:453
std::unordered_set< WorldObject * > _passengers
Definition: GameObject.cpp:496
float GetTransportOrientation() const override
Definition: GameObject.cpp:438
std::vector< uint32 > _stopFrames
Definition: GameObject.cpp:493
TimeTracker _positionUpdateTimer
Definition: GameObject.cpp:495
void OnStateChanged(GOState oldState, GOState newState) override
Definition: GameObject.cpp:348
void CalculatePassengerOffset(float &x, float &y, float &z, float *o) const override
This method transforms supplied global coordinates into local offsets.
Definition: GameObject.cpp:473
Transport(GameObject &owner)
Definition: GameObject.cpp:134
TransportAnimation const * _animationInfo
Definition: GameObject.cpp:489
uint32 GetTransportPeriod() const
Definition: GameObject.cpp:423
void OnRelocated() override
Definition: GameObject.cpp:407
void CalculatePassengerPosition(float &x, float &y, float &z, float *o) const override
This method transforms supplied transport offsets into global coordinates.
Definition: GameObject.cpp:468
void Update(uint32 diff) override
Definition: GameObject.cpp:183
void SetAutoCycleBetweenStopFrames(bool on)
Definition: GameObject.cpp:483
int32 GetMapIdForSpawning() const override
Definition: GameObject.cpp:478
std::vector< uint32 > const * GetPauseTimes() const
Definition: GameObject.cpp:431
void AddPassenger(WorldObject *passenger) override
Definition: GameObject.cpp:440
static constexpr Milliseconds PositionUpdateInterval
Definition: GameObject.cpp:132
ObjectGuid GetTransportGUID() const override
Definition: GameObject.cpp:436
void SetLocalRotationAngles(float z_rot, float y_rot, float x_rot)
void UpdateCapturePoint()
void BuildValuesUpdateForPlayerWithMask(UpdateData *data, UF::ObjectData::Mask const &requestedObjectMask, UF::GameObjectData::Mask const &requestedGameObjectMask, Player const *target) const
bool HasStringId(std::string_view id) const
void GetRespawnPosition(float &x, float &y, float &z, float *ori=nullptr) const
void SetGoState(GOState state)
ObjectGuid GetOwnerGUID() const override
Definition: GameObject.h:242
bool IsWithinDistInMap(Player const *player) const
void UseDoorOrButton(uint32 time_to_restore=0, bool alternative=false, Unit *user=nullptr)
GameObjectValue m_goValue
Definition: GameObject.h:483
GOState GetGoStateFor(ObjectGuid const &viewer) const
GameObjectTemplate const * GetGOInfo() const
Definition: GameObject.h:202
void UpdateDynamicFlagsForNearbyPlayers()
void CreateModel()
GOState GetGoState() const
Definition: GameObject.h:281
bool MeetsInteractCondition(Player const *user) const
time_t m_respawnTime
Definition: GameObject.h:457
bool IsInvisibleDueToDespawn(WorldObject const *seer) const override
void ClearLoot()
std::string GetDebugInfo() const override
time_t m_cooldownTime
Definition: GameObject.h:465
std::unordered_map< ObjectGuid, PerPlayerState > & GetOrCreatePerPlayerStates()
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool=true)
void AddUse()
Definition: GameObject.h:320
void RemoveFlag(GameObjectFlags flags)
Definition: GameObject.h:275
uint32 GetGoArtKit() const
Definition: GameObject.h:285
bool hasInvolvedQuest(uint32 quest_id) const override
ObjectGuid const & GetFlagCarrierGUID() const
bool HasFlag(GameObjectFlags flags) const
Definition: GameObject.h:273
void SetSpellVisualId(int32 spellVisualId, ObjectGuid activatorGuid=ObjectGuid::Empty)
GameObjectData const * m_goData
Definition: GameObject.h:481
LootState getLootState() const
Definition: GameObject.h:298
uint32 GetSpellId() const
Definition: GameObject.h:249
uint8 GetGoAnimProgress() const
Definition: GameObject.h:287
int64 m_packedRotation
Definition: GameObject.h:487
Position m_stationaryPosition
Definition: GameObject.h:489
bool IsFullyLooted() const
void Delete()
QuaternionData const & GetLocalRotation() const
Definition: GameObject.h:218
time_t m_restockTime
Definition: GameObject.h:464
uint32 GetUniqueUseCount() const
Definition: GameObject.h:323
void ReplaceAllFlags(GameObjectFlags flags)
Definition: GameObject.h:276
void RemoveFromWorld() override
Definition: GameObject.cpp:931
void EnableCollision(bool enable)
std::unordered_map< ObjectGuid, std::unique_ptr< Loot > > m_personalLoot
Definition: GameObject.h:328
void SetGoAnimProgress(uint8 animprogress)
Definition: GameObject.h:288
ObjectGuid m_lootStateUnitGUID
Definition: GameObject.h:462
static GameObject * CreateGameObject(uint32 entry, Map *map, Position const &pos, QuaternionData const &rotation, uint32 animProgress, GOState goState, uint32 artKit=0)
uint8 GetLevelForTarget(WorldObject const *target) const override
bool IsAtInteractDistance(Position const &pos, float radius) const
bool isSpawned() const
Definition: GameObject.h:256
void SetOwnerGUID(ObjectGuid owner)
Definition: GameObject.h:232
void SetVignette(uint32 vignetteId)
void DespawnOrUnsummon(Milliseconds delay=0ms, Seconds forceRespawnTime=0s)
void SetDestructibleState(GameObjectDestructibleState state, WorldObject *attackerOrHealer=nullptr, bool setHealth=false)
ChairSlotAndUser ChairListSlots
Definition: GameObject.h:476
void HandleCustomTypeCommand(GameObjectTypeBase::CustomCommand const &command) const
void SetScriptStringId(std::string id)
time_t GetFlagTakenFromBaseTime() const
bool ActivateToQuest(Player const *target) const
void OnLootRelease(Player *looter)
void SetFlag(GameObjectFlags flags)
Definition: GameObject.h:274
Loot * GetFishLootJunk(Player *lootOwner)
uint32 m_spellId
Definition: GameObject.h:456
bool IsAlwaysVisibleFor(WorldObject const *seer) const override
void SetWorldEffectID(uint32 worldEffectID)
Definition: GameObject.h:425
bool HasLootRecipient() const
Definition: GameObject.h:333
void SetLootState(LootState s, Unit *unit=nullptr)
static GameObject * CreateGameObjectFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap=true)
uint32 m_respawnDelayTime
Definition: GameObject.h:458
SpellInfo const * GetSpellForLock(Player const *player) const
GameObjectAI * AI() const
Definition: GameObject.h:378
void ResetLootMode()
Definition: GameObject.h:307
GuidSet m_unique_users
Definition: GameObject.h:472
GameObject * GetLinkedTrap()
GuidUnorderedSet const * GetInsidePlayers() const
std::unique_ptr< Vignettes::VignetteData > m_vignette
Definition: GameObject.h:513
bool IsInRange(float x, float y, float z, float radius) const
void SetRespawnTime(int32 respawn)
void TriggeringLinkedGameObject(uint32 trapEntry, Unit *target)
void SetRespawnCompatibilityMode(bool mode=true)
Definition: GameObject.h:373
GameobjectTypes GetGoType() const
Definition: GameObject.h:279
void SendGameObjectDespawn()
void SetGoType(GameobjectTypes type)
Definition: GameObject.h:280
uint32 m_despawnDelay
Definition: GameObject.h:459
Seconds m_despawnRespawnTime
Definition: GameObject.h:460
QuaternionData m_localRotation
Definition: GameObject.h:488
void SetLinkedTrap(GameObject *linkedTrap)
Definition: GameObject.h:337
void SetLocalRotation(float qx, float qy, float qz, float qw)
std::string GetNameForLocaleIdx(LocaleConstant locale) const override
GameObjectData const * GetGameObjectData() const
Definition: GameObject.h:205
bool m_respawnCompatibilityMode
Definition: GameObject.h:509
GameObjectTemplateAddon const * m_goTemplateAddon
Definition: GameObject.h:480
ObjectGuid::LowType GetSpawnId() const
Definition: GameObject.h:212
void Respawn()
bool AIM_Initialize()
Definition: GameObject.cpp:858
void SaveRespawnTime(uint32 forceDelay=0)
float GetInteractionDistance() const
void RemoveFromOwner()
Definition: GameObject.cpp:885
Loot * GetFishLoot(Player *lootOwner)
void SendCustomAnim(uint32 anim)
void Refresh()
time_t GetRespawnTimeEx() const
bool hasQuest(uint32 quest_id) const override
FlagState GetFlagState() const
GuidUnorderedSet m_tapList
Definition: GameObject.h:491
GameObjectAI * m_AI
Definition: GameObject.h:508
uint32 GetDisplayId() const
Definition: GameObject.h:385
GameObjectModel * m_model
Definition: GameObject.h:391
void ResetDoorOrButton()
std::unique_ptr< Loot > m_loot
Definition: GameObject.h:327
void SetLevel(uint32 level)
Definition: GameObject.h:278
UF::UpdateField< UF::GameObjectData, 0, TYPEID_GAMEOBJECT > m_gameObjectData
Definition: GameObject.h:451
uint32 GetScriptId() const
bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects=false) const override
uint8 GetNameSetId() const
bool CanInteractWithCapturePoint(Player const *target) const
Optional< std::string > m_scriptStringId
Definition: GameObject.h:485
void UpdateModelPosition()
void AfterRelocation()
void AIM_Destroy()
Definition: GameObject.cpp:852
void SetPathProgressForClient(float progress)
GameObjectTemplateAddon const * GetTemplateAddon() const
Definition: GameObject.h:203
void ModifyHealth(int32 change, WorldObject *attackerOrHealer=nullptr, uint32 spellId=0)
void DespawnForPlayer(Player *seer, Seconds respawnTime)
GameObject * LookupFishingHoleAround(float range)
uint16 _animKitId
Definition: GameObject.h:510
void SetDisplayId(uint32 displayid)
GameObjectTemplate const * m_goInfo
Definition: GameObject.h:479
GuidUnorderedSet const & GetTapList() const
Definition: GameObject.h:330
ObjectGuid::LowType m_spawnId
For new or temporary gameobjects is 0 for saved it is lowguid.
Definition: GameObject.h:478
void ClearUpdateMask(bool remove) override
void UpdateModel()
void Use(Unit *user)
void ActivateObject(GameObjectActions action, int32 param, WorldObject *spellCaster=nullptr, uint32 spellId=0, int32 effectIndex=-1)
ObjectGuid m_linkedTrap
Definition: GameObject.h:494
bool IsDynTransport() const
Position const & GetStationaryPosition() const
Definition: GameObject.h:404
void SwitchDoorOrButton(bool activate, bool alternative=false)
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition: GameObject.cpp:876
bool IsDestructibleBuilding() const
void SaveToDB()
Loot * GetLootForPlayer(Player const *) const override
uint16 GetLootMode() const
Definition: GameObject.h:302
TransportBase * ToTransportBase()
Definition: GameObject.h:394
void SetGoStateFor(GOState state, Player const *viewer)
QuaternionData GetWorldRotation() const
void AssaultCapturePoint(Player *player)
void SetAnimKitId(uint16 animKitId, bool oneshot)
std::array< std::string_view, 3 > m_stringIds
Definition: GameObject.h:484
static bool DeleteFromDB(ObjectGuid::LowType spawnId)
void BuildValuesCreate(ByteBuffer *data, Player const *target) const override
void UpdatePackedRotation()
Transport * ToTransport()
Definition: GameObject.h:397
bool m_spawnedByDefault
Definition: GameObject.h:463
void SetGoArtKit(uint32 artkit)
void AddToWorld() override
Definition: GameObject.cpp:904
bool Create(uint32 entry, Map *map, Position const &pos, QuaternionData const &rotation, uint32 animProgress, GOState goState, uint32 artKit, bool dynamic, ObjectGuid::LowType spawnid)
Definition: GameObject.cpp:956
GameObjectDestructibleState GetDestructibleState() const
Definition: GameObject.h:363
std::unique_ptr< std::unordered_map< ObjectGuid, PerPlayerState > > m_perPlayerState
Definition: GameObject.h:522
void Update(uint32 p_time) override
bool IsLootAllowedFor(Player const *player) const
LootState m_lootState
Definition: GameObject.h:461
void AddUniqueUse(Player *player)
void BuildValuesUpdate(ByteBuffer *data, Player const *target) const override
std::string const & GetAIName() const
Definition: GameObject.cpp:871
GameObjectOverride const * GetGameObjectOverride() const
void SetParentRotation(QuaternionData const &rotation)
std::unique_ptr< GameObjectTypeBase > m_goTypeImpl
Definition: GameObject.h:482
ObjectGuid m_ritualOwnerGUID
Definition: GameObject.h:471
uint32 m_usetimes
Definition: GameObject.h:473
void SetSpellId(uint32 id)
Definition: GameObject.h:244
GOState m_prevGoState
Definition: GameObject.h:467
std::vector< uint32 > const * GetPauseTimes() const
bool IsTransport() const
void SetFaction(uint32 faction) override
Definition: GameObject.h:389
GuidSet m_SkillupList
Definition: GameObject.h:469
GroupReference * next()
Definition: Group.h:197
Definition: Item.h:170
bool HaveQuestLootForPlayer(uint32 loot_id, Player const *player) const
Definition: LootMgr.cpp:209
Definition: Map.h:189
void GameObjectRelocation(GameObject *go, float x, float y, float z, float orientation, bool respawnRelocationOnFail=true)
Definition: Map.cpp:1112
void UpdateSpawnGroupConditions()
Definition: Map.cpp:2504
MapStoredObjectTypesContainer & GetObjectsStore()
Definition: Map.h:422
void RemoveGameObjectModel(GameObjectModel const &model)
Definition: Map.h:462
bool AddToMap(T *)
Definition: Map.cpp:550
time_t GetLinkedRespawnTime(ObjectGuid guid) const
Definition: Map.cpp:3642
void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, CharacterDatabaseTransaction dbTrans=nullptr, bool alwaysDeleteFromDB=false)
Definition: Map.h:687
void ApplyDynamicModeRespawnScaling(WorldObject const *obj, ObjectGuid::LowType spawnId, uint32 &respawnDelay, uint32 mode) const
Definition: Map.cpp:2275
ObjectGuid::LowType GenerateLowGuid()
Definition: Map.h:519
time_t GetGORespawnTime(ObjectGuid::LowType spawnId) const
Definition: Map.h:486
void SaveRespawnInfoDB(RespawnInfo const &info, CharacterDatabaseTransaction dbTrans=nullptr)
Definition: Map.cpp:3584
void SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, CharacterDatabaseTransaction dbTrans=nullptr, bool startup=false)
Definition: Map.cpp:3551
GameObjectBySpawnIdContainer & GetGameObjectBySpawnIdStore()
Definition: Map.h:429
void InsertGameObjectModel(GameObjectModel const &model)
Definition: Map.h:463
bool Instanceable() const
Definition: Map.cpp:3233
uint32 GetId() const
Definition: Map.cpp:3228
SpawnedPoolData & GetPoolData()
Definition: Map.h:715
void Respawn(RespawnInfo *info, CharacterDatabaseTransaction dbTrans=nullptr)
Definition: Map.cpp:2058
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
std::string ToString() const
Definition: ObjectGuid.cpp:554
uint64 LowType
Definition: ObjectGuid.h:278
void Clear()
Definition: ObjectGuid.h:286
static std::string_view GetLocaleString(std::vector< std::string > const &data, LocaleConstant locale)
Definition: ObjectMgr.h:1682
void SetDynamicFlag(uint32 flag)
Definition: Object.h:169
uint16 m_objectType
Definition: Object.h:401
float GetObjectScale() const
Definition: Object.h:164
static Unit * ToUnit(Object *o)
Definition: Object.h:225
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
void AddToObjectUpdateIfNeeded()
Definition: Object.cpp:784
bool HasDynamicFlag(uint32 flag) const
Definition: Object.h:168
TypeID GetTypeId() const
Definition: Object.h:173
CreateObjectBits m_updateFlag
Definition: Object.h:404
virtual void ClearUpdateMask(bool remove)
Definition: Object.cpp:790
void SetUpdateFieldValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type value)
Definition: Object.h:287
void ReplaceAllDynamicFlags(uint32 flag)
Definition: Object.h:171
uint32 GetEntry() const
Definition: Object.h:161
uint32 GetDynamicFlags() const
Definition: Object.h:167
UF::UpdateFieldHolder m_values
Definition: Object.h:266
void RemoveDynamicFlag(uint32 flag)
Definition: Object.h:170
void _Create(ObjectGuid const &guid)
Definition: Object.cpp:101
ByteBuffer & PrepareValuesUpdateBuffer(UpdateData *data) const
Definition: Object.cpp:225
void DoWithSuppressingObjectUpdates(Action &&action)
Definition: Object.h:381
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void SetEntry(uint32 entry)
Definition: Object.h:162
virtual void SetObjectScale(float scale)
Definition: Object.h:165
void SendUpdateToPlayer(Player *player)
Definition: Object.cpp:183
virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const
Definition: Object.cpp:770
TypeID m_objectTypeId
Definition: Object.h:403
static Player * ToPlayer(Object *o)
Definition: Object.h:213
static void InitDbVisibleMapId(PhaseShift &phaseShift, int32 visibleMapId)
static void InitDbPhaseShift(PhaseShift &phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId)
bool IsInSameRaidWith(Player const *p) const
Definition: Player.cpp:2160
UF::UpdateField< UF::PlayerData, 0, TYPEID_PLAYER > m_playerData
Definition: Player.h:2863
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
uint16 GetSkillValue(uint32 skill) const
Definition: Player.cpp:6052
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={})
Definition: Player.cpp:1250
bool CanUseBattlegroundObject(GameObject *gameobject) const
Definition: Player.cpp:26192
void GiveXP(uint32 xp, Unit *victim, float group_rate=1.0f)
Definition: Player.cpp:2210
Item * GetItemByEntry(uint32 entry, ItemSearchLocation where=ItemSearchLocation::Default) const
Definition: Player.cpp:12589
void SendPreparedGossip(WorldObject *source)
Definition: Player.cpp:14137
void UpdateVisibilityOf(WorldObject *target)
Definition: Player.cpp:23902
PlayerSpellMap const & GetSpellMap() const
Definition: Player.h:1901
void SendLoot(Loot &loot, bool aeLooting=false)
Definition: Player.cpp:9119
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
bool HasQuestForGO(int32 goId) const
Definition: Player.cpp:25184
Battleground * GetBattleground() const
Definition: Player.cpp:24976
void SendCinematicStart(uint32 CinematicSequenceId) const
Definition: Player.cpp:6329
uint32 GetProfessionSkillForExp(uint32 skill, int32 expansion) const
Definition: Player.cpp:6005
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition: Player.cpp:16050
void KillCreditGO(uint32 entry, ObjectGuid guid=ObjectGuid::Empty)
Definition: Player.cpp:16704
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
void PrepareGossipMenu(WorldObject *source, uint32 menuId, bool showQuests=false)
Definition: Player.cpp:14036
bool UpdateFishingSkill(int32 expansion)
Definition: Player.cpp:5634
Item * GetItemByGuid(ObjectGuid guid) const
Definition: Player.cpp:9566
Team GetBGTeam() const
Definition: Player.cpp:23609
void setInt32(const uint8 index, const int32 value)
void setFloat(const uint8 index, const float value)
void setUInt8(const uint8 index, const uint8 value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt16(const uint8 index, const uint16 value)
void setString(const uint8 index, const std::string &value)
void setUInt64(const uint8 index, const uint64 value)
static uint32 RoundXPValue(uint32 xp)
Definition: QuestDef.cpp:769
float GetMaxRange(bool positive=false, WorldObject *caster=nullptr, Spell *spell=nullptr) const
Definition: SpellInfo.cpp:3768
uint32 const Id
Definition: SpellInfo.h:325
bool IsPositive() const
Definition: SpellInfo.cpp:1709
virtual void CalculatePassengerPosition(float &x, float &y, float &z, float *o=nullptr) const =0
This method transforms supplied transport offsets into global coordinates.
void UpdatePassengerPosition(Map *map, WorldObject *passenger, float x, float y, float z, float o, bool setHomePosition)
Definition: Transport.cpp:39
virtual void CalculatePassengerOffset(float &x, float &y, float &z, float *o=nullptr) const =0
This method transforms supplied global coordinates into local offsets.
bool Remove(KEY_TYPE const &handle)
bool Insert(KEY_TYPE const &handle, SPECIFIC_TYPE *obj)
void ClearChanged(UpdateField< T, BlockBit, Bit >(Derived::*))
Definition: UpdateField.h:572
Mask const & GetChangesMask() const
Definition: UpdateField.h:605
void MarkChanged(UpdateField< T, BlockBit, Bit >(Derived::*))
Definition: UpdateField.h:527
MutableFieldReference< T, false > ModifyValue(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UpdateField.h:683
void ClearChangesMask(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UpdateField.h:690
bool HasChanged(uint32 index) const
Definition: UpdateField.h:701
uint32 GetChangedObjectTypeMask() const
Definition: UpdateField.h:696
Definition: Unit.h:627
Vehicle * GetVehicle() const
Definition: Unit.h:1713
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3812
void RemoveGameObject(GameObject *gameObj, bool del)
Definition: Unit.cpp:5238
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition: Unit.cpp:10100
void FinishSpell(CurrentSpellTypes spellType, SpellCastResult result=SPELL_CAST_OK)
Definition: Unit.cpp:3047
bool IsAlive() const
Definition: Unit.h:1164
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4560
void NearTeleportTo(Position const &pos, bool casting=false)
Definition: Unit.cpp:12327
ObjectGuid GetTarget() const
Definition: Unit.h:1759
uint8 GetLevel() const
Definition: Unit.h:746
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition: Unit.h:1442
bool BuildPacket(WorldPacket *packet)
Definition: UpdateData.cpp:40
void AddUpdateBlock()
Definition: UpdateData.h:49
uint32 GetBlock(uint32 index) const
Definition: UpdateMask.h:53
void Set(uint32 index)
Definition: UpdateMask.h:84
constexpr uint32 GetMapId() const
Definition: Position.h:201
bool InSamePhase(PhaseShift const &phaseShift) const
Definition: Object.h:527
virtual bool IsInvisibleDueToDespawn(WorldObject const *seer) const
Definition: Object.h:823
bool IsWithinDist3d(float x, float y, float z, float dist) const
Definition: Object.cpp:1122
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition: Object.cpp:1744
Map * GetMap() const
Definition: Object.h:624
void AddToWorld() override
Definition: Object.cpp:1011
virtual bool IsAlwaysVisibleFor(WorldObject const *seer) const
Definition: Object.h:822
void RemoveFromWorld() override
Definition: Object.cpp:1017
virtual void UpdateObjectVisibilityOnDestroy()
Definition: Object.h:724
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
std::string GetDebugInfo() const override
Definition: Object.cpp:3785
uint32 LastUsedScriptID
Definition: Object.h:747
PhaseShift & GetPhaseShift()
Definition: Object.h:523
Unit * GetOwner() const
Definition: Object.cpp:2229
FlaggedValuesArray32< int32, uint64, InvisibilityType, TOTAL_INVISIBILITY_TYPES > m_invisibility
Definition: Object.h:616
ZoneScript * GetZoneScript() const
Definition: Object.h:630
void SetZoneScript()
Definition: Object.cpp:2011
TransportBase * GetTransport() const
Definition: Object.h:750
void setActive(bool isActiveObject)
Definition: Object.cpp:922
float GetDistance2d(WorldObject const *obj) const
Definition: Object.cpp:1096
ZoneScript * m_zoneScript
Definition: Object.h:800
std::string const & GetName() const
Definition: Object.h:555
virtual void SetMap(Map *map)
Definition: Object.cpp:1794
void AddObjectToRemoveList()
Definition: Object.cpp:1824
void UpdatePositionData()
Definition: Object.cpp:992
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition: Object.cpp:2252
void SetName(std::string newname)
Definition: Object.h:556
FlaggedValuesArray32< int32, uint32, StealthType, TOTAL_STEALTH_TYPES > m_stealth
Definition: Object.h:613
uint32 GetAreaId() const
Definition: Object.h:546
void SetVisibilityDistanceOverride(VisibilityDistanceType type)
Definition: Object.cpp:945
MovementInfo m_movementInfo
Definition: Object.h:761
virtual bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects=false) const
Definition: Object.h:821
bool IsFriendlyTo(WorldObject const *target) const
Definition: Object.cpp:2865
bool IsInMap(WorldObject const *obj) const
Definition: Object.cpp:1115
virtual void Update(uint32 diff)
Definition: Object.cpp:898
int32 GetDBPhase() const
Definition: Object.h:540
virtual void UpdateObjectVisibility(bool forced=true)
Definition: Object.cpp:3650
virtual void CleanupsBeforeDelete(bool finalCleanup=true)
Definition: Object.cpp:981
void SetTransport(TransportBase *t)
Definition: Object.h:759
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket && Move()
Definition: Packet.h:54
virtual uint32 GetGameObjectEntry(ObjectGuid::LowType, uint32 entry)
Definition: ZoneScript.h:69
virtual void OnGameObjectRemove(GameObject *)
Definition: ZoneScript.h:75
virtual void OnGameObjectCreate(GameObject *)
Definition: ZoneScript.h:74
#define sWorld
Definition: World.h:931
@ CONFIG_RESPAWN_DYNAMICMODE
Definition: World.h:430
ObjectData const gameObjectData[]
TC_GAME_API uint32 GetId(std::string_view username)
GameObjectAI * SelectGameObjectAI(GameObject *go)
TC_GAME_API void Trigger(uint32 gameEventId, WorldObject *source, WorldObject *target)
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
Definition: GameTime.cpp:54
time_t GetGameTime()
Definition: GameTime.cpp:44
uint32 GetGameTimeMS()
Definition: GameTime.cpp:49
ItemContext GetContextForPlayer(MapDifficultyEntry const *mapDifficulty, Player const *player)
Definition: wmo.h:163
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API GameObject * GetGameObject(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition: Containers.h:109
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition: MapUtils.h:29
void MultimapErasePair(M< K, V, Rest... > &multimap, K const &key, V const &value)
Definition: MapUtils.h:39
GridCoord ComputeGridCoord(float x, float y)
Definition: GridDefines.h:194
UpdateFieldFlag
Definition: UpdateField.h:34
std::unique_ptr< VignetteData > Create(VignetteEntry const *vignetteData, WorldObject const *owner)
Definition: Vignette.cpp:72
void Update(VignetteData &vignette, WorldObject const *owner)
Definition: Vignette.cpp:90
void Remove(VignetteData &vignette, WorldObject const *owner)
Definition: Vignette.cpp:100
CastSpellExtraArgs & SetOriginalCaster(ObjectGuid const &guid)
Definition: SpellDefines.h:471
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:203
static void VisitGridObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:179
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:191
bool Rotation
Definition: Object.h:93
bool Stationary
Definition: Object.h:88
bool GameObject
Definition: Object.h:95
bool ServerTime
Definition: Object.h:90
QuaternionData ParentRotation
InvisibilityType invisibilityType
QuaternionData rotation
std::array< uint32, 5 > ArtKits
struct GameObjectTemplate::@213::@278 raw
std::string StringId
uint32 GetAutoCloseTime() const
struct GameObjectTemplate::@213::@262 itemForge
struct GameObjectTemplate::@213::@248 destructibleBuilding
struct GameObjectTemplate::@213::@241 flagDrop
struct GameObjectTemplate::@213::@218 chest
WorldPacket QueryData[TOTAL_LOCALES]
bool IsLargeGameObject() const
bool IsUsableMounted() const
uint32 GetNoDamageImmune() const
struct GameObjectTemplate::@213::@237 spellCaster
bool IsGiganticGameObject() const
WorldPacket BuildQueryData(LocaleConstant loc) const
Definition: GameObject.cpp:69
void InitializeQueryData()
Definition: GameObject.cpp:63
struct GameObjectTemplate::@213::@265 gatheringNode
bool IsInfiniteGameObject() const
bool IsDespawnAtAction() const
struct GameObjectTemplate::@213::@257 capturePoint
struct GameObjectTemplate::@213::@226 transport
struct GameObjectTemplate::@213::@251 newflag
uint32 GetCharges() const
struct GameObjectTemplate::@213::@233 ritual
uint32 CaptureBroadcastAlliance
uint32 DefendedBroadcastAlliance
struct GameObjectTemplate::@213::@244 controlZone
struct GameObjectTemplate::@213::@247 barberChair
uint32 casterTargetSpellTargets
std::string castBarCaption
struct GameObjectTemplate::@213::@225 goober
struct GameObjectTemplate::@213::@258 phaseableMO
struct GameObjectTemplate::@213::@220 generic
uint32 AssaultBroadcastAlliance
uint32 GetLockId() const
std::string IconName
struct GameObjectTemplate::@213::@222 chair
struct GameObjectTemplate::@213::@221 trap
uint32 GetConditionID1() const
uint32 GetLootId() const
SystemTimePoint ValidUntil
Definition: GameObject.h:517
Optional< GOState > State
Definition: GameObject.h:518
void operator()(Player const *player) const
std::array< uint8, MAX_LOCK_CASE > Type
std::array< uint16, MAX_LOCK_CASE > Skill
std::array< int32, MAX_LOCK_CASE > Index
Definition: Loot.h:281
bool AutoStore(Player *player, uint8 bag, uint8 slot, bool broadcast=false, bool createdByPlayer=false)
Definition: Loot.cpp:849
bool isLooted() const
Definition: Loot.h:307
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
Definition: Loot.cpp:745
void SetDungeonEncounterId(uint32 dungeonEncounterId)
Definition: Loot.h:305
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT, ItemContext context=ItemContext::NONE)
Definition: Loot.cpp:759
struct MovementInfo::TransportInfo transport
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
std::string ToString() const
Definition: Position.cpp:128
float GetExactDist(float x, float y, float z) const
Definition: Position.h:118
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
bool IsPositionValid() const
Definition: Position.cpp:42
constexpr void Relocate(float x, float y)
Definition: Position.h:63
constexpr float GetExactDistSq(float x, float y, float z) const
Definition: Position.h:110
constexpr Position GetPosition() const
Definition: Position.h:84
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
void toEulerAnglesZYX(float &Z, float &Y, float &X) const
Definition: GameObject.cpp:113
bool isUnit() const
Definition: GameObject.cpp:108
static QuaternionData fromEulerAnglesZYX(float Z, float Y, float X)
Definition: GameObject.cpp:118
ObjectGuid::LowType spawnId
Definition: Map.h:168
time_t respawnTime
Definition: Map.h:170
SpawnObjectType type
Definition: Map.h:167
uint8 phaseUseFlags
Definition: SpawnData.h:106
uint32 id
Definition: SpawnData.h:104
uint32 phaseId
Definition: SpawnData.h:107
Position spawnPoint
Definition: SpawnData.h:105
int32 spawntimesecs
Definition: SpawnData.h:111
int32 terrainSwapMap
Definition: SpawnData.h:109
uint32 phaseGroup
Definition: SpawnData.h:108
uint32 poolId
Definition: SpawnData.h:110
std::string StringId
Definition: SpawnData.h:114
std::vector< Difficulty > spawnDifficulties
Definition: SpawnData.h:112
SpawnGroupFlags flags
Definition: SpawnData.h:70
SpawnGroupTemplateData const * spawnGroupData
Definition: SpawnData.h:96
uint64 spawnId
Definition: SpawnData.h:93
uint32 mapId
Definition: SpawnData.h:94
void Update(int32 diff)
Definition: Timer.h:121
bool Passed() const
Definition: Timer.h:131
void Reset(int32 expiry)
Definition: Timer.h:136
TransportRotationEntry const * GetNextAnimRotation(uint32 time) const
TransportAnimationEntry const * GetNextAnimNode(uint32 time) const
TransportAnimationEntry const * GetPrevAnimNode(uint32 time) const
TransportRotationEntry const * GetPrevAnimRotation(uint32 time) const
std::array< float, 4 > Rot
UpdateField< int32, 0, 4 > DisplayID
UpdateField< QuaternionData, 0, 13 > ParentRotation
UpdateField< uint32, 0, 7 > SpawnTrackingStateAnimID
UpdateField< uint32, 0, 18 > ArtKit
UpdateField< uint32, 0, 5 > SpellVisualID
UpdateField< int8, 0, 15 > State
UpdateField< uint32, 0, 2 > DynamicFlags
Definition: UpdateFields.h:53
std::array< uint32, MAX_GAMEOBJECT_DATA > Data
Definition: QueryPackets.h:237
TeamId LastTeamCapture
Definition: GameObject.h:144
uint32 AssaultTimer
Definition: GameObject.h:146
struct GameObjectValue::@211 Building
struct GameObjectValue::@212 CapturePoint
struct GameObjectValue::@209 FishingHole
WorldPackets::Battleground::BattlegroundCapturePointState State
Definition: GameObject.h:145
uint32 MaxHealth
Definition: GameObject.h:139