From 7b9e5dc4e043427f8f7600441e18bb00ff8bfeb2 Mon Sep 17 00:00:00 2001 From: John Taylor Date: Fri, 21 Mar 2025 15:31:51 +0100 Subject: [PATCH 1/4] Fix #11528: Added possibility to build tracks through bridges/tunnels without laying unnecessary pieces. --- src/rail_cmd.cpp | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 97a775940d..c21a305bd0 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -886,22 +886,40 @@ static CommandCost CmdRailTrackHelper(DoCommandFlags flags, TileIndex tile, Tile if (ret.Failed()) return ret; bool had_success = false; + bool redundant_track = false; + bool skip = false; + bool first_tile = true; CommandCost last_error = CMD_ERROR; for (;;) { - ret = remove ? Command::Do(flags, tile, TrackdirToTrack(trackdir)) : Command::Do(flags, tile, railtype, TrackdirToTrack(trackdir), auto_remove_signals); - - if (ret.Failed()) { - last_error = std::move(ret); - if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) { - if (fail_on_obstacle) return last_error; - if (had_success) break; // Keep going if we haven't constructed any rail yet, skipping the start of the drag + /* Check if hopping bridge/tunnel (#11528). */ + if (IsDiagonalTrackdir(trackdir) && GetTileType(tile) == MP_TUNNELBRIDGE && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { + /* If the building direction is the same as the bridge/tunnel direction, skip building tracks until the bridge/tunnel ends. */ + if (GetTunnelBridgeDirection(tile) == TrackdirToExitdir(trackdir)) { + redundant_track = true; // Either above tunnel or below bridge and perpendicular, which means unnecessary to build. + skip = true; + } else if (redundant_track) { + redundand_track = false; // The tunnel/bridge has ended, the next track should be built. + } else if (!first_tile && GetTunnelBridgeDirection(tile) == TrackdirToExitdir(ReverseTrackdir(trackdir))) { + break; // Upon running into a bridge ramp from the underside, we should stop building tracks. } + } - /* Ownership errors are more important. */ - if (last_error.GetErrorMessage() == STR_ERROR_OWNED_BY && remove) break; - } else { - had_success = true; - total_cost.AddCost(ret.GetCost()); + if (!skip) { + ret = remove ? Command::Do(flags, tile, TrackdirToTrack(trackdir)) : Command::Do(flags, tile, railtype, TrackdirToTrack(trackdir), auto_remove_signals); + + if (ret.Failed()) { + last_error = std::move(ret); + if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) { + if (fail_on_obstacle) return last_error; + if (had_success) break; // Keep going if we haven't constructed any rail yet, skipping the start of the drag + } + + /* Ownership errors are more important. */ + if (last_error.GetErrorMessage() == STR_ERROR_OWNED_BY && remove) break; + } else { + had_success = true; + total_cost.AddCost(ret.GetCost()); + } } if (tile == end_tile) break; @@ -910,6 +928,12 @@ static CommandCost CmdRailTrackHelper(DoCommandFlags flags, TileIndex tile, Tile /* toggle railbit for the non-diagonal tracks */ if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0); + + /* Reset skip flag for the next tile after tunnel/bridge ending. */ + if (skip && !redundant_track) { + skip = false; + } + first_tile = false; } if (had_success) return total_cost; From 5941fb3257277e9573d1f6056390e7b8fd3e63da Mon Sep 17 00:00:00 2001 From: John Taylor Date: Fri, 21 Mar 2025 16:09:35 +0100 Subject: [PATCH 2/4] Fix #11528: Fixed typo. --- src/rail_cmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index c21a305bd0..136f1a175c 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -898,7 +898,7 @@ static CommandCost CmdRailTrackHelper(DoCommandFlags flags, TileIndex tile, Tile redundant_track = true; // Either above tunnel or below bridge and perpendicular, which means unnecessary to build. skip = true; } else if (redundant_track) { - redundand_track = false; // The tunnel/bridge has ended, the next track should be built. + redundant_track = false; // The tunnel/bridge has ended, the next track should be built. } else if (!first_tile && GetTunnelBridgeDirection(tile) == TrackdirToExitdir(ReverseTrackdir(trackdir))) { break; // Upon running into a bridge ramp from the underside, we should stop building tracks. } From 895c8c6a6168def7d95c91098c968097187688a3 Mon Sep 17 00:00:00 2001 From: John Taylor Date: Fri, 21 Mar 2025 18:38:07 +0100 Subject: [PATCH 3/4] Fix #11528: Moved to different logic to handle edge cases better. --- src/rail_cmd.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 136f1a175c..0ac45fa755 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -886,25 +886,21 @@ static CommandCost CmdRailTrackHelper(DoCommandFlags flags, TileIndex tile, Tile if (ret.Failed()) return ret; bool had_success = false; - bool redundant_track = false; - bool skip = false; bool first_tile = true; + TileIndex wormhole_end = INVALID_TILE; CommandCost last_error = CMD_ERROR; for (;;) { /* Check if hopping bridge/tunnel (#11528). */ - if (IsDiagonalTrackdir(trackdir) && GetTileType(tile) == MP_TUNNELBRIDGE && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { + if (!first_tile && wormhole_end == INVALID_TILE && IsDiagonalTrackdir(trackdir) && GetTileType(tile) == MP_TUNNELBRIDGE && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { /* If the building direction is the same as the bridge/tunnel direction, skip building tracks until the bridge/tunnel ends. */ if (GetTunnelBridgeDirection(tile) == TrackdirToExitdir(trackdir)) { - redundant_track = true; // Either above tunnel or below bridge and perpendicular, which means unnecessary to build. - skip = true; - } else if (redundant_track) { - redundant_track = false; // The tunnel/bridge has ended, the next track should be built. - } else if (!first_tile && GetTunnelBridgeDirection(tile) == TrackdirToExitdir(ReverseTrackdir(trackdir))) { + wormhole_end = GetOtherTunnelBridgeEnd(tile); + } else if (GetTunnelBridgeDirection(tile) == TrackdirToExitdir(ReverseTrackdir(trackdir))) { break; // Upon running into a bridge ramp from the underside, we should stop building tracks. } } - if (!skip) { + if (wormhole_end == INVALID_TILE) { ret = remove ? Command::Do(flags, tile, TrackdirToTrack(trackdir)) : Command::Do(flags, tile, railtype, TrackdirToTrack(trackdir), auto_remove_signals); if (ret.Failed()) { @@ -924,15 +920,16 @@ static CommandCost CmdRailTrackHelper(DoCommandFlags flags, TileIndex tile, Tile if (tile == end_tile) break; + /* Reset skip flag for the next tile after tunnel/bridge ending. */ + if (wormhole_end == tile) { + wormhole_end = INVALID_TILE; + } + tile += ToTileIndexDiff(_trackdelta[trackdir]); /* toggle railbit for the non-diagonal tracks */ if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0); - /* Reset skip flag for the next tile after tunnel/bridge ending. */ - if (skip && !redundant_track) { - skip = false; - } first_tile = false; } From 235c6e2c55680bb759c276582ca8b91cbd6097c3 Mon Sep 17 00:00:00 2001 From: John Taylor Date: Sat, 22 Mar 2025 22:01:27 +0100 Subject: [PATCH 4/4] Fix #11528: Fixed edge case when starting drag from bridge ramp. --- src/rail_cmd.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 0ac45fa755..2b3e2685b2 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -891,11 +891,11 @@ static CommandCost CmdRailTrackHelper(DoCommandFlags flags, TileIndex tile, Tile CommandCost last_error = CMD_ERROR; for (;;) { /* Check if hopping bridge/tunnel (#11528). */ - if (!first_tile && wormhole_end == INVALID_TILE && IsDiagonalTrackdir(trackdir) && GetTileType(tile) == MP_TUNNELBRIDGE && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { + if (wormhole_end == INVALID_TILE && IsDiagonalTrackdir(trackdir) && GetTileType(tile) == MP_TUNNELBRIDGE && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { /* If the building direction is the same as the bridge/tunnel direction, skip building tracks until the bridge/tunnel ends. */ if (GetTunnelBridgeDirection(tile) == TrackdirToExitdir(trackdir)) { wormhole_end = GetOtherTunnelBridgeEnd(tile); - } else if (GetTunnelBridgeDirection(tile) == TrackdirToExitdir(ReverseTrackdir(trackdir))) { + } else if (!first_tile && GetTunnelBridgeDirection(tile) == TrackdirToExitdir(ReverseTrackdir(trackdir))) { break; // Upon running into a bridge ramp from the underside, we should stop building tracks. } }