MCPcopy Create free account
hub / github.com/OpenTTD/OpenTTD / FlowRiver

Function FlowRiver

src/landscape.cpp:1373–1450  ·  view source on GitHub ↗

* Try to flow the river down from a given begin. * @param spring The springing point of the river. * @param begin The begin point we are looking from; somewhere down hill from the spring. * @param min_river_length The minimum length for the river. * @return First element: True iff a river could/has been built, otherwise false; second element: River ends at sea. */

Source from the content-addressed store, hash-verified

1371 * @return First element: True iff a river could/has been built, otherwise false; second element: River ends at sea.
1372 */
1373static std::tuple<bool, bool> FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
1374{
1375 if (IsWaterTile(begin)) {
1376 return { DistanceManhattan(spring, begin) > min_river_length, GetTileZ(begin) == 0 };
1377 }
1378
1379 int height_begin = TileHeight(begin);
1380
1381 std::unordered_set<TileIndex> marks;
1382 marks.insert(begin);
1383
1384 std::vector<TileIndex> queue;
1385 queue.push_back(begin);
1386
1387 /* Breadth first search for the closest tile we can flow down to.
1388 * We keep the queue to find the Nth tile for lake guessing. The tiles
1389 * in the queue are neatly ordered by insertion.
1390 */
1391 bool found = false;
1392 TileIndex end;
1393 for (size_t i = 0; i != queue.size(); i++) {
1394 end = queue[i];
1395
1396 int height_end;
1397 if (IsTileFlat(end, &height_end) && (height_end < height_begin || (height_end == height_begin && IsWaterTile(end)))) {
1398 if (IsWaterTile(end) && GetWaterClass(end) == WaterClass::Sea) {
1399 /* 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. */
1400 const uint MAX_SEA_SIZE_THRESHOLD = 1024;
1401 const uint SEA_SIZE_THRESHOLD = std::min(static_cast<uint>(2 * std::sqrt(Map::SizeX() * Map::SizeY())), MAX_SEA_SIZE_THRESHOLD);
1402 std::unordered_set<TileIndex> sea;
1403 /* Count the connected tiles, if the sea is large we can end the river here. */
1404 bool found_edge = CountConnectedSeaTiles(end, sea, SEA_SIZE_THRESHOLD);
1405 if (found_edge || sea.size() > SEA_SIZE_THRESHOLD) {
1406 found = true;
1407 break;
1408 } else {
1409 /* Sea is too small, flatten it so the river keeps looking or forms a lake / wetland. */
1410 for (TileIndex sea_tile : sea) {
1411 Command<CMD_TERRAFORM_LAND>::Do(DoCommandFlag::Execute, sea_tile, SLOPE_ELEVATED, false);
1412 Slope slope = ComplementSlope(GetTileSlope(sea_tile));
1413 Command<CMD_TERRAFORM_LAND>::Do(DoCommandFlag::Execute, sea_tile, slope, true);
1414 }
1415 }
1416 } else {
1417 /* We've found a river. */
1418 found = true;
1419 break;
1420 }
1421 }
1422
1423 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
1424 TileIndex t = end + TileOffsByDiagDir(d);
1425 if (IsValidTile(t) && !marks.contains(t) && RiverFlowsDown(end, t)) {
1426 marks.insert(t);
1427 queue.push_back(t);
1428 }
1429 }
1430 }

Callers 1

CreateRiversFunction · 0.85

Calls 15

IsWaterTileFunction · 0.85
DistanceManhattanFunction · 0.85
GetTileZFunction · 0.85
TileHeightFunction · 0.85
IsTileFlatFunction · 0.85
GetWaterClassFunction · 0.85
CountConnectedSeaTilesFunction · 0.85
ComplementSlopeFunction · 0.85
GetTileSlopeFunction · 0.85
TileOffsByDiagDirFunction · 0.85
IsValidTileFunction · 0.85
RiverFlowsDownFunction · 0.85

Tested by

no test coverage detected