summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Lutz <michi@icosahedron.de>2019-03-10 09:12:47 +0100
committerPeterN <peter@fuzzle.org>2019-03-10 08:12:47 +0000
commitcc5f17561571b45b52e7406fb66051446f8cceb4 (patch)
tree2d5f5d0ffd8fd9495b0f82ae3b46196c9f38e192
parent26b0615c476039c43b4a845c6b01d590d1fb20dd (diff)
downloadopenttd-cc5f17561571b45b52e7406fb66051446f8cceb4.tar.xz
Feature: Railtype flags to allow/disallow 90 degree curves. (#7352)
-rw-r--r--src/pathfinder/follow_track.hpp2
-rw-r--r--src/pathfinder/npf/npf.cpp13
-rw-r--r--src/pbs.cpp4
-rw-r--r--src/rail.h25
-rw-r--r--src/train_cmd.cpp14
5 files changed, 43 insertions, 15 deletions
diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp
index acdff68a7..2bbad8d70 100644
--- a/src/pathfinder/follow_track.hpp
+++ b/src/pathfinder/follow_track.hpp
@@ -157,7 +157,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 d7722ae67..32c6e982d 100644
--- a/src/pathfinder/npf/npf.cpp
+++ b/src/pathfinder/npf/npf.cpp
@@ -803,12 +803,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));
@@ -836,7 +837,9 @@ 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) trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);
+ if (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);
@@ -877,7 +880,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
if (CheckIgnoreFirstTile(&current->path)) {
/* 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);
@@ -901,7 +904,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 */
@@ -910,7 +913,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 eec87bfb3..ac5805d09 100644
--- a/src/rail.h
+++ b/src/rail.h
@@ -21,6 +21,7 @@
#include "strings_type.h"
#include "date_type.h"
#include "signal_type.h"
+#include "settings_type.h"
/** Railtype flags. */
enum RailTypeFlags {
@@ -28,12 +29,16 @@ enum RailTypeFlags {
RTF_NO_LEVEL_CROSSING = 1, ///< Bit number for disallowing level crossings.
RTF_HIDDEN = 2, ///< Bit number for hiding from selection.
RTF_NO_SPRITE_COMBINE = 3, ///< Bit number for using non-combined junctions.
+ RTF_ALLOW_90DEG = 4, ///< Bit number for always allowed 90 degree turns, regardless of setting.
+ RTF_DISALLOW_90DEG = 5, ///< Bit number for never allowed 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_HIDDEN = 1 << RTF_HIDDEN, ///< Value for hiding from selection.
RTFB_NO_SPRITE_COMBINE = 1 << RTF_NO_SPRITE_COMBINE, ///< Value for using non-combined junctions.
+ 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 never allowed 90 degree turns, regardless of setting.
};
DECLARE_ENUM_AS_BIT_SET(RailTypeFlags)
@@ -342,6 +347,26 @@ static inline bool RailNoLevelCrossings(RailType rt)
}
/**
+ * Test if 90 degree turns are disallowed 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 disallowed 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.
* @return The cost multiplier.
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index 29b2e543e..9f17bd898 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);
@@ -2339,7 +2339,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;
}
@@ -2391,7 +2391,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);
}
@@ -2626,7 +2626,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));
}
@@ -2718,7 +2718,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);
@@ -3139,7 +3139,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));
@@ -3711,7 +3711,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));
}