From b1a5d181a0ed4595e0a164d43a3497fd0d1477f6 Mon Sep 17 00:00:00 2001 From: SamuXarick <43006711+SamuXarick@users.noreply.github.com> Date: Thu, 23 Jan 2025 18:12:57 +0000 Subject: [PATCH] Fix: Don't block nearby river slope connection with terraform When two sloped rivers are adjacent to one another, RiverMakeWider's terraform could at times close the connection to one of the rivers. Implemented a more robust method to deal with widening of inclined river slopes, by weighing in the consequences in advance to performing the terraform. --- src/landscape.cpp | 68 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/src/landscape.cpp b/src/landscape.cpp index 6fb980657c..b4328b7e4e 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -1063,7 +1063,7 @@ static bool RiverMakeWider(TileIndex tile, void *user_data) if (IsSteepSlope(cur_slope)) return false; bool flat_river_found = false; - bool sloped_river_found = false; + std::vector> sloped_rivers; /* There are two common possibilities: * 1. River flat, adjacent tile has one corner lowered. @@ -1080,22 +1080,70 @@ static bool RiverMakeWider(TileIndex tile, void *user_data) /* If the adjacent river tile flows downhill, we need to check where we are relative to the slope. */ if (IsInclinedSlope(other_slope) && GetTileMaxZ(tile) == GetTileMaxZ(other_tile)) { /* Check for a parallel slope. If we don't find one, we're above or below the slope instead. */ - if (GetInclinedSlopeDirection(other_slope) == ChangeDiagDir(d, DIAGDIRDIFF_90RIGHT) || - GetInclinedSlopeDirection(other_slope) == ChangeDiagDir(d, DIAGDIRDIFF_90LEFT)) { - desired_slope = other_slope; - sloped_river_found = true; - break; + for (DiagDirDiff dir_diff : { DIAGDIRDIFF_90RIGHT, DIAGDIRDIFF_90LEFT }) { + DiagDirection other_d = ChangeDiagDir(d, dir_diff); + if (GetInclinedSlopeDirection(other_slope) == other_d) { + /* Calculate the length of the parallel slope. */ + int length = 0; + TileIndex parallel_tile = other_tile; + for (;;) { + length++; + parallel_tile = AddTileIndexDiffCWrap(parallel_tile, TileIndexDiffCByDiagDir(d)); + if (parallel_tile == INVALID_TILE) break; + if (!IsWaterTile(parallel_tile) || !IsRiver(parallel_tile)) break; + if (GetTileMaxZ(parallel_tile) != GetTileMaxZ(tile)) break; + Slope parallel_slope = GetTileSlope(parallel_tile); + if (!IsInclinedSlope(parallel_slope) || GetInclinedSlopeDirection(parallel_slope) != other_d) break; + } + /* Store the slope, its length, and distance to the origin tile. */ + sloped_rivers.push_back(std::make_tuple(other_slope, length, DistanceManhattan(other_tile, origin_tile))); + break; + } } } /* If we find an adjacent river tile, remember it. We'll terraform to match it later if we don't find a slope. */ if (IsTileFlat(other_tile)) flat_river_found = true; } } - /* We didn't find either an inclined or flat river, so we're climbing the wrong slope. Bail out. */ - if (!sloped_river_found && !flat_river_found) return false; - /* We didn't find an inclined river, but there is a flat river. */ - if (!sloped_river_found && flat_river_found) desired_slope = SLOPE_FLAT; + if (sloped_rivers.empty()) { + /* We didn't find either an inclined or flat river, so we're climbing the wrong slope. Bail out. */ + if (!flat_river_found) return false; + + /* We didn't find an inclined river, but there is a flat river. */ + desired_slope = SLOPE_FLAT; + } else if (sloped_rivers.size() == 1) { + /* We found an inclined river. */ + desired_slope = std::get<0>(sloped_rivers[0]); + } else { + /* We found two inclined rivers. */ + assert(sloped_rivers.size() == 2); + + /* Initialize slopes. */ + auto &[short_slope, short_length, short_dist] = sloped_rivers[0]; + [[maybe_unused]] auto &[_, wider_length, wider_dist] = sloped_rivers[1]; + + /* Swap values if needed. */ + if (short_length > wider_length) { + std::swap(sloped_rivers[0], sloped_rivers[1]); + } + + if (short_dist <= wider_dist && desired_slope != short_slope) { + int length_difference = wider_length - short_length; + + /* If the lengths of both slopes are equal, do nothing. + * If one slope is shorter, decide whether to widen the shorter river slope at the cost of the longer one: + * - If the difference in lengths is 1, there's a 50% chance to widen the shorter slope. + * - If the difference in lengths is exactly 2, always widen the shorter slope to make them equal. + * - If the difference in lengths is greater than 2, always widen the shorter slope, but they will not be equal. + * For example, if the lengths are 1 and 4, widening will result in lengths of 2 and 3. */ + if (length_difference == 1) { + if (Chance16(1, 2)) desired_slope = short_slope; + } else if (length_difference >= 2) { + desired_slope = short_slope; + } + } + } /* Now that we know the desired slope, it's time to terraform! */