Core/GameObjects: Transport (type 11) improvements

Port From (https://github.com/TrinityCore/TrinityCore/commit/630b60eb0dcd3d9ce41582664ab822b049365431)
This commit is contained in:
hondacrx
2022-06-03 16:20:41 -04:00
parent e65ce31742
commit 40444525b2
30 changed files with 807 additions and 377 deletions
@@ -93,7 +93,7 @@ namespace Framework.Constants
Max = 3
}
public enum GameObjectDynamicLowFlags
public enum GameObjectDynamicLowFlags : ushort
{
HideModel = 0x02,
Activate = 0x04,
+1 -1
View File
@@ -1360,7 +1360,7 @@ namespace Game.AI
break;
if (e.GetTargetType() == SmartTargets.Self)
_me.SetFacingTo((_me.GetTransport() ? _me.GetTransportHomePosition() : _me.GetHomePosition()).GetOrientation());
_me.SetFacingTo((_me.GetTransport() != null ? _me.GetTransportHomePosition() : _me.GetHomePosition()).GetOrientation());
else if (e.GetTargetType() == SmartTargets.Position)
_me.SetFacingTo(e.Target.o);
else if (!targets.Empty())
+1 -1
View File
@@ -1079,7 +1079,7 @@ namespace Game.Chat
[Command("transport", RBACPermissions.CommandDebugTransport)]
static bool HandleDebugTransportCommand(CommandHandler handler, string operation)
{
Transport transport = handler.GetSession().GetPlayer().GetTransport();
Transport transport = handler.GetSession().GetPlayer().GetTransport<Transport>();
if (!transport)
return false;
+1 -1
View File
@@ -959,7 +959,7 @@ namespace Game.Chat
areaId, (areaEntry != null ? areaEntry.AreaName[handler.GetSessionDbcLocale()] : unknown),
obj.GetPositionX(), obj.GetPositionY(), obj.GetPositionZ(), obj.GetOrientation());
Transport transport = obj.GetTransport();
Transport transport = obj.GetTransport<Transport>();
if (transport)
{
handler.SendSysMessage(CypherStrings.TransportPosition, transport.GetGoInfo().MoTransport.SpawnMap, obj.GetTransOffsetX(), obj.GetTransOffsetY(), obj.GetTransOffsetZ(), obj.GetTransOffsetO(),
+1 -1
View File
@@ -654,7 +654,7 @@ namespace Game.Chat
Player chr = handler.GetSession().GetPlayer();
Map map = chr.GetMap();
Transport trans = chr.GetTransport();
Transport trans = chr.GetTransport<Transport>();
if (trans)
{
ulong guid = Global.ObjectMgr.GenerateCreatureSpawnId();
@@ -191,8 +191,8 @@ namespace Game.Entities
}
// movement on transport of areatriggers on unit is handled by themself
Transport transport = m_movementInfo.transport.guid.IsEmpty() ? caster.GetTransport() : null;
if (transport)
ITransport transport = m_movementInfo.transport.guid.IsEmpty() ? caster.GetTransport() : null;
if (transport != null)
{
float x, y, z, o;
pos.GetPosition(out x, out y, out z, out o);
@@ -211,7 +211,7 @@ namespace Game.Entities
if (!GetMap().AddToMap(this))
{ // Returning false will cause the object to be deleted - remove from transport
if (transport)
if (transport != null)
transport.RemovePassenger(this);
return false;
}
+1
View File
@@ -286,6 +286,7 @@ namespace Game.Entities
}
public CorpseDynFlags GetCorpseDynamicFlags() { return (CorpseDynFlags)(uint)m_corpseData.DynamicFlags; }
public bool HasCorpseDynamicFlag(CorpseDynFlags flag) { return (m_corpseData.DynamicFlags & (uint)flag) != 0; }
public void SetCorpseDynamicFlag(CorpseDynFlags dynamicFlags) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.DynamicFlags), (uint)dynamicFlags); }
public void RemoveCorpseDynamicFlag(CorpseDynFlags dynamicFlags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.DynamicFlags), (uint)dynamicFlags); }
public void ReplaceAllCorpseDynamicFlags(CorpseDynFlags dynamicFlags) { SetUpdateFieldValue(m_values.ModifyValue(m_corpseData).ModifyValue(m_corpseData.DynamicFlags), (uint)dynamicFlags); }
+6 -1
View File
@@ -1254,7 +1254,12 @@ namespace Game.Entities
return;
}
uint mapId = GetTransport() ? (uint)GetTransport().GetGoInfo().MoTransport.SpawnMap : GetMapId();
uint mapId = GetMapId();
ITransport transport = GetTransport();
if (transport != null)
if (transport.GetMapIdForSpawning() >= 0)
mapId = (uint)transport.GetMapIdForSpawning();
SaveToDB(mapId, data.SpawnDifficulties);
}
+3 -3
View File
@@ -111,8 +111,8 @@ namespace Game.Entities
if (IsWorldObject())
SetActive(true); //must before add to map to be put in world container
Transport transport = caster.GetTransport();
if (transport)
ITransport transport = caster.GetTransport();
if (transport != null)
{
float x, y, z, o;
pos.GetPosition(out x, out y, out z, out o);
@@ -126,7 +126,7 @@ namespace Game.Entities
if (!GetMap().AddToMap(this))
{
// Returning false will cause the object to be deleted - remove from transport
if (transport)
if (transport != null)
transport.RemovePassenger(this);
return false;
}
+496 -115
View File
@@ -60,8 +60,6 @@ namespace Game.Entities
{
m_AI = null;
m_model = null;
if (m_goInfo != null && m_goInfo.type == GameObjectTypes.Transport)
m_goValue.Transport.StopFrames.Clear();
base.Dispose();
}
@@ -311,38 +309,15 @@ namespace Game.Entities
SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.ParentRotation), new Quaternion(goInfo.DestructibleBuilding.DestructibleModelRec, 0f, 0f, 0f));
break;
case GameObjectTypes.Transport:
m_goValue.Transport.AnimationInfo = Global.TransportMgr.GetTransportAnimInfo(goInfo.entry);
m_goValue.Transport.PathProgress = Time.GetMSTime();
if (!m_goValue.Transport.AnimationInfo.Path.Empty())
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 List<uint>();
if (goInfo.Transport.Timeto2ndfloor > 0)
m_goValue.Transport.StopFrames.Add(goInfo.Transport.Timeto2ndfloor);
if (goInfo.Transport.Timeto3rdfloor > 0)
m_goValue.Transport.StopFrames.Add(goInfo.Transport.Timeto3rdfloor);
if (goInfo.Transport.Timeto4thfloor > 0)
m_goValue.Transport.StopFrames.Add(goInfo.Transport.Timeto4thfloor);
if (goInfo.Transport.Timeto5thfloor > 0)
m_goValue.Transport.StopFrames.Add(goInfo.Transport.Timeto5thfloor);
if (goInfo.Transport.Timeto6thfloor > 0)
m_goValue.Transport.StopFrames.Add(goInfo.Transport.Timeto6thfloor);
if (goInfo.Transport.Timeto7thfloor > 0)
m_goValue.Transport.StopFrames.Add(goInfo.Transport.Timeto7thfloor);
if (goInfo.Transport.Timeto8thfloor > 0)
m_goValue.Transport.StopFrames.Add(goInfo.Transport.Timeto8thfloor);
if (goInfo.Transport.Timeto9thfloor > 0)
m_goValue.Transport.StopFrames.Add(goInfo.Transport.Timeto9thfloor);
if (goInfo.Transport.Timeto10thfloor > 0)
m_goValue.Transport.StopFrames.Add(goInfo.Transport.Timeto10thfloor);
m_goTypeImpl = new GameObjectType.Transport(this);
if (goInfo.Transport.startOpen != 0)
SetTransportState(GameObjectState.TransportStopped, goInfo.Transport.startOpen - 1);
SetGoState(GameObjectState.TransportStopped);
else
SetTransportState(GameObjectState.TransportActive);
SetGoState(GameObjectState.TransportActive);
SetGoAnimProgress(animProgress);
SetActive(true);
break;
case GameObjectTypes.FishingNode:
SetLevel(1);
@@ -452,6 +427,9 @@ namespace Game.Entities
}
}
if (m_goTypeImpl != null)
m_goTypeImpl.Update(diff);
switch (m_lootState)
{
case LootState.NotReady:
@@ -475,50 +453,6 @@ namespace Game.Entities
m_lootState = LootState.Ready;
break;
}
case GameObjectTypes.Transport:
if (m_goValue.Transport.AnimationInfo.Path.Empty())
break;
m_goValue.Transport.PathProgress += diff;
if (GetGoState() == GameObjectState.TransportActive)
{
m_goValue.Transport.PathProgress += diff;
/* TODO: Fix movement in unloaded grid - currently GO will just disappear
public uint 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 = 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());
TC_LOG_DEBUG("misc", "Src: {0} Dest: {1}", src.toString().c_str(), pos.toString().c_str());
GetMap().GameObjectRelocation(this, pos.x, pos.y, pos.z, GetOrientation());
}
*/
if (!m_goValue.Transport.StopFrames.Empty())
{
uint visualStateBefore = (m_goValue.Transport.StateUpdateTimer / 20000) & 1;
m_goValue.Transport.StateUpdateTimer += diff;
uint visualStateAfter = (m_goValue.Transport.StateUpdateTimer / 20000) & 1;
if (visualStateBefore != visualStateAfter)
{
m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.Level);
m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.State);
ForceUpdateFieldChange();
}
}
}
break;
case GameObjectTypes.FishingNode:
{
// fishing code (bobber ready)
@@ -1072,7 +1006,13 @@ namespace Game.Entities
return;
}
SaveToDB(GetMapId(), data.SpawnDifficulties);
uint mapId = GetMapId();
ITransport transport = GetTransport();
if (transport != null)
if (transport.GetMapIdForSpawning() >= 0)
mapId = (uint)transport.GetMapIdForSpawning();
SaveToDB(mapId, data.SpawnDifficulties);
}
public void SaveToDB(uint mapid, List<Difficulty> spawnDifficulties)
@@ -1293,7 +1233,7 @@ namespace Game.Entities
if (gInfo == null)
return false;
return gInfo.type == GameObjectTypes.MapObjTransport || (gInfo.type == GameObjectTypes.Transport && m_goValue.Transport.StopFrames.Empty());
return gInfo.type == GameObjectTypes.MapObjTransport || gInfo.type == GameObjectTypes.Transport;
}
public bool IsDestructibleBuilding()
@@ -1581,7 +1521,7 @@ namespace Game.Entities
case GameObjectActions.GoTo9thFloor:
case GameObjectActions.GoTo10thFloor:
if (GetGoType() == GameObjectTypes.Transport)
SetTransportState(GameObjectState.TransportStopped, (uint)(action - GameObjectActions.GoTo1stFloor));
SetGoState((GameObjectState)action);
else
Log.outError(LogFilter.Spells, $"Spell {spellId} targeted non-transport gameobject for transport only action \"Go to Floor\" {action} in effect {effectIndex}");
break;
@@ -2453,7 +2393,7 @@ namespace Game.Entities
{
Quaternion localRotation = GetLocalRotation();
Transport transport = GetTransport();
Transport transport = GetTransport<Transport>();
if (transport != null)
{
Quaternion worldRotation = transport.GetWorldRotation();
@@ -2473,7 +2413,7 @@ namespace Game.Entities
{
return $"{base.GetDebugInfo()}\nSpawnId: {GetSpawnId()} GoState: {GetGoState()} ScriptId: {GetScriptId()} AIName: {GetAIName()}";
}
public bool IsAtInteractDistance(Player player, SpellInfo spell = null)
{
if (spell != null || (spell = GetSpellForLock(player)) != null)
@@ -2518,7 +2458,7 @@ namespace Game.Entities
{
return IsInMap(player) && IsInPhase(player) && IsAtInteractDistance(player);
}
public SpellInfo GetSpellForLock(Player player)
{
if (!player)
@@ -2563,7 +2503,6 @@ namespace Game.Entities
return null;
}
public void ModifyHealth(int change, WorldObject attackerOrHealer = null, uint spellId = 0)
{
if (m_goValue.Building.MaxHealth == 0 || change == 0)
@@ -2742,9 +2681,14 @@ namespace Game.Entities
public void SetGoState(GameObjectState state)
{
GameObjectState oldState = GetGoState();
SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.State), (sbyte)state);
if (GetAI() != null)
GetAI().OnStateChanged(state);
if (m_goTypeImpl != null)
m_goTypeImpl.OnStateChanged(oldState, state);
if (m_model != null && !IsTransport())
{
if (!IsInWorld)
@@ -2759,38 +2703,6 @@ namespace Game.Entities
}
}
public virtual uint GetTransportPeriod()
{
Cypher.Assert(GetGoInfo().type == GameObjectTypes.Transport);
if (!m_goValue.Transport.AnimationInfo.Path.Empty())
return m_goValue.Transport.AnimationInfo.TotalTime;
return 0;
}
public void SetTransportState(GameObjectState state, uint stopFrame = 0)
{
if (GetGoState() == state)
return;
Cypher.Assert(GetGoInfo().type == GameObjectTypes.Transport);
Cypher.Assert(state >= GameObjectState.TransportActive);
if (state == GameObjectState.TransportActive)
{
m_goValue.Transport.StateUpdateTimer = 0;
m_goValue.Transport.PathProgress = Time.GetMSTime();
if (GetGoState() >= GameObjectState.TransportStopped)
m_goValue.Transport.PathProgress += m_goValue.Transport.StopFrames.LookupByIndex(GetGoState() - GameObjectState.TransportStopped);
SetGoState(GameObjectState.TransportActive);
}
else
{
Cypher.Assert(stopFrame < m_goValue.Transport.StopFrames.Count);
m_goValue.Transport.PathProgress = Time.GetMSTime() + m_goValue.Transport.StopFrames[(int)stopFrame];
SetGoState((GameObjectState)((int)GameObjectState.TransportStopped + stopFrame));
}
}
public void SetDisplayId(uint displayid)
{
SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.DisplayID), displayid);
@@ -2985,6 +2897,33 @@ namespace Game.Entities
base.ClearUpdateMask(remove);
}
public List<uint> GetPauseTimes()
{
GameObjectType.Transport transport = m_goTypeImpl as GameObjectType.Transport;
if (transport != null)
return transport.GetPauseTimes();
return null;
}
public void SetPathProgressForClient(float progress)
{
DoWithSuppressingObjectUpdates(() =>
{
ObjectFieldData dynflagMask = new();
dynflagMask.MarkChanged(m_objectData.DynamicFlags);
bool marked = (m_objectData.GetUpdateMask() & dynflagMask.GetUpdateMask()).IsAnySet();
uint dynamicFlags = (uint)GetDynamicFlags();
dynamicFlags &= 0xFFFF; // remove high bits
dynamicFlags |= (uint)(progress * 65535.0f) << 16;
ReplaceAllDynamicFlags((GameObjectDynamicLowFlags)dynamicFlags);
if (!marked)
m_objectData.ClearChanged(m_objectData.DynamicFlags);
});
}
public void GetRespawnPosition(out float x, out float y, out float z, out float ori)
{
if (m_goData != null)
@@ -2993,6 +2932,31 @@ namespace Game.Entities
GetPosition(out x, out y, out z, out ori);
}
public ITransport ToTransportBase()
{
switch (GetGoType())
{
case GameObjectTypes.Transport:
return (GameObjectType.Transport)m_goTypeImpl;
case GameObjectTypes.MapObjTransport:
return (Transport)this;
default:
break;
}
return null;
}
public void AfterRelocation()
{
UpdateModelPosition();
UpdatePositionData();
if (m_goTypeImpl != null)
m_goTypeImpl.OnRelocated();
UpdateObjectVisibility(false);
}
public float GetInteractionDistance()
{
switch (GetGoType())
@@ -3239,7 +3203,7 @@ namespace Game.Entities
return m_goValue.CapturePoint.State == BattlegroundCapturePointState.ContestedHorde
|| m_goValue.CapturePoint.State == BattlegroundCapturePointState.HordeCaptured;
}
public override ushort GetAIAnimKitId() { return _animKitId; }
public uint GetWorldEffectID() { return _worldEffectID; }
@@ -3308,6 +3272,12 @@ namespace Game.Entities
public void ReplaceAllFlags(GameObjectFlags flags) { SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.Flags), (uint)flags); }
public void SetLevel(uint level) { SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.Level), level); }
public GameObjectDynamicLowFlags GetDynamicFlags() { return (GameObjectDynamicLowFlags)(uint)m_objectData.DynamicFlags; }
public bool HasDynamicFlag(GameObjectDynamicLowFlags flag) { return (m_objectData.DynamicFlags & (uint)flag) != 0; }
public void SetDynamicFlag(GameObjectDynamicLowFlags flag) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.DynamicFlags), (uint)flag); }
public void RemoveDynamicFlag(GameObjectDynamicLowFlags flag) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.DynamicFlags), (uint)flag); }
public void ReplaceAllDynamicFlags(GameObjectDynamicLowFlags flag) { SetUpdateFieldValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.DynamicFlags), (uint)flag); }
public GameObjectTypes GetGoType() { return (GameObjectTypes)(sbyte)m_gameObjectData.TypeID; }
public void SetGoType(GameObjectTypes type) { SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.TypeID), (sbyte)type); }
public GameObjectState GetGoState() { return (GameObjectState)(sbyte)m_gameObjectData.State; }
@@ -3389,6 +3359,7 @@ namespace Game.Entities
public override float GetStationaryY() { return StationaryPosition.GetPositionY(); }
public override float GetStationaryZ() { return StationaryPosition.GetPositionZ(); }
public override float GetStationaryO() { return StationaryPosition.GetOrientation(); }
public Position GetStationaryPosition() { return StationaryPosition; }
public void RelocateStationaryPosition(float x, float y, float z, float o) { StationaryPosition.Relocate(x, y, z, o); }
@@ -3407,6 +3378,12 @@ namespace Game.Entities
Cell.VisitWorldObjects(this, deliverer, GetVisibilityRange());
}
void HandleCustomTypeCommand(GameObjectTypeBase.CustomCommand command)
{
if (m_goTypeImpl != null)
command.Execute(m_goTypeImpl);
}
public void CreateModel()
{
m_model = GameObjectModel.Create(new GameObjectModelOwnerImpl(this));
@@ -3419,8 +3396,9 @@ namespace Game.Entities
public bool GetRespawnCompatibilityMode() { return m_respawnCompatibilityMode; }
#region Fields
protected GameObjectFieldData m_gameObjectData;
protected GameObjectValue m_goValue;
public GameObjectFieldData m_gameObjectData;
GameObjectTypeBase m_goTypeImpl;
protected GameObjectValue m_goValue; // TODO: replace with m_goTypeImpl
protected GameObjectTemplate m_goInfo;
protected GameObjectTemplateAddon m_goTemplateAddon;
GameObjectData m_goData;
@@ -3509,6 +3487,26 @@ namespace Game.Entities
GameObject _owner;
}
// Base class for GameObject type specific implementations
class GameObjectTypeBase
{
protected GameObject _owner;
public GameObjectTypeBase(GameObject owner)
{
_owner = owner;
}
public virtual void Update(uint diff) { }
public virtual void OnStateChanged(GameObjectState oldState, GameObjectState newState) { }
public virtual void OnRelocated() { }
public class CustomCommand
{
public virtual void Execute(GameObjectTypeBase type) { }
}
}
public struct GameObjectValue
{
public transport Transport;
@@ -3549,4 +3547,387 @@ namespace Game.Entities
public uint AssaultTimer;
}
}
namespace GameObjectType
{
//11 GAMEOBJECT_TYPE_TRANSPORT
class Transport : GameObjectTypeBase, ITransport
{
TransportAnimation _animationInfo;
uint _pathProgress;
uint _stateChangeTime;
uint _stateChangeProgress;
List<uint> _stopFrames = new();
bool _autoCycleBetweenStopFrames;
TimeTracker _positionUpdateTimer;
List<WorldObject> _passengers = new();
static TimeSpan PositionUpdateInterval = TimeSpan.FromMilliseconds(50);
public Transport(GameObject owner) : base(owner)
{
_animationInfo = Global.TransportMgr.GetTransportAnimInfo(owner.GetGoInfo().entry);
_pathProgress = GameTime.GetGameTimeMS() % GetTransportPeriod();
_stateChangeTime = GameTime.GetGameTimeMS();
_stateChangeProgress = _pathProgress;
GameObjectTemplate goInfo = _owner.GetGoInfo();
if (goInfo.Transport.Timeto2ndfloor > 0)
{
_stopFrames.Add(goInfo.Transport.Timeto2ndfloor);
if (goInfo.Transport.Timeto3rdfloor > 0)
{
_stopFrames.Add(goInfo.Transport.Timeto3rdfloor);
if (goInfo.Transport.Timeto4thfloor > 0)
{
_stopFrames.Add(goInfo.Transport.Timeto4thfloor);
if (goInfo.Transport.Timeto5thfloor > 0)
{
_stopFrames.Add(goInfo.Transport.Timeto5thfloor);
if (goInfo.Transport.Timeto6thfloor > 0)
{
_stopFrames.Add(goInfo.Transport.Timeto6thfloor);
if (goInfo.Transport.Timeto7thfloor > 0)
{
_stopFrames.Add(goInfo.Transport.Timeto7thfloor);
if (goInfo.Transport.Timeto8thfloor > 0)
{
_stopFrames.Add(goInfo.Transport.Timeto8thfloor);
if (goInfo.Transport.Timeto9thfloor > 0)
{
_stopFrames.Add(goInfo.Transport.Timeto9thfloor);
if (goInfo.Transport.Timeto10thfloor > 0)
_stopFrames.Add(goInfo.Transport.Timeto10thfloor);
}
}
}
}
}
}
}
}
_positionUpdateTimer.Reset(PositionUpdateInterval);
}
public override void Update(uint diff)
{
if (_animationInfo == null)
return;
_positionUpdateTimer.Update(diff);
if (!_positionUpdateTimer.Passed())
return;
_positionUpdateTimer.Reset(PositionUpdateInterval);
uint now = GameTime.GetGameTimeMS();
uint period = GetTransportPeriod();
uint newProgress = 0;
if (_stopFrames.Empty())
newProgress = now % period;
else
{
int stopTargetTime = 0;
if (_owner.GetGoState() == GameObjectState.TransportActive)
stopTargetTime = 0;
else
stopTargetTime = (int)(_stopFrames[_owner.GetGoState() - GameObjectState.TransportStopped]);
if (now < _owner.m_gameObjectData.Level)
{
int timeToStop = (int)(_owner.m_gameObjectData.Level - _stateChangeTime);
float stopSourcePathPct = (float)_stateChangeProgress / (float)period;
float stopTargetPathPct = (float)stopTargetTime / (float)period;
float timeSinceStopProgressPct = (float)(now - _stateChangeTime) / (float)timeToStop;
float progressPct;
if (!_owner.HasDynamicFlag(GameObjectDynamicLowFlags.InvertedMovement))
{
if (_owner.GetGoState() == GameObjectState.TransportActive)
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 = (uint)((float)period * progressPct) % period;
}
else
newProgress = (uint)stopTargetTime;
if (newProgress == stopTargetTime && newProgress != _pathProgress)
{
uint eventId;
switch (_owner.GetGoState() - GameObjectState.TransportActive)
{
case 0:
eventId = _owner.GetGoInfo().Transport.Reached1stfloor;
break;
case 1:
eventId = _owner.GetGoInfo().Transport.Reached2ndfloor;
break;
case 2:
eventId = _owner.GetGoInfo().Transport.Reached3rdfloor;
break;
case 3:
eventId = _owner.GetGoInfo().Transport.Reached4thfloor;
break;
case 4:
eventId = _owner.GetGoInfo().Transport.Reached5thfloor;
break;
case 5:
eventId = _owner.GetGoInfo().Transport.Reached6thfloor;
break;
case 6:
eventId = _owner.GetGoInfo().Transport.Reached7thfloor;
break;
case 7:
eventId = _owner.GetGoInfo().Transport.Reached8thfloor;
break;
case 8:
eventId = _owner.GetGoInfo().Transport.Reached9thfloor;
break;
case 9:
eventId = _owner.GetGoInfo().Transport.Reached10thfloor;
break;
default:
eventId = 0u;
break;
}
if (eventId != 0)
GameEvents.Trigger(eventId, _owner, null);
if (_autoCycleBetweenStopFrames)
{
GameObjectState currentState = _owner.GetGoState();
GameObjectState newState;
if (currentState == GameObjectState.TransportActive)
newState = GameObjectState.TransportStopped;
else if (currentState - GameObjectState.TransportActive == _stopFrames.Count)
newState = currentState - 1;
else if (_owner.HasDynamicFlag(GameObjectDynamicLowFlags.InvertedMovement))
newState = currentState - 1;
else
newState = currentState + 1;
_owner.SetGoState(newState);
}
}
}
if (_pathProgress == newProgress)
return;
_pathProgress = newProgress;
TransportAnimationRecord oldAnimation = _animationInfo.GetPrevAnimNode(newProgress);
TransportAnimationRecord newAnimation = _animationInfo.GetNextAnimNode(newProgress);
if (oldAnimation != null && newAnimation != null)
{
Matrix4x4 pathRotation = Matrix4x4.CreateFromQuaternion(new Quaternion(_owner.m_gameObjectData.ParentRotation.GetValue().X, _owner.m_gameObjectData.ParentRotation.GetValue().Y,
_owner.m_gameObjectData.ParentRotation.GetValue().Z, _owner.m_gameObjectData.ParentRotation.GetValue().W));
Vector3 prev = new(oldAnimation.Pos.X, oldAnimation.Pos.Y, oldAnimation.Pos.Z);
Vector3 next = new(newAnimation.Pos.X, newAnimation.Pos.Y, newAnimation.Pos.Z);
float animProgress = (float)(newProgress - oldAnimation.TimeIndex) / (float)(newAnimation.TimeIndex - oldAnimation.TimeIndex);
Vector3 dst = Vector3.Transform(Vector3.Lerp(prev, next, animProgress), pathRotation);//todo check this
dst += _owner.GetStationaryPosition();
_owner.GetMap().GameObjectRelocation(_owner, dst.X, dst.Y, dst.Z, _owner.GetOrientation());
}
TransportRotationRecord oldRotation = _animationInfo.GetPrevAnimRotation(newProgress);
TransportRotationRecord newRotation = _animationInfo.GetNextAnimRotation(newProgress);
if (oldRotation != null && newRotation != null)
{
Quaternion prev = new(oldRotation.Rot[0], oldRotation.Rot[1], oldRotation.Rot[2], oldRotation.Rot[3]);
Quaternion next = new(newRotation.Rot[0], newRotation.Rot[1], newRotation.Rot[2], newRotation.Rot[3]);
float animProgress = (float)(newProgress - oldRotation.TimeIndex) / (float)(newRotation.TimeIndex - oldRotation.TimeIndex);
Quaternion rotation = Quaternion.Lerp(prev, 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);
}
public override void OnStateChanged(GameObjectState oldState, GameObjectState newState)
{
Cypher.Assert(newState >= GameObjectState.TransportActive);
// transports without stop frames just keep animating in state 24
if (_stopFrames.Empty())
{
if (newState != GameObjectState.TransportActive)
_owner.SetGoState(GameObjectState.TransportActive);
return;
}
uint stopPathProgress = 0;
if (newState != GameObjectState.TransportActive)
{
Cypher.Assert(newState < (GameObjectState)(GameObjectState.TransportStopped + 9));
int stopFrame = (int)(newState - GameObjectState.TransportStopped);
Cypher.Assert(stopFrame < _stopFrames.Count);
stopPathProgress = _stopFrames[stopFrame];
}
_stateChangeTime = GameTime.GetGameTimeMS();
_stateChangeProgress = _pathProgress;
uint timeToStop = (uint)Math.Abs(_pathProgress - stopPathProgress);
_owner.SetLevel(GameTime.GetGameTimeMS() + timeToStop);
_owner.SetPathProgressForClient((float)_pathProgress / (float)GetTransportPeriod());
if (oldState == GameObjectState.Active || oldState == newState)
{
// initialization
if (_pathProgress > stopPathProgress)
_owner.SetDynamicFlag(GameObjectDynamicLowFlags.InvertedMovement);
else
_owner.RemoveDynamicFlag(GameObjectDynamicLowFlags.InvertedMovement);
return;
}
int pauseTimesCount = _stopFrames.Count;
int newToOldStateDelta = newState - oldState;
if (newToOldStateDelta < 0)
newToOldStateDelta += pauseTimesCount + 1;
int oldToNewStateDelta = oldState - newState;
if (oldToNewStateDelta < 0)
oldToNewStateDelta += pauseTimesCount + 1;
if (oldToNewStateDelta < newToOldStateDelta)
_owner.SetDynamicFlag(GameObjectDynamicLowFlags.InvertedMovement);
else
_owner.RemoveDynamicFlag(GameObjectDynamicLowFlags.InvertedMovement);
}
public override void OnRelocated()
{
UpdatePassengerPositions();
}
public void UpdatePassengerPositions()
{
foreach (WorldObject passenger in _passengers)
{
float x, y, z, o;
passenger.m_movementInfo.transport.pos.GetPosition(out x, out y, out z, out o);
CalculatePassengerPosition(ref x, ref y, ref z, ref o);
ITransport.UpdatePassengerPosition(this, _owner.GetMap(), passenger, x, y, z, o, true);
}
}
public uint GetTransportPeriod()
{
if (_animationInfo != null)
return _animationInfo.TotalTime;
return 1;
}
public List<uint> GetPauseTimes()
{
return _stopFrames;
}
public ObjectGuid GetTransportGUID() { return _owner.GetGUID(); }
public float GetTransportOrientation() { return _owner.GetOrientation(); }
public void AddPassenger(WorldObject passenger)
{
if (!_owner.IsInWorld)
return;
if (!_passengers.Contains(passenger))
{
_passengers.Add(passenger);
passenger.SetTransport(this);
passenger.m_movementInfo.transport.guid = GetTransportGUID();
Log.outDebug(LogFilter.Transport, $"Object {passenger.GetName()} boarded transport {_owner.GetName()}.");
}
}
public ITransport RemovePassenger(WorldObject passenger)
{
if (_passengers.Remove(passenger))
{
passenger.SetTransport(null);
passenger.m_movementInfo.transport.Reset();
Log.outDebug(LogFilter.Transport, $"Object {passenger.GetName()} removed from transport {_owner.GetName()}.");
Player plr = passenger.ToPlayer();
if (plr != null)
plr.SetFallInformation(0, plr.GetPositionZ());
}
return this;
}
public void CalculatePassengerPosition(ref float x, ref float y, ref float z, ref float o)
{
ITransport.CalculatePassengerPosition(ref x, ref y, ref z, ref o, _owner.GetPositionX(), _owner.GetPositionY(), _owner.GetPositionZ(), _owner.GetOrientation());
}
public void CalculatePassengerOffset(ref float x, ref float y, ref float z, ref float o)
{
ITransport.CalculatePassengerOffset(ref x, ref y, ref z, ref o, _owner.GetPositionX(), _owner.GetPositionY(), _owner.GetPositionZ(), _owner.GetOrientation());
}
public int GetMapIdForSpawning()
{
return _owner.GetGoInfo().Transport.SpawnMap;
}
public void SetAutoCycleBetweenStopFrames(bool on)
{
_autoCycleBetweenStopFrames = on;
}
}
class SetTransportAutoCycleBetweenStopFrames : GameObjectTypeBase.CustomCommand
{
bool _on;
public SetTransportAutoCycleBetweenStopFrames(bool on)
{
_on = on;
}
public override void Execute(GameObjectTypeBase type)
{
Transport transport = (Transport)type;
if (transport != null)
transport.SetAutoCycleBetweenStopFrames(_on);
}
}
}
}
@@ -544,6 +544,8 @@ namespace Game.Entities
return SpellFocus.GiganticAOI != 0;
case GameObjectTypes.Goober:
return Goober.GiganticAOI != 0;
case GameObjectTypes.Transport:
return true;
case GameObjectTypes.SpellCaster:
return SpellCaster.GiganticAOI != 0;
case GameObjectTypes.FlagStand:
@@ -79,27 +79,27 @@ namespace Game.Entities
uint GetViewerDependentDynamicFlags(ObjectFieldData objectData, WorldObject obj, Player receiver)
{
UnitDynFlags unitDynFlags = (UnitDynFlags)(uint)objectData.DynamicFlags;
uint unitDynFlags = objectData.DynamicFlags;
Unit unit = obj.ToUnit();
if (unit != null)
{
unitDynFlags &= ~UnitDynFlags.Tapped;
unitDynFlags &= ~(uint)UnitDynFlags.Tapped;
Creature creature = obj.ToCreature();
if (creature != null)
{
if (creature.HasLootRecipient() && !creature.IsTappedBy(receiver))
unitDynFlags |= UnitDynFlags.Tapped;
unitDynFlags |= (uint)UnitDynFlags.Tapped;
if (!receiver.IsAllowedToLoot(creature))
unitDynFlags &= ~UnitDynFlags.Lootable;
unitDynFlags &= ~(uint)UnitDynFlags.Lootable;
}
// unit UNIT_DYNFLAG_TRACK_UNIT should only be sent to caster of SPELL_AURA_MOD_STALKED auras
if (unitDynFlags.HasAnyFlag(UnitDynFlags.TrackUnit))
if (unitDynFlags.HasAnyFlag((uint)UnitDynFlags.TrackUnit))
if (!unit.HasAuraTypeWithCaster(AuraType.ModStalked, receiver.GetGUID()))
unitDynFlags &= ~UnitDynFlags.TrackUnit;
unitDynFlags &= ~(uint)UnitDynFlags.TrackUnit;
}
else
{
@@ -126,12 +126,18 @@ namespace Game.Entities
dynFlags |= GameObjectDynamicLowFlags.Sparkle | GameObjectDynamicLowFlags.Highlight;
break;
case GameObjectTypes.Transport:
{
dynFlags = (GameObjectDynamicLowFlags)((int)unitDynFlags & 0xFFFF);
pathProgress = (ushort)((int)unitDynFlags >> 16);
break;
}
case GameObjectTypes.MapObjTransport:
{
uint transportPeriod = gameObject.GetTransportPeriod();
Transport transport = gameObject.ToTransport();
uint transportPeriod = transport.GetTransportPeriod();
if (transportPeriod != 0)
{
float timer = (float)(gameObject.GetGoValue().Transport.PathProgress % transportPeriod);
float timer = (float)(transport.GetTimer() % transportPeriod);
pathProgress = (ushort)(timer / (float)transportPeriod * 65535.0f);
}
break;
@@ -146,11 +152,11 @@ namespace Game.Entities
break;
}
unitDynFlags = (UnitDynFlags)((pathProgress << 16) | (ushort)dynFlags);
unitDynFlags = (uint)((pathProgress << 16) | (ushort)dynFlags);
}
}
return (uint)unitDynFlags;
return unitDynFlags;
}
}
@@ -4946,13 +4952,13 @@ namespace Game.Entities
data.WriteFloat(rotation.Z);
data.WriteFloat(rotation.W);
data.WriteUInt32(FactionTemplate);
data.WriteInt8(GetViewerGameObjectState(this, owner, receiver));
data.WriteInt8(State);
data.WriteInt8(TypeID);
data.WriteUInt8(PercentHealth);
data.WriteUInt32(ArtKit);
data.WriteInt32(EnableDoodadSets.Size());
data.WriteUInt32(CustomParam);
data.WriteUInt32(GetViewerGameObjectLevel(this, owner, receiver));
data.WriteUInt32(Level);
data.WriteUInt32(AnimGroupInstance);
for (int i = 0; i < EnableDoodadSets.Size(); ++i)
{
@@ -5053,7 +5059,7 @@ namespace Game.Entities
}
if (changesMask[14])
{
data.WriteInt8(GetViewerGameObjectState(this, owner, receiver));
data.WriteInt8(State);
}
if (changesMask[15])
{
@@ -5073,7 +5079,7 @@ namespace Game.Entities
}
if (changesMask[19])
{
data.WriteUInt32(GetViewerGameObjectLevel(this, owner, receiver));
data.WriteUInt32(Level);
}
if (changesMask[20])
{
@@ -5116,24 +5122,6 @@ namespace Game.Entities
return flags;
}
uint GetViewerGameObjectLevel(GameObjectFieldData gameObjectData, GameObject gameObject, Player receiver)
{
uint level = gameObjectData.Level;
bool isStoppableTransport = gameObject.GetGoType() == GameObjectTypes.Transport && !gameObject.GetGoValue().Transport.StopFrames.Empty();
return isStoppableTransport ? gameObject.GetGoValue().Transport.PathProgress : level;
}
sbyte GetViewerGameObjectState(GameObjectFieldData gameObjectData, GameObject gameObject, Player receiver)
{
sbyte state = gameObjectData.State;
bool isStoppableTransport = gameObject.GetGoType() == GameObjectTypes.Transport && !gameObject.GetGoValue().Transport.StopFrames.Empty();
if (isStoppableTransport && gameObject.GetGoState() == GameObjectState.TransportActive)
if (((gameObject.GetGoValue().Transport.StateUpdateTimer / 20000) & 1) != 0)
state = (sbyte)GameObjectState.TransportStopped;
return state;
}
}
public class DynamicObjectData : BaseUpdateData<DynamicObject>
+23 -52
View File
@@ -246,14 +246,10 @@ namespace Game.Entities
public void BuildMovementUpdate(WorldPacket data, CreateObjectBits flags, Player target)
{
int PauseTimesCount = 0;
List<uint> PauseTimes = null;
GameObject go = ToGameObject();
if (go)
{
if (go.GetGoType() == GameObjectTypes.Transport)
PauseTimesCount = go.GetGoValue().Transport.StopFrames.Count;
}
PauseTimes = go.GetPauseTimes();
data.WriteBit(flags.NoBirthAnim);
data.WriteBit(flags.EnablePortals);
@@ -368,7 +364,7 @@ namespace Game.Entities
MovementExtensions.WriteCreateObjectSplineDataBlock(unit.MoveSpline, data);
}
data.WriteInt32(PauseTimesCount);
data.WriteInt32(PauseTimes != null ? PauseTimes.Count : 0);
if (flags.Stationary)
{
@@ -381,20 +377,9 @@ namespace Game.Entities
if (flags.CombatVictim)
data.WritePackedGuid(ToUnit().GetVictim().GetGUID()); // CombatVictim
if (flags.ServerTime)
{
GameObject go1 = 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 (go1 && go1.ToTransport()) // ServerTime
data.WriteUInt32(go1.GetGoValue().Transport.PathProgress);
else
data.WriteUInt32(GameTime.GetGameTimeMS());
}
data.WriteUInt32(GameTime.GetGameTimeMS());
if (flags.Vehicle)
{
@@ -413,11 +398,9 @@ namespace Game.Entities
if (flags.Rotation)
data.WriteInt64(ToGameObject().GetPackedLocalRotation()); // Rotation
if (go)
{
for (int i = 0; i < PauseTimesCount; ++i)
data.WriteUInt32(go.GetGoValue().Transport.StopFrames[i]);
}
if (PauseTimes != null && !PauseTimes.Empty())
foreach (var stopFrame in PauseTimes)
data.WriteUInt32(stopFrame);
if (flags.MovementTransport)
{
@@ -969,19 +952,9 @@ namespace Game.Entities
return;
if (on)
{
if (IsTypeId(TypeId.Unit))
map.AddToActive(ToCreature());
else if (IsTypeId(TypeId.DynamicObject))
map.AddToActive(ToDynamicObject());
}
map.AddToActive(this);
else
{
if (IsTypeId(TypeId.Unit))
map.RemoveFromActive(ToCreature());
else if (IsTypeId(TypeId.DynamicObject))
map.RemoveFromActive(ToDynamicObject());
}
map.RemoveFromActive(this);
}
bool IsFarVisible() { return m_isFarVisible; }
@@ -1010,8 +983,8 @@ namespace Game.Entities
if (IsInWorld)
RemoveFromWorld();
Transport transport = GetTransport();
if (transport)
ITransport transport = GetTransport();
if (transport != null)
transport.RemovePassenger(this);
}
@@ -2957,12 +2930,6 @@ namespace Game.Entities
public float GetObjectScale() { return m_objectData.Scale; }
public virtual void SetObjectScale(float scale) { SetUpdateFieldValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.Scale), scale); }
public UnitDynFlags GetDynamicFlags() { return (UnitDynFlags)(uint)m_objectData.DynamicFlags; }
public bool HasDynamicFlag(UnitDynFlags flag) { return (m_objectData.DynamicFlags & (uint)flag) != 0; }
public void SetDynamicFlag(UnitDynFlags flag) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.DynamicFlags), (uint)flag); }
public void RemoveDynamicFlag(UnitDynFlags flag) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.DynamicFlags), (uint)flag); }
public void ReplaceAllDynamicFlags(UnitDynFlags flag) { SetUpdateFieldValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.DynamicFlags), (uint)flag); }
public TypeId GetTypeId() { return ObjectTypeId; }
public bool IsTypeId(TypeId typeId) { return GetTypeId() == typeId; }
public bool IsTypeMask(TypeMask mask) { return Convert.ToBoolean(mask & ObjectTypeMask); }
@@ -3007,7 +2974,11 @@ namespace Game.Entities
public bool IsActiveObject() { return m_isActive; }
public bool IsPermanentWorldObject() { return m_isWorldObject; }
public Transport GetTransport() { return m_transport; }
public ITransport GetTransport() { return m_transport; }
public T GetTransport<T>() where T : ITransport
{
return (T)m_transport;
}
public float GetTransOffsetX() { return m_movementInfo.transport.pos.GetPositionX(); }
public float GetTransOffsetY() { return m_movementInfo.transport.pos.GetPositionY(); }
public float GetTransOffsetZ() { return m_movementInfo.transport.pos.GetPositionZ(); }
@@ -3017,12 +2988,12 @@ namespace Game.Entities
public sbyte GetTransSeat() { return m_movementInfo.transport.seat; }
public virtual ObjectGuid GetTransGUID()
{
if (GetTransport())
return GetTransport().GetGUID();
if (GetTransport() != null)
return GetTransport().GetTransportGUID();
return ObjectGuid.Empty;
}
public void SetTransport(Transport t) { m_transport = t; }
public void SetTransport(ITransport t) { m_transport = t; }
public virtual float GetStationaryX() { return GetPositionX(); }
public virtual float GetStationaryY() { return GetPositionY(); }
@@ -3065,7 +3036,7 @@ namespace Game.Entities
Position thisOrTransport = this;
Position objOrObjTransport = obj;
if (GetTransport() && obj.GetTransport() != null && obj.GetTransport().GetGUID() == GetTransport().GetGUID())
if (GetTransport() != null && obj.GetTransport() != null && obj.GetTransport().GetTransportGUID() == GetTransport().GetTransportGUID())
{
thisOrTransport = m_movementInfo.transport.pos;
objOrObjTransport = obj.m_movementInfo.transport.pos;
@@ -3340,7 +3311,7 @@ namespace Game.Entities
public void UpdateAllowedPositionZ(float x, float y, ref float z, ref float groundZ)
{
// TODO: Allow transports to be part of dynamic vmap tree
if (GetTransport())
if (GetTransport() != null)
{
groundZ = z;
return;
@@ -3690,7 +3661,7 @@ namespace Game.Entities
bool m_isWorldObject;
public ZoneScript m_zoneScript;
Transport m_transport;
ITransport m_transport;
Map _currMap;
uint instanceId;
PhaseShift _phaseShift = new();
+6 -4
View File
@@ -3429,8 +3429,9 @@ namespace Game.Entities
stmt.AddValue(index++, finiteAlways(GetTransOffsetZ()));
stmt.AddValue(index++, finiteAlways(GetTransOffsetO()));
ulong transLowGUID = 0;
if (GetTransport())
transLowGUID = GetTransport().GetGUID().GetCounter();
Transport transport = GetTransport<Transport>();
if (transport != null)
transLowGUID = transport.GetGUID().GetCounter();
stmt.AddValue(index++, transLowGUID);
StringBuilder ss = new();
@@ -3570,8 +3571,9 @@ namespace Game.Entities
stmt.AddValue(index++, finiteAlways(GetTransOffsetZ()));
stmt.AddValue(index++, finiteAlways(GetTransOffsetO()));
ulong transLowGUID = 0;
if (GetTransport())
transLowGUID = GetTransport().GetGUID().GetCounter();
Transport transport = GetTransport<Transport>();
if (transport != null)
transLowGUID = transport.GetGUID().GetCounter();
stmt.AddValue(index++, transLowGUID);
StringBuilder ss = new();
+1 -1
View File
@@ -803,7 +803,7 @@ namespace Game.Entities
m_MirrorTimerFlags |= PlayerUnderwaterState.InWater;
// Fatigue bar state (if not on flight path or transport)
if (newLiquidData.type_flags.HasAnyFlag(LiquidHeaderTypeFlags.DarkWater) && !IsInFlight() && !GetTransport())
if (newLiquidData.type_flags.HasAnyFlag(LiquidHeaderTypeFlags.DarkWater) && !IsInFlight() && GetTransport() == null)
m_MirrorTimerFlags |= PlayerUnderwaterState.InDarkWater;
// Lava state (any contact)
+7 -15
View File
@@ -1686,8 +1686,8 @@ namespace Game.Entities
{
Log.outDebug(LogFilter.Maps, "Player {0} using client without required expansion tried teleport to non accessible map {1}", GetName(), mapid);
Transport _transport = GetTransport();
if (_transport)
ITransport _transport = GetTransport();
if (_transport != null)
{
_transport.RemovePassenger(this);
RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
@@ -1708,8 +1708,8 @@ namespace Game.Entities
DisableSpline();
GetMotionMaster().Remove(MovementGeneratorType.Effect);
Transport transport = GetTransport();
if (transport)
ITransport transport = GetTransport();
if (transport != null)
{
if (!options.HasAnyFlag(TeleportToOptions.NotLeaveTransport))
transport.RemovePassenger(this);
@@ -1849,11 +1849,11 @@ namespace Game.Entities
transferPending.MapID = (int)mapid;
transferPending.OldMapPosition = GetPosition();
transport = GetTransport();
if (transport)
Transport transport1 = (Transport)GetTransport();
if (transport1 != null)
{
TransferPending.ShipTransferPending shipTransferPending = new();
shipTransferPending.Id = transport.GetEntry();
shipTransferPending.Id = transport1.GetEntry();
shipTransferPending.OriginMapID = (int)GetMapId();
transferPending.Ship = shipTransferPending;
}
@@ -6242,14 +6242,6 @@ namespace Game.Entities
{
switch (target.GetTypeId())
{
case TypeId.GameObject:
// @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.ToGameObject().IsDynTransport())
s64.Add(target.GetGUID());
break;
case TypeId.Unit:
s64.Add(target.GetGUID());
v.Add(target.ToCreature());
+102 -77
View File
@@ -27,37 +27,102 @@ namespace Game.Entities
{
public interface ITransport
{
ObjectGuid GetTransportGUID();
// This method transforms supplied transport offsets into global coordinates
void CalculatePassengerPosition(ref float x, ref float y, ref float z, ref float o);
// This method transforms supplied global coordinates into local offsets
void CalculatePassengerOffset(ref float x, ref float y, ref float z, ref float o);
}
public class TransportPosHelper
{
public static void CalculatePassengerPosition(ref float x, ref float y, ref float z, ref float o, float transX, float transY, float transZ, float transO)
float GetTransportOrientation();
void AddPassenger(WorldObject passenger);
ITransport RemovePassenger(WorldObject passenger);
public static void UpdatePassengerPosition(ITransport transport, Map map, WorldObject passenger, float x, float y, float z, float o, bool setHomePosition)
{
// transport teleported but passenger not yet (can happen for players)
if (passenger.GetMap() != map)
return;
// 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
Unit unit = passenger.ToUnit();
if (unit != null)
if (unit.GetVehicle())
return;
// Do not use Unit::UpdatePosition here, we don't want to remove auras
// as if regular movement occurred
switch (passenger.GetTypeId())
{
case TypeId.Unit:
{
Creature creature = passenger.ToCreature();
map.CreatureRelocation(creature, x, y, z, o, false);
if (setHomePosition)
{
creature.GetTransportHomePosition(out x, out y, out z, out o);
transport.CalculatePassengerPosition(ref x, ref y, ref z, ref o);
creature.SetHomePosition(x, y, z, o);
}
break;
}
case TypeId.Player:
//relocate only passengers in world and skip any player that might be still logging in/teleporting
if (passenger.IsInWorld && !passenger.ToPlayer().IsBeingTeleported())
{
map.PlayerRelocation(passenger.ToPlayer(), x, y, z, o);
passenger.ToPlayer().SetFallInformation(0, passenger.GetPositionZ());
}
break;
case TypeId.GameObject:
map.GameObjectRelocation(passenger.ToGameObject(), x, y, z, o, false);
passenger.ToGameObject().RelocateStationaryPosition(x, y, z, o);
break;
case TypeId.DynamicObject:
map.DynamicObjectRelocation(passenger.ToDynamicObject(), x, y, z, o);
break;
case TypeId.AreaTrigger:
map.AreaTriggerRelocation(passenger.ToAreaTrigger(), x, y, z, o);
break;
default:
break;
}
if (unit != null)
{
Vehicle vehicle = unit.GetVehicleKit();
if (vehicle != null)
vehicle.RelocatePassengers();
}
}
static void CalculatePassengerPosition(ref float x, ref float y, ref float z, ref float o, float transX, float transY, float transZ, float transO)
{
float inx = x, iny = y, inz = z;
o = Position.NormalizeOrientation(transO + o);
x = transX + inx * (float)Math.Cos(transO) - iny * (float)Math.Sin(transO);
y = transY + iny * (float)Math.Cos(transO) + inx * (float)Math.Sin(transO);
x = transX + inx * MathF.Cos(transO) - iny * MathF.Sin(transO);
y = transY + iny * MathF.Cos(transO) + inx * MathF.Sin(transO);
z = transZ + inz;
}
public static void CalculatePassengerOffset(ref float x, ref float y, ref float z, ref float o, float transX, float transY, float transZ, float transO)
static void CalculatePassengerOffset(ref float x, ref float y, ref float z, ref float o, float transX, float transY, float transZ, float transO)
{
o = Position.NormalizeOrientation(o - transO);
z -= transZ;
y -= transY;
x -= transX;
y -= transY; // y = searchedY * std::cos(o) + searchedX * std::sin(o)
x -= transX; // x = searchedX * std::cos(o) + searchedY * std::sin(o + pi)
float inx = x, iny = y;
y = (iny - inx * (float)Math.Tan(transO)) / ((float)Math.Cos(transO) + (float)Math.Sin(transO) * (float)Math.Tan(transO));
x = (inx + iny * (float)Math.Tan(transO)) / ((float)Math.Cos(transO) + (float)Math.Sin(transO) * (float)Math.Tan(transO));
y = (iny - inx * MathF.Tan(transO)) / (MathF.Cos(transO) + MathF.Sin(transO) * MathF.Tan(transO));
x = (inx + iny * MathF.Tan(transO)) / (MathF.Cos(transO) + MathF.Sin(transO) * MathF.Tan(transO));
}
int GetMapIdForSpawning();
}
public class Transport : GameObject, ITransport
@@ -122,7 +187,6 @@ namespace Game.Entities
ReplaceAllFlags(goOverride.Flags);
}
m_goValue.Transport.PathProgress = 0;
SetObjectScale(goinfo.size);
SetPeriod(tInfo.pathTime);
SetEntry(goinfo.entry);
@@ -163,9 +227,9 @@ namespace Game.Entities
return;
if (IsMoving() || !_pendingStop)
m_goValue.Transport.PathProgress += diff;
_pathProgress += diff;
uint timer = m_goValue.Transport.PathProgress % GetTransportPeriod();
uint timer = _pathProgress % GetTransportPeriod();
bool justStopped = false;
// Set current waypoint
@@ -189,9 +253,9 @@ namespace Game.Entities
if (_pendingStop && GetGoState() != GameObjectState.Ready)
{
SetGoState(GameObjectState.Ready);
m_goValue.Transport.PathProgress /= GetTransportPeriod();
m_goValue.Transport.PathProgress *= GetTransportPeriod();
m_goValue.Transport.PathProgress += _currentFrame.ArriveTime;
_pathProgress /= GetTransportPeriod();
_pathProgress *= GetTransportPeriod();
_pathProgress += _currentFrame.ArriveTime;
}
break; // its a stop frame and we are waiting
}
@@ -296,7 +360,7 @@ namespace Game.Entities
}
}
public void RemovePassenger(WorldObject passenger)
public ITransport RemovePassenger(WorldObject passenger)
{
bool erased = _passengers.Remove(passenger);
@@ -313,6 +377,8 @@ namespace Game.Entities
plr.SetFallInformation(0, plr.GetPositionZ());
}
}
return this;
}
public Creature CreateNPCPassenger(ulong guid, CreatureData data)
@@ -511,14 +577,19 @@ namespace Game.Entities
public void CalculatePassengerPosition(ref float x, ref float y, ref float z, ref float o)
{
TransportPosHelper.CalculatePassengerPosition(ref x, ref y, ref z, ref o, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
ITransport.CalculatePassengerPosition(ref x, ref y, ref z, ref o, GetPositionX(), GetPositionY(), GetPositionZ(), GetTransportOrientation());
}
public void CalculatePassengerOffset(ref float x, ref float y, ref float z, ref float o)
{
TransportPosHelper.CalculatePassengerOffset(ref x, ref y, ref z, ref o, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
ITransport.CalculatePassengerOffset(ref x, ref y, ref z, ref o, GetPositionX(), GetPositionY(), GetPositionZ(), GetTransportOrientation());
}
public int GetMapIdForSpawning()
{
return GetGoInfo().MoTransport.SpawnMap;
}
public void UpdatePosition(float x, float y, float z, float o)
{
bool newActive = GetMap().IsGridLoaded(x, y);
@@ -652,7 +723,7 @@ namespace Game.Entities
float destX, destY, destZ, destO;
obj.m_movementInfo.transport.pos.GetPosition(out destX, out destY, out destZ, out destO);
TransportPosHelper.CalculatePassengerPosition(ref destX, ref destY, ref destZ, ref destO, x, y, z, o);
ITransport.CalculatePassengerPosition(ref destX, ref destY, ref destZ, ref destO, x, y, z, o);
obj.ToUnit().NearTeleportTo(destX, destY, destZ, destO);
}
@@ -683,7 +754,7 @@ namespace Game.Entities
{
float destX, destY, destZ, destO;
obj.m_movementInfo.transport.pos.GetPosition(out destX, out destY, out destZ, out destO);
TransportPosHelper.CalculatePassengerPosition(ref destX, ref destY, ref destZ, ref destO, x, y, z, o);
ITransport.CalculatePassengerPosition(ref destX, ref destY, ref destZ, ref destO, x, y, z, o);
switch (obj.GetTypeId())
{
@@ -707,62 +778,12 @@ namespace Game.Entities
void UpdatePassengerPositions(HashSet<WorldObject> passengers)
{
foreach (var passenger in passengers)
foreach (WorldObject passenger in passengers)
{
// 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
Unit unit = passenger.ToUnit();
if (unit)
if (unit.GetVehicle() != null)
continue;
// Do not use Unit.UpdatePosition here, we don't want to remove auras
// as if regular movement occurred
float x, y, z, o;
passenger.m_movementInfo.transport.pos.GetPosition(out x, out y, out z, out o);
CalculatePassengerPosition(ref x, ref y, ref z, ref o);
switch (passenger.GetTypeId())
{
case TypeId.Unit:
{
Creature creature = passenger.ToCreature();
GetMap().CreatureRelocation(creature, x, y, z, o, false);
creature.GetTransportHomePosition(out x, out y, out z, out o);
CalculatePassengerPosition(ref x, ref y, ref z, ref o);
creature.SetHomePosition(x, y, z, o);
break;
}
case TypeId.Player:
if (passenger.IsInWorld && !passenger.ToPlayer().IsBeingTeleported())
{
GetMap().PlayerRelocation(passenger.ToPlayer(), x, y, z, o);
passenger.ToPlayer().SetFallInformation(0, passenger.GetPositionZ());
}
break;
case TypeId.GameObject:
GetMap().GameObjectRelocation(passenger.ToGameObject(), x, y, z, o, false);
passenger.ToGameObject().RelocateStationaryPosition(x, y, z, o);
break;
case TypeId.DynamicObject:
GetMap().DynamicObjectRelocation(passenger.ToDynamicObject(), x, y, z, o);
break;
case TypeId.AreaTrigger:
GetMap().AreaTriggerRelocation(passenger.ToAreaTrigger(), x, y, z, o);
break;
default:
break;
}
if (unit != null)
{
Vehicle vehicle = unit.GetVehicleKit();
if (vehicle != null)
vehicle.RelocatePassengers();
}
ITransport.UpdatePassengerPosition(this, GetMap(), passenger, x, y, z, o, true);
}
}
@@ -790,9 +811,12 @@ namespace Game.Entities
public HashSet<WorldObject> GetPassengers() { return _passengers; }
public override uint GetTransportPeriod() { return m_gameObjectData.Level; }
public ObjectGuid GetTransportGUID() { return GetGUID(); }
public float GetTransportOrientation() { return GetOrientation(); }
public uint GetTransportPeriod() { return m_gameObjectData.Level; }
public void SetPeriod(uint period) { SetLevel(period); }
uint GetTimer() { return m_goValue.Transport.PathProgress; }
public uint GetTimer() { return _pathProgress; }
public List<KeyFrame> GetKeyFrames() { return _transportInfo.keyFrames; }
public TransportTemplate GetTransportTemplate() { return _transportInfo; }
@@ -805,6 +829,7 @@ namespace Game.Entities
KeyFrame _currentFrame;
int _nextFrame;
uint _pathProgress;
TimeTracker _positionChangeTimer = new();
bool _isMoving;
bool _pendingStop;
+2 -2
View File
@@ -209,7 +209,7 @@ namespace Game.Entities
MoveSplineInit init = new(this);
init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
if (GetTransport())
if (GetTransport() != null)
init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
init.SetFacing(ori);
@@ -1834,7 +1834,7 @@ namespace Game.Entities
if (GetVehicle() != null)
return GetVehicleBase().GetGUID();
if (GetTransport() != null)
return GetTransport().GetGUID();
return GetTransport().GetTransportGUID();
return ObjectGuid.Empty;
}
+1 -1
View File
@@ -295,7 +295,7 @@ namespace Game.Entities
return false;
}
if (IsTypeId(TypeId.Player) && ToPlayer().GetTransport())
if (IsPlayer() && ToPlayer().GetTransport() != null)
{
Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: Player on transport is trying to charm {0} (GUID {1})", GetEntry(), GetGUID().ToString());
return false;
+8 -2
View File
@@ -1003,7 +1003,7 @@ namespace Game.Entities
}
Cypher.Assert(!m_vehicle);
vehicle.AddPassenger(this, seatId);
vehicle.AddVehiclePassenger(this, seatId);
}
public void ChangeSeat(sbyte seatId, bool next = true)
@@ -1067,7 +1067,7 @@ namespace Game.Entities
// This should be done before dismiss, because there may be some aura removal
VehicleSeatAddon seatAddon = m_vehicle.GetSeatAddonForSeatOfPassenger(this);
Vehicle vehicle = m_vehicle.RemovePassenger(this);
Vehicle vehicle = (Vehicle)m_vehicle.RemovePassenger(this);
if (vehicle == null)
{
@@ -1998,6 +1998,12 @@ namespace Game.Entities
public void RemoveUnitFlag3(UnitFlags3 flags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Flags3), (uint)flags); }
public void ReplaceAllUnitFlags3(UnitFlags3 flags) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Flags3), (uint)flags); }
public UnitDynFlags GetDynamicFlags() { return (UnitDynFlags)(uint)m_objectData.DynamicFlags; }
public bool HasDynamicFlag(UnitDynFlags flag) { return (m_objectData.DynamicFlags & (uint)flag) != 0; }
public void SetDynamicFlag(UnitDynFlags flag) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.DynamicFlags), (uint)flag); }
public void RemoveDynamicFlag(UnitDynFlags flag) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.DynamicFlags), (uint)flag); }
public void ReplaceAllDynamicFlags(UnitDynFlags flag) { SetUpdateFieldValue(m_values.ModifyValue(m_objectData).ModifyValue(m_objectData.DynamicFlags), (uint)flag); }
public void SetCreatedBySpell(uint spellId) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.CreatedBySpell), spellId); }
public Emote GetEmoteState() { return (Emote)(int)m_unitData.EmoteState; }
+18 -6
View File
@@ -291,7 +291,7 @@ namespace Game.Entities
// @VehicleJoinEvent.Abort
}
public bool AddPassenger(Unit unit, sbyte seatId)
public bool AddVehiclePassenger(Unit unit, sbyte seatId)
{
// @Prevent adding passengers when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
if (_status == Status.UnInstalling)
@@ -355,8 +355,12 @@ namespace Game.Entities
return true;
}
public Vehicle RemovePassenger(Unit unit)
public ITransport RemovePassenger(WorldObject passenger)
{
Unit unit = passenger.ToUnit();
if (unit == null)
return null;
if (unit.GetVehicle() != this)
return null;
@@ -421,8 +425,8 @@ namespace Game.Entities
}
}
foreach (var pair in seatRelocation)
pair.Item1.UpdatePosition(pair.Item2);
foreach (var (passenger, position) in seatRelocation)
ITransport.UpdatePassengerPosition(this, _me.GetMap(), passenger, position.GetPositionX(), position.GetPositionY(), position.GetPositionZ(), position.GetOrientation(), false);
}
public bool IsVehicleInUse()
@@ -487,20 +491,28 @@ namespace Game.Entities
return ret;
}
public ObjectGuid GetTransportGUID() { return GetBase().GetGUID(); }
public float GetTransportOrientation() { return GetBase().GetOrientation(); }
public void AddPassenger(WorldObject passenger) { Log.outFatal(LogFilter.Vehicle, "Vehicle cannot directly gain passengers without auras"); }
public void CalculatePassengerPosition(ref float x, ref float y, ref float z, ref float o)
{
TransportPosHelper.CalculatePassengerPosition(ref x, ref y, ref z, ref o,
ITransport.CalculatePassengerPosition(ref x, ref y, ref z, ref o,
GetBase().GetPositionX(), GetBase().GetPositionY(),
GetBase().GetPositionZ(), GetBase().GetOrientation());
}
public void CalculatePassengerOffset(ref float x, ref float y, ref float z, ref float o)
{
TransportPosHelper.CalculatePassengerOffset(ref x, ref y, ref z, ref o,
ITransport.CalculatePassengerOffset(ref x, ref y, ref z, ref o,
GetBase().GetPositionX(), GetBase().GetPositionY(),
GetBase().GetPositionZ(), GetBase().GetOrientation());
}
public int GetMapIdForSpawning() { return (int)GetBase().GetMapId(); }
public void RemovePendingEvent(VehicleJoinEvent e)
{
foreach (var Event in _pendingJoinEvents)
+1 -1
View File
@@ -839,7 +839,7 @@ namespace Game.Garrisons
float y = spawn.GetPositionY();
float z = spawn.GetPositionZ();
float o = spawn.GetOrientation();
TransportPosHelper.CalculatePassengerPosition(ref x, ref y, ref z, ref o, building.GetPositionX(), building.GetPositionY(), building.GetPositionZ(), building.GetOrientation());
ITransport.CalculatePassengerPosition(ref x, ref y, ref z, ref o, building.GetPositionX(), building.GetPositionY(), building.GetPositionZ(), building.GetOrientation());
spawn.Relocate(x, y, z, o);
switch (spawn.GetTypeId())
+22 -16
View File
@@ -110,31 +110,37 @@ namespace Game
if (plrMover)
{
if (!plrMover.GetTransport())
if (plrMover.GetTransport() == null)
{
Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid);
if (transport)
transport.AddPassenger(plrMover);
GameObject go = plrMover.GetMap().GetGameObject(movementInfo.transport.guid);
if (go != null)
{
ITransport transport = go.ToTransportBase();
if (transport != null)
transport.AddPassenger(plrMover);
}
}
else if (plrMover.GetTransport().GetGUID() != movementInfo.transport.guid)
else if (plrMover.GetTransport().GetTransportGUID() != movementInfo.transport.guid)
{
plrMover.GetTransport().RemovePassenger(plrMover);
Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid);
if (transport)
transport.AddPassenger(plrMover);
GameObject go = plrMover.GetMap().GetGameObject(movementInfo.transport.guid);
if (go != null)
{
ITransport transport = go.ToTransportBase();
if (transport != null)
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() != GameObjectTypes.Transport)
movementInfo.transport.Reset();
}
if (mover.GetTransport() == null && !mover.GetVehicle())
movementInfo.transport.Reset();
}
else if (plrMover && plrMover.GetTransport()) // if we were on a transport, leave
else if (plrMover && plrMover.GetTransport() != null) // if we were on a transport, leave
plrMover.GetTransport().RemovePassenger(plrMover);
// fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
@@ -531,7 +537,7 @@ namespace Game
return;
}
if (!GetPlayer().GetTransport() && Math.Abs(GetPlayer().GetSpeed(move_type) - packet.Speed) > 0.01f)
if (GetPlayer().GetTransport() == null && Math.Abs(GetPlayer().GetSpeed(move_type) - packet.Speed) > 0.01f)
{
if (GetPlayer().GetSpeed(move_type) > packet.Speed) // must be greater - just correct
{
+4 -1
View File
@@ -103,7 +103,7 @@ namespace Game.Maps
{
// 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
Transport transport = i_player.GetTransport();
Transport transport = i_player.GetTransport<Transport>();
if (transport)
{
foreach (var obj in transport.GetPassengers())
@@ -128,6 +128,9 @@ namespace Game.Maps
case TypeId.DynamicObject:
i_player.UpdateVisibilityOf(obj.ToDynamicObject(), i_data, i_visibleNow);
break;
case TypeId.AreaTrigger:
i_player.UpdateVisibilityOf(obj.ToAreaTrigger(), i_data, i_visibleNow);
break;
default:
break;
}
+6 -10
View File
@@ -1131,9 +1131,7 @@ namespace Game.Maps
else
{
go.Relocate(x, y, z, orientation);
go.UpdateModelPosition();
go.UpdatePositionData();
go.UpdateObjectVisibility(false);
go.AfterRelocation();
RemoveGameObjectFromMoveList(go);
}
@@ -1354,9 +1352,7 @@ namespace Game.Maps
{
// update pos
go.Relocate(go._newPosition);
go.UpdateModelPosition();
go.UpdatePositionData();
go.UpdateObjectVisibility(false);
go.AfterRelocation();
}
else
{
@@ -2247,7 +2243,7 @@ namespace Game.Maps
var data = new UpdateData(player.GetMapId());
// attach to player data current transport data
Transport transport = player.GetTransport();
Transport transport = player.GetTransport<Transport>();
if (transport != null)
{
transport.BuildCreateUpdateBlockForPlayer(data, player);
@@ -4168,8 +4164,8 @@ namespace Game.Maps
if (!summon.Create(GenerateLowGuid(HighGuid.Creature), this, entry, pos, null, vehId, true))
return null;
Transport transport = summoner != null ? summoner.GetTransport() : null;
if (transport)
ITransport transport = summoner != null ? summoner.GetTransport() : null;
if (transport != null)
{
pos.GetPosition(out float x, out float y, out float z, out float o);
transport.CalculatePassengerOffset(ref x, ref y, ref z, ref o);
@@ -4209,7 +4205,7 @@ namespace Game.Maps
if (!AddToMap(summon.ToCreature()))
{
// Returning false will cause the object to be deleted - remove from transport
if (transport)
if (transport != null)
transport.RemovePassenger(summon);
summon.Dispose();
+57 -20
View File
@@ -425,6 +425,18 @@ namespace Game.Maps
_transportAnimations[transportEntry] = animNode;
}
public void AddPathRotationToTransport(uint transportEntry, uint timeSeg, TransportRotationRecord node)
{
if (!_transportAnimations.ContainsKey(transportEntry))
_transportAnimations[transportEntry] = new();
TransportAnimation animNode = _transportAnimations[transportEntry];
animNode.Rotations[timeSeg] = node;
if (animNode.Path.Empty() && animNode.TotalTime < timeSeg)
animNode.TotalTime = timeSeg;
}
public Transport CreateTransport(uint entry, ulong guid = 0, Map map = null, PhaseUseFlagsValues phaseUseFlags = 0, uint phaseId = 0, uint phaseGroupId = 0)
{
// instance case, execute GetGameObjectEntry hook
@@ -530,14 +542,6 @@ namespace Game.Maps
{
return _transportSpawns.LookupByKey(spawnId);
}
public void AddPathRotationToTransport(uint transportEntry, uint timeSeg, TransportRotationRecord node)
{
if (!_transportAnimations.ContainsKey(transportEntry))
_transportAnimations[transportEntry] = new TransportAnimation();
_transportAnimations[transportEntry].Rotations[timeSeg] = node;
}
Dictionary<uint, TransportTemplate> _transportTemplates = new();
MultiMap<uint, uint> _instanceTransports = new();
@@ -557,8 +561,8 @@ namespace Game.Maps
mode = Spline.EvaluationMode.Catmullrom;
cyclic = false;
points = new Vector3[_points.Count];
for(var i = 0; i < _points.Count; ++i)
for (var i = 0; i < _points.Count; ++i)
points[i] = _points[i];
lo = 1;
@@ -627,26 +631,59 @@ namespace Game.Maps
public class TransportAnimation
{
TransportAnimationRecord GetAnimNode(uint time)
public Dictionary<uint, TransportAnimationRecord> Path = new();
public Dictionary<uint, TransportRotationRecord> Rotations = new();
public uint TotalTime;
public TransportAnimationRecord GetPrevAnimNode(uint time)
{
if (Path.Empty())
return null;
foreach (var pair in Path)
if (time >= pair.Key)
return pair.Value;
List<uint> lKeys = Path.Keys.ToList();
int reqIndex = lKeys.IndexOf(time) - 1;
return Path.First().Value;
if (reqIndex != -1)
return Path[lKeys[reqIndex]];
return Path.LastOrDefault().Value;
}
TransportRotationRecord GetAnimRotation(uint time)
public TransportRotationRecord GetPrevAnimRotation(uint time)
{
return Rotations.LookupByKey(time);
if (Rotations.Empty())
return null;
List<uint> lKeys = Rotations.Keys.ToList();
int reqIndex = lKeys.IndexOf(time) - 1;
if (reqIndex != -1)
return Rotations[lKeys[reqIndex]];
return Rotations.LastOrDefault().Value;
}
public Dictionary<uint, TransportAnimationRecord> Path = new();
public Dictionary<uint, TransportRotationRecord> Rotations = new();
public uint TotalTime;
public TransportAnimationRecord GetNextAnimNode(uint time)
{
if (Path.Empty())
return null;
if (Path.TryGetValue(time, out TransportAnimationRecord record))
return record;
return Path.FirstOrDefault().Value;
}
public TransportRotationRecord GetNextAnimRotation(uint time)
{
if (Rotations.Empty())
return null;
if (Rotations.TryGetValue(time, out TransportRotationRecord record))
return record;
return Rotations.FirstOrDefault().Value;
}
}
public class TransportSpawn
@@ -303,10 +303,10 @@ namespace Game.Movement
owner.SetHomePosition(x, y, z, o);
else
{
Transport trans = owner.GetTransport();
if (trans)
ITransport trans = owner.GetTransport();
if (trans != null)
{
o -= trans.GetOrientation();
o -= trans.GetTransportOrientation();
owner.SetTransportHomePosition(x, y, z, o);
trans.CalculatePassengerPosition(ref x, ref y, ref z, ref o);
owner.SetHomePosition(x, y, z, o);
+7 -4
View File
@@ -222,11 +222,14 @@ namespace Game.Movement
if (args.TransformForTransport)
{
Unit vehicle = unit.GetVehicleBase();
Transport transport = unit.GetTransport();
if (vehicle != null)
angle -= vehicle.Orientation;
else if (transport != null)
angle -= transport.Orientation;
angle -= vehicle.GetOrientation();
else
{
ITransport transport = unit.GetTransport();
if (transport != null)
angle -= transport.GetTransportOrientation();
}
}
args.facing.angle = MathFunctions.wrap(angle, 0.0f, MathFunctions.TwoPi);
+2 -2
View File
@@ -7077,8 +7077,8 @@ namespace Game.Spells
if (target.GetGUID() != corpse.GetOwnerGUID())
return false;
if (!corpse.HasDynamicFlag(UnitDynFlags.Lootable))
if (!corpse.HasCorpseDynamicFlag(CorpseDynFlags.Lootable))
return false;
if (!corpse.IsWithinLOSInMap(m_caster, LineOfSightChecks.All, ModelIgnoreFlags.M2))
+1 -1
View File
@@ -186,7 +186,7 @@ namespace Scripts.World.ItemScripts
if (player.GetZoneId() != Misc.ZoneIdHowling)
return false;
if (!player.GetTransport() || player.GetAreaId() != Misc.AreaIdShatteredStraits)
if (player.GetTransport() == null || player.GetAreaId() != Misc.AreaIdShatteredStraits)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.PetrovBomb, Difficulty.None);
if (spellInfo != null)