Add creation of wide rivers

pull/275/head
Andreas Schmitt 3 years ago
parent 758d71716e
commit 99e32488f2

@ -93,6 +93,15 @@ extern const byte _slope_to_sprite_offset[32] = {
*/
static SnowLine *_snow_line = nullptr;
/** The current spring during river generation */
static TileIndex _current_spring = INVALID_TILE;
/** The current estuary during river generation when one river flows into another */
static TileIndex _current_estuary = INVALID_TILE;
/** Whether the current river is a big river that others flow into */
static bool _is_main_river = false;
byte _cached_snowline = 0;
/**
@ -1183,16 +1192,49 @@ static void River_GetNeighbours(AyStar *aystar, OpenListNode *current)
}
}
/** Callback to widen a river tile. */
static bool RiverMakeWider(TileIndex tile, void *data)
{
if (IsValidTile(tile) && !IsWaterTile(tile) && GetTileSlope(tile) == GetTileSlope(*(TileIndex *)data)) {
MakeRiver(tile, Random());
/* Remove desert directly around the river tile. */
TileIndex cur_tile = tile;
MarkTileDirtyByTile(cur_tile);
CircularTileSearch(&cur_tile, _settings_game.game_creation.river_tropics_width, RiverModifyDesertZone, nullptr);
}
return false;
}
/* AyStar callback when an route has been found. */
static void River_FoundEndNode(AyStar *aystar, OpenListNode *current)
{
/* Count river length. */
uint length = 0;
for (PathNode *path = &current->path; path != nullptr; path = path->parent) {
length++;
}
uint cur_pos = 0;
for (PathNode *path = &current->path; path != nullptr; path = path->parent, cur_pos++) {
TileIndex tile = path->node.tile;
if (!IsWaterTile(tile)) {
MakeRiver(tile, Random());
// Widen river depending on how far we are away from the source.
const uint current_river_length = DistanceManhattan(_current_spring, path->node.tile);
const uint long_river_length = _settings_game.game_creation.min_river_length * 4;
const uint radius = std::min(3u, (current_river_length / (long_river_length / 3u)) + 1u);
MarkTileDirtyByTile(tile);
/* Remove desert directly around the river tile. */
CircularTileSearch(&tile, _settings_game.game_creation.river_tropics_width, RiverModifyDesertZone, nullptr);
if (_is_main_river && (radius > 1)) {
CircularTileSearch(&tile, radius + RandomRange(1), RiverMakeWider, (void *)&path->node.tile);
} else {
/* Remove desert directly around the river tile. */
CircularTileSearch(&tile, _settings_game.game_creation.river_tropics_width, RiverModifyDesertZone, nullptr);
}
}
}
}
@ -1239,15 +1281,24 @@ static void BuildRiver(TileIndex begin, TileIndex end)
* 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 True iff a river could/has been built, otherwise false.
*/
static bool FlowRiver(TileIndex spring, TileIndex begin)
static bool FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
{
# define SET_MARK(x) marks.insert(x)
# define IS_MARKED(x) (marks.find(x) != marks.end())
uint height = TileHeight(begin);
if (IsWaterTile(begin)) return DistanceManhattan(spring, begin) > _settings_game.game_creation.min_river_length;
if (IsWaterTile(begin))
{
if (GetTileZ(begin) == 0) {
_current_estuary = begin;
_is_main_river = true;
}
return DistanceManhattan(spring, begin) > min_river_length;
}
btree::btree_set<TileIndex> marks;
SET_MARK(begin);
@ -1281,7 +1332,7 @@ static bool FlowRiver(TileIndex spring, TileIndex begin)
if (found) {
/* Flow further down hill. */
found = FlowRiver(spring, end);
found = FlowRiver(spring, end, min_river_length);
} else if (count > 32) {
/* Maybe we can make a lake. Find the Nth of the considered tiles. */
TileIndex lakeCenter = 0;
@ -1300,7 +1351,7 @@ static bool FlowRiver(TileIndex spring, TileIndex begin)
/* We don't want lakes in the desert. */
(_settings_game.game_creation.landscape != LT_TROPIC || _settings_game.game_creation.lakes_allowed_in_deserts || GetTropicZone(lakeCenter) != TROPICZONE_DESERT) &&
/* We only want a lake if the river is long enough. */
DistanceManhattan(spring, lakeCenter) > _settings_game.game_creation.min_river_length) {
DistanceManhattan(spring, lakeCenter) > min_river_length) {
end = lakeCenter;
MakeRiver(lakeCenter, Random());
MarkTileDirtyByTile(lakeCenter);
@ -1345,14 +1396,28 @@ static void CreateRivers()
if (amount == 0) return;
uint wells = ScaleByMapSize(4 << _settings_game.game_creation.amount_of_rivers);
const uint num_short_rivers = wells - std::max(1u, wells / 10);
SetGeneratingWorldProgress(GWP_RIVER, wells + 256 / 64); // Include the tile loop calls below.
for (; wells > num_short_rivers; wells--) {
IncreaseGeneratingWorldProgress(GWP_RIVER);
for (int tries = 0; tries < 512; tries++) {
TileIndex t = RandomTile();
if (!CircularTileSearch(&t, 8, FindSpring, nullptr)) continue;
_current_spring = t;
_is_main_river = false;
if (FlowRiver(t, t, _settings_game.game_creation.min_river_length * 4)) break;
}
}
for (; wells != 0; wells--) {
IncreaseGeneratingWorldProgress(GWP_RIVER);
for (int tries = 0; tries < 128; tries++) {
TileIndex t = RandomTile();
if (!CircularTileSearch(&t, 8, FindSpring, nullptr)) continue;
if (FlowRiver(t, t)) break;
_current_spring = t;
_is_main_river = false;
if (FlowRiver(t, t, _settings_game.game_creation.min_river_length)) break;
}
}

Loading…
Cancel
Save