Core/Creatures: Taxi improvements

* Fixed flight master minimap icon
* Fixed crash on Argus
* Implemented teleport taxi nodes
Port From (https://github.com/TrinityCore/TrinityCore/commit/73e0b3e77c04a7821f58d79211f344b9129602f1)
This commit is contained in:
hondacrx
2024-02-02 10:20:04 -05:00
parent 80f4ece2e5
commit 871928ebb7
9 changed files with 126 additions and 67 deletions
+10 -3
View File
@@ -2115,13 +2115,20 @@ namespace Framework.Constants
DontDismissWhenEncounterIsAborted = 0x80000000 // NYI DontDismissWhenEncounterIsAborted = 0x80000000 // NYI
} }
[Flags]
public enum TaxiNodeFlags : int public enum TaxiNodeFlags : int
{ {
Alliance = 0x1, ShowOnAllianceMap = 0x01,
Horde = 0x2, ShowOnHordeMap = 0x02,
UseFavoriteMount = 0x10 ShowOnMapBorder = 0x04,
ShowIfClientPassesCondition = 0x08,
UsePlayerFavoriteMount = 0x10,
EndPointPnly = 0x20,
IgnoreForFindNearest = 0x40,
DoNotShowInWorldMapUI = 0x80,
} }
[Flags]
public enum TaxiPathNodeFlags : int public enum TaxiPathNodeFlags : int
{ {
Teleport = 0x1, Teleport = 0x1,
+3 -3
View File
@@ -413,7 +413,7 @@ namespace Game.DataStorage
foreach (var node in TaxiNodesStorage.Values) foreach (var node in TaxiNodesStorage.Values)
{ {
if (!node.Flags.HasAnyFlag(TaxiNodeFlags.Alliance | TaxiNodeFlags.Horde)) if (!node.IsPartOfTaxiNetwork())
continue; continue;
// valid taxi network node // valid taxi network node
@@ -421,9 +421,9 @@ namespace Game.DataStorage
byte submask = (byte)(1 << (int)((node.Id - 1) % 8)); byte submask = (byte)(1 << (int)((node.Id - 1) % 8));
TaxiNodesMask[field] |= submask; TaxiNodesMask[field] |= submask;
if (node.Flags.HasAnyFlag(TaxiNodeFlags.Horde)) if (node.GetFlags().HasFlag(TaxiNodeFlags.ShowOnHordeMap))
HordeTaxiNodesMask[field] |= submask; HordeTaxiNodesMask[field] |= submask;
if (node.Flags.HasAnyFlag(TaxiNodeFlags.Alliance)) if (node.GetFlags().HasFlag(TaxiNodeFlags.ShowOnAllianceMap))
AllianceTaxiNodesMask[field] |= submask; AllianceTaxiNodesMask[field] |= submask;
int uiMapId; int uiMapId;
+17 -1
View File
@@ -36,13 +36,29 @@ namespace Game.DataStorage
public ushort ContinentID; public ushort ContinentID;
public uint ConditionID; public uint ConditionID;
public ushort CharacterBitNumber; public ushort CharacterBitNumber;
public TaxiNodeFlags Flags; public int Flags;
public int UiTextureKitID; public int UiTextureKitID;
public int MinimapAtlasMemberID; public int MinimapAtlasMemberID;
public float Facing; public float Facing;
public uint SpecialIconConditionID; public uint SpecialIconConditionID;
public uint VisibilityConditionID; public uint VisibilityConditionID;
public uint[] MountCreatureID = new uint[2]; public uint[] MountCreatureID = new uint[2];
public TaxiNodeFlags GetFlags() { return (TaxiNodeFlags)Flags; }
public bool IsPartOfTaxiNetwork()
{
return GetFlags().HasFlag(TaxiNodeFlags.ShowOnAllianceMap | TaxiNodeFlags.ShowOnHordeMap)
// manually whitelisted nodes
|| Id == 1985 // [Hidden] Argus Ground Points Hub (Ground TP out to here, TP to Vindicaar from here)
|| Id == 1986 // [Hidden] Argus Vindicaar Ground Hub (Vindicaar TP out to here, TP to ground from here)
|| Id == 1987 // [Hidden] Argus Vindicaar No Load Hub (Vindicaar No Load transition goes through here)
|| Id == 2627 // [Hidden] 9.0 Bastion Ground Points Hub (Ground TP out to here, TP to Sanctum from here)
|| Id == 2628 // [Hidden] 9.0 Bastion Ground Hub (Sanctum TP out to here, TP to ground from here)
|| Id == 2732 // [HIDDEN] 9.2 Resonant Peaks - Teleport Network - Hidden Hub (Connects all Nodes to each other without unique paths)
|| Id == 2835 // [Hidden] 10.0 Travel Network - Destination Input
|| Id == 2843; // [Hidden] 10.0 Travel Network - Destination Output
}
} }
public sealed class TaxiPathRecord public sealed class TaxiPathRecord
+26 -18
View File
@@ -358,7 +358,15 @@ namespace Game.Entities
// checked and error show at loading templates // checked and error show at loading templates
var factionTemplate = CliDB.FactionTemplateStorage.LookupByKey(cInfo.Faction); var factionTemplate = CliDB.FactionTemplateStorage.LookupByKey(cInfo.Faction);
if (factionTemplate != null) if (factionTemplate != null)
{
SetPvP(factionTemplate.Flags.HasAnyFlag((ushort)FactionTemplateFlags.PVP)); SetPvP(factionTemplate.Flags.HasAnyFlag((ushort)FactionTemplateFlags.PVP));
if (IsTaxi())
{
uint taxiNodesId = Global.ObjectMgr.GetNearestTaxiNode(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(),
(factionTemplate.FactionGroup & (byte)FactionMasks.Alliance) != 0 ? Team.Alliance : Team.Horde);
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.TaxiNodesID), (int)taxiNodesId);
}
}
// updates spell bars for vehicles and set player's faction - should be called here, to overwrite faction that is set from the new template // updates spell bars for vehicles and set player's faction - should be called here, to overwrite faction that is set from the new template
if (IsVehicle()) if (IsVehicle())
@@ -407,7 +415,7 @@ namespace Game.Entities
// Apply all other side effects of flag changes // Apply all other side effects of flag changes
SetTemplateRooted(flags.HasFlag(CreatureStaticFlags.Sessile)); SetTemplateRooted(flags.HasFlag(CreatureStaticFlags.Sessile));
} }
public override void Update(uint diff) public override void Update(uint diff)
{ {
if (IsAIEnabled() && triggerJustAppeared && m_deathState != DeathState.Dead) if (IsAIEnabled() && triggerJustAppeared && m_deathState != DeathState.Dead)
@@ -1132,14 +1140,14 @@ namespace Game.Entities
SummonCreature(npcEntry, GetPosition(), TempSummonType.TimedDespawn, TimeSpan.FromSeconds(1), 0, 0); SummonCreature(npcEntry, GetPosition(), TempSummonType.TimedDespawn, TimeSpan.FromSeconds(1), 0, 0);
} }
public bool HasFlag(CreatureStaticFlags flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags flag) { return _staticFlags.HasFlag(flag); }
public bool HasFlag(CreatureStaticFlags2 flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags2 flag) { return _staticFlags.HasFlag(flag); }
public bool HasFlag(CreatureStaticFlags3 flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags3 flag) { return _staticFlags.HasFlag(flag); }
public bool HasFlag(CreatureStaticFlags4 flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags4 flag) { return _staticFlags.HasFlag(flag); }
public bool HasFlag(CreatureStaticFlags5 flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags5 flag) { return _staticFlags.HasFlag(flag); }
public bool HasFlag(CreatureStaticFlags6 flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags6 flag) { return _staticFlags.HasFlag(flag); }
public bool HasFlag(CreatureStaticFlags7 flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags7 flag) { return _staticFlags.HasFlag(flag); }
public bool HasFlag(CreatureStaticFlags8 flag) { return _staticFlags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags8 flag) { return _staticFlags.HasFlag(flag); }
public uint GetGossipMenuId() public uint GetGossipMenuId()
{ {
@@ -1150,7 +1158,7 @@ namespace Game.Entities
{ {
_gossipMenuId = gossipMenuId; _gossipMenuId = gossipMenuId;
} }
public uint GetTrainerId() public uint GetTrainerId()
{ {
if (_trainerId.HasValue) if (_trainerId.HasValue)
@@ -1202,7 +1210,7 @@ namespace Game.Entities
} }
public bool IsTapListNotClearedOnEvade() { return m_dontClearTapListOnEvade; } public bool IsTapListNotClearedOnEvade() { return m_dontClearTapListOnEvade; }
public void SetTappedBy(Unit unit, bool withGroup = true) public void SetTappedBy(Unit unit, bool withGroup = true)
{ {
// set the player whose group should receive the right // set the player whose group should receive the right
@@ -1285,7 +1293,7 @@ namespace Game.Entities
public bool CanHaveLoot() { return !_staticFlags.HasFlag(CreatureStaticFlags.NoLoot); } public bool CanHaveLoot() { return !_staticFlags.HasFlag(CreatureStaticFlags.NoLoot); }
public void SetCanHaveLoot(bool canHaveLoot) { _staticFlags.ApplyFlag(CreatureStaticFlags.NoLoot, !canHaveLoot); } public void SetCanHaveLoot(bool canHaveLoot) { _staticFlags.ApplyFlag(CreatureStaticFlags.NoLoot, !canHaveLoot); }
public void SaveToDB() public void SaveToDB()
{ {
// this should only be used when the creature has already been loaded // this should only be used when the creature has already been loaded
@@ -1633,7 +1641,7 @@ namespace Game.Entities
return true; return true;
} }
bool CreateFromProto(ulong guidlow, uint entry, CreatureData data = null, uint vehId = 0) bool CreateFromProto(ulong guidlow, uint entry, CreatureData data = null, uint vehId = 0)
{ {
SetZoneScript(); SetZoneScript();
@@ -1740,7 +1748,7 @@ namespace Game.Entities
} }
public bool IsTemplateRooted() { return _staticFlags.HasFlag(CreatureStaticFlags.Sessile); } public bool IsTemplateRooted() { return _staticFlags.HasFlag(CreatureStaticFlags.Sessile); }
public void SetTemplateRooted(bool rooted) public void SetTemplateRooted(bool rooted)
{ {
_staticFlags.ApplyFlag(CreatureStaticFlags.Sessile, rooted); _staticFlags.ApplyFlag(CreatureStaticFlags.Sessile, rooted);
@@ -3295,7 +3303,7 @@ namespace Game.Entities
return (CreatureAI)i_AI; return (CreatureAI)i_AI;
} }
public T GetAI<T>() where T : CreatureAI public new T GetAI<T>() where T : CreatureAI
{ {
return (T)i_AI; return (T)i_AI;
} }
@@ -3308,7 +3316,7 @@ namespace Game.Entities
public void SetCanMelee(bool canMelee) { _staticFlags.ApplyFlag(CreatureStaticFlags.NoMelee, !canMelee); } public void SetCanMelee(bool canMelee) { _staticFlags.ApplyFlag(CreatureStaticFlags.NoMelee, !canMelee); }
public bool CanIgnoreLineOfSightWhenCastingOnMe() { return _staticFlags.HasFlag(CreatureStaticFlags4.IgnoreLosWhenCastingOnMe); } public bool CanIgnoreLineOfSightWhenCastingOnMe() { return _staticFlags.HasFlag(CreatureStaticFlags4.IgnoreLosWhenCastingOnMe); }
public sbyte GetOriginalEquipmentId() { return m_originalEquipmentId; } public sbyte GetOriginalEquipmentId() { return m_originalEquipmentId; }
public byte GetCurrentEquipmentId() { return m_equipmentId; } public byte GetCurrentEquipmentId() { return m_equipmentId; }
public void SetCurrentEquipmentId(byte id) { m_equipmentId = id; } public void SetCurrentEquipmentId(byte id) { m_equipmentId = id; }
@@ -3316,7 +3324,7 @@ namespace Game.Entities
public CreatureTemplate GetCreatureTemplate() { return m_creatureInfo; } public CreatureTemplate GetCreatureTemplate() { return m_creatureInfo; }
public CreatureData GetCreatureData() { return m_creatureData; } public CreatureData GetCreatureData() { return m_creatureData; }
public CreatureDifficulty GetCreatureDifficulty() { return m_creatureDifficulty; } public CreatureDifficulty GetCreatureDifficulty() { return m_creatureDifficulty; }
public override bool LoadFromDB(ulong spawnId, Map map, bool addToMap, bool allowDuplicate) public override bool LoadFromDB(ulong spawnId, Map map, bool addToMap, bool allowDuplicate)
{ {
if (!allowDuplicate) if (!allowDuplicate)
@@ -3458,7 +3466,7 @@ namespace Game.Entities
bool CanRegenerateHealth() { return !_staticFlags.HasFlag(CreatureStaticFlags5.NoHealthRegen) && _regenerateHealth; } bool CanRegenerateHealth() { return !_staticFlags.HasFlag(CreatureStaticFlags5.NoHealthRegen) && _regenerateHealth; }
public void SetRegenerateHealth(bool value) { _staticFlags.ApplyFlag(CreatureStaticFlags5.NoHealthRegen, !value); } public void SetRegenerateHealth(bool value) { _staticFlags.ApplyFlag(CreatureStaticFlags5.NoHealthRegen, !value); }
public void SetHomePosition(float x, float y, float z, float o) public void SetHomePosition(float x, float y, float z, float o)
{ {
m_homePosition.Relocate(x, y, z, o); m_homePosition.Relocate(x, y, z, o);
+1 -1
View File
@@ -7036,7 +7036,7 @@ namespace Game.Entities
// change but I couldn't find a suitable alternative. OK to use class because only DK // change but I couldn't find a suitable alternative. OK to use class because only DK
// can use this taxi. // can use this taxi.
uint mount_display_id; uint mount_display_id;
if (node.Flags.HasAnyFlag(TaxiNodeFlags.UseFavoriteMount) && preferredMountDisplay != 0) if (node.GetFlags().HasFlag(TaxiNodeFlags.UsePlayerFavoriteMount) && preferredMountDisplay != 0)
mount_display_id = preferredMountDisplay; mount_display_id = preferredMountDisplay;
else else
mount_display_id = ObjectMgr.GetTaxiMountDisplayId(sourcenode, GetTeam(), npc == null || (sourcenode == 315 && GetClass() == Class.Deathknight)); mount_display_id = ObjectMgr.GetTaxiMountDisplayId(sourcenode, GetTeam(), npc == null || (sourcenode == 315 && GetClass() == Class.Deathknight));
+28 -19
View File
@@ -84,7 +84,7 @@ namespace Game.Entities
static uint GetVertexIDFromNodeID(TaxiNodesRecord node) static uint GetVertexIDFromNodeID(TaxiNodesRecord node)
{ {
return m_verticesByNode.ContainsKey(node.Id) ? m_verticesByNode[node.Id] : uint.MaxValue; return m_verticesByNode.LookupByKey(node.Id);
} }
static uint GetNodeIDFromVertexID(uint vertexID) static uint GetNodeIDFromVertexID(uint vertexID)
@@ -107,7 +107,7 @@ namespace Game.Entities
{ {
TaxiNodesRecord from = CliDB.TaxiNodesStorage.LookupByKey(path.FromTaxiNode); TaxiNodesRecord from = CliDB.TaxiNodesStorage.LookupByKey(path.FromTaxiNode);
TaxiNodesRecord to = CliDB.TaxiNodesStorage.LookupByKey(path.ToTaxiNode); TaxiNodesRecord to = CliDB.TaxiNodesStorage.LookupByKey(path.ToTaxiNode);
if (from != null && to != null && from.Flags.HasAnyFlag(TaxiNodeFlags.Alliance | TaxiNodeFlags.Horde) && to.Flags.HasAnyFlag(TaxiNodeFlags.Alliance | TaxiNodeFlags.Horde)) if (from != null && to != null && from.IsPartOfTaxiNetwork() && to.IsPartOfTaxiNetwork())
AddVerticeAndEdgeFromNodeInfo(from, to, path.Id, edges); AddVerticeAndEdgeFromNodeInfo(from, to, path.Id, edges);
} }
@@ -141,25 +141,30 @@ namespace Game.Entities
else else
{ {
shortestPath.Clear(); shortestPath.Clear();
// We want to use Dijkstra on this graph
DijkstraShortestPath g = new(m_graph, (int)GetVertexIDFromNodeID(from));
var path = g.PathTo((int)GetVertexIDFromNodeID(to));
// found a path to the goal
shortestPath.Add(from.Id);
foreach (var edge in path)
{
//todo test me No clue about this....
var To = m_nodesByVertex[(int)edge.To];
TaxiNodeFlags requireFlag = (player.GetTeam() == Team.Alliance) ? TaxiNodeFlags.Alliance : TaxiNodeFlags.Horde;
if (!To.Flags.HasAnyFlag(requireFlag))
continue;
PlayerConditionRecord condition = CliDB.PlayerConditionStorage.LookupByKey(To.ConditionID); uint fromVertexId = GetVertexIDFromNodeID(from);
if (condition != null) uint toVertexId = GetVertexIDFromNodeID(to);
if (!ConditionManager.IsPlayerMeetingCondition(player, condition)) if (fromVertexId != 0 && toVertexId != 0)
{
// We want to use Dijkstra on this graph
DijkstraShortestPath dijkstra = new(m_graph, (int)fromVertexId);
var path = dijkstra.PathTo((int)toVertexId);
// found a path to the goal
shortestPath.Add(from.Id);
foreach (var edge in path)
{
var To = m_nodesByVertex[(int)edge.To];
TaxiNodeFlags requireFlag = (player.GetTeam() == Team.Alliance) ? TaxiNodeFlags.ShowOnAllianceMap : TaxiNodeFlags.ShowOnHordeMap;
if (!To.GetFlags().HasFlag(requireFlag))
continue; continue;
shortestPath.Add(GetNodeIDFromVertexID(edge.To)); PlayerConditionRecord condition = CliDB.PlayerConditionStorage.LookupByKey(To.ConditionID);
if (condition != null)
if (!ConditionManager.IsPlayerMeetingCondition(player, condition))
continue;
shortestPath.Add(GetNodeIDFromVertexID(edge.To));
}
} }
} }
@@ -169,7 +174,11 @@ namespace Game.Entities
//todo test me //todo test me
public static void GetReachableNodesMask(TaxiNodesRecord from, byte[] mask) public static void GetReachableNodesMask(TaxiNodesRecord from, byte[] mask)
{ {
DepthFirstSearch depthFirst = new(m_graph, GetVertexIDFromNodeID(from), vertex => uint vertexId = GetVertexIDFromNodeID(from);
if (vertexId == 0)
return;
DepthFirstSearch depthFirst = new(m_graph, vertexId, vertex =>
{ {
TaxiNodesRecord taxiNode = CliDB.TaxiNodesStorage.LookupByKey(GetNodeIDFromVertexID(vertex)); TaxiNodesRecord taxiNode = CliDB.TaxiNodesStorage.LookupByKey(GetNodeIDFromVertexID(vertex));
if (taxiNode != null) if (taxiNode != null)
+2 -2
View File
@@ -10398,11 +10398,11 @@ namespace Game
float dist = 10000; float dist = 10000;
uint id = 0; uint id = 0;
TaxiNodeFlags requireFlag = (team == Team.Alliance) ? TaxiNodeFlags.Alliance : TaxiNodeFlags.Horde; TaxiNodeFlags requireFlag = (team == Team.Alliance) ? TaxiNodeFlags.ShowOnAllianceMap : TaxiNodeFlags.ShowOnHordeMap;
foreach (var node in CliDB.TaxiNodesStorage.Values) foreach (var node in CliDB.TaxiNodesStorage.Values)
{ {
var i = node.Id; var i = node.Id;
if (node.ContinentID != mapid || !node.Flags.HasAnyFlag(requireFlag)) if (node.ContinentID != mapid || !node.GetFlags().HasFlag(requireFlag) || node.GetFlags().HasFlag(TaxiNodeFlags.IgnoreForFindNearest))
continue; continue;
uint field = (i - 1) / 8; uint field = (i - 1) / 8;
+16 -6
View File
@@ -750,17 +750,27 @@ namespace Game
TaxiNodesRecord curDestNode = CliDB.TaxiNodesStorage.LookupByKey(curDest); TaxiNodesRecord curDestNode = CliDB.TaxiNodesStorage.LookupByKey(curDest);
// far teleport case // far teleport case
if (curDestNode != null && curDestNode.ContinentID != GetPlayer().GetMapId() && GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight) if (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
{ {
FlightPathMovementGenerator flight = GetPlayer().GetMotionMaster().GetCurrentMovementGenerator() as FlightPathMovementGenerator; FlightPathMovementGenerator flight = GetPlayer().GetMotionMaster().GetCurrentMovementGenerator() as FlightPathMovementGenerator;
if (flight != null) if (flight != null)
{ {
// short preparations to continue flight bool shouldTeleport = curDestNode != null && curDestNode.ContinentID != GetPlayer().GetMapId();
flight.SetCurrentNodeAfterTeleport(); if (!shouldTeleport)
TaxiPathNodeRecord node = flight.GetPath()[(int)flight.GetCurrentNode()]; {
flight.SkipCurrentNode(); var currentNode = flight.GetPath()[(int)flight.GetCurrentNode()];
shouldTeleport = currentNode.Flags.HasFlag(TaxiPathNodeFlags.Teleport);
}
GetPlayer().TeleportTo(curDestNode.ContinentID, node.Loc.X, node.Loc.Y, node.Loc.Z, GetPlayer().GetOrientation()); if (shouldTeleport)
{
// short preparations to continue flight
flight.SetCurrentNodeAfterTeleport();
var node = flight.GetPath()[(int)flight.GetCurrentNode()];
flight.SkipCurrentNode();
GetPlayer().TeleportTo(curDestNode.ContinentID, node.Loc.X, node.Loc.Y, node.Loc.Z, GetPlayer().GetOrientation());
}
} }
} }
@@ -55,7 +55,7 @@ namespace Game.Movement
Vector3 vertice = new(_path[i].Loc.X, _path[i].Loc.Y, _path[i].Loc.Z); Vector3 vertice = new(_path[i].Loc.X, _path[i].Loc.Y, _path[i].Loc.Z);
init.Path().Add(vertice); init.Path().Add(vertice);
} }
init.SetFirstPointId((int)GetCurrentNode()); init.SetFirstPointId((int)GetCurrentNode());
init.SetFly(); init.SetFly();
init.SetSmooth(); init.SetSmooth();
@@ -127,14 +127,17 @@ namespace Game.Movement
owner.Dismount(); owner.Dismount();
owner.RemoveUnitFlag(UnitFlags.RemoveClientControl | UnitFlags.OnTaxi); owner.RemoveUnitFlag(UnitFlags.RemoveClientControl | UnitFlags.OnTaxi);
if (owner.m_taxi.Empty())
// update z position to ground and orientation for landing point
// this prevent cheating with landing point at lags
// when client side flight end early in comparison server side
owner.StopMoving();
// When the player reaches the last flight point, teleport to destination taxi node location
if (!_path.Empty() && (_path.Count < 2 || !_path[_path.Count - 2].Flags.HasFlag(TaxiPathNodeFlags.Teleport)))
{ {
// update z position to ground and orientation for landing point var lastPath = CliDB.TaxiPathStorage.LookupByKey(_path.Last().PathID);
// this prevent cheating with landing point at lags var node = CliDB.TaxiNodesStorage.LookupByKey(lastPath.ToTaxiNode);
// when client side flight end early in comparison server side
owner.StopMoving();
// When the player reaches the last flight point, teleport to destination taxi node location
var node = CliDB.TaxiNodesStorage.LookupByKey(taxiNodeId);
if (node != null) if (node != null)
{ {
owner.SetFallInformation(0, node.Pos.Z); owner.SetFallInformation(0, node.Pos.Z);
@@ -155,6 +158,8 @@ namespace Game.Movement
{ {
if (_path[i].ContinentID != curMapId) if (_path[i].ContinentID != curMapId)
return (uint)i; return (uint)i;
if (i > 0 && _path[i - 1].Flags.HasFlag(TaxiPathNodeFlags.Teleport))
return (uint)i;
} }
return (uint)_path.Count; return (uint)_path.Count;
@@ -162,7 +167,10 @@ namespace Game.Movement
bool IsNodeIncludedInShortenedPath(TaxiPathNodeRecord p1, TaxiPathNodeRecord p2) bool IsNodeIncludedInShortenedPath(TaxiPathNodeRecord p1, TaxiPathNodeRecord p2)
{ {
return p1.ContinentID != p2.ContinentID || Math.Pow(p1.Loc.X - p2.Loc.X, 2) + Math.Pow(p1.Loc.Y - p2.Loc.Y, 2) > (40.0f * 40.0f); return p1.ContinentID != p2.ContinentID
|| MathF.Pow(p1.Loc.X - p2.Loc.X, 2) + MathF.Pow(p1.Loc.Y - p2.Loc.Y, 2) > 40.0f * 40.0f
|| p2.Flags.HasFlag(TaxiPathNodeFlags.Teleport)
|| (p2.Flags.HasFlag(TaxiPathNodeFlags.Stop) && p2.Delay != 0);
} }
public void LoadPath(Player player, uint startNode = 0) public void LoadPath(Player player, uint startNode = 0)
@@ -191,7 +199,8 @@ namespace Game.Movement
if (passedPreviousSegmentProximityCheck || src == 0 || _path.Empty() || IsNodeIncludedInShortenedPath(_path.Last(), nodes[i])) if (passedPreviousSegmentProximityCheck || src == 0 || _path.Empty() || IsNodeIncludedInShortenedPath(_path.Last(), nodes[i]))
{ {
if ((src == 0 || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) && if ((src == 0 || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) &&
(dst == taxi.Count - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.Length - 1))) (dst == taxi.Count - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && (i < nodes.Length - 1 || _path.Empty()))) &&
(!nodes[i].Flags.HasFlag(TaxiPathNodeFlags.Teleport) || _path.Empty() || !_path.Last().Flags.HasFlag(TaxiPathNodeFlags.Teleport))) // skip consecutive teleports, only keep the first one
{ {
passedPreviousSegmentProximityCheck = true; passedPreviousSegmentProximityCheck = true;
_path.Add(nodes[i]); _path.Add(nodes[i]);
@@ -205,7 +214,7 @@ namespace Game.Movement
} }
} }
_pointsForPathSwitch.Add(new TaxiNodeChangeInfo((uint)(_path.Count - 1), (long)Math.Ceiling(cost * discount))); _pointsForPathSwitch.Add(new TaxiNodeChangeInfo((uint)(Math.Max(_path.Count, 1) - 1), (long)Math.Ceiling(cost * discount)));
} }
} }
@@ -217,7 +226,7 @@ namespace Game.Movement
uint map0 = _path[_currentNode].ContinentID; uint map0 = _path[_currentNode].ContinentID;
for (int i = _currentNode + 1; i < _path.Count; ++i) for (int i = _currentNode + 1; i < _path.Count; ++i)
{ {
if (_path[i].ContinentID != map0) if (_path[i].ContinentID != map0 || _path[i - 1].Flags.HasFlag(TaxiPathNodeFlags.Teleport))
{ {
_currentNode = i; _currentNode = i;
return; return;
@@ -277,13 +286,13 @@ namespace Game.Movement
return _path[index].PathID; return _path[index].PathID;
} }
public override string GetDebugInfo() public override string GetDebugInfo()
{ {
return $"Current Node: {GetCurrentNode()}\n{base.GetDebugInfo()}\nStart Path Id: {GetPathId(0)} Path Size: {_path.Count} HasArrived: {HasArrived()} End Grid X: {_endGridX} " + return $"Current Node: {GetCurrentNode()}\n{base.GetDebugInfo()}\nStart Path Id: {GetPathId(0)} Path Size: {_path.Count} HasArrived: {HasArrived()} End Grid X: {_endGridX} " +
$"End Grid Y: {_endGridY} End Map Id: {_endMapId} Preloaded Target Node: {_preloadTargetNode}"; $"End Grid Y: {_endGridY} End Map Id: {_endMapId} Preloaded Target Node: {_preloadTargetNode}";
} }
public override bool GetResetPosition(Unit u, out float x, out float y, out float z) public override bool GetResetPosition(Unit u, out float x, out float y, out float z)
{ {
var node = _path[_currentNode]; var node = _path[_currentNode];