From 2b1d73cb3d5cf5625685ed7c452dd91374d2a13a Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Tue, 15 Jun 2021 16:40:21 +0200 Subject: [PATCH] Fix tunnel glitch --- src/road.cpp | 163 +++++++++++++++++++++++++++++---------------------- 1 file changed, 94 insertions(+), 69 deletions(-) diff --git a/src/road.cpp b/src/road.cpp index e7888029ed..04dc973665 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -598,98 +598,123 @@ static bool IsBlockedByPreviousBridgeOrTunnel(OpenListNode *current, TileIndex s /** AyStar callback for getting the neighbouring nodes of the given node. */ static void PublicRoad_GetNeighbours(AyStar *aystar, OpenListNode *current) { - const TileIndex tile = current->path.node.tile; + const auto current_tile = current->path.node.tile; + const auto previous_tile = current->path.parent != nullptr ? current->path.parent->node.tile : INVALID_TILE; + const auto forward_direction = DiagdirBetweenTiles(previous_tile, current_tile); aystar->num_neighbours = 0; // Check if we just went through a tunnel or a bridge. - if (current->path.parent != nullptr && !AreTilesAdjacent(tile, current->path.parent->node.tile)) { - const auto previous_tile = current->path.parent->node.tile; - + if (previous_tile != INVALID_TILE && !AreTilesAdjacent(current_tile, previous_tile)) { + // We went through a tunnel or bridge, this limits our options to proceed to only forward. - const auto tunnel_bridge_direction = DiagdirBetweenTiles(previous_tile, tile); - - const TileIndex tunnel_bridge_end = tile + TileOffsByDiagDir(tunnel_bridge_direction); + const TileIndex tunnel_bridge_end = current_tile + TileOffsByDiagDir(forward_direction); - if (IsValidNeighbourOfPreviousTile(tunnel_bridge_end, tile)) { + if (IsValidNeighbourOfPreviousTile(tunnel_bridge_end, current_tile)) { aystar->neighbours[aystar->num_neighbours].tile = tunnel_bridge_end; aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; aystar->num_neighbours++; } - } else { - // Handle all the regular neighbours and existing tunnels/bridges. - std::vector potential_neighbours; + } else if (IsTileType(current_tile, MP_TUNNELBRIDGE)) { + // Handle existing tunnels and bridges + const auto tunnel_bridge_end = GetOtherTunnelBridgeEnd(current_tile); + const auto tunnel_bridge_direction = DiagdirBetweenTiles(current_tile, tunnel_bridge_end); + + // Thanks to custom bridge heads we can come towards a bridge from anywhere but the reverse direction. + if (forward_direction == ReverseDiagDir(tunnel_bridge_direction)) { + return; + } - if (IsTileType(tile, MP_TUNNELBRIDGE)) { - auto neighbour = GetOtherTunnelBridgeEnd(tile); + // For tunnels we need to come directly towards the tunnel though. + if (IsTunnel(current_tile) && forward_direction != tunnel_bridge_direction) { + return; + } + + aystar->neighbours[aystar->num_neighbours].tile = tunnel_bridge_end; + aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; + aystar->num_neighbours++; + + // Handle regular neighbors for bridges thanks to custom bridge heads. + if (IsBridge(current_tile)) { + for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) { + if (d == tunnel_bridge_direction) { + // We already added this direction. + // The direct neighbor in that direction makes no sense for a bridge. + continue; + } - aystar->neighbours[aystar->num_neighbours].tile = neighbour; - aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; - aystar->num_neighbours++; + const auto neighbour = current_tile + TileOffsByDiagDir(d); + + if (neighbour == previous_tile) { + // That's where we came from. + continue; + } + + if (IsValidNeighbourOfPreviousTile(neighbour, current_tile)) { + aystar->neighbours[aystar->num_neighbours].tile = neighbour; + aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; + aystar->num_neighbours++; + } + } + } + } else { + // Handle regular neighbors. + for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) { + const auto neighbour = current_tile + TileOffsByDiagDir(d); - neighbour = tile + TileOffsByDiagDir(ReverseDiagDir(DiagdirBetweenTiles(tile, neighbour))); + if (neighbour == previous_tile) { + continue; + } - if (IsValidNeighbourOfPreviousTile(neighbour, tile)) { + if (IsValidNeighbourOfPreviousTile(neighbour, current_tile)) { aystar->neighbours[aystar->num_neighbours].tile = neighbour; aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; aystar->num_neighbours++; } - } else { - for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) { - const auto neighbour = tile + TileOffsByDiagDir(d); - - if (IsValidNeighbourOfPreviousTile(neighbour, tile)) { - aystar->neighbours[aystar->num_neighbours].tile = neighbour; + } + + // Check if we can turn this into a tunnel or a bridge. + if (current->path.parent != nullptr) { + if (IsUpwardsSlope(current_tile, forward_direction)) { + const auto tunnel_end = BuildTunnel(¤t->path); + + if (tunnel_end != INVALID_TILE && + !IsBlockedByPreviousBridgeOrTunnel(current, current_tile, tunnel_end) && + !IsSteepSlope(GetTileSlope(tunnel_end)) && + !IsHalftileSlope(GetTileSlope(tunnel_end)) && + (GetTileSlope(tunnel_end) == ComplementSlope(GetTileSlope(current_tile)))) { + assert(IsValidDiagDirection(DiagdirBetweenTiles(current_tile, tunnel_end))); + aystar->neighbours[aystar->num_neighbours].tile = tunnel_end; aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; aystar->num_neighbours++; } } - - // Check if we can turn this into a tunnel or a bridge. - if (current->path.parent != nullptr) { - const auto road_direction = DiagdirBetweenTiles(current->path.parent->node.tile, tile); - - if (IsUpwardsSlope(tile, road_direction)) { - const auto tunnel_end = BuildTunnel(¤t->path); - - if (tunnel_end != INVALID_TILE && - !IsBlockedByPreviousBridgeOrTunnel(current, current->path.node.tile, tunnel_end) && - !IsSteepSlope(GetTileSlope(tunnel_end)) && - !IsHalftileSlope(GetTileSlope(tunnel_end)) && - (GetTileSlope(tunnel_end) == ComplementSlope(GetTileSlope(current->path.node.tile)))) { - assert(IsValidDiagDirection(DiagdirBetweenTiles(tile, tunnel_end))); - aystar->neighbours[aystar->num_neighbours].tile = tunnel_end; - aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; - aystar->num_neighbours++; - } - } - else if (IsDownwardsSlope(tile, road_direction)) { - const auto bridge_end = BuildBridge(¤t->path, road_direction); - - if (bridge_end != INVALID_TILE && - !IsBlockedByPreviousBridgeOrTunnel(current, current->path.node.tile, bridge_end) && - !IsSteepSlope(GetTileSlope(bridge_end)) && - !IsHalftileSlope(GetTileSlope(bridge_end)) && - (GetTileSlope(bridge_end) == ComplementSlope(GetTileSlope(current->path.node.tile)))) { - assert(IsValidDiagDirection(DiagdirBetweenTiles(tile, bridge_end))); - aystar->neighbours[aystar->num_neighbours].tile = bridge_end; - aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; - aystar->num_neighbours++; - } + else if (IsDownwardsSlope(current_tile, forward_direction)) { + const auto bridge_end = BuildBridge(¤t->path, forward_direction); + + if (bridge_end != INVALID_TILE && + !IsBlockedByPreviousBridgeOrTunnel(current, current_tile, bridge_end) && + !IsSteepSlope(GetTileSlope(bridge_end)) && + !IsHalftileSlope(GetTileSlope(bridge_end)) && + (GetTileSlope(bridge_end) == ComplementSlope(GetTileSlope(current_tile)))) { + assert(IsValidDiagDirection(DiagdirBetweenTiles(current_tile, bridge_end))); + aystar->neighbours[aystar->num_neighbours].tile = bridge_end; + aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; + aystar->num_neighbours++; } - else if (GetTileSlope(tile) == SLOPE_FLAT) - { - // Check if we could bridge a river from a flat tile. Not looking pretty on the map but you gotta do what you gotta do. - const auto bridge_end = BuildRiverBridge(¤t->path, road_direction); - assert(bridge_end == INVALID_TILE || GetTileSlope(bridge_end) == SLOPE_FLAT); - - if (bridge_end != INVALID_TILE && - !IsBlockedByPreviousBridgeOrTunnel(current, current->path.node.tile, bridge_end)) { - assert(IsValidDiagDirection(DiagdirBetweenTiles(tile, bridge_end))); - aystar->neighbours[aystar->num_neighbours].tile = bridge_end; - aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; - aystar->num_neighbours++; - } + } + else if (GetTileSlope(current_tile) == SLOPE_FLAT) + { + // Check if we could bridge a river from a flat tile. Not looking pretty on the map but you gotta do what you gotta do. + const auto bridge_end = BuildRiverBridge(¤t->path, forward_direction); + assert(bridge_end == INVALID_TILE || GetTileSlope(bridge_end) == SLOPE_FLAT); + + if (bridge_end != INVALID_TILE && + !IsBlockedByPreviousBridgeOrTunnel(current, current_tile, bridge_end)) { + assert(IsValidDiagDirection(DiagdirBetweenTiles(current_tile, bridge_end))); + aystar->neighbours[aystar->num_neighbours].tile = bridge_end; + aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; + aystar->num_neighbours++; } } }