mirror of
https://github.com/OpenTTD/OpenTTD
synced 2025-12-10 15:02:06 +01:00
Change: Eliminate small seas instead of ending rivers there (#14797)
This commit is contained in:
@@ -1326,6 +1326,39 @@ bool RiverFlowsDown(TileIndex begin, TileIndex end)
|
|||||||
return slope_end == SLOPE_FLAT || slope_begin == SLOPE_FLAT;
|
return slope_end == SLOPE_FLAT || slope_begin == SLOPE_FLAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the size of a patch of connected sea tiles.
|
||||||
|
* @param tile The starting tile to search.
|
||||||
|
* @param sea The set of sea tiles found.
|
||||||
|
* @param limit How many tiles to find before cutting the search short.
|
||||||
|
* @return True iff we found a map edge and broke out early, otherwise false (use the sea parameter as the output count/tile set).
|
||||||
|
*/
|
||||||
|
static bool CountConnectedSeaTiles(TileIndex tile, std::unordered_set<TileIndex> &sea, const uint limit)
|
||||||
|
{
|
||||||
|
/* This tile might not be sea. */
|
||||||
|
if (!IsWaterTile(tile) || GetWaterClass(tile) != WaterClass::Sea || !IsTileFlat(tile)) return false;
|
||||||
|
|
||||||
|
/* If we've found an edge tile, we are "connected to the sea outside the map." */
|
||||||
|
if (DistanceFromEdge(tile) <= 1) return true;
|
||||||
|
|
||||||
|
/* We have now evaluated this tile and don't want to check it again. */
|
||||||
|
sea.insert(tile);
|
||||||
|
|
||||||
|
/* We might want to cut our search short if the size of the sea is "big enough".
|
||||||
|
* Count this tile but don't check its neighbors. */
|
||||||
|
if (sea.size() > limit) return false;
|
||||||
|
|
||||||
|
/* Count adjacent tiles using recusion. */
|
||||||
|
for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
|
||||||
|
TileIndex t = tile + TileOffsByDiagDir(d);
|
||||||
|
if (IsValidTile(t) && !sea.contains(t)) {
|
||||||
|
if (CountConnectedSeaTiles(t, sea, limit)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to flow the river down from a given begin.
|
* Try to flow the river down from a given begin.
|
||||||
* @param spring The springing point of the river.
|
* @param spring The springing point of the river.
|
||||||
@@ -1358,8 +1391,29 @@ static std::tuple<bool, bool> FlowRiver(TileIndex spring, TileIndex begin, uint
|
|||||||
|
|
||||||
int height_end;
|
int height_end;
|
||||||
if (IsTileFlat(end, &height_end) && (height_end < height_begin || (height_end == height_begin && IsWaterTile(end)))) {
|
if (IsTileFlat(end, &height_end) && (height_end < height_begin || (height_end == height_begin && IsWaterTile(end)))) {
|
||||||
|
if (IsWaterTile(end) && GetWaterClass(end) == WaterClass::Sea) {
|
||||||
|
/* If we've found the sea, make sure it's large enough. Scale by the map size but set a cap to avoid performance issues on large maps. */
|
||||||
|
const uint MAX_SEA_SIZE_THRESHOLD = 1024;
|
||||||
|
const uint SEA_SIZE_THRESHOLD = std::min(static_cast<uint>(2 * std::sqrt(Map::SizeX() * Map::SizeY())), MAX_SEA_SIZE_THRESHOLD);
|
||||||
|
std::unordered_set<TileIndex> sea;
|
||||||
|
/* Count the connected tiles, if the sea is large we can end the river here. */
|
||||||
|
bool found_edge = CountConnectedSeaTiles(end, sea, SEA_SIZE_THRESHOLD);
|
||||||
|
if (found_edge || sea.size() > SEA_SIZE_THRESHOLD) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
/* Sea is too small, flatten it so the river keeps looking or forms a lake / wetland. */
|
||||||
|
for (TileIndex sea_tile : sea) {
|
||||||
|
Command<CMD_TERRAFORM_LAND>::Do(DoCommandFlag::Execute, sea_tile, SLOPE_ELEVATED, false);
|
||||||
|
Slope slope = ComplementSlope(GetTileSlope(sea_tile));
|
||||||
|
Command<CMD_TERRAFORM_LAND>::Do(DoCommandFlag::Execute, sea_tile, slope, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* We've found a river. */
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
|
for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user