Core/GameObjects: Transport (type 11) improvements
* Fully synchronize serverside animation progress with client * Implemented updating passenger positions on elevators * Removed visibility hack for elevators that always forced CreateObject packet to be sent to client
This commit is contained in:
1 parent
b596675c3b
commit
25465699f7
32 files changed
+681
-323
No files matched your search
@@ -1279,7 +1279,11 @@ void Creature::SaveToDB()
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 mapId = GetTransport() ? GetTransport()->GetGOInfo()->moTransport.mapID : GetMapId();
|
||||
uint32 mapId = GetMapId();
|
||||
if (TransportBase* transport = GetTransport())
|
||||
if (transport->GetMapIdForSpawning() >= 0)
|
||||
mapId = transport->GetMapIdForSpawning();
|
||||
|
||||
SaveToDB(mapId, data->spawnMask);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,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;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "CellImpl.h"
|
||||
#include "CreatureAISelector.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "G3DPosition.hpp"
|
||||
#include "GameObjectAI.h"
|
||||
#include "GameEventSender.h"
|
||||
#include "GameObjectModel.h"
|
||||
@@ -59,6 +60,341 @@ 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:
|
||||
// @todo: chronofy timer trackers for 4.x
|
||||
//static constexpr Milliseconds PositionUpdateInterval = 50ms;
|
||||
static constexpr uint8 PositionUpdateInterval = 50;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_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.GetUInt32Value(GAMEOBJECT_LEVEL)))
|
||||
{
|
||||
int32 timeToStop = _owner.GetInt32Value(GAMEOBJECT_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.HasFlag(GAMEOBJECT_DYNAMIC, 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;
|
||||
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.HasFlag(GAMEOBJECT_DYNAMIC, 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.GetFloatValue(GAMEOBJECT_PARENTROTATION + 0), _owner.GetFloatValue(GAMEOBJECT_PARENTROTATION + 1),
|
||||
_owner.GetFloatValue(GAMEOBJECT_PARENTROTATION + 2), _owner.GetFloatValue(GAMEOBJECT_PARENTROTATION + 3)).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->X, oldRotation->Y, oldRotation->Z, oldRotation->W);
|
||||
G3D::Quat next(newRotation->X, newRotation->Y, newRotation->Z, newRotation->W);
|
||||
|
||||
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.SetUInt32Value(GAMEOBJECT_LEVEL, GameTime::GetGameTimeMS() + timeToStop);
|
||||
_owner.SetPathProgressForClient(float(_pathProgress) / float(GetTransportPeriod()));
|
||||
|
||||
if (oldState == GO_STATE_ACTIVE || oldState == newState)
|
||||
{
|
||||
// initialization
|
||||
if (int32(_pathProgress) > stopPathProgress)
|
||||
_owner.SetFlag(GAMEOBJECT_DYNAMIC, GO_DYNFLAG_LO_INVERTED_MOVEMENT);
|
||||
else
|
||||
_owner.RemoveFlag(GAMEOBJECT_DYNAMIC, 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.SetFlag(GAMEOBJECT_DYNAMIC, GO_DYNFLAG_LO_INVERTED_MOVEMENT);
|
||||
else
|
||||
_owner.RemoveFlag(GAMEOBJECT_DYNAMIC, 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;
|
||||
TimeTrackerSmall _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);
|
||||
}
|
||||
}
|
||||
|
||||
void GameObjectTemplate::InitializeQueryData()
|
||||
{
|
||||
WorldPacket queryTemp;
|
||||
@@ -154,10 +490,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()
|
||||
@@ -364,32 +696,14 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, P
|
||||
break;
|
||||
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)
|
||||
{
|
||||
if (!goinfo->transport.startOpen)
|
||||
m_goValue.Transport.StopFrames->push_back(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);
|
||||
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:
|
||||
@@ -476,6 +790,9 @@ void GameObject::Update(uint32 diff)
|
||||
}
|
||||
}
|
||||
|
||||
if (m_goTypeImpl)
|
||||
m_goTypeImpl->Update(diff);
|
||||
|
||||
switch (m_lootState)
|
||||
{
|
||||
case GO_NOT_READY:
|
||||
@@ -497,53 +814,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)
|
||||
{
|
||||
ForceValuesUpdateAtIndex(GAMEOBJECT_LEVEL);
|
||||
ForceValuesUpdateAtIndex(GAMEOBJECT_BYTES_1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GAMEOBJECT_TYPE_FISHINGNODE:
|
||||
{
|
||||
// fishing code (bobber ready)
|
||||
@@ -1011,7 +1281,12 @@ void GameObject::SaveToDB()
|
||||
return;
|
||||
}
|
||||
|
||||
SaveToDB(GetMapId(), data->spawnMask);
|
||||
uint32 mapId = GetMapId();
|
||||
if (TransportBase* transport = GetTransport())
|
||||
if (transport->GetMapIdForSpawning() >= 0)
|
||||
mapId = transport->GetMapIdForSpawning();
|
||||
|
||||
SaveToDB(mapId, data->spawnMask);
|
||||
}
|
||||
|
||||
void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask)
|
||||
@@ -1216,7 +1491,7 @@ bool GameObject::IsDynTransport() const
|
||||
if (!gInfo)
|
||||
return false;
|
||||
|
||||
return gInfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT || (gInfo->type == GAMEOBJECT_TYPE_TRANSPORT && m_goValue.Transport.StopFrames->empty());
|
||||
return gInfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT || gInfo->type == GAMEOBJECT_TYPE_TRANSPORT;
|
||||
}
|
||||
|
||||
bool GameObject::IsDestructibleBuilding() const
|
||||
@@ -2278,7 +2553,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();
|
||||
|
||||
@@ -2475,9 +2750,14 @@ void GameObject::SetLootGenerationTime()
|
||||
|
||||
void GameObject::SetGoState(GOState state)
|
||||
{
|
||||
GOState oldState = GetGoState();
|
||||
SetByteValue(GAMEOBJECT_BYTES_1, 0, state);
|
||||
if (AI())
|
||||
AI()->OnStateChanged(state);
|
||||
|
||||
if (m_goTypeImpl)
|
||||
m_goTypeImpl->OnStateChanged(oldState, state);
|
||||
|
||||
if (m_model && !IsTransport())
|
||||
{
|
||||
if (!IsInWorld())
|
||||
@@ -2492,48 +2772,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 something that will nicely divide for GAMEOBJECT_DYNAMIC value calculation
|
||||
return m_goValue.Transport.PathProgress;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
uint32 stopFrameTime = m_goValue.Transport.StopFrames->at(stopFrame);
|
||||
if (!stopFrameTime) // returning to a previous stop frame that has no travel time (e.g. stop frame at 0ms)
|
||||
stopFrameTime = m_goValue.Transport.StopFrames->at(stopFrame + 1);
|
||||
|
||||
m_goValue.Transport.PathProgress = getMSTime() + stopFrameTime;
|
||||
SetGoState(GOState(GO_STATE_TRANSPORT_STOPPED + stopFrame));
|
||||
}
|
||||
|
||||
ForceValuesUpdateAtIndex(GAMEOBJECT_LEVEL);
|
||||
ForceValuesUpdateAtIndex(GAMEOBJECT_BYTES_1);
|
||||
}
|
||||
|
||||
void GameObject::SetDisplayId(uint32 displayid)
|
||||
{
|
||||
SetUInt32Value(GAMEOBJECT_DISPLAYID, displayid);
|
||||
@@ -2632,7 +2870,6 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
bool isStoppableTransport = GetGoType() == GAMEOBJECT_TYPE_TRANSPORT && !m_goValue.Transport.StopFrames->empty();
|
||||
bool forcedFlags = GetGoType() == GAMEOBJECT_TYPE_CHEST && GetGOInfo()->chest.groupLootRules && HasLootRecipient();
|
||||
bool targetIsGM = target->IsGameMaster();
|
||||
|
||||
@@ -2655,8 +2892,7 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
|
||||
|
||||
if (index == GAMEOBJECT_DYNAMIC)
|
||||
{
|
||||
uint16 dynFlags = 0;
|
||||
int16 pathProgress = -1;
|
||||
uint32 dynFlags = m_uint32Values[GAMEOBJECT_DYNAMIC];
|
||||
switch (GetGoType())
|
||||
{
|
||||
case GAMEOBJECT_TYPE_QUESTGIVER:
|
||||
@@ -2674,27 +2910,11 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
|
||||
if (ActivateToQuest(target))
|
||||
dynFlags |= GO_DYNFLAG_LO_SPARKLE;
|
||||
break;
|
||||
case GAMEOBJECT_TYPE_TRANSPORT:
|
||||
{
|
||||
float timer = float(m_goValue.Transport.PathProgress % GetTransportPeriod());
|
||||
pathProgress = int16(timer / float(GetTransportPeriod()) * 65535.0f);
|
||||
break;
|
||||
}
|
||||
case GAMEOBJECT_TYPE_MO_TRANSPORT:
|
||||
{
|
||||
if (uint32 transportPeriod = GetTransportPeriod())
|
||||
{
|
||||
float timer = float(m_goValue.Transport.PathProgress % transportPeriod);
|
||||
pathProgress = int16(timer / float(transportPeriod) * 65535.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fieldBuffer << uint16(dynFlags);
|
||||
fieldBuffer << int16(pathProgress);
|
||||
fieldBuffer << uint32(dynFlags);
|
||||
}
|
||||
else if (index == GAMEOBJECT_FLAGS)
|
||||
{
|
||||
@@ -2705,27 +2925,6 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
|
||||
|
||||
fieldBuffer << goFlags;
|
||||
}
|
||||
else if (index == GAMEOBJECT_LEVEL)
|
||||
{
|
||||
if (isStoppableTransport)
|
||||
fieldBuffer << uint32(m_goValue.Transport.PathProgress);
|
||||
else
|
||||
fieldBuffer << m_uint32Values[index];
|
||||
}
|
||||
else if (index == GAMEOBJECT_BYTES_1)
|
||||
{
|
||||
uint32 bytes1 = m_uint32Values[index];
|
||||
if (isStoppableTransport && GetGoState() == GO_STATE_TRANSPORT_ACTIVE)
|
||||
{
|
||||
if ((m_goValue.Transport.StateUpdateTimer / 20000) & 1)
|
||||
{
|
||||
bytes1 &= 0xFFFFFF00;
|
||||
bytes1 |= GO_STATE_TRANSPORT_STOPPED;
|
||||
}
|
||||
}
|
||||
|
||||
fieldBuffer << bytes1;
|
||||
}
|
||||
else
|
||||
fieldBuffer << m_uint32Values[index]; // other cases
|
||||
}
|
||||
@@ -2735,6 +2934,27 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
|
||||
data->append(fieldBuffer);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
bool hasPendingUpdate = _changesMask.GetBit(GAMEOBJECT_DYNAMIC);
|
||||
|
||||
uint32 dynamicFlags = GetUInt32Value(GAMEOBJECT_DYNAMIC);
|
||||
dynamicFlags &= 0xFFFF; // remove high bits
|
||||
dynamicFlags |= uint32(progress * 65535.0f) << 16;
|
||||
UpdateUInt32Value(GAMEOBJECT_DYNAMIC, dynamicFlags);
|
||||
|
||||
if (!hasPendingUpdate)
|
||||
_changesMask.UnsetBit(GAMEOBJECT_DYNAMIC);
|
||||
}
|
||||
|
||||
void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = nullptr*/) const
|
||||
{
|
||||
if (m_goData)
|
||||
@@ -2753,6 +2973,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_MO_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())
|
||||
@@ -2821,6 +3066,12 @@ private:
|
||||
GameObject* _owner;
|
||||
};
|
||||
|
||||
void GameObject::HandleCustomTypeCommand(GameObjectTypeBase::CustomCommand const& command) const
|
||||
{
|
||||
if (m_goTypeImpl)
|
||||
command.Execute(*m_goTypeImpl);
|
||||
}
|
||||
|
||||
GameObjectModel* GameObject::CreateModel()
|
||||
{
|
||||
return GameObjectModel::Create(Trinity::make_unique<GameObjectModelOwnerImpl>(this), sWorld->GetDataPath());
|
||||
|
||||
@@ -25,27 +25,56 @@
|
||||
#include "MapObject.h"
|
||||
#include "SharedDefines.h"
|
||||
|
||||
class GameObject;
|
||||
class GameObjectAI;
|
||||
class GameObjectModel;
|
||||
class Group;
|
||||
class OPvPCapturePoint;
|
||||
class SpellInfo;
|
||||
class Transport;
|
||||
class TransportBase;
|
||||
class Unit;
|
||||
struct TransportAnimation;
|
||||
enum TriggerCastFlags : uint32;
|
||||
|
||||
// Base class for GameObject type specific implementations
|
||||
class GameObjectTypeBase
|
||||
{
|
||||
public:
|
||||
class TC_GAME_API CustomCommand
|
||||
{
|
||||
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
|
||||
{
|
||||
//11 GAMEOBJECT_TYPE_TRANSPORT
|
||||
struct
|
||||
{
|
||||
uint32 PathProgress;
|
||||
TransportAnimation const* AnimationInfo;
|
||||
uint32 CurrentSeg;
|
||||
std::vector<uint32>* StopFrames;
|
||||
uint32 StateUpdateTimer;
|
||||
} Transport;
|
||||
//25 GAMEOBJECT_TYPE_FISHINGHOLE
|
||||
struct
|
||||
{
|
||||
@@ -165,14 +194,15 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
|
||||
GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
|
||||
void SetGoState(GOState state);
|
||||
virtual uint32 GetTransportPeriod() const;
|
||||
void SetTransportState(GOState state, uint32 stopFrame = 0);
|
||||
uint8 GetGoArtKit() const { return GetByteValue(GAMEOBJECT_BYTES_1, 2); }
|
||||
void SetGoArtKit(uint8 artkit);
|
||||
uint8 GetGoAnimProgress() const { return GetByteValue(GAMEOBJECT_BYTES_1, 3); }
|
||||
void SetGoAnimProgress(uint8 animprogress) { SetByteValue(GAMEOBJECT_BYTES_1, 3, animprogress); }
|
||||
static void SetGoArtKit(uint8 artkit, GameObject* go, ObjectGuid::LowType lowguid = 0);
|
||||
|
||||
std::vector<uint32> const* GetPauseTimes() const;
|
||||
void SetPathProgressForClient(float progress);
|
||||
|
||||
void PlayAnimKit(int32 animKit);
|
||||
|
||||
void EnableCollision(bool enable);
|
||||
@@ -277,6 +307,10 @@ 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_MO_TRANSPORT) return reinterpret_cast<Transport*>(this); else return nullptr; }
|
||||
Transport const* ToTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT) return reinterpret_cast<Transport const*>(this); else return nullptr; }
|
||||
|
||||
@@ -284,8 +318,11 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
float GetStationaryY() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionY(); return GetPositionY(); }
|
||||
float GetStationaryZ() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); }
|
||||
float GetStationaryO() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetOrientation(); return 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();
|
||||
@@ -301,6 +338,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
void AIM_Destroy();
|
||||
bool AIM_Initialize();
|
||||
|
||||
void HandleCustomTypeCommand(GameObjectTypeBase::CustomCommand const& command) const;
|
||||
|
||||
protected:
|
||||
GameObjectModel* CreateModel();
|
||||
void UpdateModel(); // updates model in case displayId were changed
|
||||
@@ -331,7 +370,9 @@ 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;
|
||||
|
||||
@@ -609,7 +609,6 @@ struct GameObjectTemplate
|
||||
case GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY: return true;
|
||||
case GAMEOBJECT_TYPE_TRAPDOOR: return true;
|
||||
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING: return true;
|
||||
case GAMEOBJECT_TYPE_TRANSPORT: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
@@ -625,6 +624,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_CAPTURE_POINT: return capturePoint.GiganticAOI != 0;
|
||||
default: return false;
|
||||
|
||||
@@ -350,10 +350,9 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint32 flags) const
|
||||
bool hasMovementAnimKit = false;
|
||||
bool hasMeleeAnimKit = false;
|
||||
|
||||
uint32 stopFrameCount = 0;
|
||||
std::vector<uint32> const* PauseTimes = nullptr;
|
||||
if (GameObject const* go = ToGameObject())
|
||||
if (go->GetGoType() == GAMEOBJECT_TYPE_TRANSPORT)
|
||||
stopFrameCount = go->GetGOValue()->Transport.StopFrames->size();
|
||||
PauseTimes = go->GetPauseTimes();
|
||||
|
||||
// Bit content
|
||||
data->WriteBit(flags & UPDATEFLAG_PLAY_HOVER_ANIM);
|
||||
@@ -364,7 +363,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint32 flags) const
|
||||
data->WriteBit(flags & UPDATEFLAG_SELF);
|
||||
data->WriteBit(flags & UPDATEFLAG_VEHICLE);
|
||||
data->WriteBit(flags & UPDATEFLAG_LIVING);
|
||||
data->WriteBits(stopFrameCount, 24);
|
||||
data->WriteBits(PauseTimes->size(), 24);
|
||||
data->WriteBit(flags & UPDATEFLAG_NO_BIRTH_ANIM);
|
||||
data->WriteBit(flags & UPDATEFLAG_GO_TRANSPORT_POSITION);
|
||||
data->WriteBit(flags & UPDATEFLAG_STATIONARY_POSITION);
|
||||
@@ -481,10 +480,8 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint32 flags) const
|
||||
|
||||
data->FlushBits();
|
||||
|
||||
// Data
|
||||
if (GameObject const* go = ToGameObject())
|
||||
for (uint32 i = 0; i < stopFrameCount; ++i)
|
||||
*data << uint32(go->GetGOValue()->Transport.StopFrames->at(i));
|
||||
if (PauseTimes && !PauseTimes->empty())
|
||||
data->append(PauseTimes->data(), PauseTimes->size());
|
||||
|
||||
if (flags & UPDATEFLAG_LIVING)
|
||||
{
|
||||
@@ -658,18 +655,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint32 flags) const
|
||||
}
|
||||
|
||||
if (flags & UPDATEFLAG_TRANSPORT)
|
||||
{
|
||||
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())
|
||||
*data << uint32(go->GetGOValue()->Transport.PathProgress);
|
||||
else
|
||||
*data << uint32(GameTime::GetGameTimeMS());
|
||||
}
|
||||
*data << uint32(GameTime::GetGameTimeMS());
|
||||
}
|
||||
|
||||
void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
|
||||
@@ -1203,19 +1189,9 @@ void WorldObject::setActive(bool on)
|
||||
return;
|
||||
|
||||
if (on)
|
||||
{
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
map->AddToActive(this->ToCreature());
|
||||
else if (GetTypeId() == TYPEID_DYNAMICOBJECT)
|
||||
map->AddToActive((DynamicObject*)this);
|
||||
}
|
||||
map->AddToActive(this);
|
||||
else
|
||||
{
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
map->RemoveFromActive(this->ToCreature());
|
||||
else if (GetTypeId() == TYPEID_DYNAMICOBJECT)
|
||||
map->RemoveFromActive((DynamicObject*)this);
|
||||
}
|
||||
map->RemoveFromActive(this);
|
||||
}
|
||||
|
||||
void WorldObject::SetFarVisible(bool on)
|
||||
@@ -1240,7 +1216,7 @@ void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
|
||||
if (IsInWorld())
|
||||
RemoveFromWorld();
|
||||
|
||||
if (Transport* transport = GetTransport())
|
||||
if (TransportBase* transport = GetTransport())
|
||||
transport->RemovePassenger(this);
|
||||
}
|
||||
|
||||
@@ -1307,7 +1283,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().GetCounter() == GetTransport()->GetGUID().GetCounter())
|
||||
if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetTransportGUID() == GetTransport()->GetTransportGUID())
|
||||
{
|
||||
thisOrTransport = &m_movementInfo.transport.pos;
|
||||
objOrObjTransport = &obj->m_movementInfo.transport.pos;
|
||||
@@ -2099,7 +2075,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonCreatur
|
||||
if (summonArgs.Summoner)
|
||||
PhasingHandler::InheritPhaseShift(summon, summonArgs.Summoner);
|
||||
|
||||
Transport* transport = summonArgs.Summoner ? summonArgs.Summoner->GetTransport() : nullptr;
|
||||
TransportBase* transport = summonArgs.Summoner ? summonArgs.Summoner->GetTransport() : nullptr;
|
||||
if (transport)
|
||||
{
|
||||
float x, y, z, o;
|
||||
@@ -2776,7 +2752,7 @@ void WorldObject::RemoveFromObjectUpdate()
|
||||
ObjectGuid WorldObject::GetTransGUID() const
|
||||
{
|
||||
if (GetTransport())
|
||||
return GetTransport()->GetGUID();
|
||||
return GetTransport()->GetTransportGUID();
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class InstanceScript;
|
||||
class Map;
|
||||
class Player;
|
||||
class TempSummon;
|
||||
class Transport;
|
||||
class TransportBase;
|
||||
class Unit;
|
||||
class UpdateData;
|
||||
class WorldObject;
|
||||
@@ -457,7 +457,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(); }
|
||||
@@ -466,7 +466,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;
|
||||
|
||||
@@ -502,8 +502,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
const bool m_isWorldObject;
|
||||
ZoneScript* m_zoneScript;
|
||||
|
||||
// transports
|
||||
Transport* m_transport;
|
||||
// transports (gameobjects only)
|
||||
TransportBase* m_transport;
|
||||
|
||||
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data);
|
||||
uint32 m_zoneId;
|
||||
|
||||
@@ -1449,7 +1449,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 teleport 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 :)
|
||||
@@ -1470,7 +1470,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
|
||||
m_movementInfo.ResetJump();
|
||||
DisableSpline();
|
||||
|
||||
if (Transport* transport = GetTransport())
|
||||
if (TransportBase* transport = GetTransport())
|
||||
{
|
||||
if (!(options & TELE_TO_NOT_LEAVE_TRANSPORT))
|
||||
transport->RemovePassenger(this);
|
||||
@@ -1605,7 +1605,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
|
||||
// send transfer packets
|
||||
WorldPackets::Movement::TransferPending transferPending;
|
||||
transferPending.MapID = mapid;
|
||||
if (Transport* transport = GetTransport())
|
||||
if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
|
||||
{
|
||||
transferPending.Ship.emplace();
|
||||
transferPending.Ship->ID = transport->GetEntry();
|
||||
@@ -19525,8 +19525,8 @@ void Player::SaveToDB(CharacterDatabaseTransaction trans, bool create /* = false
|
||||
stmt->setFloat(index++, finiteAlways(GetTransOffsetZ()));
|
||||
stmt->setFloat(index++, finiteAlways(GetTransOffsetO()));
|
||||
ObjectGuid::LowType transLowGUID = 0;
|
||||
if (GetTransport())
|
||||
transLowGUID = GetTransport()->GetGUID().GetCounter();
|
||||
if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
|
||||
transLowGUID = transport->GetGUID().GetCounter();
|
||||
stmt->setUInt32(index++, transLowGUID);
|
||||
|
||||
std::ostringstream ss;
|
||||
@@ -19660,8 +19660,8 @@ void Player::SaveToDB(CharacterDatabaseTransaction trans, bool create /* = false
|
||||
stmt->setFloat(index++, finiteAlways(GetTransOffsetZ()));
|
||||
stmt->setFloat(index++, finiteAlways(GetTransOffsetO()));
|
||||
ObjectGuid::LowType transLowGUID = 0;
|
||||
if (GetTransport())
|
||||
transLowGUID = GetTransport()->GetGUID().GetCounter();
|
||||
if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
|
||||
transLowGUID = transport->GetGUID().GetCounter();
|
||||
stmt->setUInt32(index++, transLowGUID);
|
||||
|
||||
std::ostringstream ss;
|
||||
@@ -23028,17 +23028,6 @@ inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target, std::set
|
||||
s64.insert(target->GetGUID());
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -85,7 +85,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)
|
||||
{
|
||||
@@ -142,7 +142,7 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid,
|
||||
SetUInt32Value(GAMEOBJECT_FLAGS, m_goTemplateAddon->flags);
|
||||
}
|
||||
|
||||
m_goValue.Transport.PathProgress = 0;
|
||||
_pathProgress = 0;
|
||||
SetObjectScale(goinfo->size);
|
||||
SetPeriod(tInfo->pathTime);
|
||||
SetEntry(goinfo->entry);
|
||||
@@ -183,9 +183,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
|
||||
@@ -209,9 +209,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
|
||||
}
|
||||
@@ -314,7 +314,7 @@ void Transport::AddPassenger(WorldObject* passenger)
|
||||
}
|
||||
}
|
||||
|
||||
void Transport::RemovePassenger(WorldObject* passenger)
|
||||
Transport* Transport::RemovePassenger(WorldObject* passenger)
|
||||
{
|
||||
bool erased = false;
|
||||
if (_passengerTeleportItr != _passengers.end())
|
||||
@@ -344,6 +344,8 @@ void Transport::RemovePassenger(WorldObject* passenger)
|
||||
plr->SetFallInformation(0, plr->GetPositionZ());
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Creature* Transport::CreateNPCPassenger(ObjectGuid::LowType guid, CreatureData const* data)
|
||||
@@ -555,6 +557,11 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu
|
||||
return summon;
|
||||
}
|
||||
|
||||
int32 Transport::GetMapIdForSpawning() const
|
||||
{
|
||||
return GetGOInfo()->moTransport.mapID;
|
||||
}
|
||||
|
||||
void Transport::UpdatePosition(float x, float y, float z, float o)
|
||||
{
|
||||
bool newActive = GetMap()->IsGridLoaded(x, y);
|
||||
|
||||
@@ -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 GetUInt32Value(GAMEOBJECT_LEVEL); }
|
||||
int32 GetMapIdForSpawning() const override;
|
||||
|
||||
uint32 GetTransportPeriod() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
|
||||
void SetPeriod(uint32 period) { SetUInt32Value(GAMEOBJECT_LEVEL, period); }
|
||||
uint32 GetTimer() const { return GetGOValue()->Transport.PathProgress; }
|
||||
uint32 GetTimer() const { return _pathProgress; }
|
||||
|
||||
KeyFrameVec const& GetKeyFrames() const { return _transportInfo->keyFrames; }
|
||||
|
||||
@@ -116,6 +122,7 @@ class TC_GAME_API Transport : public GameObject, public TransportBase
|
||||
|
||||
KeyFrameVec::const_iterator _currentFrame;
|
||||
KeyFrameVec::const_iterator _nextFrame;
|
||||
uint32 _pathProgress;
|
||||
TimeTrackerSmall _positionChangeTimer;
|
||||
bool _isMoving;
|
||||
bool _pendingStop;
|
||||
|
||||
@@ -12581,7 +12581,7 @@ ObjectGuid Unit::GetTransGUID() const
|
||||
if (GetVehicle())
|
||||
return GetVehicleBase()->GetGUID();
|
||||
if (GetTransport())
|
||||
return GetTransport()->GetGUID();
|
||||
return GetTransport()->GetTransportGUID();
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
@@ -13539,7 +13539,7 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a
|
||||
SetControlled(true, UNIT_STATE_ROOT);
|
||||
|
||||
ASSERT(!m_vehicle);
|
||||
(void)vehicle->AddPassenger(this, seatId);
|
||||
(void)vehicle->AddVehiclePassenger(this, seatId);
|
||||
}
|
||||
|
||||
void Unit::ChangeSeat(int8 seatId, bool next)
|
||||
|
||||
@@ -455,7 +455,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)
|
||||
@@ -527,9 +527,10 @@ 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)
|
||||
{
|
||||
if (unit->GetVehicle() != this)
|
||||
Unit* unit = passenger->ToUnit();
|
||||
if (!unit)
|
||||
return nullptr;
|
||||
|
||||
SeatMap::iterator seat = GetSeatIteratorForPassenger(unit);
|
||||
@@ -976,7 +977,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());
|
||||
}
|
||||
|
||||
@@ -55,8 +55,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);
|
||||
Vehicle* RemovePassenger(Unit* passenger);
|
||||
bool AddVehiclePassenger(Unit* unit, int8 seatId = -1);
|
||||
Vehicle* RemovePassenger(WorldObject* passenger) override;
|
||||
void RelocatePassengers();
|
||||
void RemoveAllPassengers();
|
||||
bool IsVehicleInUse() const;
|
||||
@@ -86,6 +86,12 @@ class TC_GAME_API Vehicle : public TransportBase
|
||||
SeatMap::iterator GetSeatIteratorForPassenger(Unit* passenger);
|
||||
void InitMovementInfoForBase();
|
||||
|
||||
ObjectGuid GetTransportGUID() const override { return GetBase()->GetGUID(); }
|
||||
|
||||
float GetTransportOrientation() const override { return GetBase()->GetOrientation(); }
|
||||
|
||||
void AddPassenger(WorldObject* /*passenger*/) override { ASSERT("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
|
||||
{
|
||||
@@ -102,6 +108,9 @@ 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);
|
||||
|
||||
|
||||
@@ -153,12 +153,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)
|
||||
@@ -184,6 +192,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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -339,28 +339,30 @@ void WorldSession::HandleMovementOpcode(uint16 opcode, MovementInfo& movementInf
|
||||
{
|
||||
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.guid.Clear();
|
||||
}
|
||||
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 == MSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight())
|
||||
|
||||
@@ -1258,9 +1258,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);
|
||||
}
|
||||
}
|
||||
@@ -1432,9 +1430,7 @@ void Map::MoveAllGameObjectsInMoveList()
|
||||
{
|
||||
// update pos
|
||||
go->Relocate(go->_newPosition);
|
||||
go->UpdateModelPosition();
|
||||
go->UpdatePositionData();
|
||||
go->UpdateObjectVisibility(false);
|
||||
go->AfterRelocation();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2860,7 +2856,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());
|
||||
@@ -2870,7 +2866,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);
|
||||
|
||||
@@ -445,6 +445,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;
|
||||
}
|
||||
@@ -88,13 +88,15 @@ struct TransportTemplate
|
||||
struct TC_GAME_API TransportAnimation
|
||||
{
|
||||
TransportAnimation() : TotalTime(0) { }
|
||||
|
||||
std::map<uint32, TransportAnimationEntry const*> Path;
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -146,10 +148,7 @@ private:
|
||||
|
||||
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;
|
||||
|
||||
@@ -1855,13 +1855,14 @@ enum GameObjectFlags
|
||||
GO_FLAG_DESTROYED = 0x00000400
|
||||
};
|
||||
|
||||
enum GameObjectDynamicLowFlags
|
||||
enum GameObjectDynamicLowFlags : uint16
|
||||
{
|
||||
GO_DYNFLAG_LO_ACTIVATE = 0x01, // enables interaction with GO
|
||||
GO_DYNFLAG_LO_ANIMATE = 0x02, // possibly more distinct animation of GO
|
||||
GO_DYNFLAG_LO_NO_INTERACT = 0x04, // appears to disable interaction (not fully verified)
|
||||
GO_DYNFLAG_LO_SPARKLE = 0x08, // makes GO sparkle
|
||||
GO_DYNFLAG_LO_STOPPED = 0x10 // Transport is stopped
|
||||
GO_DYNFLAG_LO_STOPPED = 0x10, // Transport is stopped
|
||||
GO_DYNFLAG_LO_INVERTED_MOVEMENT = 0x40, // GAMEOBJECT_TYPE_TRANSPORT only
|
||||
};
|
||||
|
||||
// client side GO show states
|
||||
|
||||
@@ -114,9 +114,9 @@ void WaypointMovementGenerator<Creature>::ProcessWaypointArrival(Creature* creat
|
||||
creature->SetHomePosition(x, y, z, o);
|
||||
else
|
||||
{
|
||||
if (Transport* trans = creature->GetTransport())
|
||||
if (TransportBase* trans = creature->GetTransport())
|
||||
{
|
||||
o -= trans->GetOrientation();
|
||||
o -= trans->GetTransportOrientation();
|
||||
creature->SetTransportHomePosition(x, y, z, o);
|
||||
trans->CalculatePassengerPosition(x, y, z, &o);
|
||||
creature->SetHomePosition(x, y, z, o);
|
||||
|
||||
@@ -228,8 +228,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());
|
||||
|
||||
@@ -3779,12 +3779,12 @@ void Spell::EffectActivateObject(SpellEffIndex effIndex)
|
||||
case GameObjectActions::GoTo8thFloor:
|
||||
case GameObjectActions::GoTo9thFloor:
|
||||
case GameObjectActions::GoTo10thFloor:
|
||||
{
|
||||
// Cast is kind of loose but it'll do
|
||||
if (Transport* transportTarget = gameObjTarget->ToTransport())
|
||||
transportTarget->SetTransportState(GO_STATE_TRANSPORT_STOPPED, uint32_t(action) - uint32(GameObjectActions::GoTo1stFloor));
|
||||
static_assert(int32(GO_STATE_TRANSPORT_ACTIVE) == int32(GameObjectActions::GoTo1stFloor));
|
||||
if (gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_TRANSPORT)
|
||||
gameObjTarget->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", m_spellInfo->Id, int32(action), int32(effIndex));
|
||||
break;
|
||||
}
|
||||
case GameObjectActions::None:
|
||||
TC_LOG_FATAL("spell", "Spell %d has action type NONE in effect %d", m_spellInfo->Id, int32(effIndex));
|
||||
break;
|
||||
|
||||
@@ -1569,7 +1569,7 @@ public:
|
||||
|
||||
static bool HandleDebugTransportCommand(ChatHandler* handler, char const* args)
|
||||
{
|
||||
Transport* transport = handler->GetSession()->GetPlayer()->GetTransport();
|
||||
Transport* transport = dynamic_cast<Transport*>(handler->GetSession()->GetPlayer()->GetTransport());
|
||||
if (!transport)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ public:
|
||||
zoneId, (zoneEntry ? zoneEntry->AreaName : unknown),
|
||||
areaId, (areaEntry ? areaEntry->AreaName : 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.mapID, object->GetTransOffsetX(), object->GetTransOffsetY(), object->GetTransOffsetZ(), object->GetTransOffsetO(),
|
||||
|
||||
@@ -350,7 +350,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);
|
||||
|
||||
+4
-4
@@ -423,7 +423,7 @@ struct boss_nefarians_end : public BossAI
|
||||
if (events.IsInPhase(PHASE_TWO) && !_elevatorLowered)
|
||||
instance->SetData(DATA_RESET_ELEVATOR, events.GetTimeUntilEvent(EVENT_ELEVATOR_LOWERED));
|
||||
else if (Transport* transport = GetElevator())
|
||||
transport->SetTransportState(GO_STATE_TRANSPORT_STOPPED, TRANSPORT_STOP_FRAME_RAISED);
|
||||
transport->SetGoState(GOState(GO_STATE_TRANSPORT_STOPPED + TRANSPORT_STOP_FRAME_RAISED));
|
||||
|
||||
if (Creature* onyxia = instance->GetCreature(DATA_ONYXIA))
|
||||
if (onyxia->IsAlive())
|
||||
@@ -753,7 +753,7 @@ struct boss_nefarians_end : public BossAI
|
||||
break;
|
||||
case EVENT_LOWER_ELEVATOR:
|
||||
if (Transport* transport = GetElevator())
|
||||
transport->SetTransportState(GO_STATE_TRANSPORT_ACTIVE);
|
||||
transport->SetGoState(GO_STATE_TRANSPORT_STOPPED);
|
||||
events.ScheduleEvent(EVENT_ELEVATOR_LOWERED, 9s, 0, PHASE_TWO);
|
||||
break;
|
||||
case EVENT_ELEVATOR_LOWERED:
|
||||
@@ -881,7 +881,7 @@ private:
|
||||
events.ScheduleEvent(EVENT_SAY_PHASE_THREE, 14s + 700ms);
|
||||
events.ScheduleEvent(EVENT_PREPARE_LANDING, 15s + 500ms, 0, PHASE_THREE);
|
||||
if (Transport* elevator = GetElevator())
|
||||
elevator->SetTransportState(GO_STATE_TRANSPORT_STOPPED, TRANSPORT_STOP_FRAME_RAISED);
|
||||
elevator->SetGoState(GOState(GO_STATE_TRANSPORT_STOPPED + TRANSPORT_STOP_FRAME_RAISED));
|
||||
|
||||
for (ObjectGuid guid : summons)
|
||||
{
|
||||
@@ -1113,7 +1113,7 @@ struct npc_nefarians_end_lord_victor_nefarius : public PassiveAI
|
||||
case EVENT_RAISE_ELEVATOR:
|
||||
if (GameObject* elevator = _instance->GetGameObject(DATA_BLACKWING_ELEVATOR_ONYXIA))
|
||||
if (Transport* transport = elevator->ToTransport())
|
||||
transport->SetTransportState(GO_STATE_TRANSPORT_STOPPED, TRANSPORT_STOP_FRAME_RAISED);
|
||||
transport->SetGoState(GOState(GO_STATE_TRANSPORT_STOPPED + TRANSPORT_STOP_FRAME_RAISED));
|
||||
break;
|
||||
case EVENT_CAST_TRANSFORM_VISUAL:
|
||||
if (Creature* stalker = me->FindNearestCreature(NPC_INVISIBLE_STALKER_CATACLYSM_BOSS, 1.0f))
|
||||
|
||||
+1
-1
@@ -465,7 +465,7 @@ class instance_blackwing_descent : public InstanceMapScript
|
||||
case EVENT_RAISE_ELEVATOR:
|
||||
if (GameObject* gameobject = GetGameObject(DATA_BLACKWING_ELEVATOR_ONYXIA))
|
||||
if (Transport* transport = gameobject->ToTransport())
|
||||
transport->SetTransportState(GO_STATE_TRANSPORT_STOPPED, 1);
|
||||
transport->SetGoState(GOState(GO_STATE_TRANSPORT_STOPPED + 1));
|
||||
break;
|
||||
case EVENT_RESPAWN_LEFT_DWARVEN_GROUP:
|
||||
instance->SpawnGroupSpawn(SPAWN_GROUP_DWARVEN_SPIRITS_LEFT, true);
|
||||
|
||||
@@ -784,11 +784,14 @@ struct go_hoo_the_makers_lift_controller : public GameObjectAI
|
||||
if (!elevator)
|
||||
return true;
|
||||
|
||||
elevator->SetGoState(GOState(GO_STATE_TRANSPORT_STOPPED + action));
|
||||
|
||||
/*
|
||||
if (action == 0 && elevator->GetGoState() >= GO_STATE_TRANSPORT_ACTIVE + 2)
|
||||
elevator->SetTransportState(GO_STATE_TRANSPORT_ACTIVE);
|
||||
else
|
||||
elevator->SetTransportState(GO_STATE_TRANSPORT_STOPPED, action);
|
||||
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -488,12 +488,16 @@ 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();
|
||||
@@ -504,6 +508,7 @@ public:
|
||||
private:
|
||||
Unit* _caster;
|
||||
uint32 _spellId;
|
||||
ObjectGuid _transport;
|
||||
ObjectGuid _otherTransport;
|
||||
};
|
||||
|
||||
@@ -686,7 +691,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))
|
||||
@@ -704,8 +709,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))
|
||||
{
|
||||
@@ -768,7 +773,8 @@ 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))
|
||||
{
|
||||
@@ -788,8 +794,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(8000));
|
||||
me->m_Events.AddEventAtOffset(new ResetEncounterEvent(me, teleportSpellId, instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE),
|
||||
instance->GetGuidData(DATA_ENEMY_GUNSHIP)), 8s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,7 +850,7 @@ class npc_high_overlord_saurfang_igb : public CreatureScript
|
||||
_instance(creature->GetInstanceScript())
|
||||
{
|
||||
_controller.ResetSlots(HORDE);
|
||||
_controller.SetTransport(creature->GetTransport());
|
||||
_controller.SetTransport(dynamic_cast<Transport*>(creature->GetTransport()));
|
||||
me->setRegeneratingHealth(false);
|
||||
me->m_CombatDistance = 70.0f;
|
||||
_firstMageCooldown = GameTime::GetGameTime() + 60;
|
||||
@@ -954,7 +960,8 @@ class npc_high_overlord_saurfang_igb : public CreatureScript
|
||||
bool GossipSelect(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/) override
|
||||
{
|
||||
me->RemoveFlag(UNIT_NPC_FLAGS, 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, 5000, 0, PHASE_INTRO);
|
||||
_events.ScheduleEvent(EVENT_INTRO_H_2, 16000, 0, PHASE_INTRO);
|
||||
@@ -1022,7 +1029,7 @@ class npc_high_overlord_saurfang_igb : public CreatureScript
|
||||
_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)))
|
||||
@@ -1108,7 +1115,7 @@ class npc_muradin_bronzebeard_igb : public CreatureScript
|
||||
_instance(creature->GetInstanceScript())
|
||||
{
|
||||
_controller.ResetSlots(ALLIANCE);
|
||||
_controller.SetTransport(creature->GetTransport());
|
||||
_controller.SetTransport(dynamic_cast<Transport*>(creature->GetTransport()));
|
||||
me->setRegeneratingHealth(false);
|
||||
me->m_CombatDistance = 70.0f;
|
||||
_firstMageCooldown = GameTime::GetGameTime() + 60;
|
||||
@@ -1218,7 +1225,8 @@ class npc_muradin_bronzebeard_igb : public CreatureScript
|
||||
bool GossipSelect(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/) override
|
||||
{
|
||||
me->RemoveFlag(UNIT_NPC_FLAGS, 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, 5000);
|
||||
_events.ScheduleEvent(EVENT_INTRO_A_2, 10000, 0, PHASE_INTRO);
|
||||
@@ -1290,7 +1298,7 @@ class npc_muradin_bronzebeard_igb : public CreatureScript
|
||||
_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)))
|
||||
@@ -1435,7 +1443,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;
|
||||
|
||||
@@ -2154,7 +2162,7 @@ class spell_igb_burning_pitch_selector : public SpellScriptLoader
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Spell.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Transport.h"
|
||||
|
||||
static std::vector<uint32> const TeleportSpells =
|
||||
{
|
||||
@@ -65,6 +66,11 @@ class icecrown_citadel_teleport : public GameObjectScript
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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 (TransportBase* transport = player->GetTransport())
|
||||
transport->RemovePassenger(player);
|
||||
|
||||
player->CastSpell(player, spell->Id, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -435,7 +435,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:
|
||||
@@ -748,7 +751,10 @@ class instance_icecrown_citadel : public InstanceMapScript
|
||||
SetTeleporterState(teleporter, true);
|
||||
|
||||
if (Transport* elevator = instance->GetTransport(LadyDeathwisperElevatorGUID))
|
||||
elevator->SetTransportState(GO_STATE_TRANSPORT_ACTIVE);
|
||||
{
|
||||
elevator->SetGoState(GO_STATE_TRANSPORT_ACTIVE);
|
||||
elevator->HandleCustomTypeCommand(GameObjectType::SetTransportAutoCycleBetweenStopFrames(true));
|
||||
}
|
||||
|
||||
SpawnGunship();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user