aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2013-10-16 18:37:29 +0200
committerShauren <shauren.trinity@gmail.com>2013-10-16 18:37:29 +0200
commitce55647c415b710c6b440d96c2f26ebbc06c1d6e (patch)
tree515af245894c37aa76c590b6e602eb4e398d68be /src/server/game/Entities
parent53cc37bceca9ce7de1b9839251ccc809ebf768b6 (diff)
Core/Transports
* Rewritten path generation, now uses splines - timers are a lot more accurate now * Implemented stopping transports * Implemented spawning transports in instances * Implemented spawning gameobjects as transport passengers * Transport passengers are now stored in creature/gameobject table using gameobject_template.data6 from transport's template as map id
Diffstat (limited to 'src/server/game/Entities')
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp26
-rw-r--r--src/server/game/Entities/Creature/Creature.h31
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp94
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h25
-rw-r--r--src/server/game/Entities/Object/Object.cpp20
-rw-r--r--src/server/game/Entities/Object/Object.h48
-rw-r--r--src/server/game/Entities/Player/Player.cpp24
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp931
-rw-r--r--src/server/game/Entities/Transport/Transport.h112
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp7
-rw-r--r--src/server/game/Entities/Unit/Unit.h6
11 files changed, 627 insertions, 697 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 4efd78d5932..f68d87de2f4 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -52,7 +52,7 @@
#include "World.h"
#include "WorldPacket.h"
-// apply implementation of the singletons
+#include "Transport.h"
TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
{
@@ -141,7 +141,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
return true;
}
-Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapCreature(),
+Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0),
m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0),
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE),
@@ -934,7 +934,8 @@ void Creature::SaveToDB()
return;
}
- SaveToDB(GetMapId(), data->spawnMask, GetPhaseMask());
+ uint32 mapId = GetTransport() ? GetTransport()->GetGOInfo()->moTransport.mapID : GetMapId();
+ SaveToDB(mapId, data->spawnMask, GetPhaseMask());
}
void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
@@ -973,10 +974,21 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
data.phaseMask = phaseMask;
data.displayid = displayId;
data.equipmentId = GetCurrentEquipmentId();
- data.posX = GetPositionX();
- data.posY = GetPositionY();
- data.posZ = GetPositionZMinusOffset();
- data.orientation = GetOrientation();
+ if (!GetTransport())
+ {
+ data.posX = GetPositionX();
+ data.posY = GetPositionY();
+ data.posZ = GetPositionZMinusOffset();
+ data.orientation = GetOrientation();
+ }
+ else
+ {
+ data.posX = GetTransOffsetX();
+ data.posY = GetTransOffsetY();
+ data.posZ = GetTransOffsetZ();
+ data.orientation = GetTransOffsetO();
+ }
+
data.spawntimesecs = m_respawnDelay;
// prevent add data integrity problems
data.spawndist = GetDefaultMovementType() == IDLE_MOTION_TYPE ? 0.0f : m_respawnradius;
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 3a07d9c101b..a555469da63 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -415,36 +415,7 @@ typedef std::map<uint32, time_t> CreatureSpellCooldowns;
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
-enum CreatureCellMoveState
-{
- CREATURE_CELL_MOVE_NONE, // not in move list
- CREATURE_CELL_MOVE_ACTIVE, // in move list
- CREATURE_CELL_MOVE_INACTIVE // in move list but should not move
-};
-
-class MapCreature
-{
- friend class Map; // map for moving creatures
- friend class ObjectGridLoader; // grid loader for loading creatures
-
-protected:
- MapCreature() : _moveState(CREATURE_CELL_MOVE_NONE) {}
-
-private:
- Cell _currentCell;
- Cell const& GetCurrentCell() const { return _currentCell; }
- void SetCurrentCell(Cell const& cell) { _currentCell = cell; }
-
- CreatureCellMoveState _moveState;
- Position _newPosition;
- void SetNewCellPosition(float x, float y, float z, float o)
- {
- _moveState = CREATURE_CELL_MOVE_ACTIVE;
- _newPosition.Relocate(x, y, z, o);
- }
-};
-
-class Creature : public Unit, public GridObject<Creature>, public MapCreature
+class Creature : public Unit, public GridObject<Creature>, public MapObject
{
public:
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index eef416b339d..9829b6019de 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -16,6 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <G3D/Quat.h>
#include "GameObjectAI.h"
#include "Battleground.h"
#include "CellImpl.h"
@@ -32,8 +33,10 @@
#include "SpellMgr.h"
#include "UpdateFieldFlags.h"
#include "World.h"
+#include "Transport.h"
-GameObject::GameObject(): WorldObject(false), m_model(NULL), m_goValue(), m_AI(NULL)
+GameObject::GameObject() : WorldObject(false), MapObject(),
+ m_model(NULL), m_goValue(), m_AI(NULL)
{
m_objectType |= TYPEMASK_GAMEOBJECT;
m_objectTypeId = TYPEID_GAMEOBJECT;
@@ -100,6 +103,9 @@ void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
if (m_uint32Values) // field array can be not exist if GameOBject not loaded
RemoveFromOwner();
+
+ if (GetTransport() && !ToTransport())
+ GetTransport()->RemovePassenger(this);
}
void GameObject::RemoveFromOwner()
@@ -169,6 +175,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
SetMap(map);
Relocate(x, y, z, ang);
+ m_stationaryPosition.Relocate(x, y, z, ang);
if (!IsPositionValid())
{
TC_LOG_ERROR(LOG_FILTER_GENERAL, "Gameobject (GUID: %u Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", guidlow, name_id, x, y);
@@ -192,6 +199,9 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
return false;
}
+ if (goinfo->type == GAMEOBJECT_TYPE_TRANSPORT)
+ m_updateFlag = (m_updateFlag | UPDATEFLAG_TRANSPORT) & ~UPDATEFLAG_POSITION;
+
Object::_Create(guidlow, goinfo->entry, HIGHGUID_GAMEOBJECT);
m_goInfo = goinfo;
@@ -238,9 +248,11 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
break;
case GAMEOBJECT_TYPE_TRANSPORT:
SetUInt32Value(GAMEOBJECT_LEVEL, goinfo->transport.pause);
- if (goinfo->transport.startOpen)
- SetGoState(GO_STATE_ACTIVE);
+ SetGoState(goinfo->transport.startOpen ? GO_STATE_ACTIVE : GO_STATE_READY);
SetGoAnimProgress(animprogress);
+ m_goValue.Transport.PathProgress = 0;
+ m_goValue.Transport.AnimationInfo = sTransportMgr->GetTransportAnimInfo(goinfo->entry);
+ m_goValue.Transport.CurrentSeg = 0;
break;
case GAMEOBJECT_TYPE_FISHINGNODE:
SetGoAnimProgress(0);
@@ -274,18 +286,10 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
void GameObject::Update(uint32 diff)
{
- if (!AI())
- {
- if (!AIM_Initialize())
- TC_LOG_ERROR(LOG_FILTER_GENERAL, "Could not initialize GameObjectAI");
- } else
+ if (AI())
AI()->UpdateAI(diff);
-
- if (IS_MO_TRANSPORT_GUID(GetGUID()))
- {
- //((Transport*)this)->Update(p_time);
- return;
- }
+ else if (!AIM_Initialize())
+ TC_LOG_ERROR(LOG_FILTER_GENERAL, "Could not initialize GameObjectAI");
switch (m_lootState)
{
@@ -308,6 +312,38 @@ void GameObject::Update(uint32 diff)
m_lootState = GO_READY;
break;
}
+ /* TODO: Fix movement in unloaded grid - currently GO will just disappear
+ case GAMEOBJECT_TYPE_TRANSPORT:
+ {
+ if (!m_goValue.Transport.AnimationInfo)
+ break;
+
+ if (GetGoState() == GO_STATE_READY)
+ {
+ m_goValue.Transport.PathProgress += diff;
+ uint32 timer = m_goValue.Transport.PathProgress % m_goValue.Transport.AnimationInfo->TotalTime;
+ 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 = m_goValue.Transport.AnimationInfo->GetAnimRotation(timer);
+ 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());
+
+ sLog->outInfo(LOG_FILTER_GENERAL, "Src: %s Dest: %s", src.toString().c_str(), pos.toString().c_str());
+
+ GetMap()->GameObjectRelocation(this, pos.x, pos.y, pos.z, GetOrientation());
+ }
+ }
+ break;
+ }
+ */
case GAMEOBJECT_TYPE_FISHINGNODE:
{
// fishing code (bobber ready)
@@ -1182,10 +1218,12 @@ void GameObject::Use(Unit* user)
if (itr->second)
{
if (Player* ChairUser = ObjectAccessor::FindPlayer(itr->second))
+ {
if (ChairUser->IsSitState() && ChairUser->getStandState() != UNIT_STAND_STATE_SIT && ChairUser->GetExactDist2d(x_i, y_i) < 0.1f)
continue; // This seat is already occupied by ChairUser. NOTE: Not sure if the ChairUser->getStandState() != UNIT_STAND_STATE_SIT check is required.
else
itr->second = 0; // This seat is unoccupied.
+ }
else
itr->second = 0; // The seat may of had an occupant, but they're offline.
}
@@ -2102,6 +2140,7 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
if (index == GAMEOBJECT_DYNAMIC)
{
uint16 dynFlags = 0;
+ int16 pathProgress = -1;
switch (GetGoType())
{
case GAMEOBJECT_TYPE_CHEST:
@@ -2115,12 +2154,13 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
if (ActivateToQuest(target))
dynFlags |= GO_DYNFLAG_LO_SPARKLE;
break;
- default:
+ case GAMEOBJECT_TYPE_MO_TRANSPORT:
+ pathProgress = int16(float(m_goValue.Transport.PathProgress) / float(GetUInt32Value(GAMEOBJECT_LEVEL)) * 65535.0f);
break;
}
fieldBuffer << uint16(dynFlags);
- fieldBuffer << uint16(-1);
+ fieldBuffer << int16(pathProgress);
}
else if (index == GAMEOBJECT_FLAGS)
{
@@ -2140,3 +2180,25 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
updateMask.AppendToPacket(data);
data->append(fieldBuffer);
}
+
+void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = NULL*/) const
+{
+ if (m_DBTableGuid)
+ {
+ if (GameObjectData const* data = sObjectMgr->GetGOData(GetDBTableGUIDLow()))
+ {
+ x = data->posX;
+ y = data->posY;
+ z = data->posZ;
+ if (ori)
+ *ori = data->orientation;
+ return;
+ }
+ }
+
+ x = GetPositionX();
+ y = GetPositionY();
+ z = GetPositionZ();
+ if (ori)
+ *ori = GetOrientation();
+}
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 3bddac81ee9..de92257893b 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -28,6 +28,7 @@
class GameObjectAI;
class Group;
+class Transport;
#define MAX_GAMEOBJECT_QUEST_ITEMS 6
@@ -229,6 +230,7 @@ struct GameObjectTemplate
uint32 transportPhysics; //5
uint32 mapID; //6
uint32 worldState1; //7
+ uint32 canBeStopped; //8
} moTransport;
//16 GAMEOBJECT_TYPE_DUELFLAG - empty
//17 GAMEOBJECT_TYPE_FISHINGNODE - empty
@@ -539,9 +541,17 @@ struct GameObjectTemplate
typedef UNORDERED_MAP<uint32, GameObjectTemplate> GameObjectTemplateContainer;
class OPvPCapturePoint;
+struct TransportAnimation;
union GameObjectValue
{
+ //11 GAMEOBJECT_TYPE_TRANSPORT
+ struct
+ {
+ uint32 PathProgress;
+ TransportAnimation const* AnimationInfo;
+ uint32 CurrentSeg;
+ } Transport;
//25 GAMEOBJECT_TYPE_FISHINGHOLE
struct
{
@@ -617,7 +627,7 @@ class GameObjectModel;
// 5 sec for bobber catch
#define FISHING_BOBBER_READY_TIME 5
-class GameObject : public WorldObject, public GridObject<GameObject>
+class GameObject : public WorldObject, public GridObject<GameObject>, public MapObject
{
public:
explicit GameObject();
@@ -811,8 +821,19 @@ class GameObject : public WorldObject, public GridObject<GameObject>
uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); }
GameObjectModel* m_model;
+ void GetRespawnPosition(float &x, float &y, float &z, float* ori = NULL) const;
+
+ Transport* ToTransport() { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT) return reinterpret_cast<Transport*>(this); else return NULL; }
+ Transport const* ToTransport() const { if (GetGOInfo()->type == GAMEOBJECT_TYPE_MO_TRANSPORT) return reinterpret_cast<Transport const*>(this); else return NULL; }
+
+ float GetStationaryX() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionX(); return GetPositionX(); }
+ float GetStationaryY() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionY(); return GetPositionY(); }
+ float GetStationaryZ() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); }
+ float GetStationaryO() const { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetOrientation(); return GetOrientation(); }
+
protected:
bool AIM_Initialize();
+ void UpdateModel(); // updates model in case displayId were changed
uint32 m_spellId;
time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()),
uint32 m_respawnDelayTime; // (secs) if 0 then current GO state no dependent from timer
@@ -835,6 +856,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>
GameObjectValue m_goValue;
uint64 m_rotation;
+ Position m_stationaryPosition;
uint64 m_lootRecipient;
uint32 m_lootRecipientGroup;
@@ -842,7 +864,6 @@ class GameObject : public WorldObject, public GridObject<GameObject>
private:
void RemoveFromOwner();
void SwitchDoorOrButton(bool activate, bool alternative = false);
- void UpdateModel(); // updates model in case displayId were changed
//! Object distance/size - overridden from Object::_IsWithinDist. Needs to take in account proper GO size.
bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool /*is3D*/) const
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 9d77e144c0b..2eb0fd65149 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -219,9 +219,6 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
case GAMEOBJECT_TYPE_FLAGDROP:
updateType = UPDATETYPE_CREATE_OBJECT2;
break;
- case GAMEOBJECT_TYPE_TRANSPORT:
- flags |= UPDATEFLAG_TRANSPORT;
- break;
default:
break;
}
@@ -414,13 +411,10 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
// 0x40
if (flags & UPDATEFLAG_STATIONARY_POSITION)
{
- *data << object->GetPositionX();
- *data << object->GetPositionY();
- if (isType(TYPEMASK_UNIT))
- *data << unit->GetPositionZMinusOffset();
- else
- *data << object->GetPositionZ();
- *data << object->GetOrientation();
+ *data << object->GetStationaryX();
+ *data << object->GetStationaryY();
+ *data << object->GetStationaryZ();
+ *data << object->GetStationaryO();
}
}
}
@@ -473,7 +467,11 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
// 0x2
if (flags & UPDATEFLAG_TRANSPORT)
{
- *data << uint32(getMSTime()); // Unknown - getMSTime is wrong.
+ GameObject const* go = ToGameObject();
+ if (go && go->IsTransport())
+ *data << uint32(go->GetGOValue()->Transport.PathProgress);
+ else
+ *data << uint32(getMSTime());
}
// 0x80
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 66b3a737e0c..3e010fa98a2 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -523,6 +523,35 @@ class FlaggedValuesArray32
T_FLAGS m_flags;
};
+enum MapObjectCellMoveState
+{
+ MAP_OBJECT_CELL_MOVE_NONE, //not in move list
+ MAP_OBJECT_CELL_MOVE_ACTIVE, //in move list
+ MAP_OBJECT_CELL_MOVE_INACTIVE, //in move list but should not move
+};
+
+class MapObject
+{
+ friend class Map; //map for moving creatures
+ friend class ObjectGridLoader; //grid loader for loading creatures
+
+ protected:
+ MapObject() : _moveState(MAP_OBJECT_CELL_MOVE_NONE) {}
+
+ private:
+ Cell _currentCell;
+ Cell const& GetCurrentCell() const { return _currentCell; }
+ void SetCurrentCell(Cell const& cell) { _currentCell = cell; }
+
+ MapObjectCellMoveState _moveState;
+ Position _newPosition;
+ void SetNewCellPosition(float x, float y, float z, float o)
+ {
+ _moveState = MAP_OBJECT_CELL_MOVE_ACTIVE;
+ _newPosition.Relocate(x, y, z, o);
+ }
+};
+
class WorldObject : public Object, public WorldLocation
{
protected:
@@ -700,16 +729,22 @@ class WorldObject : public Object, public WorldLocation
// Transports
Transport* GetTransport() const { return m_transport; }
- virtual float GetTransOffsetX() const { return 0; }
- virtual float GetTransOffsetY() const { return 0; }
- virtual float GetTransOffsetZ() const { return 0; }
- virtual float GetTransOffsetO() const { return 0; }
- virtual uint32 GetTransTime() const { return 0; }
- virtual int8 GetTransSeat() const { return -1; }
+ 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(); }
+ float GetTransOffsetO() const { return m_movementInfo.transport.pos.GetOrientation(); }
+ uint32 GetTransTime() const { return m_movementInfo.transport.time; }
+ int8 GetTransSeat() const { return m_movementInfo.transport.seat; }
virtual uint64 GetTransGUID() const;
void SetTransport(Transport* t) { m_transport = t; }
MovementInfo m_movementInfo;
+
+ virtual float GetStationaryX() const { return GetPositionX(); }
+ virtual float GetStationaryY() const { return GetPositionY(); }
+ virtual float GetStationaryZ() const { return GetPositionZ(); }
+ virtual float GetStationaryO() const { return GetOrientation(); }
+
protected:
std::string m_name;
bool m_isActive;
@@ -739,7 +774,6 @@ class WorldObject : public Object, public WorldLocation
uint16 m_notifyflags;
uint16 m_executed_notifies;
-
virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const;
bool CanNeverSee(WorldObject const* obj) const;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 9ada25b1c81..40dbe6c2fe7 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -17182,17 +17182,15 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
}
else
{
- for (MapManager::TransportSet::iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter)
+ if (GameObject* go = HashMapHolder<GameObject>::Find(m_movementInfo.transport.guid))
+ m_transport = go->ToTransport();
+
+ if (m_transport)
{
- if ((*iter)->GetGUIDLow() == transGUID)
- {
- m_transport = *iter;
- m_transport->AddPassenger(this);
- mapId = (m_transport->GetMapId());
- break;
- }
+ m_transport->AddPassenger(this);
+ mapId = m_transport->GetMapId();
}
- if (!m_transport)
+ else
{
TC_LOG_ERROR(LOG_FILTER_PLAYER, "Player (guidlow %d) have problems with transport guid (%u). Teleport to bind location.",
guid, transGUID);
@@ -22165,7 +22163,7 @@ inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, T* target, std::set
template<>
inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, GameObject* target, std::set<Unit*>& /*v*/)
{
- // Don't update only GAMEOBJECT_TYPE_TRANSPORT (or all transports and destructible buildings?)
+ // @HACK: This is to prevent objects like deeprun tram from disappearing when player moves far from its spawn point while riding it
if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
s64.insert(target->GetGUID());
}
@@ -22217,9 +22215,6 @@ void Player::UpdateVisibilityOf(WorldObject* target)
{
if (CanSeeOrDetect(target, false, true))
{
- //if (target->isType(TYPEMASK_UNIT) && ((Unit*)target)->m_Vehicle)
- // UpdateVisibilityOf(((Unit*)target)->m_Vehicle);
-
target->SendUpdateToPlayer(this);
m_clientGUIDs.insert(target->GetGUID());
@@ -22308,9 +22303,6 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& vi
{
if (CanSeeOrDetect(target, false, true))
{
- //if (target->isType(TYPEMASK_UNIT) && ((Unit*)target)->m_Vehicle)
- // UpdateVisibilityOf(((Unit*)target)->m_Vehicle, data, visibleNow);
-
target->BuildCreateUpdateBlockForPlayer(&data, this);
UpdateVisibilityOf_helper(m_clientGUIDs, target, visibleNow);
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index 23197b40ad0..e6ca93307e7 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -26,166 +26,23 @@
#include "DBCStores.h"
#include "World.h"
#include "GameObjectAI.h"
+#include "Vehicle.h"
+#include "MapReference.h"
#include "Player.h"
-void MapManager::LoadTransports()
+Transport::Transport() : GameObject(),
+ _transportInfo(NULL), _isMoving(true), _pendingStop(false)
{
- uint32 oldMSTime = getMSTime();
-
- QueryResult result = WorldDatabase.Query("SELECT guid, entry, name, period, ScriptName FROM transports");
-
- if (!result)
- {
- TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 transports. DB table `transports` is empty!");
- return;
- }
-
- uint32 count = 0;
-
- do
- {
-
- Field* fields = result->Fetch();
- uint32 lowguid = fields[0].GetUInt32();
- uint32 entry = fields[1].GetUInt32();
- std::string name = fields[2].GetString();
- uint32 period = fields[3].GetUInt32();
- uint32 scriptId = sObjectMgr->GetScriptId(fields[4].GetCString());
-
- GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
-
- if (!goinfo)
- {
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport ID:%u, Name: %s, will not be loaded, gameobject_template missing", entry, name.c_str());
- continue;
- }
-
- if (goinfo->type != GAMEOBJECT_TYPE_MO_TRANSPORT)
- {
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport ID:%u, Name: %s, will not be loaded, gameobject_template type wrong", entry, name.c_str());
- continue;
- }
-
- // TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, "Loading transport %d between %s, %s", entry, name.c_str(), goinfo->name);
-
- std::set<uint32> mapsUsed;
-
- Transport* t = new Transport(period, scriptId);
- if (!t->GenerateWaypoints(goinfo->moTransport.taxiPathId, mapsUsed))
- // skip transports with empty waypoints list
- {
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport (path id %u) path size = 0. Transport ignored, check DBC files or transport GO data0 field.", goinfo->moTransport.taxiPathId);
- delete t;
- continue;
- }
-
- float x = t->m_WayPoints[0].x;
- float y = t->m_WayPoints[0].y;
- float z = t->m_WayPoints[0].z;
- uint32 mapid = t->m_WayPoints[0].mapid;
- float o = 1.0f;
-
- // creates the Gameobject
- if (!t->Create(lowguid, entry, mapid, x, y, z, o, 255, 0))
- {
- delete t;
- continue;
- }
-
- m_Transports.insert(t);
-
- for (std::set<uint32>::const_iterator i = mapsUsed.begin(); i != mapsUsed.end(); ++i)
- m_TransportsByMap[*i].insert(t);
-
- //If we someday decide to use the grid to track transports, here:
- t->SetMap(sMapMgr->CreateBaseMap(mapid));
- t->AddToWorld();
-
- ++count;
- }
- while (result->NextRow());
-
- // check transport data DB integrity
- result = WorldDatabase.Query("SELECT gameobject.guid, gameobject.id, transports.name FROM gameobject, transports WHERE gameobject.id = transports.entry");
- if (result) // wrong data found
- {
- do
- {
- Field* fields = result->Fetch();
-
- uint32 guid = fields[0].GetUInt32();
- uint32 entry = fields[1].GetUInt32();
- std::string name = fields[2].GetString();
- TC_LOG_ERROR(LOG_FILTER_SQL, "Transport %u '%s' have record (GUID: %u) in `gameobject`. Transports must not have any records in `gameobject` or its behavior will be unpredictable/bugged.", entry, name.c_str(), guid);
- }
- while (result->NextRow());
- }
-
- TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded %u transports in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-}
-
-void MapManager::LoadTransportNPCs()
-{
- uint32 oldMSTime = getMSTime();
-
- // 0 1 2 3 4 5 6 7
- QueryResult result = WorldDatabase.Query("SELECT guid, npc_entry, transport_entry, TransOffsetX, TransOffsetY, TransOffsetZ, TransOffsetO, emote FROM creature_transport");
-
- if (!result)
- {
- TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 transport NPCs. DB table `creature_transport` is empty!");
- return;
- }
-
- uint32 count = 0;
-
- do
- {
- Field* fields = result->Fetch();
- uint32 guid = fields[0].GetInt32();
- uint32 entry = fields[1].GetInt32();
- uint32 transportEntry = fields[2].GetInt32();
- float tX = fields[3].GetFloat();
- float tY = fields[4].GetFloat();
- float tZ = fields[5].GetFloat();
- float tO = fields[6].GetFloat();
- uint32 anim = fields[7].GetInt32();
-
- for (MapManager::TransportSet::iterator itr = m_Transports.begin(); itr != m_Transports.end(); ++itr)
- {
- if ((*itr)->GetEntry() == transportEntry)
- {
- (*itr)->AddNPCPassenger(guid, entry, tX, tY, tZ, tO, anim);
- break;
- }
- }
-
- ++count;
- }
- while (result->NextRow());
-
- TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded %u transport npcs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-}
-
-Transport::Transport(uint32 period, uint32 script) : GameObject(), m_pathTime(0), m_timer(0),
-currenttguid(0), m_period(period), ScriptId(script), m_nextNodeTime(0)
-{
- m_updateFlag = (UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION);
+ m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
}
Transport::~Transport()
{
- for (CreatureSet::iterator itr = m_NPCPassengerSet.begin(); itr != m_NPCPassengerSet.end(); ++itr)
- {
- (*itr)->SetTransport(NULL);
- GetMap()->AddObjectToRemoveList(*itr);
- }
}
-bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags)
+bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress)
{
Relocate(x, y, z, ang);
- // instance id and phaseMask isn't set to values different from std.
if (!IsPositionValid())
{
@@ -206,520 +63,510 @@ bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, floa
m_goInfo = goinfo;
- SetObjectScale(goinfo->size);
+ TransportTemplate const* tInfo = sTransportMgr->GetTransportTemplate(entry);
+ if (!tInfo)
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "Transport %u (name: %s) will not be created, missing `transport_template` entry.", entry, goinfo->name);
+ return false;
+ }
+
+ _transportInfo = tInfo;
+ // initialize waypoints
+ _nextFrame = tInfo->keyFrames.begin();
+ _currentFrame = _nextFrame++;
+ _triggeredArrivalEvent = false;
+ _triggeredDepartureEvent = false;
+
+ m_goValue.Transport.PathProgress = 0;
+ SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size);
SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
- SetUInt32Value(GAMEOBJECT_LEVEL, m_period);
+ SetPeriod(tInfo->pathTime);
SetEntry(goinfo->entry);
-
SetDisplayId(goinfo->displayId);
-
SetGoState(GO_STATE_READY);
- SetGoType(GameobjectTypes(goinfo->type));
-
+ _pendingStop = goinfo->moTransport.canBeStopped != 0;
+ SetGoType(GAMEOBJECT_TYPE_MO_TRANSPORT);
SetGoAnimProgress(animprogress);
- if (dynflags)
- SetUInt32Value(GAMEOBJECT_DYNAMIC, MAKE_PAIR32(0, dynflags));
-
SetName(goinfo->name);
-
- SetZoneScript();
-
+ UpdateRotationFields(0.0f, 1.0f);
return true;
}
-struct keyFrame
+void Transport::Update(uint32 diff)
{
- explicit keyFrame(TaxiPathNodeEntry const& _node) : node(&_node),
- distSinceStop(-1.0f), distUntilStop(-1.0f), distFromPrev(-1.0f), tFrom(0.0f), tTo(0.0f)
- {
- }
+ uint32 const positionUpdateDelay = 200;
- TaxiPathNodeEntry const* node;
+ if (AI())
+ AI()->UpdateAI(diff);
+ else if (!AIM_Initialize())
+ TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Could not initialize GameObjectAI for Transport");
- float distSinceStop;
- float distUntilStop;
- float distFromPrev;
- float tFrom, tTo;
-};
+ if (GetKeyFrames().size() <= 1)
+ return;
-bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
-{
- if (pathid >= sTaxiPathNodesByPath.size())
- return false;
+ m_goValue.Transport.PathProgress += diff;
- TaxiPathNodeList const& path = sTaxiPathNodesByPath[pathid];
+ uint32 timer = m_goValue.Transport.PathProgress % GetPeriod();
- std::vector<keyFrame> keyFrames;
- int mapChange = 0;
- mapids.clear();
- for (size_t i = 1; i < path.size() - 1; ++i)
+ // Set current waypoint
+ // Desired outcome: _currentFrame->DepartureTime < timer < _nextFrame->ArriveTime
+ // ... arrive | ... delay ... | departure
+ // event / event /
+ for (;;)
{
- if (mapChange == 0)
+ if (timer >= _currentFrame->ArriveTime)
{
- TaxiPathNodeEntry const& node_i = path[i];
- if (node_i.mapid == path[i+1].mapid)
+ if (!_triggeredArrivalEvent)
{
- keyFrame k(node_i);
- keyFrames.push_back(k);
- mapids.insert(k.node->mapid);
+ DoEventIfAny(*_currentFrame, false);
+ _triggeredArrivalEvent = true;
}
- else
+
+ if (timer < _currentFrame->DepartureTime)
{
- mapChange = 1;
+ SetMoving(false);
+ if (_pendingStop)
+ SetGoState(GO_STATE_READY);
+ break; // its a stop frame and we are waiting
}
}
- else
- {
- --mapChange;
- }
- }
-
- int lastStop = -1;
- int firstStop = -1;
- // first cell is arrived at by teleportation :S
- keyFrames[0].distFromPrev = 0;
- if (keyFrames[0].node->actionFlag == 2)
- {
- lastStop = 0;
- }
-
- // find the rest of the distances between key points
- for (size_t i = 1; i < keyFrames.size(); ++i)
- {
- if ((keyFrames[i].node->actionFlag == 1) || (keyFrames[i].node->mapid != keyFrames[i-1].node->mapid))
+ if (_pendingStop && timer >= _currentFrame->DepartureTime && GetGoState() == GO_STATE_READY)
{
- keyFrames[i].distFromPrev = 0;
+ m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetPeriod());
+ m_goValue.Transport.PathProgress *= GetPeriod();
+ m_goValue.Transport.PathProgress += _currentFrame->ArriveTime;
+ break;
}
- else
- {
- keyFrames[i].distFromPrev =
- sqrt(pow(keyFrames[i].node->x - keyFrames[i - 1].node->x, 2) +
- pow(keyFrames[i].node->y - keyFrames[i - 1].node->y, 2) +
- pow(keyFrames[i].node->z - keyFrames[i - 1].node->z, 2));
- }
- if (keyFrames[i].node->actionFlag == 2)
+
+ if (timer >= _currentFrame->DepartureTime && !_triggeredDepartureEvent)
{
- // remember first stop frame
- if (firstStop == -1)
- firstStop = i;
- lastStop = i;
+ DoEventIfAny(*_currentFrame, true); // departure event
+ _triggeredDepartureEvent = true;
}
- }
-
- float tmpDist = 0;
- for (size_t i = 0; i < keyFrames.size(); ++i)
- {
- int j = (i + lastStop) % keyFrames.size();
- if (keyFrames[j].node->actionFlag == 2)
- tmpDist = 0;
- else
- tmpDist += keyFrames[j].distFromPrev;
- keyFrames[j].distSinceStop = tmpDist;
- }
- for (int i = int(keyFrames.size()) - 1; i >= 0; i--)
- {
- int j = (i + (firstStop+1)) % keyFrames.size();
- tmpDist += keyFrames[(j + 1) % keyFrames.size()].distFromPrev;
- keyFrames[j].distUntilStop = tmpDist;
- if (keyFrames[j].node->actionFlag == 2)
- tmpDist = 0;
- }
+ if (timer >= _currentFrame->DepartureTime && timer < _currentFrame->NextArriveTime)
+ break; // found current waypoint
- for (size_t i = 0; i < keyFrames.size(); ++i)
- {
- if (keyFrames[i].distSinceStop < (30 * 30 * 0.5f))
- keyFrames[i].tFrom = sqrt(2 * keyFrames[i].distSinceStop);
- else
- keyFrames[i].tFrom = ((keyFrames[i].distSinceStop - (30 * 30 * 0.5f)) / 30) + 30;
+ MoveToNextWaypoint();
- if (keyFrames[i].distUntilStop < (30 * 30 * 0.5f))
- keyFrames[i].tTo = sqrt(2 * keyFrames[i].distUntilStop);
- else
- keyFrames[i].tTo = ((keyFrames[i].distUntilStop - (30 * 30 * 0.5f)) / 30) + 30;
+ // not waiting anymore
+ SetMoving(true);
- keyFrames[i].tFrom *= 1000;
- keyFrames[i].tTo *= 1000;
- }
-
- // for (int i = 0; i < keyFrames.size(); ++i) {
- // TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "%f, %f, %f, %f, %f, %f, %f", keyFrames[i].x, keyFrames[i].y, keyFrames[i].distUntilStop, keyFrames[i].distSinceStop, keyFrames[i].distFromPrev, keyFrames[i].tFrom, keyFrames[i].tTo);
- // }
+ // Enable movement
+ if (GetGOInfo()->moTransport.canBeStopped)
+ SetGoState(GO_STATE_ACTIVE);
- // Now we're completely set up; we can move along the length of each waypoint at 100 ms intervals
- // speed = max(30, t) (remember x = 0.5s^2, and when accelerating, a = 1 unit/s^2
- int t = 0;
- bool teleport = false;
- if (keyFrames[keyFrames.size() - 1].node->mapid != keyFrames[0].node->mapid)
- teleport = true;
+ // Departure event
+ if (_currentFrame->IsTeleportFrame())
+ TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z);
- m_WayPoints[0] = WayPoint(keyFrames[0].node->mapid, keyFrames[0].node->x, keyFrames[0].node->y, keyFrames[0].node->z, teleport, 0,
- keyFrames[0].node->arrivalEventID, keyFrames[0].node->departureEventID);
+ sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
- t += keyFrames[0].node->delay * 1000;
+ TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName(), _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
+ }
- uint32 cM = keyFrames[0].node->mapid;
- for (size_t i = 0; i < keyFrames.size() - 1; ++i)
+ // Set position
+ _positionChangeTimer.Update(diff);
+ if (_positionChangeTimer.Passed())
{
- float d = 0;
- float tFrom = keyFrames[i].tFrom;
- float tTo = keyFrames[i].tTo;
-
- // keep the generation of all these points; we use only a few now, but may need the others later
- if (((d < keyFrames[i + 1].distFromPrev) && (tTo > 0)))
+ _positionChangeTimer.Reset(positionUpdateDelay);
+ if (IsMoving())
{
- while ((d < keyFrames[i + 1].distFromPrev) && (tTo > 0))
- {
- tFrom += 100;
- tTo -= 100;
-
- if (d > 0)
- {
- float newX = keyFrames[i].node->x + (keyFrames[i + 1].node->x - keyFrames[i].node->x) * d / keyFrames[i + 1].distFromPrev;
- float newY = keyFrames[i].node->y + (keyFrames[i + 1].node->y - keyFrames[i].node->y) * d / keyFrames[i + 1].distFromPrev;
- float newZ = keyFrames[i].node->z + (keyFrames[i + 1].node->z - keyFrames[i].node->z) * d / keyFrames[i + 1].distFromPrev;
-
- teleport = false;
- if (keyFrames[i].node->mapid != cM)
- {
- teleport = true;
- cM = keyFrames[i].node->mapid;
- }
-
- // TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "T: %d, D: %f, x: %f, y: %f, z: %f", t, d, newX, newY, newZ);
- if (teleport)
- m_WayPoints[t] = WayPoint(keyFrames[i].node->mapid, newX, newY, newZ, teleport, 0);
- }
-
- if (tFrom < tTo) // caught in tFrom dock's "gravitational pull"
- {
- if (tFrom <= 30000)
- {
- d = 0.5f * (tFrom / 1000) * (tFrom / 1000);
- }
- else
- {
- d = 0.5f * 30 * 30 + 30 * ((tFrom - 30000) / 1000);
- }
- d = d - keyFrames[i].distSinceStop;
- }
- else
- {
- if (tTo <= 30000)
- {
- d = 0.5f * (tTo / 1000) * (tTo / 1000);
- }
- else
- {
- d = 0.5f * 30 * 30 + 30 * ((tTo - 30000) / 1000);
- }
- d = keyFrames[i].distUntilStop - d;
- }
- t += 100;
- }
- t -= 100;
+ float t = CalculateSegmentPos(float(timer) * 0.001f);
+ G3D::Vector3 pos, dir;
+ _currentFrame->Spline->evaluate_percent(_currentFrame->Index, t, pos);
+ //_currentFrame->Spline->evaluate_derivative(_currentFrame->Index, t, dir);
+ UpdatePosition(pos.x, pos.y, pos.z, 0.0f/*atan2(dir.x, dir.y)*/);
}
-
- if (keyFrames[i + 1].tFrom > keyFrames[i + 1].tTo)
- t += 100 - ((long)keyFrames[i + 1].tTo % 100);
- else
- t += (long)keyFrames[i + 1].tTo % 100;
-
- teleport = false;
- if ((keyFrames[i + 1].node->actionFlag == 1) || (keyFrames[i + 1].node->mapid != keyFrames[i].node->mapid))
- {
- teleport = true;
- cM = keyFrames[i + 1].node->mapid;
- }
-
- m_WayPoints[t] = WayPoint(keyFrames[i + 1].node->mapid, keyFrames[i + 1].node->x, keyFrames[i + 1].node->y, keyFrames[i + 1].node->z, teleport,
- 0, keyFrames[i + 1].node->arrivalEventID, keyFrames[i + 1].node->departureEventID);
- // TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "T: %d, x: %f, y: %f, z: %f, t:%d", t, pos.x, pos.y, pos.z, teleport);
-
- t += keyFrames[i + 1].node->delay * 1000;
}
- uint32 timer = t;
-
- // TC_LOG_INFO(LOG_FILTER_TRANSPORTS, " Generated %lu waypoints, total time %u.", (unsigned long)m_WayPoints.size(), timer);
-
- m_curr = m_WayPoints.begin();
- m_next = GetNextWayPoint();
- m_pathTime = timer;
+ sScriptMgr->OnTransportUpdate(this, diff);
+}
- m_nextNodeTime = m_curr->first;
+void Transport::AddPassenger(WorldObject* passenger)
+{
+ if (_passengers.insert(passenger).second)
+ TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, "Object %s boarded transport %s.", passenger->GetName(), GetName());
- return true;
+ if (Player* plr = passenger->ToPlayer())
+ sScriptMgr->OnAddPassenger(this, plr);
}
-Transport::WayPointMap::const_iterator Transport::GetNextWayPoint()
+void Transport::RemovePassenger(WorldObject* passenger)
{
- WayPointMap::const_iterator iter = m_curr;
- ++iter;
- if (iter == m_WayPoints.end())
- iter = m_WayPoints.begin();
- return iter;
+ if (_passengers.erase(passenger) || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload
+ TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, "Object %s removed from transport %s.", passenger->GetName(), GetName());
+
+
+ if (Player* plr = passenger->ToPlayer())
+ sScriptMgr->OnRemovePassenger(this, plr);
}
-void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
+Creature* Transport::CreateNPCPassenger(uint32 guid, CreatureData const* data)
{
- Map const* oldMap = GetMap();
- Relocate(x, y, z);
+ Map* map = GetMap();
+ Creature* creature = new Creature();
- for (PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();)
+ if (!creature->LoadCreatureFromDB(guid, map, false))
{
- Player* player = *itr;
- ++itr;
-
- if (player->isDead() && !player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
- player->ResurrectPlayer(1.0f);
-
- player->TeleportTo(newMapid, x, y, z, GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT);
+ delete creature;
+ return NULL;
}
- //we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference...
- //player far teleport would try to create same instance, but we need it NOW for transport...
+ float x = data->posX;
+ float y = data->posY;
+ float z = data->posZ;
+ float o = data->orientation;
- RemoveFromWorld();
- ResetMap();
- Map* newMap = sMapMgr->CreateBaseMap(newMapid);
- SetMap(newMap);
- ASSERT(GetMap());
- AddToWorld();
+ creature->SetTransport(this);
+ creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ creature->m_movementInfo.transport.guid = GetGUID();
+ creature->m_movementInfo.transport.pos.Relocate(x, y, z, o);
+ CalculatePassengerPosition(x, y, z, &o);
+ creature->Relocate(x, y, z, o);
+ creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
+ creature->SetTransportHomePosition(creature->m_movementInfo.transport.pos);
- if (oldMap != newMap)
+ if (!creature->IsPositionValid())
{
- UpdateForMap(oldMap);
- UpdateForMap(newMap);
+ TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Creature (guidlow %d, entry %d) not created. Suggested coordinates aren't valid (X: %f Y: %f)",creature->GetGUIDLow(),creature->GetEntry(),creature->GetPositionX(),creature->GetPositionY());
+ delete creature;
+ return NULL;
}
- for (CreatureSet::iterator itr = m_NPCPassengerSet.begin(); itr != m_NPCPassengerSet.end(); ++itr)
- (*itr)->FarTeleportTo(newMap, x, y, z, (*itr)->GetOrientation());
-}
-
-bool Transport::AddPassenger(Player* passenger)
-{
- if (m_passengers.insert(passenger).second)
- TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "Player %s boarded transport %s.", passenger->GetName().c_str(), GetName().c_str());
+ map->AddToMap(creature);
+ _staticPassengers.insert(creature);
- sScriptMgr->OnAddPassenger(this, passenger);
- return true;
+ sScriptMgr->OnAddCreaturePassenger(this, creature);
+ return creature;
}
-bool Transport::RemovePassenger(Player* passenger)
+GameObject* Transport::CreateGOPassenger(uint32 guid, GameObjectData const* data)
{
- if (m_passengers.erase(passenger))
- TC_LOG_INFO(LOG_FILTER_TRANSPORTS, "Player %s removed from transport %s.", passenger->GetName().c_str(), GetName().c_str());
-
- sScriptMgr->OnRemovePassenger(this, passenger);
- return true;
-}
+ Map* map = GetMap();
+ GameObject* go = new GameObject();
-void Transport::Update(uint32 p_diff)
-{
- if (!AI())
+ if (!go->LoadGameObjectFromDB(guid, map, false))
{
- if (!AIM_Initialize())
- TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Could not initialize GameObjectAI for Transport");
- } else
- AI()->UpdateAI(p_diff);
-
- if (m_WayPoints.size() <= 1)
- return;
+ delete go;
+ return NULL;
+ }
- m_timer = getMSTime() % m_period;
- while (((m_timer - m_curr->first) % m_pathTime) > ((m_next->first - m_curr->first) % m_pathTime))
- {
- DoEventIfAny(*m_curr, true);
+ float x = data->posX;
+ float y = data->posY;
+ float z = data->posZ;
+ float o = data->orientation;
- m_curr = GetNextWayPoint();
- m_next = GetNextWayPoint();
+ go->SetTransport(this);
+ go->m_movementInfo.transport.guid = GetGUID();
+ go->m_movementInfo.transport.pos.Relocate(x, y, z, o);
+ CalculatePassengerPosition(x, y, z, &o);
+ go->Relocate(x, y, z, o);
- DoEventIfAny(*m_curr, false);
+ if (!go->IsPositionValid())
+ {
+ TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "GameObject (guidlow %d, entry %d) not created. Suggested coordinates aren't valid (X: %f Y: %f)", go->GetGUIDLow(), go->GetEntry(), go->GetPositionX(), go->GetPositionY());
+ delete go;
+ return NULL;
+ }
- // first check help in case client-server transport coordinates de-synchronization
- if (m_curr->second.mapid != GetMapId() || m_curr->second.teleport)
- {
- TeleportTransport(m_curr->second.mapid, m_curr->second.x, m_curr->second.y, m_curr->second.z);
- }
- else
- {
- Relocate(m_curr->second.x, m_curr->second.y, m_curr->second.z, GetAngle(m_next->second.x, m_next->second.y) + float(M_PI));
- UpdatePassengerPositions(); // COME BACK MARKER
- }
+ map->AddToMap(go);
+ _staticPassengers.insert(go);
- sScriptMgr->OnRelocate(this, m_curr->first, m_curr->second.mapid, m_curr->second.x, m_curr->second.y, m_curr->second.z);
+ //sScriptMgr->OnAddCreaturePassenger(this, go);
+ return go;
+}
- m_nextNodeTime = m_curr->first;
+void Transport::CalculatePassengerPosition(float& x, float& y, float& z, float* o /*= NULL*/) const
+{
+ float inx = x, iny = y, inz = z;
+ if (o)
+ *o = Position::NormalizeOrientation(GetOrientation() + *o);
- if (m_curr == m_WayPoints.begin())
- TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, " ************ BEGIN ************** %s", m_name.c_str());
+ x = GetPositionX() + inx * std::cos(GetOrientation()) - iny * std::sin(GetOrientation());
+ y = GetPositionY() + iny * std::cos(GetOrientation()) + inx * std::sin(GetOrientation());
+ z = GetPositionZ() + inz;
+}
- TC_LOG_DEBUG(LOG_FILTER_TRANSPORTS, "%s moved to %d %f %f %f %d", m_name.c_str(), m_curr->second.id, m_curr->second.x, m_curr->second.y, m_curr->second.z, m_curr->second.mapid);
- }
+void Transport::CalculatePassengerOffset(float& x, float& y, float& z, float* o /*= NULL*/) const
+{
+ if (o)
+ *o = Position::NormalizeOrientation(*o - GetOrientation());
- sScriptMgr->OnTransportUpdate(this, p_diff);
+ z -= GetPositionZ();
+ y -= GetPositionY(); // y = searchedY * std::cos(o) + searchedX * std::sin(o)
+ x -= GetPositionX(); // x = searchedX * std::cos(o) + searchedY * std::sin(o + pi)
+ float inx = x, iny = y;
+ y = (iny - inx * std::tan(GetOrientation())) / (std::cos(GetOrientation()) + std::sin(GetOrientation()) * std::tan(GetOrientation()));
+ x = (inx + iny * std::tan(GetOrientation())) / (std::cos(GetOrientation()) + std::sin(GetOrientation()) * std::tan(GetOrientation()));
}
-void Transport::UpdateForMap(Map const* targetMap)
+void Transport::UpdatePosition(float x, float y, float z, float o)
{
- Map::PlayerList const& player = targetMap->GetPlayers();
- if (player.isEmpty())
- return;
+ bool newActive = GetMap()->IsGridLoaded(x, y);
+
+ Relocate(x, y, z, o);
+
+ UpdatePassengerPositions(_passengers);
+
+ /* There are four possible scenarios that trigger loading/unloading passengers:
+ 1. transport moves from inactive to active grid
+ 2. the grid that transport is currently in becomes active
+ 3. transport moves from active to inactive grid
+ 4. the grid that transport is currently in unloads
+ */
+ if (_staticPassengers.empty() && newActive) // 1. and 2.
+ LoadStaticPassengers();
+ else if (!_staticPassengers.empty() && !newActive && Cell(x, y).DiffGrid(Cell(GetPositionX(), GetPositionY()))) // 3.
+ UnloadStaticPassengers();
+ else
+ UpdatePassengerPositions(_staticPassengers);
+ // 4. is handed by grid unload
+}
- if (GetMapId() == targetMap->GetId())
+void Transport::LoadStaticPassengers()
+{
+ if (uint32 mapId = GetGOInfo()->moTransport.mapID)
{
- for (Map::PlayerList::const_iterator itr = player.begin(); itr != player.end(); ++itr)
+ CellObjectGuidsMap const& cells = sObjectMgr->GetMapObjectGuids(mapId, GetMap()->GetSpawnMode());
+ CellGuidSet::const_iterator guidEnd;
+ for (CellObjectGuidsMap::const_iterator cellItr = cells.begin(); cellItr != cells.end(); ++cellItr)
{
- if (this != itr->GetSource()->GetTransport())
- {
- UpdateData transData;
- BuildCreateUpdateBlockForPlayer(&transData, itr->GetSource());
- WorldPacket packet;
- transData.BuildPacket(&packet);
- itr->GetSource()->SendDirectMessage(&packet);
- }
+ // Creatures on transport
+ guidEnd = cellItr->second.creatures.end();
+ for (CellGuidSet::const_iterator guidItr = cellItr->second.creatures.begin(); guidItr != guidEnd; ++guidItr)
+ CreateNPCPassenger(*guidItr, sObjectMgr->GetCreatureData(*guidItr));
+
+ // GameObjects on transport
+ guidEnd = cellItr->second.gameobjects.end();
+ for (CellGuidSet::const_iterator guidItr = cellItr->second.gameobjects.begin(); guidItr != guidEnd; ++guidItr)
+ CreateGOPassenger(*guidItr, sObjectMgr->GetGOData(*guidItr));
}
}
- else
- {
- UpdateData transData;
- BuildOutOfRangeUpdateBlock(&transData);
- WorldPacket out_packet;
- transData.BuildPacket(&out_packet);
-
- for (Map::PlayerList::const_iterator itr = player.begin(); itr != player.end(); ++itr)
- if (this != itr->GetSource()->GetTransport())
- itr->GetSource()->SendDirectMessage(&out_packet);
- }
}
-void Transport::DoEventIfAny(WayPointMap::value_type const& node, bool departure)
+void Transport::UnloadStaticPassengers()
{
- if (uint32 eventid = departure ? node.second.departureEventID : node.second.arrivalEventID)
+ while (!_staticPassengers.empty())
{
- TC_LOG_DEBUG(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.first, GetName().c_str());
- GetMap()->ScriptsStart(sEventScripts, eventid, this, this);
- EventInform(eventid);
+ WorldObject* obj = *_staticPassengers.begin();
+ obj->AddObjectToRemoveList(); // also removes from _staticPassengers
}
}
-void Transport::BuildStartMovePacket(Map const* targetMap)
+void Transport::EnableMovement(bool enabled)
{
- SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
- SetGoState(GO_STATE_ACTIVE);
- UpdateForMap(targetMap);
+ if (!GetGOInfo()->moTransport.canBeStopped)
+ return;
+
+ _pendingStop = !enabled;
}
-void Transport::BuildStopMovePacket(Map const* targetMap)
+void Transport::MoveToNextWaypoint()
{
- RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
- SetGoState(GO_STATE_READY);
- UpdateForMap(targetMap);
+ // Clear events flagging
+ _triggeredArrivalEvent = false;
+ _triggeredDepartureEvent = false;
+
+ // Set frames
+ _currentFrame = _nextFrame++;
+ if (_nextFrame == GetKeyFrames().end())
+ _nextFrame = GetKeyFrames().begin();
}
-uint32 Transport::AddNPCPassenger(uint32 tguid, uint32 entry, float x, float y, float z, float o, uint32 anim)
+float Transport::CalculateSegmentPos(float now)
{
- Map* map = GetMap();
- //make it world object so it will not be unloaded with grid
- Creature* creature = new Creature(true);
-
- if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, GetPhaseMask(), entry, 0, GetGOInfo()->faction, 0, 0, 0, 0))
+ KeyFrame const& frame = *_currentFrame;
+ const float speed = float(m_goInfo->moTransport.moveSpeed);
+ const float accel = float(m_goInfo->moTransport.accelRate);
+ float timeSinceStop = frame.TimeFrom + (now - (1.0f/IN_MILLISECONDS) * frame.DepartureTime);
+ float timeUntilStop = frame.TimeTo - (now - (1.0f/IN_MILLISECONDS) * frame.DepartureTime);
+ float segmentPos, dist;
+ float accelTime = _transportInfo->accelTime;
+ float accelDist = _transportInfo->accelDist;
+ // calculate from nearest stop, less confusing calculation...
+ if (timeSinceStop < timeUntilStop)
{
- delete creature;
- return 0;
+ if (timeSinceStop < accelTime)
+ dist = 0.5f * accel * timeSinceStop * timeSinceStop;
+ else
+ dist = accelDist + (timeSinceStop - accelTime) * speed;
+ segmentPos = dist - frame.DistSinceStop;
+ }
+ else
+ {
+ if (timeUntilStop < _transportInfo->accelTime)
+ dist = 0.5f * accel * timeUntilStop * timeUntilStop;
+ else
+ dist = accelDist + (timeUntilStop - accelTime) * speed;
+ segmentPos = frame.DistUntilStop - dist;
}
- creature->SetTransport(this);
- creature->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
- creature->m_movementInfo.guid = GetGUID();
- creature->m_movementInfo.transport.pos.Relocate(x, y, z, o);
+ return segmentPos / frame.NextDistFromPrev;
+}
+
+void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
+{
+ Map const* oldMap = GetMap();
- if (anim)
- creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, anim);
+ if (oldMap->GetId() != newMapid)
+ {
+ Map* newMap = sMapMgr->CreateBaseMap(newMapid);
+ Map::PlayerList const& oldPlayers = GetMap()->GetPlayers();
+ if (!oldPlayers.isEmpty())
+ {
+ UpdateData data;
+ BuildOutOfRangeUpdateBlock(&data);
+ WorldPacket packet;
+ data.BuildPacket(&packet);
+ for (Map::PlayerList::const_iterator itr = oldPlayers.begin(); itr != oldPlayers.end(); ++itr)
+ if (itr->GetSource()->GetTransport() != this)
+ itr->GetSource()->SendDirectMessage(&packet);
+ }
- creature->Relocate(
- GetPositionX() + (x * std::cos(GetOrientation()) + y * std::sin(GetOrientation() + float(M_PI))),
- GetPositionY() + (y * std::cos(GetOrientation()) + x * std::sin(GetOrientation())),
- z + GetPositionZ(),
- o + GetOrientation());
+ UnloadStaticPassengers();
+ GetMap()->RemoveFromMap<Transport>(this, false);
+ SetMap(newMap);
- creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
- creature->SetTransportHomePosition(creature->m_movementInfo.transport.pos);
+ Map::PlayerList const& newPlayers = GetMap()->GetPlayers();
+ if (!newPlayers.isEmpty())
+ {
+ for (Map::PlayerList::const_iterator itr = newPlayers.begin(); itr != newPlayers.end(); ++itr)
+ {
+ if (itr->GetSource()->GetTransport() != this)
+ {
+ UpdateData data;
+ BuildCreateUpdateBlockForPlayer(&data, itr->GetSource());
+ WorldPacket packet;
+ data.BuildPacket(&packet);
+ itr->GetSource()->SendDirectMessage(&packet);
+ }
+ }
+ }
- if (!creature->IsPositionValid())
- {
- TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)", creature->GetGUIDLow(), creature->GetEntry(), creature->GetPositionX(), creature->GetPositionY());
- delete creature;
- return 0;
- }
+ // Teleport passengers after everyone on destination map are sent create packet
+ // but before transport itself is registered there and begins updating
+ for (std::set<WorldObject*>::iterator itr = _staticPassengers.begin(); itr != _staticPassengers.end(); ++itr)
+ {
+ switch ((*itr)->GetTypeId())
+ {
+ case TYPEID_UNIT:
+ (*itr)->ToCreature()->FarTeleportTo(newMap, x, y, z, (*itr)->GetOrientation());
+ break;
+ case TYPEID_GAMEOBJECT:
+ {
+ GameObject* go = (*itr)->ToGameObject();
+ go->GetMap()->RemoveFromMap(go, false);
+ Relocate(x, y, z, go->GetOrientation());
+ SetMap(newMap);
+ newMap->AddToMap(go);
+ break;
+ }
+ }
+ }
- map->AddToMap(creature);
- m_NPCPassengerSet.insert(creature);
+ for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
+ {
+ switch ((*itr)->GetTypeId())
+ {
+ case TYPEID_UNIT:
+ if (!IS_PLAYER_GUID((*itr)->ToUnit()->GetOwnerGUID())) // pets should be teleported with player
+ (*itr)->ToCreature()->FarTeleportTo(newMap, x, y, z, (*itr)->GetOrientation());
+ break;
+ case TYPEID_GAMEOBJECT:
+ {
+ GameObject* go = (*itr)->ToGameObject();
+ go->GetMap()->RemoveFromMap(go, false);
+ Relocate(x, y, z, go->GetOrientation());
+ SetMap(newMap);
+ newMap->AddToMap(go);
+ break;
+ }
+ case TYPEID_PLAYER:
+ (*itr)->ToPlayer()->TeleportTo(newMapid, x, y, z, (*itr)->GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT);
+ break;
+ }
+ }
- if (tguid == 0)
- {
- ++currenttguid;
- tguid = currenttguid;
+ GetMap()->AddToMap<Transport>(this);
}
else
- currenttguid = std::max(tguid, currenttguid);
-
- creature->SetGUIDTransport(tguid);
- sScriptMgr->OnAddCreaturePassenger(this, creature);
- return tguid;
-}
-
-void Transport::UpdatePosition(MovementInfo* mi)
-{
- float transport_o = mi->pos.GetOrientation() - mi->transport.pos.GetOrientation();
- float transport_x = mi->pos.m_positionX - (mi->transport.pos.m_positionX * std::cos(transport_o) - mi->transport.pos.m_positionY * std::sin(transport_o));
- float transport_y = mi->pos.m_positionY - (mi->transport.pos.m_positionY * std::cos(transport_o) + mi->transport.pos.m_positionX * std::sin(transport_o));
- float transport_z = mi->pos.m_positionZ - mi->transport.pos.m_positionZ;
+ {
+ // Teleport players, they need to know it
+ for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
+ if ((*itr)->GetTypeId() == TYPEID_PLAYER)
+ (*itr)->ToUnit()->NearTeleportTo(x, y, z, GetOrientation());
+ }
- Relocate(transport_x, transport_y, transport_z, transport_o);
- UpdatePassengerPositions();
+ UpdatePosition(x, y, z, GetOrientation());
}
-void Transport::UpdatePassengerPositions()
+void Transport::UpdatePassengerPositions(std::set<WorldObject*>& passengers)
{
- for (CreatureSet::iterator itr = m_NPCPassengerSet.begin(); itr != m_NPCPassengerSet.end(); ++itr)
+ for (std::set<WorldObject*>::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
{
- Creature* npc = *itr;
+ WorldObject* passenger = *itr;
+ // transport teleported but passenger not yet (can happen for players)
+ if (passenger->GetMap() != GetMap())
+ continue;
+ // if passenger is on vehicle we have to assume the vehicle is also on transport
+ // and its the vehicle that will be updating its passengers
+ if (Unit* unit = passenger->ToUnit())
+ if (unit->GetVehicle())
+ continue;
+
+ // Do not use Unit::UpdatePosition here, we don't want to remove auras
+ // as if regular movement occurred
float x, y, z, o;
- npc->m_movementInfo.transport.pos.GetPosition(x, y, z, o);
- CalculatePassengerPosition(x, y, z, &o);
- GetMap()->CreatureRelocation(npc, x, y, z, o, false);
- npc->GetTransportHomePosition(x, y, z, o);
+ passenger->m_movementInfo.transport.pos.GetPosition(x, y, z, o);
CalculatePassengerPosition(x, y, z, &o);
- npc->SetHomePosition(x, y, z, o);
+ switch (passenger->GetTypeId())
+ {
+ case TYPEID_UNIT:
+ {
+ Creature* creature = passenger->ToCreature();
+ GetMap()->CreatureRelocation(creature, x, y, z, o, false);
+ creature->GetTransportHomePosition(x, y, z, o);
+ CalculatePassengerPosition(x, y, z, &o);
+ creature->SetHomePosition(x, y, z, o);
+ break;
+ }
+ case TYPEID_PLAYER:
+ GetMap()->PlayerRelocation(passenger->ToPlayer(), x, y, z, o);
+ break;
+ case TYPEID_GAMEOBJECT:
+ GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o, false);
+ break;
+ }
+
+ if (Unit* unit = passenger->ToUnit())
+ if (Vehicle* vehicle = unit->GetVehicleKit())
+ vehicle->RelocatePassengers();
}
}
-void Transport::CalculatePassengerPosition(float& x, float& y, float& z, float* o /*= NULL*/) const
+void Transport::DoEventIfAny(KeyFrame const& node, bool departure)
{
- float inx = x, iny = y, inz = z;
- if (o)
- *o = Position::NormalizeOrientation(GetOrientation() + *o);
-
- x = GetPositionX() + inx * std::cos(GetOrientation()) - iny * std::sin(GetOrientation());
- y = GetPositionY() + iny * std::cos(GetOrientation()) + inx * std::sin(GetOrientation());
- z = GetPositionZ() + inz;
+ if (uint32 eventid = departure ? node.Node->departureEventID : node.Node->arrivalEventID)
+ {
+ TC_LOG_DEBUG(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of %s path", departure ? "departure" : "arrival", eventid, node.Node->index, GetName());
+ GetMap()->ScriptsStart(sEventScripts, eventid, this, this);
+ EventInform(eventid);
+ }
}
-void Transport::CalculatePassengerOffset(float& x, float& y, float& z, float* o /*= NULL*/) const
+void Transport::BuildUpdate(UpdateDataMapType& data_map)
{
- if (o)
- *o = Position::NormalizeOrientation(*o - GetOrientation());
+ Map::PlayerList const& players = GetMap()->GetPlayers();
+ if (players.isEmpty())
+ return;
- z -= GetPositionZ();
- y -= GetPositionY(); // y = searchedY * std::cos(o) + searchedX * std::sin(o)
- x -= GetPositionX(); // x = searchedX * std::cos(o) + searchedY * std::sin(o + pi)
- float inx = x, iny = y;
- y = (iny - inx * std::tan(GetOrientation())) / (std::cos(GetOrientation()) + std::sin(GetOrientation()) * std::tan(GetOrientation()));
- x = (inx + iny * std::tan(GetOrientation())) / (std::cos(GetOrientation()) + std::sin(GetOrientation()) * std::tan(GetOrientation()));
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ BuildFieldsUpdate(itr->GetSource(), data_map);
+
+ ClearUpdateMask(true);
}
diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h
index 445bec456fd..22a54e8428d 100644
--- a/src/server/game/Entities/Transport/Transport.h
+++ b/src/server/game/Entities/Transport/Transport.h
@@ -20,34 +20,30 @@
#define TRANSPORTS_H
#include "GameObject.h"
+#include "TransportMgr.h"
#include "VehicleDefines.h"
-#include <map>
-#include <set>
-#include <string>
+struct CreatureData;
class Transport : public GameObject, public TransportBase
{
+ friend Transport* TransportMgr::CreateTransport(uint32, uint32, Map*);
+
+ Transport();
public:
- Transport(uint32 period, uint32 script);
~Transport();
- bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags);
- bool GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids);
- void Update(uint32 p_time);
- bool AddPassenger(Player* passenger);
- bool RemovePassenger(Player* passenger);
+ bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress);
+ void Update(uint32 diff);
- void RemovePassenger(Creature* passenger) { m_NPCPassengerSet.erase(passenger); }
+ void BuildUpdate(UpdateDataMapType& data_map);
- typedef std::set<Player*> PlayerSet;
- PlayerSet const& GetPassengers() const { return m_passengers; }
+ void AddPassenger(WorldObject* passenger);
+ void RemovePassenger(WorldObject* passenger);
+ std::set<WorldObject*> const& GetPassengers() const { return _passengers; }
- typedef std::set<Creature*> CreatureSet;
- CreatureSet m_NPCPassengerSet;
- uint32 AddNPCPassenger(uint32 tguid, uint32 entry, float x, float y, float z, float o, uint32 anim=0);
- void UpdatePosition(MovementInfo* mi);
- void UpdatePassengerPositions();
+ Creature* CreateNPCPassenger(uint32 guid, CreatureData const* data);
+ GameObject* CreateGOPassenger(uint32 guid, GameObjectData const* data);
/// This method transforms supplied transport offsets into global coordinates
void CalculatePassengerPosition(float& x, float& y, float& z, float* o = NULL) const;
@@ -55,50 +51,48 @@ class Transport : public GameObject, public TransportBase
/// This method transforms supplied global coordinates into local offsets
void CalculatePassengerOffset(float& x, float& y, float& z, float* o = NULL) const;
- void BuildStartMovePacket(Map const* targetMap);
- void BuildStopMovePacket(Map const* targetMap);
- uint32 GetScriptId() const { return ScriptId; }
- private:
- struct WayPoint
- {
- WayPoint() : mapid(0), x(0), y(0), z(0), teleport(false), id(0) {}
- WayPoint(uint32 _mapid, float _x, float _y, float _z, bool _teleport, uint32 _id = 0,
- uint32 _arrivalEventID = 0, uint32 _departureEventID = 0)
- : mapid(_mapid), x(_x), y(_y), z(_z), teleport(_teleport), id(_id),
- arrivalEventID(_arrivalEventID), departureEventID(_departureEventID)
- {
- }
- uint32 mapid;
- float x;
- float y;
- float z;
- bool teleport;
- uint32 id;
- uint32 arrivalEventID;
- uint32 departureEventID;
- };
-
- typedef std::map<uint32, WayPoint> WayPointMap;
-
- WayPointMap::const_iterator m_curr;
- WayPointMap::const_iterator m_next;
- uint32 m_pathTime;
- uint32 m_timer;
-
- PlayerSet m_passengers;
-
- uint32 currenttguid;
- uint32 m_period;
- uint32 ScriptId;
- public:
- WayPointMap m_WayPoints;
- uint32 m_nextNodeTime;
+ uint32 GetPeriod() const { return GetUInt32Value(GAMEOBJECT_LEVEL); }
+ void SetPeriod(uint32 period) { SetUInt32Value(GAMEOBJECT_LEVEL, period); }
+ uint32 GetTimer() const { return GetGOValue()->Transport.PathProgress; }
+
+ KeyFrameVec const& GetKeyFrames() const { return _transportInfo->keyFrames; }
+
+ void UpdatePosition(float x, float y, float z, float o);
+
+ //! Needed when transport moves from inactive to active grid
+ void LoadStaticPassengers();
+
+ //! Needed when transport enters inactive grid
+ void UnloadStaticPassengers();
+
+ void EnableMovement(bool enabled);
private:
+ void MoveToNextWaypoint();
+ float CalculateSegmentPos(float perc);
void TeleportTransport(uint32 newMapid, float x, float y, float z);
- void UpdateForMap(Map const* map);
- void DoEventIfAny(WayPointMap::value_type const& node, bool departure);
- WayPointMap::const_iterator GetNextWayPoint();
+ void UpdatePassengerPositions(std::set<WorldObject*>& passengers);
+ void DoEventIfAny(KeyFrame const& node, bool departure);
+
+ //! Helpers to know if stop frame was reached
+ bool IsMoving() const { return _isMoving; }
+ void SetMoving(bool val) { _isMoving = val; }
+
+ TransportTemplate const* _transportInfo;
+
+ KeyFrameVec::const_iterator _currentFrame;
+ KeyFrameVec::const_iterator _nextFrame;
+ uint32 _moveTimer;
+ TimeTrackerSmall _positionChangeTimer;
+ bool _isMoving;
+ bool _pendingStop;
+
+ //! These are needed to properly control events triggering only once for each frame
+ bool _triggeredArrivalEvent;
+ bool _triggeredDepartureEvent;
+
+ std::set<WorldObject*> _passengers;
+ std::set<WorldObject*> _staticPassengers;
};
-#endif
+#endif
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 74c50145311..2fd1c500305 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -17329,6 +17329,8 @@ void Unit::SetFacingTo(float ori)
{
Movement::MoveSplineInit init(this);
init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset(), false);
+ if (HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && GetTransGUID())
+ init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
init.SetFacing(ori);
init.Launch();
}
@@ -17340,7 +17342,10 @@ void Unit::SetFacingToObject(WorldObject* object)
return;
/// @todo figure out under what conditions creature will move towards object instead of facing it where it currently is.
- SetFacingTo(GetAngle(object));
+ Movement::MoveSplineInit init(this);
+ init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
+ init.SetFacing(GetAngle(object)); // when on transport, GetAngle will still return global coordinates (and angle) that needs transforming
+ init.Launch();
}
bool Unit::SetWalk(bool enable)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 13f8c8e781f..25352a924ef 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -2078,12 +2078,6 @@ class Unit : public WorldObject
bool IsOnVehicle(const Unit* vehicle) const;
Unit* GetVehicleBase() const;
Creature* GetVehicleCreatureBase() const;
- 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(); }
- float GetTransOffsetO() const { return m_movementInfo.transport.pos.GetOrientation(); }
- uint32 GetTransTime() const { return m_movementInfo.transport.time; }
- int8 GetTransSeat() const { return m_movementInfo.transport.seat; }
uint64 GetTransGUID() const;
/// Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
TransportBase* GetDirectTransport() const;