From a2c0e6aa1863db1a7b1b32b6834f240bd44c5cf7 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 3 Jun 2023 22:04:24 +0100 Subject: [PATCH] Fix #10831: Level crossing parts left barred after crossing tile removal (#10874) --- src/rail_cmd.cpp | 2 +- src/road_cmd.cpp | 2 +- src/road_func.h | 1 + src/train_cmd.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 1f44022211..eee3856a24 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -651,7 +651,7 @@ CommandCost CmdRemoveSingleRail(DoCommandFlag flags, TileIndex tile, Track track cost.AddCost(RailClearCost(GetRailType(tile))); if (flags & DC_EXEC) { - MarkDirtyAdjacentLevelCrossingTiles(tile, GetCrossingRoadAxis(tile)); + UpdateAdjacentLevelCrossingTilesOnLevelCrossingRemoval(tile, GetCrossingRoadAxis(tile)); if (HasReservedTracks(tile, trackbit)) { v = GetTrainForReservation(tile, track); diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 0f112dc0a7..c29fef09e7 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -504,7 +504,7 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec } if (flags & DC_EXEC) { - MarkDirtyAdjacentLevelCrossingTiles(tile, GetCrossingRoadAxis(tile)); + UpdateAdjacentLevelCrossingTilesOnLevelCrossingRemoval(tile, GetCrossingRoadAxis(tile)); /* A full diagonal road tile has two road bits. */ UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -2); diff --git a/src/road_func.h b/src/road_func.h index 3c770a9de1..9b66fcc85b 100644 --- a/src/road_func.h +++ b/src/road_func.h @@ -155,6 +155,7 @@ RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date void UpdateLevelCrossing(TileIndex tile, bool sound = true, bool force_bar = false); void MarkDirtyAdjacentLevelCrossingTiles(TileIndex tile, Axis road_axis); +void UpdateAdjacentLevelCrossingTilesOnLevelCrossingRemoval(TileIndex tile, Axis road_axis); void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count); struct TileInfo; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 13c241f4e9..6a0243d26c 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1790,7 +1790,8 @@ void UpdateLevelCrossing(TileIndex tile, bool sound, bool force_bar) /** * Find adjacent level crossing tiles in this multi-track crossing and mark them dirty. - * @param The tile which causes the update. + * @param tile The tile which causes the update. + * @param road_axis The road axis. */ void MarkDirtyAdjacentLevelCrossingTiles(TileIndex tile, Axis road_axis) { @@ -1804,6 +1805,44 @@ void MarkDirtyAdjacentLevelCrossingTiles(TileIndex tile, Axis road_axis) } } +/** + * Update adjacent level crossing tiles in this multi-track crossing, due to removal of a level crossing tile. + * @param tile The crossing tile which has been or is about to be removed, and which caused the update. + * @param road_axis The road axis. + */ +void UpdateAdjacentLevelCrossingTilesOnLevelCrossingRemoval(TileIndex tile, Axis road_axis) +{ + const DiagDirection dir1 = AxisToDiagDir(road_axis); + const DiagDirection dir2 = ReverseDiagDir(dir1); + for (DiagDirection dir : { dir1, dir2 }) { + const TileIndexDiff diff = TileOffsByDiagDir(dir); + bool occupied = false; + for (TileIndex t = tile + diff; t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis; t += diff) { + occupied |= CheckLevelCrossing(t); + } + if (occupied) { + /* Mark the immediately adjacent tile dirty */ + const TileIndex t = tile + diff; + if (t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis) { + MarkTileDirtyByTile(t); + } + } else { + /* Unbar the crossing tiles in this direction as necessary */ + for (TileIndex t = tile + diff; t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis; t += diff) { + if (IsCrossingBarred(t)) { + /* The crossing tile is barred, unbar it and continue to check the next tile */ + SetCrossingBarred(t, false); + MarkTileDirtyByTile(t); + } else { + /* The crossing tile is already unbarred, mark the tile dirty and stop checking */ + MarkTileDirtyByTile(t); + break; + } + } + } + } +} + /** * Bars crossing and plays ding-ding sound if not barred already * @param tile tile with crossing