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 Max = 3
} }
public enum GameObjectDynamicLowFlags public enum GameObjectDynamicLowFlags : ushort
{ {
HideModel = 0x02, HideModel = 0x02,
Activate = 0x04, Activate = 0x04,
+1 -1
View File
@@ -1360,7 +1360,7 @@ namespace Game.AI
break; break;
if (e.GetTargetType() == SmartTargets.Self) 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) else if (e.GetTargetType() == SmartTargets.Position)
_me.SetFacingTo(e.Target.o); _me.SetFacingTo(e.Target.o);
else if (!targets.Empty()) else if (!targets.Empty())
+1 -1
View File
@@ -1079,7 +1079,7 @@ namespace Game.Chat
[Command("transport", RBACPermissions.CommandDebugTransport)] [Command("transport", RBACPermissions.CommandDebugTransport)]
static bool HandleDebugTransportCommand(CommandHandler handler, string operation) static bool HandleDebugTransportCommand(CommandHandler handler, string operation)
{ {
Transport transport = handler.GetSession().GetPlayer().GetTransport(); Transport transport = handler.GetSession().GetPlayer().GetTransport<Transport>();
if (!transport) if (!transport)
return false; return false;
+1 -1
View File
@@ -959,7 +959,7 @@ namespace Game.Chat
areaId, (areaEntry != null ? areaEntry.AreaName[handler.GetSessionDbcLocale()] : unknown), areaId, (areaEntry != null ? areaEntry.AreaName[handler.GetSessionDbcLocale()] : unknown),
obj.GetPositionX(), obj.GetPositionY(), obj.GetPositionZ(), obj.GetOrientation()); obj.GetPositionX(), obj.GetPositionY(), obj.GetPositionZ(), obj.GetOrientation());
Transport transport = obj.GetTransport(); Transport transport = obj.GetTransport<Transport>();
if (transport) if (transport)
{ {
handler.SendSysMessage(CypherStrings.TransportPosition, transport.GetGoInfo().MoTransport.SpawnMap, obj.GetTransOffsetX(), obj.GetTransOffsetY(), obj.GetTransOffsetZ(), obj.GetTransOffsetO(), 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(); Player chr = handler.GetSession().GetPlayer();
Map map = chr.GetMap(); Map map = chr.GetMap();
Transport trans = chr.GetTransport(); Transport trans = chr.GetTransport<Transport>();
if (trans) if (trans)
{ {
ulong guid = Global.ObjectMgr.GenerateCreatureSpawnId(); ulong guid = Global.ObjectMgr.GenerateCreatureSpawnId();
@@ -191,8 +191,8 @@ namespace Game.Entities
} }
// movement on transport of areatriggers on unit is handled by themself // movement on transport of areatriggers on unit is handled by themself
Transport transport = m_movementInfo.transport.guid.IsEmpty() ? caster.GetTransport() : null; ITransport transport = m_movementInfo.transport.guid.IsEmpty() ? caster.GetTransport() : null;
if (transport) if (transport != null)
{ {
float x, y, z, o; float x, y, z, o;
pos.GetPosition(out x, out y, out z, out o); pos.GetPosition(out x, out y, out z, out o);
@@ -211,7 +211,7 @@ namespace Game.Entities
if (!GetMap().AddToMap(this)) if (!GetMap().AddToMap(this))
{ // Returning false will cause the object to be deleted - remove from transport { // Returning false will cause the object to be deleted - remove from transport
if (transport) if (transport != null)
transport.RemovePassenger(this); transport.RemovePassenger(this);
return false; return false;
} }
+1
View File
@@ -286,6 +286,7 @@ namespace Game.Entities
} }
public CorpseDynFlags GetCorpseDynamicFlags() { return (CorpseDynFlags)(uint)m_corpseData.DynamicFlags; } 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 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 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); } 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; 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); SaveToDB(mapId, data.SpawnDifficulties);
} }
+3 -3
View File
@@ -111,8 +111,8 @@ namespace Game.Entities
if (IsWorldObject()) if (IsWorldObject())
SetActive(true); //must before add to map to be put in world container SetActive(true); //must before add to map to be put in world container
Transport transport = caster.GetTransport(); ITransport transport = caster.GetTransport();
if (transport) if (transport != null)
{ {
float x, y, z, o; float x, y, z, o;
pos.GetPosition(out x, out y, out z, out o); pos.GetPosition(out x, out y, out z, out o);
@@ -126,7 +126,7 @@ namespace Game.Entities
if (!GetMap().AddToMap(this)) if (!GetMap().AddToMap(this))
{ {
// Returning false will cause the object to be deleted - remove from transport // Returning false will cause the object to be deleted - remove from transport
if (transport) if (transport != null)
transport.RemovePassenger(this); transport.RemovePassenger(this);
return false; return false;
} }
+496 -115
View File
@@ -60,8 +60,6 @@ namespace Game.Entities
{ {
m_AI = null; m_AI = null;
m_model = null; m_model = null;
if (m_goInfo != null && m_goInfo.type == GameObjectTypes.Transport)
m_goValue.Transport.StopFrames.Clear();
base.Dispose(); 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)); SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.ParentRotation), new Quaternion(goInfo.DestructibleBuilding.DestructibleModelRec, 0f, 0f, 0f));
break; break;
case GameObjectTypes.Transport: case GameObjectTypes.Transport:
m_goValue.Transport.AnimationInfo = Global.TransportMgr.GetTransportAnimInfo(goInfo.entry); m_goTypeImpl = new GameObjectType.Transport(this);
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);
if (goInfo.Transport.startOpen != 0) if (goInfo.Transport.startOpen != 0)
SetTransportState(GameObjectState.TransportStopped, goInfo.Transport.startOpen - 1); SetGoState(GameObjectState.TransportStopped);
else else
SetTransportState(GameObjectState.TransportActive); SetGoState(GameObjectState.TransportActive);
SetGoAnimProgress(animProgress); SetGoAnimProgress(animProgress);
SetActive(true);
break; break;
case GameObjectTypes.FishingNode: case GameObjectTypes.FishingNode:
SetLevel(1); SetLevel(1);
@@ -452,6 +427,9 @@ namespace Game.Entities
} }
} }
if (m_goTypeImpl != null)
m_goTypeImpl.Update(diff);
switch (m_lootState) switch (m_lootState)
{ {
case LootState.NotReady: case LootState.NotReady:
@@ -475,50 +453,6 @@ namespace Game.Entities
m_lootState = LootState.Ready; m_lootState = LootState.Ready;
break; 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: case GameObjectTypes.FishingNode:
{ {
// fishing code (bobber ready) // fishing code (bobber ready)
@@ -1072,7 +1006,13 @@ namespace Game.Entities
return; 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) public void SaveToDB(uint mapid, List<Difficulty> spawnDifficulties)
@@ -1293,7 +1233,7 @@ namespace Game.Entities
if (gInfo == null) if (gInfo == null)
return false; 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() public bool IsDestructibleBuilding()
@@ -1581,7 +1521,7 @@ namespace Game.Entities
case GameObjectActions.GoTo9thFloor: case GameObjectActions.GoTo9thFloor:
case GameObjectActions.GoTo10thFloor: case GameObjectActions.GoTo10thFloor:
if (GetGoType() == GameObjectTypes.Transport) if (GetGoType() == GameObjectTypes.Transport)
SetTransportState(GameObjectState.TransportStopped, (uint)(action - GameObjectActions.GoTo1stFloor)); SetGoState((GameObjectState)action);
else else
Log.outError(LogFilter.Spells, $"Spell {spellId} targeted non-transport gameobject for transport only action \"Go to Floor\" {action} in effect {effectIndex}"); Log.outError(LogFilter.Spells, $"Spell {spellId} targeted non-transport gameobject for transport only action \"Go to Floor\" {action} in effect {effectIndex}");
break; break;
@@ -2453,7 +2393,7 @@ namespace Game.Entities
{ {
Quaternion localRotation = GetLocalRotation(); Quaternion localRotation = GetLocalRotation();
Transport transport = GetTransport(); Transport transport = GetTransport<Transport>();
if (transport != null) if (transport != null)
{ {
Quaternion worldRotation = transport.GetWorldRotation(); Quaternion worldRotation = transport.GetWorldRotation();
@@ -2473,7 +2413,7 @@ namespace Game.Entities
{ {
return $"{base.GetDebugInfo()}\nSpawnId: {GetSpawnId()} GoState: {GetGoState()} ScriptId: {GetScriptId()} AIName: {GetAIName()}"; return $"{base.GetDebugInfo()}\nSpawnId: {GetSpawnId()} GoState: {GetGoState()} ScriptId: {GetScriptId()} AIName: {GetAIName()}";
} }
public bool IsAtInteractDistance(Player player, SpellInfo spell = null) public bool IsAtInteractDistance(Player player, SpellInfo spell = null)
{ {
if (spell != null || (spell = GetSpellForLock(player)) != null) if (spell != null || (spell = GetSpellForLock(player)) != null)
@@ -2518,7 +2458,7 @@ namespace Game.Entities
{ {
return IsInMap(player) && IsInPhase(player) && IsAtInteractDistance(player); return IsInMap(player) && IsInPhase(player) && IsAtInteractDistance(player);
} }
public SpellInfo GetSpellForLock(Player player) public SpellInfo GetSpellForLock(Player player)
{ {
if (!player) if (!player)
@@ -2563,7 +2503,6 @@ namespace Game.Entities
return null; return null;
} }
public void ModifyHealth(int change, WorldObject attackerOrHealer = null, uint spellId = 0) public void ModifyHealth(int change, WorldObject attackerOrHealer = null, uint spellId = 0)
{ {
if (m_goValue.Building.MaxHealth == 0 || change == 0) if (m_goValue.Building.MaxHealth == 0 || change == 0)
@@ -2742,9 +2681,14 @@ namespace Game.Entities
public void SetGoState(GameObjectState state) public void SetGoState(GameObjectState state)
{ {
GameObjectState oldState = GetGoState();
SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.State), (sbyte)state); SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.State), (sbyte)state);
if (GetAI() != null) if (GetAI() != null)
GetAI().OnStateChanged(state); GetAI().OnStateChanged(state);
if (m_goTypeImpl != null)
m_goTypeImpl.OnStateChanged(oldState, state);
if (m_model != null && !IsTransport()) if (m_model != null && !IsTransport())
{ {
if (!IsInWorld) 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) public void SetDisplayId(uint displayid)
{ {
SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.DisplayID), displayid); SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.DisplayID), displayid);
@@ -2985,6 +2897,33 @@ namespace Game.Entities
base.ClearUpdateMask(remove); 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) public void GetRespawnPosition(out float x, out float y, out float z, out float ori)
{ {
if (m_goData != null) if (m_goData != null)
@@ -2993,6 +2932,31 @@ namespace Game.Entities
GetPosition(out x, out y, out z, out ori); 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() public float GetInteractionDistance()
{ {
switch (GetGoType()) switch (GetGoType())
@@ -3239,7 +3203,7 @@ namespace Game.Entities
return m_goValue.CapturePoint.State == BattlegroundCapturePointState.ContestedHorde return m_goValue.CapturePoint.State == BattlegroundCapturePointState.ContestedHorde
|| m_goValue.CapturePoint.State == BattlegroundCapturePointState.HordeCaptured; || m_goValue.CapturePoint.State == BattlegroundCapturePointState.HordeCaptured;
} }
public override ushort GetAIAnimKitId() { return _animKitId; } public override ushort GetAIAnimKitId() { return _animKitId; }
public uint GetWorldEffectID() { return _worldEffectID; } 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 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 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 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 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; } 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 GetStationaryY() { return StationaryPosition.GetPositionY(); }
public override float GetStationaryZ() { return StationaryPosition.GetPositionZ(); } public override float GetStationaryZ() { return StationaryPosition.GetPositionZ(); }
public override float GetStationaryO() { return StationaryPosition.GetOrientation(); } 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); } 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()); Cell.VisitWorldObjects(this, deliverer, GetVisibilityRange());
} }
void HandleCustomTypeCommand(GameObjectTypeBase.CustomCommand command)
{
if (m_goTypeImpl != null)
command.Execute(m_goTypeImpl);
}
public void CreateModel() public void CreateModel()
{ {
m_model = GameObjectModel.Create(new GameObjectModelOwnerImpl(this)); m_model = GameObjectModel.Create(new GameObjectModelOwnerImpl(this));
@@ -3419,8 +3396,9 @@ namespace Game.Entities
public bool GetRespawnCompatibilityMode() { return m_respawnCompatibilityMode; } public bool GetRespawnCompatibilityMode() { return m_respawnCompatibilityMode; }
#region Fields #region Fields
protected GameObjectFieldData m_gameObjectData; public GameObjectFieldData m_gameObjectData;
protected GameObjectValue m_goValue; GameObjectTypeBase m_goTypeImpl;
protected GameObjectValue m_goValue; // TODO: replace with m_goTypeImpl
protected GameObjectTemplate m_goInfo; protected GameObjectTemplate m_goInfo;
protected GameObjectTemplateAddon m_goTemplateAddon; protected GameObjectTemplateAddon m_goTemplateAddon;
GameObjectData m_goData; GameObjectData m_goData;
@@ -3509,6 +3487,26 @@ namespace Game.Entities
GameObject _owner; 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 struct GameObjectValue
{ {
public transport Transport; public transport Transport;
@@ -3549,4 +3547,387 @@ namespace Game.Entities
public uint AssaultTimer; 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; return SpellFocus.GiganticAOI != 0;
case GameObjectTypes.Goober: case GameObjectTypes.Goober:
return Goober.GiganticAOI != 0; return Goober.GiganticAOI != 0;
case GameObjectTypes.Transport:
return true;
case GameObjectTypes.SpellCaster: case GameObjectTypes.SpellCaster:
return SpellCaster.GiganticAOI != 0; return SpellCaster.GiganticAOI != 0;
case GameObjectTypes.FlagStand: case GameObjectTypes.FlagStand:
@@ -79,27 +79,27 @@ namespace Game.Entities
uint GetViewerDependentDynamicFlags(ObjectFieldData objectData, WorldObject obj, Player receiver) uint GetViewerDependentDynamicFlags(ObjectFieldData objectData, WorldObject obj, Player receiver)
{ {
UnitDynFlags unitDynFlags = (UnitDynFlags)(uint)objectData.DynamicFlags; uint unitDynFlags = objectData.DynamicFlags;
Unit unit = obj.ToUnit(); Unit unit = obj.ToUnit();
if (unit != null) if (unit != null)
{ {
unitDynFlags &= ~UnitDynFlags.Tapped; unitDynFlags &= ~(uint)UnitDynFlags.Tapped;
Creature creature = obj.ToCreature(); Creature creature = obj.ToCreature();
if (creature != null) if (creature != null)
{ {
if (creature.HasLootRecipient() && !creature.IsTappedBy(receiver)) if (creature.HasLootRecipient() && !creature.IsTappedBy(receiver))
unitDynFlags |= UnitDynFlags.Tapped; unitDynFlags |= (uint)UnitDynFlags.Tapped;
if (!receiver.IsAllowedToLoot(creature)) 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 // 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())) if (!unit.HasAuraTypeWithCaster(AuraType.ModStalked, receiver.GetGUID()))
unitDynFlags &= ~UnitDynFlags.TrackUnit; unitDynFlags &= ~(uint)UnitDynFlags.TrackUnit;
} }
else else
{ {
@@ -126,12 +126,18 @@ namespace Game.Entities
dynFlags |= GameObjectDynamicLowFlags.Sparkle | GameObjectDynamicLowFlags.Highlight; dynFlags |= GameObjectDynamicLowFlags.Sparkle | GameObjectDynamicLowFlags.Highlight;
break; break;
case GameObjectTypes.Transport: case GameObjectTypes.Transport:
{
dynFlags = (GameObjectDynamicLowFlags)((int)unitDynFlags & 0xFFFF);
pathProgress = (ushort)((int)unitDynFlags >> 16);
break;
}
case GameObjectTypes.MapObjTransport: case GameObjectTypes.MapObjTransport:
{ {
uint transportPeriod = gameObject.GetTransportPeriod(); Transport transport = gameObject.ToTransport();
uint transportPeriod = transport.GetTransportPeriod();
if (transportPeriod != 0) if (transportPeriod != 0)
{ {
float timer = (float)(gameObject.GetGoValue().Transport.PathProgress % transportPeriod); float timer = (float)(transport.GetTimer() % transportPeriod);
pathProgress = (ushort)(timer / (float)transportPeriod * 65535.0f); pathProgress = (ushort)(timer / (float)transportPeriod * 65535.0f);
} }
break; break;
@@ -146,11 +152,11 @@ namespace Game.Entities
break; 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.Z);
data.WriteFloat(rotation.W); data.WriteFloat(rotation.W);
data.WriteUInt32(FactionTemplate); data.WriteUInt32(FactionTemplate);
data.WriteInt8(GetViewerGameObjectState(this, owner, receiver)); data.WriteInt8(State);
data.WriteInt8(TypeID); data.WriteInt8(TypeID);
data.WriteUInt8(PercentHealth); data.WriteUInt8(PercentHealth);
data.WriteUInt32(ArtKit); data.WriteUInt32(ArtKit);
data.WriteInt32(EnableDoodadSets.Size()); data.WriteInt32(EnableDoodadSets.Size());
data.WriteUInt32(CustomParam); data.WriteUInt32(CustomParam);
data.WriteUInt32(GetViewerGameObjectLevel(this, owner, receiver)); data.WriteUInt32(Level);
data.WriteUInt32(AnimGroupInstance); data.WriteUInt32(AnimGroupInstance);
for (int i = 0; i < EnableDoodadSets.Size(); ++i) for (int i = 0; i < EnableDoodadSets.Size(); ++i)
{ {
@@ -5053,7 +5059,7 @@ namespace Game.Entities
} }
if (changesMask[14]) if (changesMask[14])
{ {
data.WriteInt8(GetViewerGameObjectState(this, owner, receiver)); data.WriteInt8(State);
} }
if (changesMask[15]) if (changesMask[15])
{ {
@@ -5073,7 +5079,7 @@ namespace Game.Entities
} }
if (changesMask[19]) if (changesMask[19])
{ {
data.WriteUInt32(GetViewerGameObjectLevel(this, owner, receiver)); data.WriteUInt32(Level);
} }
if (changesMask[20]) if (changesMask[20])
{ {
@@ -5116,24 +5122,6 @@ namespace Game.Entities
return flags; 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> 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) public void BuildMovementUpdate(WorldPacket data, CreateObjectBits flags, Player target)
{ {
int PauseTimesCount = 0; List<uint> PauseTimes = null;
GameObject go = ToGameObject(); GameObject go = ToGameObject();
if (go) if (go)
{ PauseTimes = go.GetPauseTimes();
if (go.GetGoType() == GameObjectTypes.Transport)
PauseTimesCount = go.GetGoValue().Transport.StopFrames.Count;
}
data.WriteBit(flags.NoBirthAnim); data.WriteBit(flags.NoBirthAnim);
data.WriteBit(flags.EnablePortals); data.WriteBit(flags.EnablePortals);
@@ -368,7 +364,7 @@ namespace Game.Entities
MovementExtensions.WriteCreateObjectSplineDataBlock(unit.MoveSpline, data); MovementExtensions.WriteCreateObjectSplineDataBlock(unit.MoveSpline, data);
} }
data.WriteInt32(PauseTimesCount); data.WriteInt32(PauseTimes != null ? PauseTimes.Count : 0);
if (flags.Stationary) if (flags.Stationary)
{ {
@@ -381,20 +377,9 @@ namespace Game.Entities
if (flags.CombatVictim) if (flags.CombatVictim)
data.WritePackedGuid(ToUnit().GetVictim().GetGUID()); // CombatVictim data.WritePackedGuid(ToUnit().GetVictim().GetGUID()); // CombatVictim
if (flags.ServerTime) if (flags.ServerTime)
{ data.WriteUInt32(GameTime.GetGameTimeMS());
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());
}
if (flags.Vehicle) if (flags.Vehicle)
{ {
@@ -413,11 +398,9 @@ namespace Game.Entities
if (flags.Rotation) if (flags.Rotation)
data.WriteInt64(ToGameObject().GetPackedLocalRotation()); // Rotation data.WriteInt64(ToGameObject().GetPackedLocalRotation()); // Rotation
if (go) if (PauseTimes != null && !PauseTimes.Empty())
{ foreach (var stopFrame in PauseTimes)
for (int i = 0; i < PauseTimesCount; ++i) data.WriteUInt32(stopFrame);
data.WriteUInt32(go.GetGoValue().Transport.StopFrames[i]);
}
if (flags.MovementTransport) if (flags.MovementTransport)
{ {
@@ -969,19 +952,9 @@ namespace Game.Entities
return; return;
if (on) if (on)
{ map.AddToActive(this);
if (IsTypeId(TypeId.Unit))
map.AddToActive(ToCreature());
else if (IsTypeId(TypeId.DynamicObject))
map.AddToActive(ToDynamicObject());
}
else else
{ map.RemoveFromActive(this);
if (IsTypeId(TypeId.Unit))
map.RemoveFromActive(ToCreature());
else if (IsTypeId(TypeId.DynamicObject))
map.RemoveFromActive(ToDynamicObject());
}
} }
bool IsFarVisible() { return m_isFarVisible; } bool IsFarVisible() { return m_isFarVisible; }
@@ -1010,8 +983,8 @@ namespace Game.Entities
if (IsInWorld) if (IsInWorld)
RemoveFromWorld(); RemoveFromWorld();
Transport transport = GetTransport(); ITransport transport = GetTransport();
if (transport) if (transport != null)
transport.RemovePassenger(this); transport.RemovePassenger(this);
} }
@@ -2957,12 +2930,6 @@ namespace Game.Entities
public float GetObjectScale() { return m_objectData.Scale; } 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 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 TypeId GetTypeId() { return ObjectTypeId; }
public bool IsTypeId(TypeId typeId) { return GetTypeId() == typeId; } public bool IsTypeId(TypeId typeId) { return GetTypeId() == typeId; }
public bool IsTypeMask(TypeMask mask) { return Convert.ToBoolean(mask & ObjectTypeMask); } 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 IsActiveObject() { return m_isActive; }
public bool IsPermanentWorldObject() { return m_isWorldObject; } 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 GetTransOffsetX() { return m_movementInfo.transport.pos.GetPositionX(); }
public float GetTransOffsetY() { return m_movementInfo.transport.pos.GetPositionY(); } public float GetTransOffsetY() { return m_movementInfo.transport.pos.GetPositionY(); }
public float GetTransOffsetZ() { return m_movementInfo.transport.pos.GetPositionZ(); } 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 sbyte GetTransSeat() { return m_movementInfo.transport.seat; }
public virtual ObjectGuid GetTransGUID() public virtual ObjectGuid GetTransGUID()
{ {
if (GetTransport()) if (GetTransport() != null)
return GetTransport().GetGUID(); return GetTransport().GetTransportGUID();
return ObjectGuid.Empty; 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 GetStationaryX() { return GetPositionX(); }
public virtual float GetStationaryY() { return GetPositionY(); } public virtual float GetStationaryY() { return GetPositionY(); }
@@ -3065,7 +3036,7 @@ namespace Game.Entities
Position thisOrTransport = this; Position thisOrTransport = this;
Position objOrObjTransport = obj; 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; thisOrTransport = m_movementInfo.transport.pos;
objOrObjTransport = obj.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) public void UpdateAllowedPositionZ(float x, float y, ref float z, ref float groundZ)
{ {
// TODO: Allow transports to be part of dynamic vmap tree // TODO: Allow transports to be part of dynamic vmap tree
if (GetTransport()) if (GetTransport() != null)
{ {
groundZ = z; groundZ = z;
return; return;
@@ -3690,7 +3661,7 @@ namespace Game.Entities
bool m_isWorldObject; bool m_isWorldObject;
public ZoneScript m_zoneScript; public ZoneScript m_zoneScript;
Transport m_transport; ITransport m_transport;
Map _currMap; Map _currMap;
uint instanceId; uint instanceId;
PhaseShift _phaseShift = new(); PhaseShift _phaseShift = new();
+6 -4
View File
@@ -3429,8 +3429,9 @@ namespace Game.Entities
stmt.AddValue(index++, finiteAlways(GetTransOffsetZ())); stmt.AddValue(index++, finiteAlways(GetTransOffsetZ()));
stmt.AddValue(index++, finiteAlways(GetTransOffsetO())); stmt.AddValue(index++, finiteAlways(GetTransOffsetO()));
ulong transLowGUID = 0; ulong transLowGUID = 0;
if (GetTransport()) Transport transport = GetTransport<Transport>();
transLowGUID = GetTransport().GetGUID().GetCounter(); if (transport != null)
transLowGUID = transport.GetGUID().GetCounter();
stmt.AddValue(index++, transLowGUID); stmt.AddValue(index++, transLowGUID);
StringBuilder ss = new(); StringBuilder ss = new();
@@ -3570,8 +3571,9 @@ namespace Game.Entities
stmt.AddValue(index++, finiteAlways(GetTransOffsetZ())); stmt.AddValue(index++, finiteAlways(GetTransOffsetZ()));
stmt.AddValue(index++, finiteAlways(GetTransOffsetO())); stmt.AddValue(index++, finiteAlways(GetTransOffsetO()));
ulong transLowGUID = 0; ulong transLowGUID = 0;
if (GetTransport()) Transport transport = GetTransport<Transport>();
transLowGUID = GetTransport().GetGUID().GetCounter(); if (transport != null)
transLowGUID = transport.GetGUID().GetCounter();
stmt.AddValue(index++, transLowGUID); stmt.AddValue(index++, transLowGUID);
StringBuilder ss = new(); StringBuilder ss = new();
+1 -1
View File
@@ -803,7 +803,7 @@ namespace Game.Entities
m_MirrorTimerFlags |= PlayerUnderwaterState.InWater; m_MirrorTimerFlags |= PlayerUnderwaterState.InWater;
// Fatigue bar state (if not on flight path or transport) // 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; m_MirrorTimerFlags |= PlayerUnderwaterState.InDarkWater;
// Lava state (any contact) // 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); Log.outDebug(LogFilter.Maps, "Player {0} using client without required expansion tried teleport to non accessible map {1}", GetName(), mapid);
Transport _transport = GetTransport(); ITransport _transport = GetTransport();
if (_transport) if (_transport != null)
{ {
_transport.RemovePassenger(this); _transport.RemovePassenger(this);
RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :) RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
@@ -1708,8 +1708,8 @@ namespace Game.Entities
DisableSpline(); DisableSpline();
GetMotionMaster().Remove(MovementGeneratorType.Effect); GetMotionMaster().Remove(MovementGeneratorType.Effect);
Transport transport = GetTransport(); ITransport transport = GetTransport();
if (transport) if (transport != null)
{ {
if (!options.HasAnyFlag(TeleportToOptions.NotLeaveTransport)) if (!options.HasAnyFlag(TeleportToOptions.NotLeaveTransport))
transport.RemovePassenger(this); transport.RemovePassenger(this);
@@ -1849,11 +1849,11 @@ namespace Game.Entities
transferPending.MapID = (int)mapid; transferPending.MapID = (int)mapid;
transferPending.OldMapPosition = GetPosition(); transferPending.OldMapPosition = GetPosition();
transport = GetTransport(); Transport transport1 = (Transport)GetTransport();
if (transport) if (transport1 != null)
{ {
TransferPending.ShipTransferPending shipTransferPending = new(); TransferPending.ShipTransferPending shipTransferPending = new();
shipTransferPending.Id = transport.GetEntry(); shipTransferPending.Id = transport1.GetEntry();
shipTransferPending.OriginMapID = (int)GetMapId(); shipTransferPending.OriginMapID = (int)GetMapId();
transferPending.Ship = shipTransferPending; transferPending.Ship = shipTransferPending;
} }
@@ -6242,14 +6242,6 @@ namespace Game.Entities
{ {
switch (target.GetTypeId()) 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: case TypeId.Unit:
s64.Add(target.GetGUID()); s64.Add(target.GetGUID());
v.Add(target.ToCreature()); v.Add(target.ToCreature());
+102 -77
View File
@@ -27,37 +27,102 @@ namespace Game.Entities
{ {
public interface ITransport public interface ITransport
{ {
ObjectGuid GetTransportGUID();
// This method transforms supplied transport offsets into global coordinates // This method transforms supplied transport offsets into global coordinates
void CalculatePassengerPosition(ref float x, ref float y, ref float z, ref float o); void CalculatePassengerPosition(ref float x, ref float y, ref float z, ref float o);
// This method transforms supplied global coordinates into local offsets // This method transforms supplied global coordinates into local offsets
void CalculatePassengerOffset(ref float x, ref float y, ref float z, ref float o); void CalculatePassengerOffset(ref float x, ref float y, ref float z, ref float o);
}
public class TransportPosHelper float GetTransportOrientation();
{
public static void CalculatePassengerPosition(ref float x, ref float y, ref float z, ref float o, float transX, float transY, float transZ, float transO) 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; float inx = x, iny = y, inz = z;
o = Position.NormalizeOrientation(transO + o); o = Position.NormalizeOrientation(transO + o);
x = transX + inx * (float)Math.Cos(transO) - iny * (float)Math.Sin(transO); x = transX + inx * MathF.Cos(transO) - iny * MathF.Sin(transO);
y = transY + iny * (float)Math.Cos(transO) + inx * (float)Math.Sin(transO); y = transY + iny * MathF.Cos(transO) + inx * MathF.Sin(transO);
z = transZ + inz; 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); o = Position.NormalizeOrientation(o - transO);
z -= transZ; z -= transZ;
y -= transY; y -= transY; // y = searchedY * std::cos(o) + searchedX * std::sin(o)
x -= transX; x -= transX; // x = searchedX * std::cos(o) + searchedY * std::sin(o + pi)
float inx = x, iny = y; float inx = x, iny = y;
y = (iny - inx * (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 * (float)Math.Tan(transO)) / ((float)Math.Cos(transO) + (float)Math.Sin(transO) * (float)Math.Tan(transO)); x = (inx + iny * MathF.Tan(transO)) / (MathF.Cos(transO) + MathF.Sin(transO) * MathF.Tan(transO));
} }
int GetMapIdForSpawning();
} }
public class Transport : GameObject, ITransport public class Transport : GameObject, ITransport
@@ -122,7 +187,6 @@ namespace Game.Entities
ReplaceAllFlags(goOverride.Flags); ReplaceAllFlags(goOverride.Flags);
} }
m_goValue.Transport.PathProgress = 0;
SetObjectScale(goinfo.size); SetObjectScale(goinfo.size);
SetPeriod(tInfo.pathTime); SetPeriod(tInfo.pathTime);
SetEntry(goinfo.entry); SetEntry(goinfo.entry);
@@ -163,9 +227,9 @@ namespace Game.Entities
return; return;
if (IsMoving() || !_pendingStop) if (IsMoving() || !_pendingStop)
m_goValue.Transport.PathProgress += diff; _pathProgress += diff;
uint timer = m_goValue.Transport.PathProgress % GetTransportPeriod(); uint timer = _pathProgress % GetTransportPeriod();
bool justStopped = false; bool justStopped = false;
// Set current waypoint // Set current waypoint
@@ -189,9 +253,9 @@ namespace Game.Entities
if (_pendingStop && GetGoState() != GameObjectState.Ready) if (_pendingStop && GetGoState() != GameObjectState.Ready)
{ {
SetGoState(GameObjectState.Ready); SetGoState(GameObjectState.Ready);
m_goValue.Transport.PathProgress /= GetTransportPeriod(); _pathProgress /= GetTransportPeriod();
m_goValue.Transport.PathProgress *= GetTransportPeriod(); _pathProgress *= GetTransportPeriod();
m_goValue.Transport.PathProgress += _currentFrame.ArriveTime; _pathProgress += _currentFrame.ArriveTime;
} }
break; // its a stop frame and we are waiting 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); bool erased = _passengers.Remove(passenger);
@@ -313,6 +377,8 @@ namespace Game.Entities
plr.SetFallInformation(0, plr.GetPositionZ()); plr.SetFallInformation(0, plr.GetPositionZ());
} }
} }
return this;
} }
public Creature CreateNPCPassenger(ulong guid, CreatureData data) 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) 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) 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) public void UpdatePosition(float x, float y, float z, float o)
{ {
bool newActive = GetMap().IsGridLoaded(x, y); bool newActive = GetMap().IsGridLoaded(x, y);
@@ -652,7 +723,7 @@ namespace Game.Entities
float destX, destY, destZ, destO; float destX, destY, destZ, destO;
obj.m_movementInfo.transport.pos.GetPosition(out destX, out destY, out destZ, out 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); obj.ToUnit().NearTeleportTo(destX, destY, destZ, destO);
} }
@@ -683,7 +754,7 @@ namespace Game.Entities
{ {
float destX, destY, destZ, destO; float destX, destY, destZ, destO;
obj.m_movementInfo.transport.pos.GetPosition(out destX, out destY, out destZ, out 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()) switch (obj.GetTypeId())
{ {
@@ -707,62 +778,12 @@ namespace Game.Entities
void UpdatePassengerPositions(HashSet<WorldObject> passengers) 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; float x, y, z, o;
passenger.m_movementInfo.transport.pos.GetPosition(out x, out y, out z, out o); passenger.m_movementInfo.transport.pos.GetPosition(out x, out y, out z, out o);
CalculatePassengerPosition(ref x, ref y, ref z, ref o); CalculatePassengerPosition(ref x, ref y, ref z, ref o);
switch (passenger.GetTypeId()) ITransport.UpdatePassengerPosition(this, GetMap(), passenger, x, y, z, o, true);
{
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();
}
} }
} }
@@ -790,9 +811,12 @@ namespace Game.Entities
public HashSet<WorldObject> GetPassengers() { return _passengers; } 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); } 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 List<KeyFrame> GetKeyFrames() { return _transportInfo.keyFrames; }
public TransportTemplate GetTransportTemplate() { return _transportInfo; } public TransportTemplate GetTransportTemplate() { return _transportInfo; }
@@ -805,6 +829,7 @@ namespace Game.Entities
KeyFrame _currentFrame; KeyFrame _currentFrame;
int _nextFrame; int _nextFrame;
uint _pathProgress;
TimeTracker _positionChangeTimer = new(); TimeTracker _positionChangeTimer = new();
bool _isMoving; bool _isMoving;
bool _pendingStop; bool _pendingStop;
+2 -2
View File
@@ -209,7 +209,7 @@ namespace Game.Entities
MoveSplineInit init = new(this); MoveSplineInit init = new(this);
init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false); init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
if (GetTransport()) if (GetTransport() != null)
init.DisableTransportPathTransformations(); // It makes no sense to target global orientation init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
init.SetFacing(ori); init.SetFacing(ori);
@@ -1834,7 +1834,7 @@ namespace Game.Entities
if (GetVehicle() != null) if (GetVehicle() != null)
return GetVehicleBase().GetGUID(); return GetVehicleBase().GetGUID();
if (GetTransport() != null) if (GetTransport() != null)
return GetTransport().GetGUID(); return GetTransport().GetTransportGUID();
return ObjectGuid.Empty; return ObjectGuid.Empty;
} }
+1 -1
View File
@@ -295,7 +295,7 @@ namespace Game.Entities
return false; 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()); Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: Player on transport is trying to charm {0} (GUID {1})", GetEntry(), GetGUID().ToString());
return false; return false;
+8 -2
View File
@@ -1003,7 +1003,7 @@ namespace Game.Entities
} }
Cypher.Assert(!m_vehicle); Cypher.Assert(!m_vehicle);
vehicle.AddPassenger(this, seatId); vehicle.AddVehiclePassenger(this, seatId);
} }
public void ChangeSeat(sbyte seatId, bool next = true) 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 // This should be done before dismiss, because there may be some aura removal
VehicleSeatAddon seatAddon = m_vehicle.GetSeatAddonForSeatOfPassenger(this); VehicleSeatAddon seatAddon = m_vehicle.GetSeatAddonForSeatOfPassenger(this);
Vehicle vehicle = m_vehicle.RemovePassenger(this); Vehicle vehicle = (Vehicle)m_vehicle.RemovePassenger(this);
if (vehicle == null) 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 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 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 void SetCreatedBySpell(uint spellId) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.CreatedBySpell), spellId); }
public Emote GetEmoteState() { return (Emote)(int)m_unitData.EmoteState; } public Emote GetEmoteState() { return (Emote)(int)m_unitData.EmoteState; }
+18 -6
View File
@@ -291,7 +291,7 @@ namespace Game.Entities
// @VehicleJoinEvent.Abort // @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.) // @Prevent adding passengers when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
if (_status == Status.UnInstalling) if (_status == Status.UnInstalling)
@@ -355,8 +355,12 @@ namespace Game.Entities
return true; 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) if (unit.GetVehicle() != this)
return null; return null;
@@ -421,8 +425,8 @@ namespace Game.Entities
} }
} }
foreach (var pair in seatRelocation) foreach (var (passenger, position) in seatRelocation)
pair.Item1.UpdatePosition(pair.Item2); ITransport.UpdatePassengerPosition(this, _me.GetMap(), passenger, position.GetPositionX(), position.GetPositionY(), position.GetPositionZ(), position.GetOrientation(), false);
} }
public bool IsVehicleInUse() public bool IsVehicleInUse()
@@ -487,20 +491,28 @@ namespace Game.Entities
return ret; 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) 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().GetPositionX(), GetBase().GetPositionY(),
GetBase().GetPositionZ(), GetBase().GetOrientation()); GetBase().GetPositionZ(), GetBase().GetOrientation());
} }
public void CalculatePassengerOffset(ref float x, ref float y, ref float z, ref float o) 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().GetPositionX(), GetBase().GetPositionY(),
GetBase().GetPositionZ(), GetBase().GetOrientation()); GetBase().GetPositionZ(), GetBase().GetOrientation());
} }
public int GetMapIdForSpawning() { return (int)GetBase().GetMapId(); }
public void RemovePendingEvent(VehicleJoinEvent e) public void RemovePendingEvent(VehicleJoinEvent e)
{ {
foreach (var Event in _pendingJoinEvents) foreach (var Event in _pendingJoinEvents)
+1 -1
View File
@@ -839,7 +839,7 @@ namespace Game.Garrisons
float y = spawn.GetPositionY(); float y = spawn.GetPositionY();
float z = spawn.GetPositionZ(); float z = spawn.GetPositionZ();
float o = spawn.GetOrientation(); 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); spawn.Relocate(x, y, z, o);
switch (spawn.GetTypeId()) switch (spawn.GetTypeId())
+22 -16
View File
@@ -110,31 +110,37 @@ namespace Game
if (plrMover) if (plrMover)
{ {
if (!plrMover.GetTransport()) if (plrMover.GetTransport() == null)
{ {
Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid); GameObject go = plrMover.GetMap().GetGameObject(movementInfo.transport.guid);
if (transport) if (go != null)
transport.AddPassenger(plrMover); {
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); plrMover.GetTransport().RemovePassenger(plrMover);
Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid); GameObject go = plrMover.GetMap().GetGameObject(movementInfo.transport.guid);
if (transport) if (go != null)
transport.AddPassenger(plrMover); {
ITransport transport = go.ToTransportBase();
if (transport != null)
transport.AddPassenger(plrMover);
else
movementInfo.ResetTransport();
}
else else
movementInfo.ResetTransport(); movementInfo.ResetTransport();
} }
} }
if (!mover.GetTransport() && !mover.GetVehicle()) if (mover.GetTransport() == null && !mover.GetVehicle())
{ movementInfo.transport.Reset();
GameObject go = mover.GetMap().GetGameObject(movementInfo.transport.guid);
if (!go || go.GetGoType() != GameObjectTypes.Transport)
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); plrMover.GetTransport().RemovePassenger(plrMover);
// fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). // 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; 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 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 // 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 // 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) if (transport)
{ {
foreach (var obj in transport.GetPassengers()) foreach (var obj in transport.GetPassengers())
@@ -128,6 +128,9 @@ namespace Game.Maps
case TypeId.DynamicObject: case TypeId.DynamicObject:
i_player.UpdateVisibilityOf(obj.ToDynamicObject(), i_data, i_visibleNow); i_player.UpdateVisibilityOf(obj.ToDynamicObject(), i_data, i_visibleNow);
break; break;
case TypeId.AreaTrigger:
i_player.UpdateVisibilityOf(obj.ToAreaTrigger(), i_data, i_visibleNow);
break;
default: default:
break; break;
} }
+6 -10
View File
@@ -1131,9 +1131,7 @@ namespace Game.Maps
else else
{ {
go.Relocate(x, y, z, orientation); go.Relocate(x, y, z, orientation);
go.UpdateModelPosition(); go.AfterRelocation();
go.UpdatePositionData();
go.UpdateObjectVisibility(false);
RemoveGameObjectFromMoveList(go); RemoveGameObjectFromMoveList(go);
} }
@@ -1354,9 +1352,7 @@ namespace Game.Maps
{ {
// update pos // update pos
go.Relocate(go._newPosition); go.Relocate(go._newPosition);
go.UpdateModelPosition(); go.AfterRelocation();
go.UpdatePositionData();
go.UpdateObjectVisibility(false);
} }
else else
{ {
@@ -2247,7 +2243,7 @@ namespace Game.Maps
var data = new UpdateData(player.GetMapId()); var data = new UpdateData(player.GetMapId());
// attach to player data current transport data // attach to player data current transport data
Transport transport = player.GetTransport(); Transport transport = player.GetTransport<Transport>();
if (transport != null) if (transport != null)
{ {
transport.BuildCreateUpdateBlockForPlayer(data, player); transport.BuildCreateUpdateBlockForPlayer(data, player);
@@ -4168,8 +4164,8 @@ namespace Game.Maps
if (!summon.Create(GenerateLowGuid(HighGuid.Creature), this, entry, pos, null, vehId, true)) if (!summon.Create(GenerateLowGuid(HighGuid.Creature), this, entry, pos, null, vehId, true))
return null; return null;
Transport transport = summoner != null ? summoner.GetTransport() : null; ITransport transport = summoner != null ? summoner.GetTransport() : null;
if (transport) if (transport != null)
{ {
pos.GetPosition(out float x, out float y, out float z, out float o); pos.GetPosition(out float x, out float y, out float z, out float o);
transport.CalculatePassengerOffset(ref x, ref y, ref z, ref o); transport.CalculatePassengerOffset(ref x, ref y, ref z, ref o);
@@ -4209,7 +4205,7 @@ namespace Game.Maps
if (!AddToMap(summon.ToCreature())) if (!AddToMap(summon.ToCreature()))
{ {
// Returning false will cause the object to be deleted - remove from transport // Returning false will cause the object to be deleted - remove from transport
if (transport) if (transport != null)
transport.RemovePassenger(summon); transport.RemovePassenger(summon);
summon.Dispose(); summon.Dispose();
+57 -20
View File
@@ -425,6 +425,18 @@ namespace Game.Maps
_transportAnimations[transportEntry] = animNode; _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) 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 // instance case, execute GetGameObjectEntry hook
@@ -530,14 +542,6 @@ namespace Game.Maps
{ {
return _transportSpawns.LookupByKey(spawnId); 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(); Dictionary<uint, TransportTemplate> _transportTemplates = new();
MultiMap<uint, uint> _instanceTransports = new(); MultiMap<uint, uint> _instanceTransports = new();
@@ -557,8 +561,8 @@ namespace Game.Maps
mode = Spline.EvaluationMode.Catmullrom; mode = Spline.EvaluationMode.Catmullrom;
cyclic = false; cyclic = false;
points = new Vector3[_points.Count]; 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]; points[i] = _points[i];
lo = 1; lo = 1;
@@ -627,26 +631,59 @@ namespace Game.Maps
public class TransportAnimation 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()) if (Path.Empty())
return null; return null;
foreach (var pair in Path) List<uint> lKeys = Path.Keys.ToList();
if (time >= pair.Key) int reqIndex = lKeys.IndexOf(time) - 1;
return pair.Value;
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 TransportAnimationRecord GetNextAnimNode(uint time)
public Dictionary<uint, TransportRotationRecord> Rotations = new(); {
public uint TotalTime; 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 public class TransportSpawn
@@ -303,10 +303,10 @@ namespace Game.Movement
owner.SetHomePosition(x, y, z, o); owner.SetHomePosition(x, y, z, o);
else else
{ {
Transport trans = owner.GetTransport(); ITransport trans = owner.GetTransport();
if (trans) if (trans != null)
{ {
o -= trans.GetOrientation(); o -= trans.GetTransportOrientation();
owner.SetTransportHomePosition(x, y, z, o); owner.SetTransportHomePosition(x, y, z, o);
trans.CalculatePassengerPosition(ref x, ref y, ref z, ref o); trans.CalculatePassengerPosition(ref x, ref y, ref z, ref o);
owner.SetHomePosition(x, y, z, o); owner.SetHomePosition(x, y, z, o);
+7 -4
View File
@@ -222,11 +222,14 @@ namespace Game.Movement
if (args.TransformForTransport) if (args.TransformForTransport)
{ {
Unit vehicle = unit.GetVehicleBase(); Unit vehicle = unit.GetVehicleBase();
Transport transport = unit.GetTransport();
if (vehicle != null) if (vehicle != null)
angle -= vehicle.Orientation; angle -= vehicle.GetOrientation();
else if (transport != null) else
angle -= transport.Orientation; {
ITransport transport = unit.GetTransport();
if (transport != null)
angle -= transport.GetTransportOrientation();
}
} }
args.facing.angle = MathFunctions.wrap(angle, 0.0f, MathFunctions.TwoPi); 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()) if (target.GetGUID() != corpse.GetOwnerGUID())
return false; return false;
if (!corpse.HasDynamicFlag(UnitDynFlags.Lootable)) if (!corpse.HasCorpseDynamicFlag(CorpseDynFlags.Lootable))
return false; return false;
if (!corpse.IsWithinLOSInMap(m_caster, LineOfSightChecks.All, ModelIgnoreFlags.M2)) 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) if (player.GetZoneId() != Misc.ZoneIdHowling)
return false; 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); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.PetrovBomb, Difficulty.None);
if (spellInfo != null) if (spellInfo != null)