Skip to content

Instantly share code, notes, and snippets.

@michicc
Last active August 12, 2018 10:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michicc/8d16426de023d015ce4f16d85d77a606 to your computer and use it in GitHub Desktop.
Save michicc/8d16426de023d015ce4f16d85d77a606 to your computer and use it in GitHub Desktop.
Railtype flag for 90 deg curves.
From 58b42eaa40c6ec8a242ba64054f50c31d62a9e3e Mon Sep 17 00:00:00 2001
From: Michael Lutz <michi@icosahedron.de>
Date: Sat, 28 Jul 2018 18:07:41 +0200
Subject: Feature: Railtype flags to allow/disallow 90 degree curves.
---
src/pathfinder/follow_track.hpp | 2 +-
src/pathfinder/npf/npf.cpp | 14 +++++++++-----
src/pbs.cpp | 4 ++--
src/rail.h | 25 +++++++++++++++++++++++++
src/train_cmd.cpp | 14 +++++++-------
5 files changed, 44 insertions(+), 15 deletions(-)
diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp
index 70f148de3..fd431a49b 100644
--- a/src/pathfinder/follow_track.hpp
+++ b/src/pathfinder/follow_track.hpp
@@ -153,7 +153,7 @@ struct CFollowTrackT
return false;
}
- if (!Allow90degTurns()) {
+ if ((!IsRailTT() && !Allow90degTurns()) || (IsRailTT() && Rail90DegTurnDisallowed(GetTileRailType(m_old_tile), GetTileRailType(m_new_tile), !Allow90degTurns()))) {
m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td);
if (m_new_td_bits == TRACKDIR_BIT_NONE) {
m_err = EC_90DEG;
diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp
index 3218d8314..211a1f7b7 100644
--- a/src/pathfinder/npf/npf.cpp
+++ b/src/pathfinder/npf/npf.cpp
@@ -798,12 +798,13 @@ static bool CanEnterTile(TileIndex tile, DiagDirection dir, AyStarUserData *user
* One-way-roads are taken into account. Signals are not tested.
*
* @param dst_tile The tile of interest.
+ * @param src_tile The originating tile.
* @param src_trackdir The direction the vehicle is currently moving.
* @param type The transporttype of the vehicle.
* @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle.
* @return The Trackdirs the vehicle can continue moving on.
*/
-static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_trackdir, TransportType type, uint subtype)
+static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, TileIndex src_tile, Trackdir src_trackdir, TransportType type, uint subtype)
{
TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, type, subtype));
@@ -831,7 +832,10 @@ static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_tr
trackdirbits &= TrackdirReachesTrackdirs(src_trackdir);
/* Filter out trackdirs that would make 90 deg turns for trains */
- if (_settings_game.pf.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);
+ if ((type == TRANSPORT_WATER && _settings_game.pf.forbid_90_deg) ||
+ (type == TRANSPORT_RAIL && Rail90DegTurnDisallowed(GetTileRailType(src_tile), GetTileRailType(dst_tile)))) {
+ trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);
+ }
DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits);
@@ -874,7 +878,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
if (ignore_src_tile) {
/* Do not perform any checks that involve src_tile */
dst_tile = src_tile + TileOffsByDiagDir(src_exitdir);
- trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
+ trackdirbits = GetDriveableTrackdirBits(dst_tile, src_tile, src_trackdir, type, subtype);
} else if (IsTileType(src_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(src_tile) == src_exitdir) {
/* We drive through the wormhole and arrive on the other side */
dst_tile = GetOtherTunnelBridgeEnd(src_tile);
@@ -898,7 +902,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
src_trackdir = ReverseTrackdir(src_trackdir);
}
- trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
+ trackdirbits = GetDriveableTrackdirBits(dst_tile, src_tile, src_trackdir, type, subtype);
if (trackdirbits == TRACKDIR_BIT_NONE) {
/* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */
@@ -907,7 +911,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
dst_tile = src_tile;
src_trackdir = ReverseTrackdir(src_trackdir);
- trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
+ trackdirbits = GetDriveableTrackdirBits(dst_tile, src_tile, src_trackdir, type, subtype);
}
}
diff --git a/src/pbs.cpp b/src/pbs.cpp
index 6bb35a696..44b5b069b 100644
--- a/src/pbs.cpp
+++ b/src/pbs.cpp
@@ -400,7 +400,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
/* Check for reachable tracks. */
ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
- if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
+ if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile), forbid_90deg)) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) return include_line_end;
if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
@@ -445,7 +445,7 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo
/* Check for reachable tracks. */
ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
- if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
+ if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile), forbid_90deg)) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
return !HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits));
}
diff --git a/src/rail.h b/src/rail.h
index 1bc403d7f..245ba67c4 100644
--- a/src/rail.h
+++ b/src/rail.h
@@ -21,15 +21,20 @@
#include "strings_type.h"
#include "date_type.h"
#include "signal_type.h"
+#include "settings_type.h"
/** Railtype flags. */
enum RailTypeFlags {
RTF_CATENARY = 0, ///< Bit number for drawing a catenary.
RTF_NO_LEVEL_CROSSING = 1, ///< Bit number for disallowing level crossings.
+ RTF_ALLOW_90DEG = 2, ///< Bit number for always allowed 90 degree turns, regardless of setting.
+ RTF_DISALLOW_90DEG = 3, ///< Bit number for always disallowed 90 degree turns, regardless of setting.
RTFB_NONE = 0, ///< All flags cleared.
RTFB_CATENARY = 1 << RTF_CATENARY, ///< Value for drawing a catenary.
RTFB_NO_LEVEL_CROSSING = 1 << RTF_NO_LEVEL_CROSSING, ///< Value for disallowing level crossings.
+ RTFB_ALLOW_90DEG = 1 << RTF_ALLOW_90DEG, ///< Value for always allowed 90 degree turns, regardless of setting.
+ RTFB_DISALLOW_90DEG = 1 << RTF_DISALLOW_90DEG, ///< Value for always allowed 90 degree turns, regardless of setting.
};
DECLARE_ENUM_AS_BIT_SET(RailTypeFlags)
@@ -336,6 +341,26 @@ static inline bool RailNoLevelCrossings(RailType rt)
return HasBit(GetRailTypeInfo(rt)->flags, RTF_NO_LEVEL_CROSSING);
}
+/**
+ * Test if 90 degree turns are allowed between two railtypes.
+ * @param rt1 First railtype to test for.
+ * @param rt2 Second railtype to test for.
+ * @param def Default value to use if the rail type doesn't specify anything.
+ * @return True if 90 degree turns are allowed between the two rail types.
+ */
+static inline bool Rail90DegTurnDisallowed(RailType rt1, RailType rt2, bool def = _settings_game.pf.forbid_90_deg)
+{
+ if (rt1 == INVALID_RAILTYPE || rt2 == INVALID_RAILTYPE) return def;
+
+ const RailtypeInfo *rti1 = GetRailTypeInfo(rt1);
+ const RailtypeInfo *rti2 = GetRailTypeInfo(rt2);
+
+ bool rt1_90deg = HasBit(rti1->flags, RTF_DISALLOW_90DEG) || (!HasBit(rti1->flags, RTF_ALLOW_90DEG) && def);
+ bool rt2_90deg = HasBit(rti2->flags, RTF_DISALLOW_90DEG) || (!HasBit(rti2->flags, RTF_ALLOW_90DEG) && def);
+
+ return rt1_90deg || rt2_90deg;
+}
+
/**
* Returns the cost of building the specified railtype.
* @param railtype The railtype being built.
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index 60a7b2ca9..8bb146e2c 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -2100,7 +2100,7 @@ static void CheckNextTrainTile(Train *v)
if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) {
/* If the next tile is a PBS signal, try to make a reservation. */
TrackBits tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits);
- if (_settings_game.pf.forbid_90_deg) {
+ if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile))) {
tracks &= ~TrackCrossesTracks(TrackdirToTrack(ft.m_old_td));
}
ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, NULL, false);
@@ -2341,7 +2341,7 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks,
if (HasOnewaySignalBlockingTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) break;
}
- if (_settings_game.pf.forbid_90_deg) {
+ if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile))) {
ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(ft.m_old_td);
if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) break;
}
@@ -2393,7 +2393,7 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks,
while (tile != stopped || cur_td != stopped_td) {
if (!ft.Follow(tile, cur_td)) break;
- if (_settings_game.pf.forbid_90_deg) {
+ if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile))) {
ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(ft.m_old_td);
assert(ft.m_new_td_bits != TRACKDIR_BIT_NONE);
}
@@ -2628,7 +2628,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir,
DiagDirection exitdir = TrackdirToExitdir(res_dest.trackdir);
TileIndex next_tile = TileAddByDiagDir(res_dest.tile, exitdir);
TrackBits reachable = TrackdirBitsToTrackBits((TrackdirBits)(GetTileTrackStatus(next_tile, TRANSPORT_RAIL, 0))) & DiagdirReachesTracks(exitdir);
- if (_settings_game.pf.forbid_90_deg) {
+ if (Rail90DegTurnDisallowed(GetTileRailType(res_dest.tile), GetTileRailType(next_tile))) {
reachable &= ~TrackCrossesTracks(TrackdirToTrack(res_dest.trackdir));
}
@@ -2720,7 +2720,7 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
TileIndex new_tile = TileAddByDiagDir(origin.tile, exitdir);
TrackBits reachable = TrackdirBitsToTrackBits(TrackStatusToTrackdirBits(GetTileTrackStatus(new_tile, TRANSPORT_RAIL, 0)) & DiagdirReachesTrackdirs(exitdir));
- if (_settings_game.pf.forbid_90_deg) reachable &= ~TrackCrossesTracks(TrackdirToTrack(origin.trackdir));
+ if (Rail90DegTurnDisallowed(GetTileRailType(origin.tile), GetTileRailType(new_tile))) reachable &= ~TrackCrossesTracks(TrackdirToTrack(origin.trackdir));
bool res_made = false;
ChooseTrainTrack(v, new_tile, exitdir, reachable, true, &res_made, mark_as_stuck);
@@ -3141,7 +3141,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs);
TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
- if (_settings_game.pf.forbid_90_deg && prev == NULL) {
+ if (Rail90DegTurnDisallowed(GetTileRailType(gp.old_tile), GetTileRailType(gp.new_tile)) && prev == NULL) {
/* We allow wagons to make 90 deg turns, because forbid_90_deg
* can be switched on halfway a turn */
bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
@@ -3713,7 +3713,7 @@ static bool TrainCheckIfLineEnds(Train *v, bool reverse)
/* mask unreachable track bits if we are forbidden to do 90deg turns */
TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
- if (_settings_game.pf.forbid_90_deg) {
+ if (Rail90DegTurnDisallowed(GetTileRailType(v->tile), GetTileRailType(tile))) {
bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
}
--
2.17.0
@jcoletto77
Copy link

Tried this, but generated s crash when a train was leaving the station. I sent the crash report to @michicc

-Snail

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment