Skip to content

Instantly share code, notes, and snippets.

@michicc
Created March 8, 2022 22:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michicc/91ac9d01052605150e6d31ba781ff01d to your computer and use it in GitHub Desktop.
Save michicc/91ac9d01052605150e6d31ba781ff01d to your computer and use it in GitHub Desktop.
diff --git a/src/landscape.cpp b/src/landscape.cpp
index 442bb61cda..c10c2191a6 100644
--- a/src/landscape.cpp
+++ b/src/landscape.cpp
@@ -89,11 +89,6 @@ 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.
@@ -1115,6 +1110,12 @@ static bool FlowsDown(TileIndex begin, TileIndex end)
((slopeEnd == slopeBegin && heightEnd < heightBegin) || slopeEnd == SLOPE_FLAT || slopeBegin == SLOPE_FLAT);
}
+/** Parameters for river generation to pass as AyStar user data. */
+struct River_UserData {
+ TileIndex spring; ///< The current spring during river generation.
+ bool main_river; ///< Whether the current river is a big river that others flow into.
+};
+
/* AyStar callback for checking whether we reached our destination. */
static int32 River_EndNodeCheck(const AyStar *aystar, const OpenListNode *current)
{
@@ -1152,6 +1153,8 @@ static void River_GetNeighbours(AyStar *aystar, OpenListNode *current)
/* AyStar callback when an route has been found. */
static void River_FoundEndNode(AyStar *aystar, OpenListNode *current)
{
+ River_UserData *data = (River_UserData *)aystar->user_data;
+
/* Count river length. */
uint length = 0;
for (PathNode *path = &current->path; path != nullptr; path = path->parent) {
@@ -1165,14 +1168,14 @@ static void River_FoundEndNode(AyStar *aystar, OpenListNode *current)
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 current_river_length = DistanceManhattan(data->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);
/* If building a main river, try to widen it. */
- if (_is_main_river && (radius > 1)) {
+ if (data->main_river && (radius > 1)) {
CircularTileSearch(&tile, radius + RandomRange(1), RiverMakeWider, (void*)&path->node.tile);
}
else {
@@ -1200,9 +1203,13 @@ static uint River_Hash(uint tile, uint dir)
* Actually build the river between the begin and end tiles using AyStar.
* @param begin The begin of the river.
* @param end The end of the river.
+ * @param spring The springing point of the river.
+ * @param main_river Whether the current river is a big river that others flow into.
*/
-static void BuildRiver(TileIndex begin, TileIndex end)
+static void BuildRiver(TileIndex begin, TileIndex end, TileIndex spring, bool main_river)
{
+ River_UserData user_data = { spring, main_river };
+
AyStar finder = {};
finder.CalculateG = River_CalculateG;
finder.CalculateH = River_CalculateH;
@@ -1210,6 +1217,7 @@ static void BuildRiver(TileIndex begin, TileIndex end)
finder.EndNodeCheck = River_EndNodeCheck;
finder.FoundEndNode = River_FoundEndNode;
finder.user_target = &end;
+ finder.user_data = &user_data;
finder.Init(River_Hash, 1 << RIVER_HASH_SIZE);
@@ -1226,20 +1234,16 @@ static void BuildRiver(TileIndex begin, TileIndex end)
* @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.
+ * @return First element: True iff a river could/has been built, otherwise false; second element: River ends at sea.
*/
-static bool FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
+static std::tuple<bool, 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))
- {
- if (GetTileZ(begin) == 0) {
- _is_main_river = true;
- }
- return DistanceManhattan(spring, begin) > min_river_length;
+ if (IsWaterTile(begin)) {
+ return { DistanceManhattan(spring, begin) > min_river_length, GetTileZ(begin) == 0 };
}
std::set<TileIndex> marks;
@@ -1272,9 +1276,10 @@ static bool FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
}
} while (!queue.empty());
+ bool main_river = false;
if (found) {
/* Flow further down hill. */
- found = FlowRiver(spring, end, min_river_length);
+ std::tie(found, main_river) = 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;
@@ -1310,8 +1315,8 @@ static bool FlowRiver(TileIndex spring, TileIndex begin, uint min_river_length)
}
marks.clear();
- if (found) BuildRiver(begin, end);
- return found;
+ if (found) BuildRiver(begin, end, spring, main_river);
+ return { found, main_river };
}
/**
@@ -1332,9 +1337,7 @@ static void CreateRivers()
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;
+ if (std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length * 4))) break;
}
}
@@ -1344,9 +1347,7 @@ static void CreateRivers()
for (int tries = 0; tries < 128; 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)) break;
+ if (std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length))) break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment