diff --git a/docs/landscape.html b/docs/landscape.html
index 86d0b8057d..b488c0dc1c 100644
--- a/docs/landscape.html
+++ b/docs/landscape.html
@@ -1473,10 +1473,76 @@
+
m2 bits 2..0: rail bridge heads track reserved for pbs
+
+
+ 0 |
+ not reserved |
+
+
+ 1 |
+ X direction |
+
+
+ 2 |
+ Y direction |
+
+
+ 3 |
+ north corner (W-E) |
+
+
+ 4 |
+ south corner (W-E) |
+
+
+ 5 |
+ west corner (N-S) |
+
+
+ 6 |
+ east corner (N-S) |
+
+
+
+ m2 bit 3: rail bridge heads opposite track is reserved, too
m3 bits 7..4: owner of tram
m3 bits 3..0: track type for railway
- m5 bit 4: pbs reservation state for railway
- m5 bits 7 clear: tunnel entrance/exit
+ m4 bits 5..0: rail bridge heads track layout: bit set = track present:
+
+
+ bit 0: |
+ in the X direction |
+
+
+
+ bit 1: |
+ in the Y direction |
+
+
+
+ bit 2: |
+ in the north corner (direction W-E) |
+
+
+
+ bit 3: |
+ in the south corner (direction W-E) |
+
+
+
+ bit 4: |
+ in the west corner (direction N-S) |
+
+
+
+ bit 5: |
+ in the east corner (direction N-S) |
+
+
+
+ m5 bit 4: pbs reservation state for railway (tunnel only)
+ m5 bit 7 clear: tunnel entrance/exit
m5 bit 7 set: bridge ramp
- m6 bits 5..2: bridge type:
diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html
index 3ba984d5d8..4ef88f0f00 100644
--- a/docs/landscape_grid.html
+++ b/docs/landscape_grid.html
@@ -347,7 +347,7 @@ the array so you can quickly see what is used and what is not.
-inherit- |
OOOO OOOO PPPP PPPP |
-inherit- |
- -inherit- |
+ OOPP PPPP |
-inherit- |
OOXX XXOO |
-inherit- |
diff --git a/src/bridge_map.h b/src/bridge_map.h
index 9a384ceca7..3e4a09024f 100644
--- a/src/bridge_map.h
+++ b/src/bridge_map.h
@@ -171,9 +171,22 @@ static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Ow
* @param d the direction this ramp must be facing
* @param r the rail type of the bridge
*/
-static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, RailType r)
+static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, RailType r, bool upgrade)
{
+ // Backup custom bridgehead data.
+ uint custom_bridge_head_reservation_backup = GB(_m[t].m2, 0, 4);
+ uint custom_bridge_head_tracks_backup = GB(_m[t].m4, 0, 6);
+
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL, r);
+
+ if (upgrade) {
+ // Restore custom bridgehead data if we're upgrading an existing bridge.
+ SB(_m[t].m2, 0, 4, custom_bridge_head_reservation_backup);
+ SB(_m[t].m4, 0, 6, custom_bridge_head_tracks_backup);
+ } else {
+ // Set bridge head tracks to axial track only.
+ SB(_m[t].m4, 0, 6, DiagDirToDiagTrackBits(d));
+ }
}
/**
@@ -255,4 +268,195 @@ static inline void SetCustomBridgeHeadRoadBits(TileIndex t, RoadType rt, RoadBit
}
}
+/**
+ * Checks if this tile is a rail bridge head
+ * @param t The tile to analyze
+ * @return true if it is a rail bridge head
+ */
+static inline bool IsRailBridgeHeadTile(TileIndex t)
+{
+ return IsBridgeTile(t) && (TransportType)GB(_m[t].m5, 2, 2) == TRANSPORT_RAIL;
+}
+
+/**
+ * Checks if this tile is a flat rail bridge head
+ * @param t The tile to analyze
+ * @return true if it is a flat rail bridge head
+ */
+static inline bool IsFlatRailBridgeHeadTile(TileIndex t)
+{
+ return IsRailBridgeHeadTile(t) && HasBridgeFlatRamp(GetTileSlope(t), DiagDirToAxis((DiagDirection)GB(_m[t].m5, 0, 2)));
+}
+
+/**
+ * Returns the track bits for a (possibly custom) rail bridge head
+ * @param tile the tile to get the track bits from
+ * @pre IsRailBridgeHeadTile(t)
+ * @return road bits for the bridge head
+ */
+static inline TrackBits GetCustomBridgeHeadTrackBits(TileIndex t)
+{
+ assert(IsRailBridgeHeadTile(t));
+ return (TrackBits)GB(_m[t].m4, 0, 6);
+}
+
+/**
+ * Sets the road track for a (possibly custom) rail bridge head
+ * @param t the tile to set the track bits of
+ * @param b the new track bits for the tile
+ * @pre IsRailBridgeHeadTile(t)
+ */
+static inline void SetCustomBridgeHeadTrackBits(TileIndex t, TrackBits b)
+{
+ assert(IsRailBridgeHeadTile(t));
+ SB(_m[t].m4, 0, 6, b);
+}
+
+/**
+ * Checks if this rail bridge head is a custom bridge head
+ * @param t The tile to analyze
+ * @pre IsRailBridgeHeadTile(t)
+ * @return true if it is a custom bridge head
+ */
+static inline bool IsRailCustomBridgeHead(TileIndex t)
+{
+ assert(IsRailBridgeHeadTile(t));
+ return GetCustomBridgeHeadTrackBits(t) != DiagDirToDiagTrackBits((DiagDirection)GB(_m[t].m5, 0, 2));
+}
+
+/**
+ * Checks if this tile is a rail bridge head with a custom bridge head
+ * @param t The tile to analyze
+ * @return true if it is a rail bridge head with a custom bridge head
+ */
+static inline bool IsRailCustomBridgeHeadTile(TileIndex t)
+{
+ return IsRailBridgeHeadTile(t) && IsRailCustomBridgeHead(t);
+}
+
+/**
+ * Checks if this tile is a bridge head with a custom bridge head
+ * @param t The tile to analyze
+ * @return true if it is a bridge head with a custom bridge head
+ */
+static inline bool IsCustomBridgeHeadTile(TileIndex t)
+{
+ return IsRailCustomBridgeHeadTile(t) || IsRoadCustomBridgeHeadTile(t);
+}
+
+/**
+ * Get the reserved track bits for a rail bridge head
+ * @pre IsRailBridgeHeadTile(t)
+ * @param t the tile
+ * @return reserved track bits
+ */
+static inline TrackBits GetBridgeReservationTrackBits(TileIndex t)
+{
+ assert(IsRailBridgeHeadTile(t));
+ byte track_b = GB(_m[t].m2, 0, 3);
+ Track track = (Track)(track_b - 1); // map array saves Track+1
+ if (track_b == 0) return TRACK_BIT_NONE;
+ return (TrackBits)(TrackToTrackBits(track) | (HasBit(_m[t].m2, 3) ? TrackToTrackBits(TrackToOppositeTrack(track)) : 0));
+}
+
+/**
+ * Sets the reserved track bits of the rail bridge head
+ * @pre IsRailBridgeHeadTile(t)
+ * @param t the tile to change
+ * @param b the track bits
+ */
+static inline void SetBridgeReservationTrackBits(TileIndex t, TrackBits b)
+{
+ assert(IsRailBridgeHeadTile(t));
+ assert(!TracksOverlap(b));
+ Track track = RemoveFirstTrack(&b);
+ SB(_m[t].m2, 0, 3, track == INVALID_TRACK ? 0 : track + 1);
+ SB(_m[t].m2, 3, 1, (byte)(b != TRACK_BIT_NONE));
+}
+
+
+/**
+ * Try to reserve a specific track on a rail bridge head tile
+ * @pre IsRailBridgeHeadTile(t) && HasBit(GetCustomBridgeHeadTrackBits(tile), t)
+ * @param tile the tile
+ * @param t the rack to reserve
+ * @return true if successful
+ */
+static inline bool TryReserveRailBridgeHead(TileIndex tile, Track t)
+{
+ assert(IsRailBridgeHeadTile(tile));
+ assert(HasBit(GetCustomBridgeHeadTrackBits(tile), t));
+ TrackBits bits = TrackToTrackBits(t);
+ TrackBits res = GetBridgeReservationTrackBits(tile);
+ if ((res & bits) != TRACK_BIT_NONE) return false; // already reserved
+ res |= bits;
+ if (TracksOverlap(res)) return false; // crossing reservation present
+ SetBridgeReservationTrackBits(tile, res);
+ return true;
+}
+
+
+/**
+ * Lift the reservation of a specific track on a rail bridge head tile
+ * @pre IsRailBridgeHeadTile(t) && HasBit(GetCustomBridgeHeadTrackBits(tile), t)
+ * @param tile the tile
+ * @param t the track to free
+ */
+static inline void UnreserveRailBridgeHeadTrack(TileIndex tile, Track t)
+{
+ assert(IsRailBridgeHeadTile(tile));
+ assert(HasBit(GetCustomBridgeHeadTrackBits(tile), t));
+ TrackBits res = GetBridgeReservationTrackBits(tile);
+ res &= ~TrackToTrackBits(t);
+ SetBridgeReservationTrackBits(tile, res);
+}
+
+/**
+ * Get the possible track bits of the bridge head tile onto/across the bridge
+ * @pre IsRailBridgeHeadTile(t)
+ * @param t the tile
+ * @return reservation state
+ */
+static inline TrackBits GetAcrossBridgePossibleTrackBits(TileIndex t)
+{
+ assert(IsRailBridgeHeadTile(t));
+ return DiagdirReachesTracks(ReverseDiagDir((DiagDirection)GB(_m[t].m5, 0, 2)));
+}
+
+/**
+ * Get the reserved track bits of the bridge head tile onto/across the bridge
+ * @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
+ * @param t the tile
+ * @return reservation state
+ */
+static inline TrackBits GetAcrossBridgeReservationTrackBits(TileIndex t)
+{
+ return GetBridgeReservationTrackBits(t) & GetAcrossBridgePossibleTrackBits(t);
+}
+
+/**
+ * Get the reservation state of the bridge head tile onto/across the bridge
+ * @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
+ * @param t the tile
+ * @return reservation state
+ */
+static inline bool HasAcrossBridgeReservation(TileIndex t)
+{
+ return GetAcrossBridgeReservationTrackBits(t) != TRACK_BIT_NONE;
+}
+
+/**
+ * Lift the reservation of a specific track on a rail bridge head tile
+ * @pre IsRailBridgeHeadTile(t)
+ * @param tile the tile
+ */
+static inline void UnreserveAcrossRailBridgeHead(TileIndex tile)
+{
+ assert(IsRailBridgeHeadTile(tile));
+ TrackBits res = GetAcrossBridgeReservationTrackBits(tile);
+ if (res != TRACK_BIT_NONE) {
+ SetBridgeReservationTrackBits(tile, GetBridgeReservationTrackBits(tile) & ~res);
+ }
+}
+
#endif /* BRIDGE_MAP_H */
diff --git a/src/elrail.cpp b/src/elrail.cpp
index ac36161617..7ca7c14357 100644
--- a/src/elrail.cpp
+++ b/src/elrail.cpp
@@ -103,7 +103,7 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
if (override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) {
*override = 1 << GetTunnelBridgeDirection(t);
}
- return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
+ return GetTunnelBridgeTrackBits(t);
case MP_ROAD:
if (!IsLevelCrossing(t)) return TRACK_BIT_NONE;
@@ -199,6 +199,8 @@ static void AdjustTileh(TileIndex tile, Slope *tileh)
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
if (IsTunnel(tile)) {
*tileh = SLOPE_STEEP; // XXX - Hack to make tunnel entrances to always have a pylon
+ } else if (IsRailCustomBridgeHeadTile(tile)) {
+ /* no change */
} else if (*tileh != SLOPE_FLAT) {
*tileh = SLOPE_FLAT;
} else {
diff --git a/src/landscape.cpp b/src/landscape.cpp
index e71e69b659..35149b7a9f 100644
--- a/src/landscape.cpp
+++ b/src/landscape.cpp
@@ -352,7 +352,7 @@ Slope GetFoundationSlope(TileIndex tile, int *z)
bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
{
- if (IsRoadCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NW) return false;
+ if (IsCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NW) return false;
int z;
@@ -371,7 +371,7 @@ bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
{
- if (IsRoadCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NE) return false;
+ if (IsCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NE) return false;
int z;
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 55ea34bae0..49ec13d859 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -1703,6 +1703,8 @@ STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Allow trains to
STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS :Enable road custom bridge heads: {STRING2}
STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS_HELPTEXT :Allow road bridges to have custom, non-straight flat entry/exit tiles
+STR_CONFIG_SETTING_ENABLE_RAIL_CUSTOM_BRIDGE_HEADS :Enable rail custom bridge heads: {STRING2}
+STR_CONFIG_SETTING_ENABLE_RAIL_CUSTOM_BRIDGE_HEADS_HELPTEXT :Allow rail bridges to have custom, non-straight flat entry/exit tiles
STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Change setting value
diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp
index cd5dad7b47..8bc36eabe2 100644
--- a/src/newgrf_station.cpp
+++ b/src/newgrf_station.cpp
@@ -209,7 +209,7 @@ static uint32 GetRailContinuationInfo(TileIndex tile)
/* With tunnels and bridges the tile has tracks, but they are not necessarily connected
* with the next tile because the ramp is not going in the right direction. */
- if (IsTileType(neighbour_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(neighbour_tile) != *diagdir) {
+ if (IsTileType(neighbour_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(neighbour_tile) == ReverseDiagDir(*diagdir)) {
continue;
}
diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp
index b1c7bfaec4..0fdcf43c7f 100644
--- a/src/pathfinder/follow_track.hpp
+++ b/src/pathfinder/follow_track.hpp
@@ -125,7 +125,7 @@ struct CFollowTrackT
m_old_td = old_td;
m_err = EC_NONE;
assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)) & TrackdirToTrackdirBits(m_old_td)) != 0) ||
- (IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR)); // Disable the assertion for single tram bits
+ (IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR) || (IsRailTT() && IsRailCustomBridgeHeadTile(m_old_tile))); // Disable the assertion for single tram bits
m_exitdir = TrackdirToExitdir(m_old_td);
if (ForcedReverse()) return true;
if (!CanExitOldTile()) return false;
@@ -153,7 +153,7 @@ struct CFollowTrackT
return false;
}
- if (!Allow90degTurns()) {
+ if (!Allow90degTurns() && m_tiles_skipped == 0) {
m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td);
if (m_new_td_bits == TRACKDIR_BIT_NONE) {
m_err = EC_90DEG;
@@ -216,7 +216,7 @@ protected:
m_tiles_skipped = GetTunnelBridgeLength(m_new_tile, m_old_tile);
return;
}
- if (!IsRoadCustomBridgeHeadTile(m_old_tile)) assert(ReverseDiagDir(enterdir) == m_exitdir);
+ if (!IsRoadCustomBridgeHeadTile(m_old_tile) && !IsRailCustomBridgeHeadTile(m_old_tile)) assert(ReverseDiagDir(enterdir) == m_exitdir);
}
/* normal or station tile, do one step */
@@ -365,13 +365,22 @@ protected:
}
}
} else { // IsBridge(m_new_tile)
+ DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile);
+ if (!m_is_bridge && ramp_enderdir == ReverseDiagDir(m_exitdir)) {
+ m_err = EC_NO_WAY;
+ return false;
+ }
if (!m_is_bridge && IsRoadTT() && IsRoadCustomBridgeHeadTile(m_new_tile)) {
if (!(DiagDirToRoadBits(ReverseDiagDir(m_exitdir)) & GetCustomBridgeHeadRoadBits(m_new_tile, IsTram() ? ROADTYPE_TRAM : ROADTYPE_ROAD))) {
m_err = EC_NO_WAY;
return false;
}
+ } else if (!m_is_bridge && IsRailTT() && IsRailCustomBridgeHeadTile(m_new_tile)) {
+ if (!(DiagdirReachesTracks(m_exitdir) & GetCustomBridgeHeadTrackBits(m_new_tile))) {
+ m_err = EC_NO_WAY;
+ return false;
+ }
} else if (!m_is_bridge) {
- DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile);
if (ramp_enderdir != m_exitdir) {
m_err = EC_NO_WAY;
return false;
diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp
index 5324e4fc87..d52196b674 100644
--- a/src/pathfinder/yapf/yapf_rail.cpp
+++ b/src/pathfinder/yapf/yapf_rail.cpp
@@ -564,7 +564,7 @@ bool YapfTrainCheckReverse(const Train *v)
int reverse_penalty = 0;
- if (v->track == TRACK_BIT_WORMHOLE) {
+ if (v->track & TRACK_BIT_WORMHOLE) {
/* front in tunnel / on bridge */
DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
@@ -579,7 +579,7 @@ bool YapfTrainCheckReverse(const Train *v)
reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH;
}
- if (last_veh->track == TRACK_BIT_WORMHOLE) {
+ if (last_veh->track & TRACK_BIT_WORMHOLE) {
/* back in tunnel / on bridge */
DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
diff --git a/src/pbs.cpp b/src/pbs.cpp
index 133293909f..07de814d3c 100644
--- a/src/pbs.cpp
+++ b/src/pbs.cpp
@@ -81,7 +81,8 @@ void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool
*/
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
{
- assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0);
+ assert_msg((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & TrackToTrackBits(t)) != 0,
+ "%X, %X, %X, %X", TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)), tile, t, TrackToTrackBits(t));
if (_settings_client.gui.show_track_reservation) {
/* show the reserved rail if needed */
@@ -123,9 +124,14 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
break;
case MP_TUNNELBRIDGE:
- if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) {
- SetTunnelBridgeReservation(tile, true);
- return true;
+ if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
+ if (IsTunnel(tile) && !HasTunnelReservation(tile)) {
+ SetTunnelReservation(tile, true);
+ return true;
+ }
+ if (IsBridge(tile)) {
+ return TryReserveRailBridgeHead(tile, t);
+ }
}
break;
@@ -177,7 +183,13 @@ void UnreserveRailTrack(TileIndex tile, Track t)
break;
case MP_TUNNELBRIDGE:
- if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) SetTunnelBridgeReservation(tile, false);
+ if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
+ if (IsTunnel(tile)) {
+ SetTunnelReservation(tile, false);
+ } else {
+ UnreserveRailBridgeHeadTrack(tile, t);
+ }
+ }
break;
default:
@@ -270,7 +282,7 @@ static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
Train *t = Train::From(v);
- if (t->track == TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) {
+ if (t->track & TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) {
t = t->First();
/* ALWAYS return the lowest ID (anti-desync!) */
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
index a5face14c5..2b1dbb4a0e 100644
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -424,6 +424,25 @@ static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits ex
return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
}
+bool IsValidFlatRailBridgeHeadTrackBits(Slope normalised_slope, DiagDirection bridge_direction, TrackBits tracks)
+{
+ /* bridge_direction c1 c2
+ * 0 0 1
+ * 1 0 3
+ * 2 2 3
+ * 3 2 1
+ */
+ const Corner c1 = (Corner) (bridge_direction & 2);
+ const Corner c2 = (Corner) (((bridge_direction + 1) & 2) + 1);
+ auto test_corner = [&](Corner c) -> bool {
+ if (normalised_slope & SlopeWithOneCornerRaised(c)) return true;
+ Slope effective_slope = normalised_slope | SlopeWithOneCornerRaised(OppositeCorner(c));
+ assert(effective_slope < lengthof(_valid_tracks_on_leveled_foundation));
+ return (_valid_tracks_on_leveled_foundation[effective_slope] & tracks) == tracks;
+ };
+ return test_corner(c1) && test_corner(c2);
+}
+
/* Validate functions for rail building */
static inline bool ValParamTrackOrientation(Track track)
{
@@ -443,6 +462,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
{
RailType railtype = Extract(p1);
Track track = Extract