Fix tunnel glitch

This commit is contained in:
Andreas Schmitt
2021-06-15 16:40:21 +02:00
committed by Jonathan G Rennison
parent 7601720ff7
commit 2b1d73cb3d

View File

@@ -598,47 +598,75 @@ static bool IsBlockedByPreviousBridgeOrTunnel(OpenListNode *current, TileIndex s
/** AyStar callback for getting the neighbouring nodes of the given node. */ /** AyStar callback for getting the neighbouring nodes of the given node. */
static void PublicRoad_GetNeighbours(AyStar *aystar, OpenListNode *current) 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; aystar->num_neighbours = 0;
// Check if we just went through a tunnel or a bridge. // Check if we just went through a tunnel or a bridge.
if (current->path.parent != nullptr && !AreTilesAdjacent(tile, current->path.parent->node.tile)) { if (previous_tile != INVALID_TILE && !AreTilesAdjacent(current_tile, previous_tile)) {
const auto previous_tile = current->path.parent->node.tile;
// We went through a tunnel or bridge, this limits our options to proceed to only forward. // 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 = current_tile + TileOffsByDiagDir(forward_direction);
const TileIndex tunnel_bridge_end = tile + TileOffsByDiagDir(tunnel_bridge_direction); if (IsValidNeighbourOfPreviousTile(tunnel_bridge_end, current_tile)) {
if (IsValidNeighbourOfPreviousTile(tunnel_bridge_end, tile)) {
aystar->neighbours[aystar->num_neighbours].tile = tunnel_bridge_end; aystar->neighbours[aystar->num_neighbours].tile = tunnel_bridge_end;
aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
aystar->num_neighbours++; aystar->num_neighbours++;
} }
} else { } else if (IsTileType(current_tile, MP_TUNNELBRIDGE)) {
// Handle all the regular neighbours and existing tunnels/bridges. // Handle existing tunnels and bridges
std::vector<TileIndex> potential_neighbours; const auto tunnel_bridge_end = GetOtherTunnelBridgeEnd(current_tile);
const auto tunnel_bridge_direction = DiagdirBetweenTiles(current_tile, tunnel_bridge_end);
if (IsTileType(tile, MP_TUNNELBRIDGE)) { // Thanks to custom bridge heads we can come towards a bridge from anywhere but the reverse direction.
auto neighbour = GetOtherTunnelBridgeEnd(tile); if (forward_direction == ReverseDiagDir(tunnel_bridge_direction)) {
return;
}
aystar->neighbours[aystar->num_neighbours].tile = neighbour; // 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->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
aystar->num_neighbours++; aystar->num_neighbours++;
neighbour = tile + TileOffsByDiagDir(ReverseDiagDir(DiagdirBetweenTiles(tile, neighbour))); // 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;
}
if (IsValidNeighbourOfPreviousTile(neighbour, tile)) { 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].tile = neighbour;
aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
aystar->num_neighbours++; aystar->num_neighbours++;
} }
}
}
} else { } else {
// Handle regular neighbors.
for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) { for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
const auto neighbour = tile + TileOffsByDiagDir(d); const auto neighbour = current_tile + TileOffsByDiagDir(d);
if (IsValidNeighbourOfPreviousTile(neighbour, tile)) { if (neighbour == previous_tile) {
continue;
}
if (IsValidNeighbourOfPreviousTile(neighbour, current_tile)) {
aystar->neighbours[aystar->num_neighbours].tile = neighbour; aystar->neighbours[aystar->num_neighbours].tile = neighbour;
aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
aystar->num_neighbours++; aystar->num_neighbours++;
@@ -647,45 +675,43 @@ static void PublicRoad_GetNeighbours(AyStar *aystar, OpenListNode *current)
// Check if we can turn this into a tunnel or a bridge. // Check if we can turn this into a tunnel or a bridge.
if (current->path.parent != nullptr) { if (current->path.parent != nullptr) {
const auto road_direction = DiagdirBetweenTiles(current->path.parent->node.tile, tile); if (IsUpwardsSlope(current_tile, forward_direction)) {
if (IsUpwardsSlope(tile, road_direction)) {
const auto tunnel_end = BuildTunnel(&current->path); const auto tunnel_end = BuildTunnel(&current->path);
if (tunnel_end != INVALID_TILE && if (tunnel_end != INVALID_TILE &&
!IsBlockedByPreviousBridgeOrTunnel(current, current->path.node.tile, tunnel_end) && !IsBlockedByPreviousBridgeOrTunnel(current, current_tile, tunnel_end) &&
!IsSteepSlope(GetTileSlope(tunnel_end)) && !IsSteepSlope(GetTileSlope(tunnel_end)) &&
!IsHalftileSlope(GetTileSlope(tunnel_end)) && !IsHalftileSlope(GetTileSlope(tunnel_end)) &&
(GetTileSlope(tunnel_end) == ComplementSlope(GetTileSlope(current->path.node.tile)))) { (GetTileSlope(tunnel_end) == ComplementSlope(GetTileSlope(current_tile)))) {
assert(IsValidDiagDirection(DiagdirBetweenTiles(tile, tunnel_end))); assert(IsValidDiagDirection(DiagdirBetweenTiles(current_tile, tunnel_end)));
aystar->neighbours[aystar->num_neighbours].tile = tunnel_end; aystar->neighbours[aystar->num_neighbours].tile = tunnel_end;
aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
aystar->num_neighbours++; aystar->num_neighbours++;
} }
} }
else if (IsDownwardsSlope(tile, road_direction)) { else if (IsDownwardsSlope(current_tile, forward_direction)) {
const auto bridge_end = BuildBridge(&current->path, road_direction); const auto bridge_end = BuildBridge(&current->path, forward_direction);
if (bridge_end != INVALID_TILE && if (bridge_end != INVALID_TILE &&
!IsBlockedByPreviousBridgeOrTunnel(current, current->path.node.tile, bridge_end) && !IsBlockedByPreviousBridgeOrTunnel(current, current_tile, bridge_end) &&
!IsSteepSlope(GetTileSlope(bridge_end)) && !IsSteepSlope(GetTileSlope(bridge_end)) &&
!IsHalftileSlope(GetTileSlope(bridge_end)) && !IsHalftileSlope(GetTileSlope(bridge_end)) &&
(GetTileSlope(bridge_end) == ComplementSlope(GetTileSlope(current->path.node.tile)))) { (GetTileSlope(bridge_end) == ComplementSlope(GetTileSlope(current_tile)))) {
assert(IsValidDiagDirection(DiagdirBetweenTiles(tile, bridge_end))); assert(IsValidDiagDirection(DiagdirBetweenTiles(current_tile, bridge_end)));
aystar->neighbours[aystar->num_neighbours].tile = bridge_end; aystar->neighbours[aystar->num_neighbours].tile = bridge_end;
aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
aystar->num_neighbours++; aystar->num_neighbours++;
} }
} }
else if (GetTileSlope(tile) == SLOPE_FLAT) 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. // 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(&current->path, road_direction); const auto bridge_end = BuildRiverBridge(&current->path, forward_direction);
assert(bridge_end == INVALID_TILE || GetTileSlope(bridge_end) == SLOPE_FLAT); assert(bridge_end == INVALID_TILE || GetTileSlope(bridge_end) == SLOPE_FLAT);
if (bridge_end != INVALID_TILE && if (bridge_end != INVALID_TILE &&
!IsBlockedByPreviousBridgeOrTunnel(current, current->path.node.tile, bridge_end)) { !IsBlockedByPreviousBridgeOrTunnel(current, current_tile, bridge_end)) {
assert(IsValidDiagDirection(DiagdirBetweenTiles(tile, bridge_end))); assert(IsValidDiagDirection(DiagdirBetweenTiles(current_tile, bridge_end)));
aystar->neighbours[aystar->num_neighbours].tile = bridge_end; aystar->neighbours[aystar->num_neighbours].tile = bridge_end;
aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR; aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
aystar->num_neighbours++; aystar->num_neighbours++;
@@ -694,7 +720,6 @@ static void PublicRoad_GetNeighbours(AyStar *aystar, OpenListNode *current)
} }
} }
} }
}
/** AyStar callback for checking whether we reached our destination. */ /** AyStar callback for checking whether we reached our destination. */
static int32 PublicRoad_EndNodeCheck(const AyStar *aystar, const OpenListNode *current) static int32 PublicRoad_EndNodeCheck(const AyStar *aystar, const OpenListNode *current)