aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.cpp2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp6
-rw-r--r--src/server/game/Entities/DynamicObject/DynamicObject.cpp2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp560
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h63
-rw-r--r--src/server/game/Entities/GameObject/GameObjectData.h1
-rw-r--r--src/server/game/Entities/Object/Object.cpp48
-rw-r--r--src/server/game/Entities/Object/Object.h10
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateFields.cpp8
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateFields.h2
-rw-r--r--src/server/game/Entities/Object/Updates/ViewerDependentValues.h43
-rw-r--r--src/server/game/Entities/Player/Player.cpp25
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp23
-rw-r--r--src/server/game/Entities/Transport/Transport.h19
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp4
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.cpp10
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.h13
-rw-r--r--src/server/game/Entities/Vehicle/VehicleDefines.h10
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.cpp5
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp24
-rw-r--r--src/server/game/Maps/Map.cpp12
-rw-r--r--src/server/game/Maps/TransportMgr.cpp47
-rw-r--r--src/server/game/Maps/TransportMgr.h12
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h2
-rw-r--r--src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp4
-rw-r--r--src/server/game/Movement/Spline/MoveSplineInit.cpp4
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp2
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp2
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp38
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/go_icecrown_citadel_teleport.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp10
33 files changed, 707 insertions, 310 deletions
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
index 5d10f1ab305..6d01620661a 100644
--- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
+++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
@@ -189,7 +189,7 @@ bool AreaTrigger::Create(uint32 areaTriggerCreatePropertiesId, Unit* caster, Uni
}
// movement on transport of areatriggers on unit is handled by themself
- Transport* transport = m_movementInfo.transport.guid.IsEmpty() ? caster->GetTransport() : nullptr;
+ TransportBase* transport = m_movementInfo.transport.guid.IsEmpty() ? caster->GetTransport() : nullptr;
if (transport)
{
float x, y, z, o;
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 3bb3e37389b..35876800ea3 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -1384,7 +1384,11 @@ void Creature::SaveToDB()
return;
}
- uint32 mapId = GetTransport() ? GetTransport()->GetGOInfo()->moTransport.SpawnMap : GetMapId();
+ uint32 mapId = GetMapId();
+ if (TransportBase* transport = GetTransport())
+ if (transport->GetMapIdForSpawning() >= 0)
+ mapId = transport->GetMapIdForSpawning();
+
SaveToDB(mapId, data->spawnDifficulties);
}
diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
index 2deee2146d9..9aeada30f46 100644
--- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp
+++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
@@ -111,7 +111,7 @@ bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caste
if (IsWorldObject())
setActive(true); //must before add to map to be put in world container
- Transport* transport = caster->GetTransport();
+ TransportBase* transport = caster->GetTransport();
if (transport)
{
float x, y, z, o;
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 16fd48efa0f..0122d0560b0 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -25,6 +25,7 @@
#include "CreatureAISelector.h"
#include "DatabaseEnv.h"
#include "DB2Stores.h"
+#include "G3DPosition.hpp"
#include "GameEventSender.h"
#include "GameObjectAI.h"
#include "GameObjectModel.h"
@@ -116,6 +117,371 @@ QuaternionData QuaternionData::fromEulerAnglesZYX(float Z, float Y, float X)
return QuaternionData(quat.x, quat.y, quat.z, quat.w);
}
+GameObjectTypeBase::CustomCommand::~CustomCommand() = default;
+
+namespace GameObjectType
+{
+//11 GAMEOBJECT_TYPE_TRANSPORT
+class Transport : public GameObjectTypeBase, public TransportBase
+{
+public:
+ static constexpr Milliseconds PositionUpdateInterval = 50ms;
+
+ explicit Transport(GameObject& owner) : GameObjectTypeBase(owner), _animationInfo(sTransportMgr->GetTransportAnimInfo(owner.GetGOInfo()->entry)),
+ _pathProgress(GameTime::GetGameTimeMS() % GetTransportPeriod()), _stateChangeTime(GameTime::GetGameTimeMS()), _stateChangeProgress(_pathProgress),
+ _autoCycleBetweenStopFrames(false)
+ {
+ GameObjectTemplate const* goInfo = _owner.GetGOInfo();
+ if (goInfo->transport.Timeto2ndfloor > 0)
+ {
+ _stopFrames.push_back(goInfo->transport.Timeto2ndfloor);
+ if (goInfo->transport.Timeto3rdfloor > 0)
+ {
+ _stopFrames.push_back(goInfo->transport.Timeto3rdfloor);
+ if (goInfo->transport.Timeto4thfloor > 0)
+ {
+ _stopFrames.push_back(goInfo->transport.Timeto4thfloor);
+ if (goInfo->transport.Timeto5thfloor > 0)
+ {
+ _stopFrames.push_back(goInfo->transport.Timeto5thfloor);
+ if (goInfo->transport.Timeto6thfloor > 0)
+ {
+ _stopFrames.push_back(goInfo->transport.Timeto6thfloor);
+ if (goInfo->transport.Timeto7thfloor > 0)
+ {
+ _stopFrames.push_back(goInfo->transport.Timeto7thfloor);
+ if (goInfo->transport.Timeto8thfloor > 0)
+ {
+ _stopFrames.push_back(goInfo->transport.Timeto8thfloor);
+ if (goInfo->transport.Timeto9thfloor > 0)
+ {
+ _stopFrames.push_back(goInfo->transport.Timeto9thfloor);
+ if (goInfo->transport.Timeto10thfloor > 0)
+ _stopFrames.push_back(goInfo->transport.Timeto10thfloor);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ _positionUpdateTimer.Reset(PositionUpdateInterval);
+ }
+
+ void Update(uint32 diff) override
+ {
+ if (!_animationInfo)
+ return;
+
+ _positionUpdateTimer.Update(diff);
+ if (!_positionUpdateTimer.Passed())
+ return;
+
+ _positionUpdateTimer.Reset(PositionUpdateInterval);
+
+ uint32 now = GameTime::GetGameTimeMS();
+ uint32 period = GetTransportPeriod();
+ uint32 newProgress = 0;
+ if (_stopFrames.empty())
+ newProgress = now % period;
+ else
+ {
+ int32 stopTargetTime = 0;
+ if (_owner.GetGoState() == GO_STATE_TRANSPORT_ACTIVE)
+ stopTargetTime = 0;
+ else
+ stopTargetTime = _stopFrames[_owner.GetGoState() - GO_STATE_TRANSPORT_STOPPED];
+
+ if (now < uint32(*_owner.m_gameObjectData->Level))
+ {
+ int32 timeToStop = _owner.m_gameObjectData->Level - _stateChangeTime;
+ float stopSourcePathPct = float(_stateChangeProgress) / float(period);
+ float stopTargetPathPct = float(stopTargetTime) / float(period);
+ float timeSinceStopProgressPct = float(now - _stateChangeTime) / float(timeToStop);
+
+ float progressPct;
+ if (!_owner.HasDynamicFlag(GO_DYNFLAG_LO_INVERTED_MOVEMENT))
+ {
+ if (_owner.GetGoState() == GO_STATE_TRANSPORT_ACTIVE)
+ stopTargetPathPct = 1.0f;
+
+ float pathPctBetweenStops = stopTargetPathPct - stopSourcePathPct;
+ if (pathPctBetweenStops < 0.0f)
+ pathPctBetweenStops += 1.0f;
+
+ progressPct = pathPctBetweenStops * timeSinceStopProgressPct + stopSourcePathPct;
+ if (progressPct > 1.0f)
+ progressPct = progressPct - 1.0f;
+ }
+ else
+ {
+ float pathPctBetweenStops = stopSourcePathPct - stopTargetPathPct;
+ if (pathPctBetweenStops < 0.0f)
+ pathPctBetweenStops += 1.0f;
+
+ progressPct = stopSourcePathPct - pathPctBetweenStops * timeSinceStopProgressPct;
+ if (progressPct < 0.0f)
+ progressPct += 1.0f;
+ }
+
+ newProgress = uint32(float(period) * progressPct) % period;
+ }
+ else
+ newProgress = stopTargetTime;
+
+ if (int32(newProgress) == stopTargetTime && newProgress != _pathProgress)
+ {
+ uint32 eventId = [&]()
+ {
+ switch (_owner.GetGoState() - GO_STATE_TRANSPORT_ACTIVE)
+ {
+ case 0:
+ return _owner.GetGOInfo()->transport.Reached1stfloor;
+ case 1:
+ return _owner.GetGOInfo()->transport.Reached2ndfloor;
+ case 2:
+ return _owner.GetGOInfo()->transport.Reached3rdfloor;
+ case 3:
+ return _owner.GetGOInfo()->transport.Reached4thfloor;
+ case 4:
+ return _owner.GetGOInfo()->transport.Reached5thfloor;
+ case 5:
+ return _owner.GetGOInfo()->transport.Reached6thfloor;
+ case 6:
+ return _owner.GetGOInfo()->transport.Reached7thfloor;
+ case 7:
+ return _owner.GetGOInfo()->transport.Reached8thfloor;
+ case 8:
+ return _owner.GetGOInfo()->transport.Reached9thfloor;
+ case 9:
+ return _owner.GetGOInfo()->transport.Reached10thfloor;
+ default:
+ return 0u;
+ }
+ }();
+ if (eventId)
+ GameEvents::Trigger(eventId, &_owner, nullptr);
+
+ if (_autoCycleBetweenStopFrames)
+ {
+ GOState currentState = _owner.GetGoState();
+ GOState newState;
+ if (currentState == GO_STATE_TRANSPORT_ACTIVE)
+ newState = GO_STATE_TRANSPORT_STOPPED;
+ else if (currentState - GO_STATE_TRANSPORT_ACTIVE == _stopFrames.size())
+ newState = GOState(currentState - 1);
+ else if (_owner.HasDynamicFlag(GO_DYNFLAG_LO_INVERTED_MOVEMENT))
+ newState = GOState(currentState - 1);
+ else
+ newState = GOState(currentState + 1);
+
+ _owner.SetGoState(newState);
+ }
+ }
+ }
+
+ if (_pathProgress == newProgress)
+ return;
+
+ _pathProgress = newProgress;
+
+ TransportAnimationEntry const* oldAnimation = _animationInfo->GetPrevAnimNode(newProgress);
+ TransportAnimationEntry const* newAnimation = _animationInfo->GetNextAnimNode(newProgress);
+ if (oldAnimation && newAnimation)
+ {
+ G3D::Matrix3 pathRotation = G3D::Quat(_owner.m_gameObjectData->ParentRotation->x, _owner.m_gameObjectData->ParentRotation->y,
+ _owner.m_gameObjectData->ParentRotation->z, _owner.m_gameObjectData->ParentRotation->w).toRotationMatrix();
+
+ G3D::Vector3 prev(oldAnimation->Pos.X, oldAnimation->Pos.Y, oldAnimation->Pos.Z);
+ G3D::Vector3 next(newAnimation->Pos.X, newAnimation->Pos.Y, newAnimation->Pos.Z);
+
+ float animProgress = float(newProgress - oldAnimation->TimeIndex) / float(newAnimation->TimeIndex - oldAnimation->TimeIndex);
+
+ G3D::Vector3 dst = prev.lerp(next, animProgress) * pathRotation;
+
+ dst += PositionToVector3(&_owner.GetStationaryPosition());
+
+ _owner.GetMap()->GameObjectRelocation(&_owner, dst.x, dst.y, dst.z, _owner.GetOrientation());
+ }
+
+ TransportRotationEntry const* oldRotation = _animationInfo->GetPrevAnimRotation(newProgress);
+ TransportRotationEntry const* newRotation = _animationInfo->GetNextAnimRotation(newProgress);
+ if (oldRotation && newRotation)
+ {
+ G3D::Quat prev(oldRotation->Rot[0], oldRotation->Rot[1], oldRotation->Rot[2], oldRotation->Rot[3]);
+ G3D::Quat next(newRotation->Rot[0], newRotation->Rot[1], newRotation->Rot[2], newRotation->Rot[3]);
+
+ float animProgress = float(newProgress - oldRotation->TimeIndex) / float(newRotation->TimeIndex - oldRotation->TimeIndex);
+
+ G3D::Quat rotation = prev.slerp(next, animProgress);
+
+ _owner.SetLocalRotation(rotation.x, rotation.y, rotation.z, rotation.w);
+ _owner.UpdateModelPosition();
+ }
+
+ // update progress marker for client
+ _owner.SetPathProgressForClient(float(_pathProgress) / float(period));
+ }
+
+ void OnStateChanged(GOState oldState, GOState newState) override
+ {
+ ASSERT(newState >= GO_STATE_TRANSPORT_ACTIVE);
+
+ // transports without stop frames just keep animating in state 24
+ if (_stopFrames.empty())
+ {
+ if (newState != GO_STATE_TRANSPORT_ACTIVE)
+ _owner.SetGoState(GO_STATE_TRANSPORT_ACTIVE);
+ return;
+ }
+
+ int32 stopPathProgress = 0;
+
+ if (newState != GO_STATE_TRANSPORT_ACTIVE)
+ {
+ ASSERT(newState < GOState(GO_STATE_TRANSPORT_STOPPED + MAX_GO_STATE_TRANSPORT_STOP_FRAMES));
+ uint32 stopFrame = newState - GO_STATE_TRANSPORT_STOPPED;
+ ASSERT(stopFrame < _stopFrames.size());
+ stopPathProgress = _stopFrames[stopFrame];
+ }
+
+ _stateChangeTime = GameTime::GetGameTimeMS();
+ _stateChangeProgress = _pathProgress;
+ uint32 timeToStop = std::abs(int32(_pathProgress) - stopPathProgress);
+ _owner.SetLevel(GameTime::GetGameTimeMS() + timeToStop);
+ _owner.SetPathProgressForClient(float(_pathProgress) / float(GetTransportPeriod()));
+
+ if (oldState == GO_STATE_ACTIVE || oldState == newState)
+ {
+ // initialization
+ if (int32(_pathProgress) > stopPathProgress)
+ _owner.SetDynamicFlag(GO_DYNFLAG_LO_INVERTED_MOVEMENT);
+ else
+ _owner.RemoveDynamicFlag(GO_DYNFLAG_LO_INVERTED_MOVEMENT);
+
+ return;
+ }
+
+ int32 pauseTimesCount = _stopFrames.size();
+ int32 newToOldStateDelta = newState - oldState;
+ if (newToOldStateDelta < 0)
+ newToOldStateDelta += pauseTimesCount + 1;
+
+ int32 oldToNewStateDelta = oldState - newState;
+ if (oldToNewStateDelta < 0)
+ oldToNewStateDelta += pauseTimesCount + 1;
+
+ if (oldToNewStateDelta < newToOldStateDelta)
+ _owner.SetDynamicFlag(GO_DYNFLAG_LO_INVERTED_MOVEMENT);
+ else
+ _owner.RemoveDynamicFlag(GO_DYNFLAG_LO_INVERTED_MOVEMENT);
+ }
+
+ void OnRelocated() override
+ {
+ UpdatePassengerPositions();
+ }
+
+ void UpdatePassengerPositions()
+ {
+ for (WorldObject* passenger : _passengers)
+ {
+ float x, y, z, o;
+ passenger->m_movementInfo.transport.pos.GetPosition(x, y, z, o);
+ CalculatePassengerPosition(x, y, z, &o);
+ UpdatePassengerPosition(_owner.GetMap(), passenger, x, y, z, o, true);
+ }
+ }
+
+ uint32 GetTransportPeriod() const
+ {
+ if (_animationInfo)
+ return _animationInfo->TotalTime;
+
+ return 1;
+ }
+
+ std::vector<uint32> const* GetPauseTimes() const
+ {
+ return &_stopFrames;
+ }
+
+ ObjectGuid GetTransportGUID() const override { return _owner.GetGUID(); }
+
+ float GetTransportOrientation() const override { return _owner.GetOrientation(); }
+
+ void AddPassenger(WorldObject* passenger) override
+ {
+ if (!_owner.IsInWorld())
+ return;
+
+ if (_passengers.insert(passenger).second)
+ {
+ passenger->SetTransport(this);
+ passenger->m_movementInfo.transport.guid = GetTransportGUID();
+ TC_LOG_DEBUG("entities.transport", "Object %s boarded transport %s.", passenger->GetName().c_str(), _owner.GetName().c_str());
+ }
+ }
+
+ TransportBase* RemovePassenger(WorldObject* passenger) override
+ {
+ if (_passengers.erase(passenger) > 0)
+ {
+ passenger->SetTransport(nullptr);
+ passenger->m_movementInfo.transport.Reset();
+ TC_LOG_DEBUG("entities.transport", "Object %s removed from transport %s.", passenger->GetName().c_str(), _owner.GetName().c_str());
+
+ if (Player* plr = passenger->ToPlayer())
+ plr->SetFallInformation(0, plr->GetPositionZ());
+ }
+
+ return this;
+ }
+
+ void CalculatePassengerPosition(float& x, float& y, float& z, float* o) const override
+ {
+ TransportBase::CalculatePassengerPosition(x, y, z, o, _owner.GetPositionX(), _owner.GetPositionY(), _owner.GetPositionZ(), _owner.GetOrientation());
+ }
+
+ void CalculatePassengerOffset(float& x, float& y, float& z, float* o) const override
+ {
+ TransportBase::CalculatePassengerOffset(x, y, z, o, _owner.GetPositionX(), _owner.GetPositionY(), _owner.GetPositionZ(), _owner.GetOrientation());
+ }
+
+ int32 GetMapIdForSpawning() const override
+ {
+ return _owner.GetGOInfo()->transport.SpawnMap;
+ }
+
+ void SetAutoCycleBetweenStopFrames(bool on)
+ {
+ _autoCycleBetweenStopFrames = on;
+ }
+
+private:
+ TransportAnimation const* _animationInfo;
+ uint32 _pathProgress;
+ uint32 _stateChangeTime;
+ uint32 _stateChangeProgress;
+ std::vector<uint32> _stopFrames;
+ bool _autoCycleBetweenStopFrames;
+ TimeTracker _positionUpdateTimer;
+ std::unordered_set<WorldObject*> _passengers;
+};
+
+SetTransportAutoCycleBetweenStopFrames::SetTransportAutoCycleBetweenStopFrames(bool on) : _on(on)
+{
+}
+
+void SetTransportAutoCycleBetweenStopFrames::Execute(GameObjectTypeBase& type) const
+{
+ if (Transport* transport = dynamic_cast<Transport*>(&type))
+ transport->SetAutoCycleBetweenStopFrames(_on);
+}
+}
+
GameObject::GameObject() : WorldObject(false), MapObject(),
m_model(nullptr), m_goValue(), m_AI(nullptr), m_respawnCompatibilityMode(false), _animKitId(0), _worldEffectID(0)
{
@@ -154,10 +520,6 @@ GameObject::~GameObject()
{
delete m_AI;
delete m_model;
- if (m_goInfo && m_goInfo->type == GAMEOBJECT_TYPE_TRANSPORT)
- delete m_goValue.Transport.StopFrames;
- //if (m_uint32Values) // field array can be not exist if GameOBject not loaded
- // CleanupsBeforeDelete();
}
void GameObject::AIM_Destroy()
@@ -388,37 +750,14 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD
}
case GAMEOBJECT_TYPE_TRANSPORT:
{
- m_goValue.Transport.AnimationInfo = sTransportMgr->GetTransportAnimInfo(goInfo->entry);
- m_goValue.Transport.PathProgress = getMSTime();
- if (m_goValue.Transport.AnimationInfo)
- m_goValue.Transport.PathProgress -= m_goValue.Transport.PathProgress % GetTransportPeriod(); // align to period
- m_goValue.Transport.CurrentSeg = 0;
- m_goValue.Transport.StateUpdateTimer = 0;
- m_goValue.Transport.StopFrames = new std::vector<uint32>();
- if (goInfo->transport.Timeto2ndfloor > 0)
- m_goValue.Transport.StopFrames->push_back(goInfo->transport.Timeto2ndfloor);
- if (goInfo->transport.Timeto3rdfloor > 0)
- m_goValue.Transport.StopFrames->push_back(goInfo->transport.Timeto3rdfloor);
- if (goInfo->transport.Timeto4thfloor > 0)
- m_goValue.Transport.StopFrames->push_back(goInfo->transport.Timeto4thfloor);
- if (goInfo->transport.Timeto5thfloor > 0)
- m_goValue.Transport.StopFrames->push_back(goInfo->transport.Timeto5thfloor);
- if (goInfo->transport.Timeto6thfloor > 0)
- m_goValue.Transport.StopFrames->push_back(goInfo->transport.Timeto6thfloor);
- if (goInfo->transport.Timeto7thfloor > 0)
- m_goValue.Transport.StopFrames->push_back(goInfo->transport.Timeto7thfloor);
- if (goInfo->transport.Timeto8thfloor > 0)
- m_goValue.Transport.StopFrames->push_back(goInfo->transport.Timeto8thfloor);
- if (goInfo->transport.Timeto9thfloor > 0)
- m_goValue.Transport.StopFrames->push_back(goInfo->transport.Timeto9thfloor);
- if (goInfo->transport.Timeto10thfloor > 0)
- m_goValue.Transport.StopFrames->push_back(goInfo->transport.Timeto10thfloor);
+ m_goTypeImpl = std::make_unique<GameObjectType::Transport>(*this);
if (goInfo->transport.startOpen)
- SetTransportState(GO_STATE_TRANSPORT_STOPPED, goInfo->transport.startOpen - 1);
+ SetGoState(GO_STATE_TRANSPORT_STOPPED);
else
- SetTransportState(GO_STATE_TRANSPORT_ACTIVE);
+ SetGoState(GO_STATE_TRANSPORT_ACTIVE);
SetGoAnimProgress(animProgress);
+ setActive(true);
break;
}
case GAMEOBJECT_TYPE_FISHINGNODE:
@@ -555,6 +894,9 @@ void GameObject::Update(uint32 diff)
}
}
+ if (m_goTypeImpl)
+ m_goTypeImpl->Update(diff);
+
switch (m_lootState)
{
case GO_NOT_READY:
@@ -576,53 +918,6 @@ void GameObject::Update(uint32 diff)
SetLootState(GO_READY);
break;
}
- case GAMEOBJECT_TYPE_TRANSPORT:
- {
- if (!m_goValue.Transport.AnimationInfo)
- break;
-
- if (GetGoState() == GO_STATE_TRANSPORT_ACTIVE)
- {
- m_goValue.Transport.PathProgress += diff;
- /* TODO: Fix movement in unloaded grid - currently GO will just disappear
- uint32 timer = m_goValue.Transport.PathProgress % GetTransportPeriod();
- TransportAnimationEntry const* node = m_goValue.Transport.AnimationInfo->GetAnimNode(timer);
- if (node && m_goValue.Transport.CurrentSeg != node->TimeSeg)
- {
- m_goValue.Transport.CurrentSeg = node->TimeSeg;
-
- G3D::Quat rotation;
- if (TransportRotationEntry const* rot = m_goValue.Transport.AnimationInfo->GetAnimRotation(timer))
- rotation = G3D::Quat(rot->X, rot->Y, rot->Z, rot->W);
-
- G3D::Vector3 pos = rotation.toRotationMatrix()
- * G3D::Matrix3::fromEulerAnglesZYX(GetOrientation(), 0.0f, 0.0f)
- * G3D::Vector3(node->X, node->Y, node->Z);
-
- pos += G3D::Vector3(GetStationaryX(), GetStationaryY(), GetStationaryZ());
-
- G3D::Vector3 src(GetPositionX(), GetPositionY(), GetPositionZ());
-
- TC_LOG_DEBUG("misc", "Src: %s Dest: %s", src.toString().c_str(), pos.toString().c_str());
-
- GetMap()->GameObjectRelocation(this, pos.x, pos.y, pos.z, GetOrientation());
- }
- */
-
- if (!m_goValue.Transport.StopFrames->empty())
- {
- uint32 visualStateBefore = (m_goValue.Transport.StateUpdateTimer / 20000) & 1;
- m_goValue.Transport.StateUpdateTimer += diff;
- uint32 visualStateAfter = (m_goValue.Transport.StateUpdateTimer / 20000) & 1;
- if (visualStateBefore != visualStateAfter)
- {
- ForceUpdateFieldChange(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::Level));
- ForceUpdateFieldChange(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::State));
- }
- }
- }
- break;
- }
case GAMEOBJECT_TYPE_FISHINGNODE:
{
// fishing code (bobber ready)
@@ -1164,7 +1459,12 @@ void GameObject::SaveToDB()
return;
}
- SaveToDB(GetMapId(), data->spawnDifficulties);
+ uint32 mapId = GetMapId();
+ if (TransportBase* transport = GetTransport())
+ if (transport->GetMapIdForSpawning() >= 0)
+ mapId = transport->GetMapIdForSpawning();
+
+ SaveToDB(mapId, data->spawnDifficulties);
}
void GameObject::SaveToDB(uint32 mapid, std::vector<Difficulty> const& spawnDifficulties)
@@ -1412,7 +1712,7 @@ bool GameObject::IsDynTransport() const
if (!gInfo)
return false;
- return gInfo->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT || (gInfo->type == GAMEOBJECT_TYPE_TRANSPORT && m_goValue.Transport.StopFrames->empty());
+ return gInfo->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT || gInfo->type == GAMEOBJECT_TYPE_TRANSPORT;
}
bool GameObject::IsDestructibleBuilding() const
@@ -1734,8 +2034,9 @@ void GameObject::ActivateObject(GameObjectActions action, int32 param, WorldObje
case GameObjectActions::GoTo8thFloor:
case GameObjectActions::GoTo9thFloor:
case GameObjectActions::GoTo10thFloor:
+ static_assert(int32(GO_STATE_TRANSPORT_ACTIVE) == int32(GameObjectActions::GoTo1stFloor));
if (GetGoType() == GAMEOBJECT_TYPE_TRANSPORT)
- SetTransportState(GO_STATE_TRANSPORT_STOPPED, uint32(action) - uint32(GameObjectActions::GoTo1stFloor));
+ SetGoState(GOState(action));
else
TC_LOG_ERROR("spell", "Spell %d targeted non-transport gameobject for transport only action \"Go to Floor\" %d in effect %d", spellId, int32(action), effectIndex);
break;
@@ -2589,7 +2890,7 @@ void GameObject::SetLocalRotationAngles(float z_rot, float y_rot, float x_rot)
QuaternionData GameObject::GetWorldRotation() const
{
QuaternionData localRotation = GetLocalRotation();
- if (Transport* transport = GetTransport())
+ if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
{
QuaternionData worldRotation = transport->GetWorldRotation();
@@ -2781,9 +3082,14 @@ void GameObject::SetLootGenerationTime()
void GameObject::SetGoState(GOState state)
{
+ GOState oldState = GetGoState();
SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::State), state);
if (AI())
AI()->OnStateChanged(state);
+
+ if (m_goTypeImpl)
+ m_goTypeImpl->OnStateChanged(oldState, state);
+
if (m_model && !IsTransport())
{
if (!IsInWorld())
@@ -2798,39 +3104,6 @@ void GameObject::SetGoState(GOState state)
}
}
-uint32 GameObject::GetTransportPeriod() const
-{
- ASSERT(GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT);
- if (m_goValue.Transport.AnimationInfo)
- return m_goValue.Transport.AnimationInfo->TotalTime;
-
- return 0;
-}
-
-void GameObject::SetTransportState(GOState state, uint32 stopFrame /*= 0*/)
-{
- if (GetGoState() == state)
- return;
-
- ASSERT(GetGOInfo()->type == GAMEOBJECT_TYPE_TRANSPORT);
- ASSERT(state >= GO_STATE_TRANSPORT_ACTIVE);
- if (state == GO_STATE_TRANSPORT_ACTIVE)
- {
- m_goValue.Transport.StateUpdateTimer = 0;
- m_goValue.Transport.PathProgress = getMSTime();
- if (GetGoState() >= GO_STATE_TRANSPORT_STOPPED)
- m_goValue.Transport.PathProgress += m_goValue.Transport.StopFrames->at(GetGoState() - GO_STATE_TRANSPORT_STOPPED);
- SetGoState(GO_STATE_TRANSPORT_ACTIVE);
- }
- else
- {
- ASSERT(state < GOState(GO_STATE_TRANSPORT_STOPPED + MAX_GO_STATE_TRANSPORT_STOP_FRAMES));
- ASSERT(stopFrame < m_goValue.Transport.StopFrames->size());
- m_goValue.Transport.PathProgress = getMSTime() + m_goValue.Transport.StopFrames->at(stopFrame);
- SetGoState(GOState(GO_STATE_TRANSPORT_STOPPED + stopFrame));
- }
-}
-
void GameObject::SetDisplayId(uint32 displayid)
{
SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::DisplayID), displayid);
@@ -3029,6 +3302,32 @@ void GameObject::ClearUpdateMask(bool remove)
Object::ClearUpdateMask(remove);
}
+std::vector<uint32> const* GameObject::GetPauseTimes() const
+{
+ if (GameObjectType::Transport const* transport = dynamic_cast<GameObjectType::Transport const*>(m_goTypeImpl.get()))
+ return transport->GetPauseTimes();
+
+ return nullptr;
+}
+
+void GameObject::SetPathProgressForClient(float progress)
+{
+ DoWithSuppressingObjectUpdates([&]()
+ {
+ UF::ObjectData::Base dynflagMask;
+ dynflagMask.MarkChanged(&UF::ObjectData::DynamicFlags);
+ bool marked = (m_objectData->GetChangesMask() & dynflagMask.GetChangesMask()).IsAnySet();
+
+ uint32 dynamicFlags = GetDynamicFlags();
+ dynamicFlags &= 0xFFFF; // remove high bits
+ dynamicFlags |= uint32(progress * 65535.0f) << 16;
+ ReplaceAllDynamicFlags(dynamicFlags);
+
+ if (!marked)
+ const_cast<UF::ObjectData&>(*m_objectData).ClearChanged(&UF::ObjectData::DynamicFlags);
+ });
+}
+
void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = nullptr*/) const
{
if (m_goData)
@@ -3047,6 +3346,31 @@ void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /*
}
}
+TransportBase const* GameObject::ToTransportBase() const
+{
+ switch (GetGoType())
+ {
+ case GAMEOBJECT_TYPE_TRANSPORT:
+ return static_cast<GameObjectType::Transport const*>(m_goTypeImpl.get());
+ case GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT:
+ return static_cast<Transport const*>(this);
+ default:
+ break;
+ }
+
+ return nullptr;
+}
+
+void GameObject::AfterRelocation()
+{
+ UpdateModelPosition();
+ UpdatePositionData();
+ if (m_goTypeImpl)
+ m_goTypeImpl->OnRelocated();
+
+ UpdateObjectVisibility(false);
+}
+
float GameObject::GetInteractionDistance() const
{
switch (GetGoType())
@@ -3315,6 +3639,12 @@ void GameObject::UpdateDynamicFlagsForNearbyPlayers() const
Cell::VisitWorldObjects(this, deliverer, GetVisibilityRange());
}
+void GameObject::HandleCustomTypeCommand(GameObjectTypeBase::CustomCommand const& command) const
+{
+ if (m_goTypeImpl)
+ command.Execute(*m_goTypeImpl);
+}
+
void GameObject::CreateModel()
{
m_model = GameObjectModel::Create(std::make_unique<GameObjectModelOwnerImpl>(this), sWorld->GetDataPath());
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index e47df17d3e0..e345f9a147d 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -25,11 +25,13 @@
#include "MapObject.h"
#include "SharedDefines.h"
+class GameObject;
class GameObjectAI;
class GameObjectModel;
class Group;
class OPvPCapturePoint;
class Transport;
+class TransportBase;
class Unit;
struct TransportAnimation;
enum TriggerCastFlags : uint32;
@@ -42,17 +44,44 @@ namespace WorldPackets
}
}
-union GameObjectValue
+// Base class for GameObject type specific implementations
+class GameObjectTypeBase
{
- //11 GAMEOBJECT_TYPE_TRANSPORT
- struct
+public:
+ class TC_GAME_API CustomCommand
{
- uint32 PathProgress;
- TransportAnimation const* AnimationInfo;
- uint32 CurrentSeg;
- std::vector<uint32>* StopFrames;
- uint32 StateUpdateTimer;
- } Transport;
+ public:
+ virtual ~CustomCommand();
+ virtual void Execute(GameObjectTypeBase& type) const = 0;
+ };
+
+ explicit GameObjectTypeBase(GameObject& owner) : _owner(owner) { }
+ virtual ~GameObjectTypeBase() = default;
+
+ virtual void Update([[maybe_unused]] uint32 diff) { }
+ virtual void OnStateChanged([[maybe_unused]] GOState oldState, [[maybe_unused]] GOState newState) { }
+ virtual void OnRelocated() { }
+
+protected:
+ GameObject& _owner;
+};
+
+namespace GameObjectType
+{
+class TC_GAME_API SetTransportAutoCycleBetweenStopFrames : public GameObjectTypeBase::CustomCommand
+{
+public:
+ explicit SetTransportAutoCycleBetweenStopFrames(bool on);
+
+ void Execute(GameObjectTypeBase& type) const override;
+
+private:
+ bool _on;
+};
+}
+
+union GameObjectValue
+{
//25 GAMEOBJECT_TYPE_FISHINGHOLE
struct
{
@@ -209,14 +238,15 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
void SetGoType(GameobjectTypes type) { SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::TypeID), type); }
GOState GetGoState() const { return GOState(*m_gameObjectData->State); }
void SetGoState(GOState state);
- virtual uint32 GetTransportPeriod() const;
- void SetTransportState(GOState state, uint32 stopFrame = 0);
uint32 GetGoArtKit() const { return m_gameObjectData->ArtKit; }
void SetGoArtKit(uint32 artkit);
uint8 GetGoAnimProgress() const { return m_gameObjectData->PercentHealth; }
void SetGoAnimProgress(uint8 animprogress) { SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::PercentHealth), animprogress); }
static void SetGoArtKit(uint32 artkit, GameObject* go, ObjectGuid::LowType lowguid = UI64LIT(0));
+ std::vector<uint32> const* GetPauseTimes() const;
+ void SetPathProgressForClient(float progress);
+
void EnableCollision(bool enable);
void Use(Unit* user);
@@ -313,6 +343,9 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
GameObjectModel* m_model;
void GetRespawnPosition(float &x, float &y, float &z, float* ori = nullptr) const;
+ TransportBase* ToTransportBase() { return const_cast<TransportBase*>(const_cast<GameObject const*>(this)->ToTransportBase()); }
+ TransportBase const* ToTransportBase() const;
+
Transport* ToTransport() { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT) return reinterpret_cast<Transport*>(this); else return nullptr; }
Transport const* ToTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT) return reinterpret_cast<Transport const*>(this); else return nullptr; }
@@ -320,8 +353,11 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
float GetStationaryY() const override { return m_stationaryPosition.GetPositionY(); }
float GetStationaryZ() const override { return m_stationaryPosition.GetPositionZ(); }
float GetStationaryO() const override { return m_stationaryPosition.GetOrientation(); }
+ Position const& GetStationaryPosition() const { return m_stationaryPosition; }
void RelocateStationaryPosition(float x, float y, float z, float o) { m_stationaryPosition.Relocate(x, y, z, o); }
+ void AfterRelocation();
+
float GetInteractionDistance() const;
void UpdateModelPosition();
@@ -352,6 +388,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
void UpdateDynamicFlagsForNearbyPlayers() const;
+ void HandleCustomTypeCommand(GameObjectTypeBase::CustomCommand const& command) const;
+
UF::UpdateField<UF::GameObjectData, 0, TYPEID_GAMEOBJECT> m_gameObjectData;
protected:
@@ -383,7 +421,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
GameObjectTemplate const* m_goInfo;
GameObjectTemplateAddon const* m_goTemplateAddon;
GameObjectData const* m_goData;
- GameObjectValue m_goValue;
+ std::unique_ptr<GameObjectTypeBase> m_goTypeImpl;
+ GameObjectValue m_goValue; // TODO: replace with m_goTypeImpl
int64 m_packedRotation;
QuaternionData m_localRotation;
diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h
index 9e7650115e4..46f87f8c9f4 100644
--- a/src/server/game/Entities/GameObject/GameObjectData.h
+++ b/src/server/game/Entities/GameObject/GameObjectData.h
@@ -1017,6 +1017,7 @@ struct GameObjectTemplate
case GAMEOBJECT_TYPE_TRAP: return trap.GiganticAOI != 0;
case GAMEOBJECT_TYPE_SPELL_FOCUS: return spellFocus.GiganticAOI != 0;
case GAMEOBJECT_TYPE_GOOBER: return goober.GiganticAOI != 0;
+ case GAMEOBJECT_TYPE_TRANSPORT: return true;
case GAMEOBJECT_TYPE_SPELLCASTER: return spellCaster.GiganticAOI != 0;
case GAMEOBJECT_TYPE_FLAGSTAND: return flagStand.GiganticAOI != 0;
case GAMEOBJECT_TYPE_FLAGDROP: return flagDrop.GiganticAOI != 0;
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index fef22d2af9a..5734afb9f3b 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -263,15 +263,8 @@ void Object::SendOutOfRangeForPlayer(Player* target) const
void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player* target) const
{
std::vector<uint32> const* PauseTimes = nullptr;
- uint32 PauseTimesCount = 0;
if (GameObject const* go = ToGameObject())
- {
- if (go->GetGoType() == GAMEOBJECT_TYPE_TRANSPORT)
- {
- PauseTimes = go->GetGOValue()->Transport.StopFrames;
- PauseTimesCount = PauseTimes->size();
- }
- }
+ PauseTimes = go->GetPauseTimes();
data->WriteBit(flags.NoBirthAnim);
data->WriteBit(flags.EnablePortals);
@@ -384,7 +377,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(*unit->movespline, *data);
}
- *data << uint32(PauseTimesCount);
+ *data << uint32(PauseTimes ? PauseTimes->size() : 0);
if (flags.Stationary)
{
@@ -399,18 +392,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
*data << ToUnit()->GetVictim()->GetGUID(); // CombatVictim
if (flags.ServerTime)
- {
- GameObject const* go = ToGameObject();
- /** @TODO Use IsTransport() to also handle type 11 (TRANSPORT)
- Currently grid objects are not updated if there are no nearby players,
- this causes clients to receive different PathProgress
- resulting in players seeing the object in a different position
- */
- if (go && go->ToTransport()) // ServerTime
- *data << uint32(go->GetGOValue()->Transport.PathProgress);
- else
- *data << uint32(GameTime::GetGameTimeMS());
- }
+ *data << uint32(GameTime::GetGameTimeMS());
if (flags.Vehicle)
{
@@ -430,7 +412,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
if (flags.Rotation)
*data << uint64(ToGameObject()->GetPackedLocalRotation()); // Rotation
- if (PauseTimesCount)
+ if (PauseTimes && !PauseTimes->empty())
data->append(PauseTimes->data(), PauseTimes->size());
if (flags.MovementTransport)
@@ -885,19 +867,9 @@ void WorldObject::setActive(bool on)
return;
if (on)
- {
- if (GetTypeId() == TYPEID_UNIT)
- map->AddToActive(ToCreature());
- else if (GetTypeId() == TYPEID_DYNAMICOBJECT)
- map->AddToActive((DynamicObject*)this);
- }
+ map->AddToActive(this);
else
- {
- if (GetTypeId() == TYPEID_UNIT)
- map->RemoveFromActive(ToCreature());
- else if (GetTypeId() == TYPEID_DYNAMICOBJECT)
- map->RemoveFromActive((DynamicObject*)this);
- }
+ map->RemoveFromActive(this);
}
void WorldObject::SetVisibilityDistanceOverride(VisibilityDistanceType type)
@@ -922,7 +894,7 @@ void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
if (IsInWorld())
RemoveFromWorld();
- if (Transport* transport = GetTransport())
+ if (TransportBase* transport = GetTransport())
transport->RemovePassenger(this);
}
@@ -999,7 +971,7 @@ bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool
Position const* thisOrTransport = this;
Position const* objOrObjTransport = obj;
- if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetGUID() == GetTransport()->GetGUID())
+ if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetTransportGUID() == GetTransport()->GetTransportGUID())
{
thisOrTransport = &m_movementInfo.transport.pos;
objOrObjTransport = &obj->m_movementInfo.transport.pos;
@@ -1843,7 +1815,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert
return nullptr;
}
- Transport* transport = summoner ? summoner->GetTransport() : nullptr;
+ TransportBase* transport = summoner ? summoner->GetTransport() : nullptr;
if (transport)
{
float x, y, z, o;
@@ -3606,7 +3578,7 @@ void WorldObject::RemoveFromObjectUpdate()
ObjectGuid WorldObject::GetTransGUID() const
{
if (GetTransport())
- return GetTransport()->GetGUID();
+ return GetTransport()->GetTransportGUID();
return ObjectGuid::Empty;
}
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index db57584c76a..acc4f688fe4 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -54,7 +54,7 @@ class SpellCastTargets;
class SpellEffectInfo;
class SpellInfo;
class TempSummon;
-class Transport;
+class TransportBase;
class Unit;
class UpdateData;
class WorldObject;
@@ -676,7 +676,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
uint32 LastUsedScriptID;
// Transports
- Transport* GetTransport() const { return m_transport; }
+ TransportBase* GetTransport() const { return m_transport; }
float GetTransOffsetX() const { return m_movementInfo.transport.pos.GetPositionX(); }
float GetTransOffsetY() const { return m_movementInfo.transport.pos.GetPositionY(); }
float GetTransOffsetZ() const { return m_movementInfo.transport.pos.GetPositionZ(); }
@@ -685,7 +685,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
uint32 GetTransTime() const { return m_movementInfo.transport.time; }
int8 GetTransSeat() const { return m_movementInfo.transport.seat; }
virtual ObjectGuid GetTransGUID() const;
- void SetTransport(Transport* t) { m_transport = t; }
+ void SetTransport(TransportBase* t) { m_transport = t; }
MovementInfo m_movementInfo;
@@ -728,8 +728,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
bool const m_isWorldObject;
ZoneScript* m_zoneScript;
- // transports
- Transport* m_transport;
+ // transports (gameobjects only)
+ TransportBase* m_transport;
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data);
uint32 m_zoneId;
diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.cpp b/src/server/game/Entities/Object/Updates/UpdateFields.cpp
index 82a1ca81712..591aeb657ac 100644
--- a/src/server/game/Entities/Object/Updates/UpdateFields.cpp
+++ b/src/server/game/Entities/Object/Updates/UpdateFields.cpp
@@ -4264,13 +4264,13 @@ void GameObjectData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fie
data << float(ParentRotation->z);
data << float(ParentRotation->w);
data << int32(FactionTemplate);
- data << int8(ViewerDependentValue<StateTag>::GetValue(this, owner, receiver));
+ data << int8(State);
data << int8(TypeID);
data << uint8(PercentHealth);
data << uint32(ArtKit);
data << uint32(EnableDoodadSets.size());
data << uint32(CustomParam);
- data << int32(ViewerDependentValue<LevelTag>::GetValue(this, owner, receiver));
+ data << int32(Level);
data << uint32(AnimGroupInstance);
for (uint32 i = 0; i < EnableDoodadSets.size(); ++i)
{
@@ -4371,7 +4371,7 @@ void GameObjectData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool
}
if (changesMask[14])
{
- data << int8(ViewerDependentValue<StateTag>::GetValue(this, owner, receiver));
+ data << int8(State);
}
if (changesMask[15])
{
@@ -4391,7 +4391,7 @@ void GameObjectData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool
}
if (changesMask[19])
{
- data << int32(ViewerDependentValue<LevelTag>::GetValue(this, owner, receiver));
+ data << int32(Level);
}
if (changesMask[20])
{
diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h
index a9967827f7a..e3cfb83fa40 100644
--- a/src/server/game/Entities/Object/Updates/UpdateFields.h
+++ b/src/server/game/Entities/Object/Updates/UpdateFields.h
@@ -804,13 +804,11 @@ struct GameObjectData : public IsUpdateFieldStructureTag, public HasChangesMask<
UpdateField<QuaternionData, 0, 12> ParentRotation;
UpdateField<int32, 0, 13> FactionTemplate;
UpdateField<int8, 0, 14> State;
- struct StateTag : ViewerDependentValueTag<int8> {};
UpdateField<int8, 0, 15> TypeID;
UpdateField<uint8, 0, 16> PercentHealth;
UpdateField<uint32, 0, 17> ArtKit;
UpdateField<uint32, 0, 18> CustomParam;
UpdateField<int32, 0, 19> Level;
- struct LevelTag : ViewerDependentValueTag<int32> {};
UpdateField<uint32, 0, 20> AnimGroupInstance;
void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, GameObject const* owner, Player const* receiver) const;
diff --git a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h
index 6d8ee14d100..755006262bd 100644
--- a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h
+++ b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h
@@ -26,6 +26,7 @@
#include "Player.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
+#include "Transport.h"
#include "World.h"
#include "WorldSession.h"
@@ -85,11 +86,17 @@ public:
dynFlags |= GO_DYNFLAG_LO_SPARKLE | GO_DYNFLAG_LO_HIGHLIGHT;
break;
case GAMEOBJECT_TYPE_TRANSPORT:
+ {
+ dynFlags = dynamicFlags & 0xFFFF;
+ pathProgress = dynamicFlags >> 16;
+ break;
+ }
case GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT:
{
- if (uint32 transportPeriod = gameObject->GetTransportPeriod())
+ Transport const* transport = gameObject->ToTransport();
+ if (uint32 transportPeriod = transport->GetTransportPeriod())
{
- float timer = float(gameObject->GetGOValue()->Transport.PathProgress % transportPeriod);
+ float timer = float(transport->GetTimer() % transportPeriod);
pathProgress = uint16(timer / float(transportPeriod) * 65535.0f);
}
break;
@@ -257,38 +264,6 @@ public:
};
template<>
-class ViewerDependentValue<UF::GameObjectData::LevelTag>
-{
-public:
- using value_type = UF::GameObjectData::LevelTag::value_type;
-
- static value_type GetValue(UF::GameObjectData const* gameObjectData, GameObject const* gameObject, Player const* /*receiver*/)
- {
- value_type level = gameObjectData->Level;
- bool isStoppableTransport = gameObject->GetGoType() == GAMEOBJECT_TYPE_TRANSPORT && !gameObject->GetGOValue()->Transport.StopFrames->empty();
- return isStoppableTransport ? gameObject->GetGOValue()->Transport.PathProgress : level;
- }
-};
-
-template<>
-class ViewerDependentValue<UF::GameObjectData::StateTag>
-{
-public:
- using value_type = UF::GameObjectData::StateTag::value_type;
-
- static value_type GetValue(UF::GameObjectData const* gameObjectData, GameObject const* gameObject, Player const* /*receiver*/)
- {
- value_type state = gameObjectData->State;
- bool isStoppableTransport = gameObject->GetGoType() == GAMEOBJECT_TYPE_TRANSPORT && !gameObject->GetGOValue()->Transport.StopFrames->empty();
- if (isStoppableTransport && gameObject->GetGoState() == GO_STATE_TRANSPORT_ACTIVE)
- if ((gameObject->GetGOValue()->Transport.StateUpdateTimer / 20000) & 1)
- state = GO_STATE_TRANSPORT_STOPPED;
-
- return state;
- }
-};
-
-template<>
class ViewerDependentValue<UF::ConversationData::LastLineEndTimeTag>
{
public:
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index bf699108081..701a433c7e3 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1342,7 +1342,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
TC_LOG_DEBUG("maps", "Player '%s' (%s) using client without required expansion tried teleporting to non accessible map (MapID: %u)",
GetName().c_str(), GetGUID().ToString().c_str(), mapid);
- if (Transport* transport = GetTransport())
+ if (TransportBase* transport = GetTransport())
{
transport->RemovePassenger(this);
RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
@@ -1364,7 +1364,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
DisableSpline();
GetMotionMaster()->Remove(EFFECT_MOTION_TYPE);
- if (Transport* transport = GetTransport())
+ if (TransportBase* transport = GetTransport())
{
if (!(options & TELE_TO_NOT_LEAVE_TRANSPORT))
transport->RemovePassenger(this);
@@ -1512,7 +1512,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
WorldPackets::Movement::TransferPending transferPending;
transferPending.MapID = mapid;
transferPending.OldMapPosition = GetPosition();
- if (Transport* transport = GetTransport())
+ if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
{
transferPending.Ship.emplace();
transferPending.Ship->ID = transport->GetEntry();
@@ -20475,8 +20475,8 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
stmt->setFloat(index++, finiteAlways(GetTransOffsetZ()));
stmt->setFloat(index++, finiteAlways(GetTransOffsetO()));
ObjectGuid::LowType transLowGUID = UI64LIT(0);
- if (GetTransport())
- transLowGUID = GetTransport()->GetGUID().GetCounter();
+ if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
+ transLowGUID = transport->GetGUID().GetCounter();
stmt->setUInt64(index++, transLowGUID);
std::ostringstream ss;
@@ -20620,8 +20620,8 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
stmt->setFloat(index++, finiteAlways(GetTransOffsetZ()));
stmt->setFloat(index++, finiteAlways(GetTransOffsetO()));
ObjectGuid::LowType transLowGUID = UI64LIT(0);
- if (GetTransport())
- transLowGUID = GetTransport()->GetGUID().GetCounter();
+ if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
+ transLowGUID = transport->GetGUID().GetCounter();
stmt->setUInt64(index++, transLowGUID);
std::ostringstream ss;
@@ -24168,17 +24168,6 @@ inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target, std::set
}
template<>
-inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, std::set<Unit*>& /*v*/)
-{
- // @HACK: This is to prevent objects like deeprun tram from disappearing when player moves far from its spawn point while riding it
- // But exclude stoppable elevators from this hack - they would be teleporting from one end to another
- // if affected transports move so far horizontally that it causes them to run out of visibility range then you are out of luck
- // fix visibility instead of adding hacks here
- if (!target->IsDynTransport())
- s64.insert(target->GetGUID());
-}
-
-template<>
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index 73e7e610e67..926ead58655 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -90,7 +90,7 @@ void TransportBase::UpdatePassengerPosition(Map* map, WorldObject* passenger, fl
}
Transport::Transport() : GameObject(),
- _transportInfo(nullptr), _isMoving(true), _pendingStop(false),
+ _transportInfo(nullptr), _pathProgress(0), _isMoving(true), _pendingStop(false),
_triggeredArrivalEvent(false), _triggeredDepartureEvent(false),
_passengerTeleportItr(_passengers.begin()), _delayedAddModel(false), _delayedTeleport(false)
{
@@ -149,7 +149,7 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid,
ReplaceAllFlags(GameObjectFlags(goOverride->Flags));
}
- m_goValue.Transport.PathProgress = 0;
+ _pathProgress = 0;
SetObjectScale(goinfo->size);
SetPeriod(tInfo->pathTime);
SetEntry(goinfo->entry);
@@ -190,9 +190,9 @@ void Transport::Update(uint32 diff)
return;
if (IsMoving() || !_pendingStop)
- m_goValue.Transport.PathProgress += diff;
+ _pathProgress += diff;
- uint32 timer = m_goValue.Transport.PathProgress % GetTransportPeriod();
+ uint32 timer = _pathProgress % GetTransportPeriod();
bool justStopped = false;
// Set current waypoint
@@ -216,9 +216,9 @@ void Transport::Update(uint32 diff)
if (_pendingStop && GetGoState() != GO_STATE_READY)
{
SetGoState(GO_STATE_READY);
- m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetTransportPeriod());
- m_goValue.Transport.PathProgress *= GetTransportPeriod();
- m_goValue.Transport.PathProgress += _currentFrame->ArriveTime;
+ _pathProgress = (_pathProgress / GetTransportPeriod());
+ _pathProgress *= GetTransportPeriod();
+ _pathProgress += _currentFrame->ArriveTime;
}
break; // its a stop frame and we are waiting
}
@@ -321,7 +321,7 @@ void Transport::AddPassenger(WorldObject* passenger)
}
}
-void Transport::RemovePassenger(WorldObject* passenger)
+Transport* Transport::RemovePassenger(WorldObject* passenger)
{
bool erased = false;
if (_passengerTeleportItr != _passengers.end())
@@ -351,6 +351,8 @@ void Transport::RemovePassenger(WorldObject* passenger)
plr->SetFallInformation(0, plr->GetPositionZ());
}
}
+
+ return this;
}
Creature* Transport::CreateNPCPassenger(ObjectGuid::LowType guid, CreatureData const* data)
@@ -565,6 +567,11 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu
return summon;
}
+int32 Transport::GetMapIdForSpawning() const
+{
+ return GetGOInfo()->moTransport.SpawnMap;
+}
+
void Transport::UpdatePosition(float x, float y, float z, float o)
{
bool newActive = GetMap()->IsGridLoaded(x, y);
diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h
index 0433cacebcd..2166fade720 100644
--- a/src/server/game/Entities/Transport/Transport.h
+++ b/src/server/game/Entities/Transport/Transport.h
@@ -43,8 +43,8 @@ class TC_GAME_API Transport : public GameObject, public TransportBase
void BuildUpdate(UpdateDataMapType& data_map) override;
- void AddPassenger(WorldObject* passenger);
- void RemovePassenger(WorldObject* passenger);
+ void AddPassenger(WorldObject* passenger) override;
+ Transport* RemovePassenger(WorldObject* passenger) override;
PassengerSet const& GetPassengers() const { return _passengers; }
Creature* CreateNPCPassenger(ObjectGuid::LowType guid, CreatureData const* data);
@@ -68,21 +68,27 @@ class TC_GAME_API Transport : public GameObject, public TransportBase
*/
TempSummon* SummonPassenger(uint32 entry, Position const& pos, TempSummonType summonType, SummonPropertiesEntry const* properties = nullptr, uint32 duration = 0, Unit* summoner = nullptr, uint32 spellId = 0, uint32 vehId = 0);
+ ObjectGuid GetTransportGUID() const override { return GetGUID(); }
+
+ float GetTransportOrientation() const override { return GetOrientation(); }
+
/// This method transforms supplied transport offsets into global coordinates
void CalculatePassengerPosition(float& x, float& y, float& z, float* o = nullptr) const override
{
- TransportBase::CalculatePassengerPosition(x, y, z, o, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
+ TransportBase::CalculatePassengerPosition(x, y, z, o, GetPositionX(), GetPositionY(), GetPositionZ(), GetTransportOrientation());
}
/// This method transforms supplied global coordinates into local offsets
void CalculatePassengerOffset(float& x, float& y, float& z, float* o = nullptr) const override
{
- TransportBase::CalculatePassengerOffset(x, y, z, o, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
+ TransportBase::CalculatePassengerOffset(x, y, z, o, GetPositionX(), GetPositionY(), GetPositionZ(), GetTransportOrientation());
}
- uint32 GetTransportPeriod() const override { return m_gameObjectData->Level; }
+ int32 GetMapIdForSpawning() const override;
+
+ uint32 GetTransportPeriod() const { return m_gameObjectData->Level; }
void SetPeriod(uint32 period) { SetLevel(period); }
- uint32 GetTimer() const { return GetGOValue()->Transport.PathProgress; }
+ uint32 GetTimer() const { return _pathProgress; }
KeyFrameVec const& GetKeyFrames() const { return _transportInfo->keyFrames; }
@@ -118,6 +124,7 @@ class TC_GAME_API Transport : public GameObject, public TransportBase
KeyFrameVec::const_iterator _currentFrame;
KeyFrameVec::const_iterator _nextFrame;
+ uint32 _pathProgress;
TimeTracker _positionChangeTimer;
bool _isMoving;
bool _pendingStop;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index b5660911c22..b78cfb76e25 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -11470,7 +11470,7 @@ ObjectGuid Unit::GetTransGUID() const
if (GetVehicle())
return GetVehicleBase()->GetGUID();
if (GetTransport())
- return GetTransport()->GetGUID();
+ return GetTransport()->GetTransportGUID();
return ObjectGuid::Empty;
}
@@ -12074,7 +12074,7 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a
}
ASSERT(!m_vehicle);
- (void)vehicle->AddPassenger(this, seatId);
+ (void)vehicle->AddVehiclePassenger(this, seatId);
}
void Unit::ChangeSeat(int8 seatId, bool next)
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 4279d472dc5..cab96560c1d 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -417,7 +417,7 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 typ
* @return true if it succeeds, false if it fails.
*/
-bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
+bool Vehicle::AddVehiclePassenger(Unit* unit, int8 seatId)
{
/// @Prevent adding passengers when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
if (_status == STATUS_UNINSTALLING)
@@ -488,8 +488,12 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
* @param [in, out] unit The passenger to remove.
*/
-Vehicle* Vehicle::RemovePassenger(Unit* unit)
+Vehicle* Vehicle::RemovePassenger(WorldObject* passenger)
{
+ Unit* unit = passenger->ToUnit();
+ if (!unit)
+ return nullptr;
+
if (unit->GetVehicle() != this)
return nullptr;
@@ -928,7 +932,7 @@ void VehicleJoinEvent::Abort(uint64)
Target->RemovePendingEvent(this);
/// @SPELL_AURA_CONTROL_VEHICLE auras can be applied even when the passenger is not (yet) on the vehicle.
- /// When this code is triggered it means that something went wrong in @Vehicle::AddPassenger, and we should remove
+ /// When this code is triggered it means that something went wrong in @Vehicle::AddVehiclePassenger, and we should remove
/// the aura manually.
Target->GetBase()->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE, Passenger->GetGUID());
}
diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h
index b6d88793419..47c9d1e0d64 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.h
+++ b/src/server/game/Entities/Vehicle/Vehicle.h
@@ -59,9 +59,8 @@ class TC_GAME_API Vehicle : public TransportBase
VehicleSeatAddon const* GetSeatAddonForSeatOfPassenger(Unit const* passenger) const;
uint8 GetAvailableSeatCount() const;
- bool AddPassenger(Unit* passenger, int8 seatId = -1);
- void EjectPassenger(Unit* passenger, Unit* controller);
- Vehicle* RemovePassenger(Unit* passenger);
+ bool AddVehiclePassenger(Unit* unit, int8 seatId = -1);
+ Vehicle* RemovePassenger(WorldObject* passenger) override;
void RelocatePassengers();
void RemoveAllPassengers();
bool IsVehicleInUse() const;
@@ -92,6 +91,12 @@ class TC_GAME_API Vehicle : public TransportBase
void InitMovementInfoForBase();
+ ObjectGuid GetTransportGUID() const override { return GetBase()->GetGUID(); }
+
+ float GetTransportOrientation() const override { return GetBase()->GetOrientation(); }
+
+ void AddPassenger(WorldObject* /*passenger*/) override { ABORT_MSG("Vehicle cannot directly gain passengers without auras"); }
+
/// This method transforms supplied transport offsets into global coordinates
void CalculatePassengerPosition(float& x, float& y, float& z, float* o /*= nullptr*/) const override
{
@@ -108,6 +113,8 @@ class TC_GAME_API Vehicle : public TransportBase
GetBase()->GetPositionZ(), GetBase()->GetOrientation());
}
+ int32 GetMapIdForSpawning() const override { return GetBase()->GetMapId(); }
+
void RemovePendingEvent(VehicleJoinEvent* e);
void RemovePendingEventsForSeat(int8 seatId);
diff --git a/src/server/game/Entities/Vehicle/VehicleDefines.h b/src/server/game/Entities/Vehicle/VehicleDefines.h
index 9d1e84bfb79..82261db0f0c 100644
--- a/src/server/game/Entities/Vehicle/VehicleDefines.h
+++ b/src/server/game/Entities/Vehicle/VehicleDefines.h
@@ -157,12 +157,20 @@ protected:
virtual ~TransportBase() { }
public:
+ virtual ObjectGuid GetTransportGUID() const = 0;
+
/// This method transforms supplied transport offsets into global coordinates
virtual void CalculatePassengerPosition(float& x, float& y, float& z, float* o = nullptr) const = 0;
/// This method transforms supplied global coordinates into local offsets
virtual void CalculatePassengerOffset(float& x, float& y, float& z, float* o = nullptr) const = 0;
+ virtual float GetTransportOrientation() const = 0;
+
+ virtual void AddPassenger(WorldObject* passenger) = 0;
+
+ virtual TransportBase* RemovePassenger(WorldObject* passenger) = 0;
+
void UpdatePassengerPosition(Map* map, WorldObject* passenger, float x, float y, float z, float o, bool setHomePosition);
static void CalculatePassengerPosition(float& x, float& y, float& z, float* o, float transX, float transY, float transZ, float transO)
@@ -188,6 +196,8 @@ public:
y = (iny - inx * std::tan(transO)) / (std::cos(transO) + std::sin(transO) * std::tan(transO));
x = (inx + iny * std::tan(transO)) / (std::cos(transO) + std::sin(transO) * std::tan(transO));
}
+
+ virtual int32 GetMapIdForSpawning() const = 0;
};
#endif
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
index 84e035fb9ff..5941bdee7ec 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
@@ -30,7 +30,7 @@ void VisibleNotifier::SendToSelf()
{
// at this moment i_clientGUIDs have guids that not iterate at grid level checks
// but exist one case when this possible and object not out of range: transports
- if (Transport* transport = i_player.GetTransport())
+ if (Transport* transport = dynamic_cast<Transport*>(i_player.GetTransport()))
{
for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
{
@@ -54,6 +54,9 @@ void VisibleNotifier::SendToSelf()
case TYPEID_DYNAMICOBJECT:
i_player.UpdateVisibilityOf((*itr)->ToDynObject(), i_data, i_visibleNow);
break;
+ case TYPEID_AREATRIGGER:
+ i_player.UpdateVisibilityOf((*itr)->ToAreaTrigger(), i_data, i_visibleNow);
+ break;
default:
break;
}
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 4fd59ea3aa7..2c8f70db994 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -357,28 +357,30 @@ void WorldSession::HandleMovementOpcode(OpcodeClient opcode, MovementInfo& movem
{
if (!plrMover->GetTransport())
{
- if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
- transport->AddPassenger(plrMover);
+ if (GameObject* go = plrMover->GetMap()->GetGameObject(movementInfo.transport.guid))
+ if (TransportBase* transport = go->ToTransportBase())
+ transport->AddPassenger(plrMover);
}
- else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid)
+ else if (plrMover->GetTransport()->GetTransportGUID() != movementInfo.transport.guid)
{
plrMover->GetTransport()->RemovePassenger(plrMover);
- if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
- transport->AddPassenger(plrMover);
+ if (GameObject* go = plrMover->GetMap()->GetGameObject(movementInfo.transport.guid))
+ {
+ if (TransportBase* transport = go->ToTransportBase())
+ transport->AddPassenger(plrMover);
+ else
+ movementInfo.ResetTransport();
+ }
else
movementInfo.ResetTransport();
}
}
if (!mover->GetTransport() && !mover->GetVehicle())
- {
- GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid);
- if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT)
- movementInfo.transport.Reset();
- }
+ movementInfo.transport.Reset();
}
else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave
- plrMover->m_transport->RemovePassenger(plrMover);
+ plrMover->GetTransport()->RemovePassenger(plrMover);
// fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
if (opcode == CMSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight())
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index ac15beaefb6..738d0d296c8 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -1265,9 +1265,7 @@ void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float
else
{
go->Relocate(x, y, z, orientation);
- go->UpdateModelPosition();
- go->UpdatePositionData();
- go->UpdateObjectVisibility(false);
+ go->AfterRelocation();
RemoveGameObjectFromMoveList(go);
}
@@ -1491,9 +1489,7 @@ void Map::MoveAllGameObjectsInMoveList()
{
// update pos
go->Relocate(go->_newPosition);
- go->UpdateModelPosition();
- go->UpdatePositionData();
- go->UpdateObjectVisibility(false);
+ go->AfterRelocation();
}
else
{
@@ -3028,7 +3024,7 @@ void Map::SendInitSelf(Player* player)
UpdateData data(player->GetMapId());
// attach to player data current transport data
- if (Transport* transport = player->GetTransport())
+ if (Transport* transport = dynamic_cast<Transport*>(player->GetTransport()))
{
transport->BuildCreateUpdateBlockForPlayer(&data, player);
player->m_visibleTransports.insert(transport->GetGUID());
@@ -3038,7 +3034,7 @@ void Map::SendInitSelf(Player* player)
player->BuildCreateUpdateBlockForPlayer(&data, player);
// build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
- if (Transport* transport = player->GetTransport())
+ if (Transport* transport = dynamic_cast<Transport*>(player->GetTransport()))
for (WorldObject* passenger : transport->GetPassengers())
if (player != passenger && player->HaveAtClient(passenger))
passenger->BuildCreateUpdateBlockForPlayer(&data, player);
diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp
index 871f43de6c1..5bcd0db73b0 100644
--- a/src/server/game/Maps/TransportMgr.cpp
+++ b/src/server/game/Maps/TransportMgr.cpp
@@ -447,6 +447,15 @@ void TransportMgr::AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg,
animNode.Path[timeSeg] = node;
}
+void TransportMgr::AddPathRotationToTransport(uint32 transportEntry, uint32 timeSeg, TransportRotationEntry const* node)
+{
+ TransportAnimation& animNode = _transportAnimations[transportEntry];
+ animNode.Rotations[timeSeg] = node;
+
+ if (animNode.Path.empty() && animNode.TotalTime < timeSeg)
+ animNode.TotalTime = timeSeg;
+}
+
Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid /*= 0*/, Map* map /*= nullptr*/, uint8 phaseUseFlags /*= 0*/, uint32 phaseId /*= 0*/, uint32 phaseGroupId /*= 0*/)
{
// instance case, execute GetGameObjectEntry hook
@@ -551,20 +560,50 @@ TransportSpawn const* TransportMgr::GetTransportSpawn(ObjectGuid::LowType spawnI
return Trinity::Containers::MapGetValuePtr(_transportSpawns, spawnId);
}
-TransportAnimationEntry const* TransportAnimation::GetAnimNode(uint32 time) const
+TransportAnimationEntry const* TransportAnimation::GetPrevAnimNode(uint32 time) const
+{
+ if (Path.empty())
+ return nullptr;
+
+ auto itr = Path.lower_bound(time);
+ if (itr != Path.begin())
+ return std::prev(itr)->second;
+
+ return Path.rbegin()->second;
+}
+
+TransportRotationEntry const* TransportAnimation::GetPrevAnimRotation(uint32 time) const
+{
+ if (Rotations.empty())
+ return nullptr;
+
+ auto itr = Rotations.lower_bound(time);
+ if (itr != Rotations.begin())
+ return std::prev(itr)->second;
+
+ return Rotations.rbegin()->second;
+}
+
+TransportAnimationEntry const* TransportAnimation::GetNextAnimNode(uint32 time) const
{
+ if (Path.empty())
+ return nullptr;
+
auto itr = Path.lower_bound(time);
if (itr != Path.end())
return itr->second;
- return nullptr;
+ return Path.begin()->second;
}
-TransportRotationEntry const* TransportAnimation::GetAnimRotation(uint32 time) const
+TransportRotationEntry const* TransportAnimation::GetNextAnimRotation(uint32 time) const
{
+ if (Rotations.empty())
+ return nullptr;
+
auto itr = Rotations.lower_bound(time);
if (itr != Rotations.end())
return itr->second;
- return nullptr;
+ return Rotations.begin()->second;
}
diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h
index 58fa2ecc807..92ce809faee 100644
--- a/src/server/game/Maps/TransportMgr.h
+++ b/src/server/game/Maps/TransportMgr.h
@@ -91,8 +91,11 @@ struct TC_GAME_API TransportAnimation
std::map<uint32, TransportRotationEntry const*> Rotations;
uint32 TotalTime;
- TransportAnimationEntry const* GetAnimNode(uint32 time) const;
- TransportRotationEntry const* GetAnimRotation(uint32 time) const;
+ TransportAnimationEntry const* GetPrevAnimNode(uint32 time) const;
+ TransportRotationEntry const* GetPrevAnimRotation(uint32 time) const;
+
+ TransportAnimationEntry const* GetNextAnimNode(uint32 time) const;
+ TransportRotationEntry const* GetNextAnimRotation(uint32 time) const;
};
struct TransportSpawn
@@ -143,10 +146,7 @@ class TC_GAME_API TransportMgr
void AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, TransportAnimationEntry const* node);
- void AddPathRotationToTransport(uint32 transportEntry, uint32 timeSeg, TransportRotationEntry const* node)
- {
- _transportAnimations[transportEntry].Rotations[timeSeg] = node;
- }
+ void AddPathRotationToTransport(uint32 transportEntry, uint32 timeSeg, TransportRotationEntry const* node);
// Container storing transport templates
std::unordered_map<uint32, TransportTemplate> _transportTemplates;
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 20107d2e581..80bd1f58270 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -2820,7 +2820,7 @@ enum GameObjectFlags
DEFINE_ENUM_FLAG(GameObjectFlags);
-enum GameObjectDynamicLowFlags
+enum GameObjectDynamicLowFlags : uint16
{
GO_DYNFLAG_LO_HIDE_MODEL = 0x0002, // Object model is not shown with this flag
GO_DYNFLAG_LO_ACTIVATE = 0x0004, // enables interaction with GO
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index 937339fbcc5..f08a17407a1 100644
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -301,9 +301,9 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
owner->SetHomePosition(x, y, z, o);
else
{
- if (Transport* trans = owner->GetTransport())
+ if (TransportBase* trans = owner->GetTransport())
{
- o -= trans->GetOrientation();
+ o -= trans->GetTransportOrientation();
owner->SetTransportHomePosition(x, y, z, o);
trans->CalculatePassengerPosition(x, y, z, &o);
owner->SetHomePosition(x, y, z, o);
diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp
index 4f68c03bcd8..fbbdc22c8d0 100644
--- a/src/server/game/Movement/Spline/MoveSplineInit.cpp
+++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp
@@ -233,8 +233,8 @@ namespace Movement
{
if (Unit* vehicle = unit->GetVehicleBase())
angle -= vehicle->GetOrientation();
- else if (Transport* transport = unit->GetTransport())
- angle -= transport->GetOrientation();
+ else if (TransportBase* transport = unit->GetTransport())
+ angle -= transport->GetTransportOrientation();
}
args.facing.angle = G3D::wrap(angle, 0.f, (float)G3D::twoPi());
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp
index f03829e4642..69dd3e9fcee 100644
--- a/src/server/scripts/Commands/cs_debug.cpp
+++ b/src/server/scripts/Commands/cs_debug.cpp
@@ -1207,7 +1207,7 @@ public:
static bool HandleDebugTransportCommand(ChatHandler* handler, std::string operation)
{
- Transport* transport = handler->GetPlayer()->GetTransport();
+ Transport* transport = dynamic_cast<Transport*>(handler->GetPlayer()->GetTransport());
if (!transport)
return false;
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index f944120ee3e..367b42e9ec1 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -283,7 +283,7 @@ public:
zoneId, (zoneEntry ? zoneEntry->AreaName[handler->GetSessionDbcLocale()] : unknown),
areaId, (areaEntry ? areaEntry->AreaName[handler->GetSessionDbcLocale()] : unknown),
object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation());
- if (Transport* transport = object->GetTransport())
+ if (Transport* transport = dynamic_cast<Transport*>(object->GetTransport()))
handler->PSendSysMessage(LANG_TRANSPORT_POSITION,
transport->GetGOInfo()->moTransport.SpawnMap, object->GetTransOffsetX(), object->GetTransOffsetY(), object->GetTransOffsetZ(), object->GetTransOffsetO(),
transport->GetEntry(), transport->GetName().c_str());
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index e7198d0afff..e48c800b294 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -124,7 +124,7 @@ public:
Player* chr = handler->GetSession()->GetPlayer();
Map* map = chr->GetMap();
- if (Transport* trans = chr->GetTransport())
+ if (Transport* trans = dynamic_cast<Transport*>(chr->GetTransport()))
{
ObjectGuid::LowType guid = sObjectMgr->GenerateCreatureSpawnId();
CreatureData& data = sObjectMgr->NewOrExistCreatureData(guid);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
index 9927849fe6b..7cd4452a088 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp
@@ -490,12 +490,15 @@ private:
class ResetEncounterEvent : public BasicEvent
{
public:
- ResetEncounterEvent(Unit* caster, uint32 spellId, ObjectGuid otherTransport) : _caster(caster), _spellId(spellId), _otherTransport(otherTransport) { }
+ ResetEncounterEvent(Unit* caster, uint32 spellId, ObjectGuid transport, ObjectGuid otherTransport) : _caster(caster), _spellId(spellId),
+ _transport(transport), _otherTransport(otherTransport) { }
bool Execute(uint64, uint32) override
{
_caster->CastSpell(_caster, _spellId, true);
- _caster->GetTransport()->AddObjectToRemoveList();
+
+ if (Transport* go = HashMapHolder<Transport>::Find(_transport))
+ go->AddObjectToRemoveList();
if (Transport* go = HashMapHolder<Transport>::Find(_otherTransport))
go->AddObjectToRemoveList();
@@ -506,6 +509,7 @@ public:
private:
Unit* _caster;
uint32 _spellId;
+ ObjectGuid _transport;
ObjectGuid _otherTransport;
};
@@ -688,7 +692,7 @@ class npc_gunship : public CreatureScript
if (_summonedFirstMage)
return;
- if (me->GetTransport()->GetEntry() != uint32(_teamInInstance == HORDE ? GO_THE_SKYBREAKER_H : GO_ORGRIMS_HAMMER_A))
+ if (me->GetTransport()->GetTransportGUID() != me->GetInstanceScript()->GetGuidData(DATA_ENEMY_GUNSHIP))
return;
if (!me->HealthBelowPctDamaged(90, damage))
@@ -706,8 +710,8 @@ class npc_gunship : public CreatureScript
_died = true;
- bool isVictory = me->GetTransport()->GetEntry() == GO_THE_SKYBREAKER_H || me->GetTransport()->GetEntry() == GO_ORGRIMS_HAMMER_A;
InstanceScript* instance = me->GetInstanceScript();
+ bool isVictory = me->GetTransport()->GetTransportGUID() == instance->GetGuidData(DATA_ENEMY_GUNSHIP);
instance->SetBossState(DATA_ICECROWN_GUNSHIP_BATTLE, isVictory ? DONE : FAIL);
if (Creature* creature = me->FindNearestCreature(me->GetEntry() == NPC_ORGRIMS_HAMMER ? NPC_THE_SKYBREAKER : NPC_ORGRIMS_HAMMER, 200.0f))
{
@@ -770,7 +774,9 @@ class npc_gunship : public CreatureScript
if (Transport* otherTransport = HashMapHolder<Transport>::Find(instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
otherTransport->EnableMovement(true);
- me->GetTransport()->EnableMovement(true);
+
+ if (Transport* transport = dynamic_cast<Transport*>(me->GetTransport()))
+ transport->EnableMovement(true);
if (Creature* ship = me->FindNearestCreature(_teamInInstance == HORDE ? NPC_ORGRIMS_HAMMER : NPC_THE_SKYBREAKER, 200.0f))
{
@@ -790,8 +796,8 @@ class npc_gunship : public CreatureScript
else
{
uint32 teleportSpellId = _teamInInstance == HORDE ? SPELL_TELEPORT_PLAYERS_ON_RESET_H : SPELL_TELEPORT_PLAYERS_ON_RESET_A;
- me->m_Events.AddEvent(new ResetEncounterEvent(me, teleportSpellId, me->GetInstanceScript()->GetGuidData(DATA_ENEMY_GUNSHIP)),
- me->m_Events.CalculateTime(8s));
+ me->m_Events.AddEventAtOffset(new ResetEncounterEvent(me, teleportSpellId, instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE),
+ instance->GetGuidData(DATA_ENEMY_GUNSHIP)), 8s);
}
}
@@ -841,7 +847,7 @@ struct npc_high_overlord_saurfang_igb : public ScriptedAI
_instance(creature->GetInstanceScript())
{
_controller.ResetSlots(HORDE);
- _controller.SetTransport(creature->GetTransport());
+ _controller.SetTransport(dynamic_cast<Transport*>(creature->GetTransport()));
me->SetRegenerateHealth(false);
me->m_CombatDistance = 70.0f;
_firstMageCooldown = GameTime::Now() + 60s;
@@ -951,7 +957,8 @@ struct npc_high_overlord_saurfang_igb : public ScriptedAI
bool OnGossipSelect(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
- me->GetTransport()->EnableMovement(true);
+ if (Transport* transport = dynamic_cast<Transport*>(me->GetTransport()))
+ transport->EnableMovement(true);
_events.SetPhase(PHASE_INTRO);
_events.ScheduleEvent(EVENT_INTRO_H_1, 5s, 0, PHASE_INTRO);
_events.ScheduleEvent(EVENT_INTRO_H_2, 16s, 0, PHASE_INTRO);
@@ -1019,7 +1026,7 @@ struct npc_high_overlord_saurfang_igb : public ScriptedAI
_controller.SummonCreatures(SLOT_MAGE_1, SLOT_MAGE_2);
_controller.SummonCreatures(SLOT_MARINE_1, Is25ManRaid() ? SLOT_MARINE_4 : SLOT_MARINE_2);
_controller.SummonCreatures(SLOT_SERGEANT_1, Is25ManRaid() ? SLOT_SERGEANT_2 : SLOT_SERGEANT_1);
- if (Transport* orgrimsHammer = me->GetTransport())
+ if (Transport* orgrimsHammer = dynamic_cast<Transport*>(me->GetTransport()))
orgrimsHammer->SummonPassenger(NPC_TELEPORT_PORTAL, OrgrimsHammerTeleportPortal, TEMPSUMMON_TIMED_DESPAWN, nullptr, 21000);
if (Transport* skybreaker = HashMapHolder<Transport>::Find(_instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
@@ -1094,7 +1101,7 @@ struct npc_muradin_bronzebeard_igb : public ScriptedAI
_instance(creature->GetInstanceScript())
{
_controller.ResetSlots(ALLIANCE);
- _controller.SetTransport(creature->GetTransport());
+ _controller.SetTransport(dynamic_cast<Transport*>(creature->GetTransport()));
me->SetRegenerateHealth(false);
me->m_CombatDistance = 70.0f;
_firstMageCooldown = GameTime::Now() + 60s;
@@ -1204,7 +1211,8 @@ struct npc_muradin_bronzebeard_igb : public ScriptedAI
bool OnGossipSelect(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
- me->GetTransport()->EnableMovement(true);
+ if (Transport* transport = dynamic_cast<Transport*>(me->GetTransport()))
+ transport->EnableMovement(true);
_events.SetPhase(PHASE_INTRO);
_events.ScheduleEvent(EVENT_INTRO_A_1, 5s);
_events.ScheduleEvent(EVENT_INTRO_A_2, 10s, 0, PHASE_INTRO);
@@ -1276,7 +1284,7 @@ struct npc_muradin_bronzebeard_igb : public ScriptedAI
_controller.SummonCreatures(SLOT_MAGE_1, SLOT_MAGE_2);
_controller.SummonCreatures(SLOT_MARINE_1, Is25ManRaid() ? SLOT_MARINE_4 : SLOT_MARINE_2);
_controller.SummonCreatures(SLOT_SERGEANT_1, Is25ManRaid() ? SLOT_SERGEANT_2 : SLOT_SERGEANT_1);
- if (Transport* skybreaker = me->GetTransport())
+ if (Transport* skybreaker = dynamic_cast<Transport*>(me->GetTransport()))
skybreaker->SummonPassenger(NPC_TELEPORT_PORTAL, SkybreakerTeleportPortal, TEMPSUMMON_TIMED_DESPAWN, nullptr, 21000);
if (Transport* orgrimsHammer = HashMapHolder<Transport>::Find(_instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
@@ -1402,7 +1410,7 @@ struct npc_gunship_boarding_addAI : public gunship_npc_AI
float x, y, z, o;
otherTransportPos.GetPosition(x, y, z, o);
- Transport* myTransport = me->GetTransport();
+ TransportBase* myTransport = me->GetTransport();
if (!myTransport)
return;
@@ -2010,7 +2018,7 @@ class spell_igb_burning_pitch_selector : public SpellScript
targets.remove_if([team](WorldObject* target) -> bool
{
- if (Transport* transport = target->GetTransport())
+ if (Transport* transport = dynamic_cast<Transport*>(target->GetTransport()))
return transport->GetEntry() != uint32(team == HORDE ? GO_ORGRIMS_HAMMER_H : GO_THE_SKYBREAKER_A);
return true;
});
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/go_icecrown_citadel_teleport.cpp b/src/server/scripts/Northrend/IcecrownCitadel/go_icecrown_citadel_teleport.cpp
index 7e1259fdcc4..72bdf4c087f 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/go_icecrown_citadel_teleport.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/go_icecrown_citadel_teleport.cpp
@@ -72,7 +72,7 @@ class icecrown_citadel_teleport : public GameObjectScript
// If the player is on the ship, Unit::NearTeleport() will try to keep the player on the ship, causing issues.
// For that we simply always remove the player from the ship.
- if (Transport* transport = player->GetTransport())
+ if (TransportBase* transport = player->GetTransport())
transport->RemovePassenger(player);
player->CastSpell(player, spell->Id, true);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
index 8dd11837c8c..1f14b55b647 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
@@ -352,7 +352,7 @@ enum ICGameObjectsIds
GO_SPIRIT_ALARM_3 = 201816,
GO_SPIRIT_ALARM_4 = 201817,
- // Lord Marrogar
+ // Lord Marrowgar
GO_DOODAD_ICECROWN_ICEWALL02 = 201910,
GO_ICEWALL = 201911,
GO_LORD_MARROWGAR_S_ENTRANCE = 201857,
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
index cedebba8633..4a737757efb 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
@@ -536,7 +536,10 @@ class instance_icecrown_citadel : public InstanceMapScript
case GO_LADY_DEATHWHISPER_ELEVATOR:
LadyDeathwisperElevatorGUID = go->GetGUID();
if (GetBossState(DATA_LADY_DEATHWHISPER) == DONE)
- go->SetTransportState(GO_STATE_TRANSPORT_ACTIVE);
+ {
+ go->SetGoState(GO_STATE_TRANSPORT_ACTIVE);
+ go->HandleCustomTypeCommand(GameObjectType::SetTransportAutoCycleBetweenStopFrames(true));
+ }
break;
case GO_THE_SKYBREAKER_H:
case GO_ORGRIMS_HAMMER_A:
@@ -874,7 +877,10 @@ class instance_icecrown_citadel : public InstanceMapScript
SetTeleporterState(teleporter, true);
if (GameObject* elevator = instance->GetGameObject(LadyDeathwisperElevatorGUID))
- elevator->SetTransportState(GO_STATE_TRANSPORT_ACTIVE);
+ {
+ elevator->SetGoState(GO_STATE_TRANSPORT_ACTIVE);
+ elevator->HandleCustomTypeCommand(GameObjectType::SetTransportAutoCycleBetweenStopFrames(true));
+ }
SpawnGunship();
}