diff --git a/src/landscape.cpp b/src/landscape.cpp index 46c10cca33..3bfecf06f4 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -431,6 +431,14 @@ void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2) if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope } +Slope GetFoundationSlopeFromTileSlope(TileIndex tile, Slope tileh, int *z) +{ + Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh); + uint z_inc = ApplyFoundationToSlope(f, &tileh); + if (z != nullptr) *z += z_inc; + return tileh; +} + /** * Get slope of a tile on top of a (possible) foundation * If a tile does not have a foundation, the function returns the same as GetTileSlope. @@ -442,10 +450,7 @@ void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2) Slope GetFoundationSlope(TileIndex tile, int *z) { Slope tileh = GetTileSlope(tile, z); - Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh); - uint z_inc = ApplyFoundationToSlope(f, &tileh); - if (z != nullptr) *z += z_inc; - return tileh; + return GetFoundationSlopeFromTileSlope(tile, tileh, z); } diff --git a/src/landscape.h b/src/landscape.h index ce90bc2b71..d0f15586a2 100644 --- a/src/landscape.h +++ b/src/landscape.h @@ -63,6 +63,7 @@ inline byte LowestTreePlacementSnowLine() } int GetSlopeZInCorner(Slope tileh, Corner corner); +Slope GetFoundationSlopeFromTileSlope(TileIndex tile, Slope tileh, int *z = nullptr); Slope GetFoundationSlope(TileIndex tile, int *z = nullptr); uint GetPartialPixelZ(int x, int y, Slope corners); diff --git a/src/road.cpp b/src/road.cpp index f9d8a979c9..bde29e52b2 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -551,8 +551,7 @@ static bool IsValidNeighbourOfPreviousTile(const TileIndex tile, const TileIndex const auto forward_direction = DiagdirBetweenTiles(previous_tile, tile); - if (IsTileType(tile, MP_TUNNELBRIDGE)) - { + if (IsTileType(tile, MP_TUNNELBRIDGE)) { if (GetOtherTunnelBridgeEnd(tile) == previous_tile) return true; const auto tunnel_direction = GetTunnelBridgeDirection(tile); @@ -562,28 +561,69 @@ static bool IsValidNeighbourOfPreviousTile(const TileIndex tile, const TileIndex if (!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES) && !IsTileType(tile, MP_ROAD) && !IsCoastTile(tile)) return false; - const Slope slope = GetTileSlope(tile); - if (IsSteepSlope(slope)) return false; + struct slope_desc { + int tile_z; + Slope tile_slope; + int z; + Slope slope; + }; - const Slope foundationSlope = GetFoundationSlope(tile); + auto get_slope_info = [](TileIndex t) -> slope_desc { + slope_desc desc; - /* Allow only trivial foundations (3 corners raised or 2 opposite corners raised -> flat) */ - if (slope != foundationSlope && !HasBit(VALID_LEVEL_CROSSING_SLOPES, slope)) return false; + desc.tile_slope = GetTileSlope(t, &desc.tile_z); - if (IsInclinedSlope(slope)) { - const auto slope_direction = GetInclinedSlopeDirection(slope); + desc.z = desc.tile_z; + desc.slope = GetFoundationSlopeFromTileSlope(t, desc.tile_slope, &desc.z); + + return desc; + }; + const slope_desc sd = get_slope_info(tile); + if (IsSteepSlope(sd.slope)) return false; + + const slope_desc previous_sd = get_slope_info(previous_tile); + + auto is_non_trivial_foundation = [](const slope_desc &sd) -> bool { + return sd.slope != sd.tile_slope && !HasBit(VALID_LEVEL_CROSSING_SLOPES, sd.tile_slope); + }; + + /* Check non-trivial foundations (those which aren't 3 corners raised or 2 opposite corners raised -> flat) */ + if (is_non_trivial_foundation(sd) || is_non_trivial_foundation(previous_sd)) { + static const Corner test_corners[16] = { + // DIAGDIR_NE + CORNER_N, CORNER_W, + CORNER_E, CORNER_S, + + // DIAGDIR_SE + CORNER_S, CORNER_W, + CORNER_E, CORNER_N, + + // DIAGDIR_SW + CORNER_S, CORNER_E, + CORNER_W, CORNER_N, + + // DIAGDIR_NW + CORNER_N, CORNER_E, + CORNER_W, CORNER_S + }; + const Corner *corners = test_corners + (forward_direction * 4); + return ((previous_sd.z + GetSlopeZInCorner(previous_sd.slope, corners[0])) == (sd.z + GetSlopeZInCorner(sd.slope, corners[1]))) && + ((previous_sd.z + GetSlopeZInCorner(previous_sd.slope, corners[2])) == (sd.z + GetSlopeZInCorner(sd.slope, corners[3]))); + } + + if (IsInclinedSlope(sd.slope)) { + const auto slope_direction = GetInclinedSlopeDirection(sd.slope); if (slope_direction != forward_direction && ReverseDiagDir(slope_direction) != forward_direction) { return false; } - } else if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, slope)) { + } else if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, sd.slope)) { return false; } else { /* Check whether the previous tile was an inclined slope, and whether we are leaving the previous tile from a valid direction */ - if (slope != SLOPE_FLAT) { - const Slope previous_slope = GetTileSlope(previous_tile); - if (IsInclinedSlope(previous_slope)) { - const DiagDirection slope_direction = GetInclinedSlopeDirection(previous_slope); + if (sd.tile_slope != SLOPE_FLAT) { + if (IsInclinedSlope(previous_sd.slope)) { + const DiagDirection slope_direction = GetInclinedSlopeDirection(previous_sd.slope); if (slope_direction != forward_direction && ReverseDiagDir(slope_direction) != forward_direction) return false; } }