Skip to content

Commit

Permalink
Feature: Wide rivers
Browse files Browse the repository at this point in the history
  • Loading branch information
2TallTyler committed Oct 19, 2021
1 parent 909a837 commit 7e53db1
Showing 1 changed file with 75 additions and 7 deletions.
82 changes: 75 additions & 7 deletions src/landscape.cpp
Expand Up @@ -88,6 +88,12 @@ 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;

/** Whether the current river is a big river that others flow into */
static bool _is_main_river = false;

/**
* Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
* Function takes into account height of tiles and foundations.
Expand Down Expand Up @@ -1073,6 +1079,25 @@ static bool MakeLake(TileIndex tile, void *user_data)
return false;
}

/**
* Widen a river by expanding into adjacent tiles via circular tile search.
* @param tile The tile to try expanding the river into.
* @param data The tile to try surrounding the river around.
* @return Always false, so it continues searching.
*/
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, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
}
return false;
}

/**
* Check whether a river at begin could (logically) flow down to end.
* @param begin The origin of the flow.
Expand Down Expand Up @@ -1132,13 +1157,33 @@ static void River_GetNeighbours(AyStar *aystar, OpenListNode *current)
/* 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());

/* Check if we should 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, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);

/* If building a main river, try to widen it. */
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, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
}
}
}
}
Expand Down Expand Up @@ -1185,15 +1230,22 @@ 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) {
_is_main_river = true;
}
return DistanceManhattan(spring, begin) > min_river_length;
}

std::set<TileIndex> marks;
SET_MARK(begin);
Expand Down Expand Up @@ -1227,7 +1279,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;
Expand All @@ -1246,7 +1298,7 @@ static bool FlowRiver(TileIndex spring, TileIndex begin)
/* We don't want lakes in the desert. */
(_settings_game.game_creation.landscape != LT_TROPIC || 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);
Expand Down Expand Up @@ -1276,14 +1328,30 @@ 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.

/* Try to create long rivers. */
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;
}
}

/* Try to create short rivers. */
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;
}
}

Expand Down

0 comments on commit 7e53db1

Please sign in to comment.