Mapgen: Generate fuzzy ellipse shaped lakes instead of squares
This commit is contained in:
@@ -1072,6 +1072,15 @@ static bool FindSpring(TileIndex tile, void *user_data)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct MakeLakeData {
|
||||
TileIndex centre; ///< Lake centre tile
|
||||
uint height; ///< Lake height
|
||||
int max_distance; ///< Max radius
|
||||
int secondary_axis_scale; ///< Multiplier for ellipse narrow axis, 16 bit fixed point
|
||||
int sin_fp; ///< sin of ellipse rotation angle, 16 bit fixed point
|
||||
int cos_fp; ///< cos of ellipse rotation angle, 16 bit fixed point
|
||||
};
|
||||
|
||||
/**
|
||||
* Make a connected lake; fill all tiles in the circular tile search that are connected.
|
||||
* @param tile The tile to consider for lake making.
|
||||
@@ -1080,10 +1089,29 @@ static bool FindSpring(TileIndex tile, void *user_data)
|
||||
*/
|
||||
static bool MakeLake(TileIndex tile, void *user_data)
|
||||
{
|
||||
uint height = *(uint*)user_data;
|
||||
if (!IsValidTile(tile) || TileHeight(tile) != height || !IsTileFlat(tile)) return false;
|
||||
const MakeLakeData *data = (const MakeLakeData *)user_data;
|
||||
if (!IsValidTile(tile) || TileHeight(tile) != data->height || !IsTileFlat(tile)) return false;
|
||||
if (_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) == TROPICZONE_DESERT) return false;
|
||||
|
||||
/* Offset from centre tile */
|
||||
const int64 x_delta = (int)TileX(tile) - (int)TileX(data->centre);
|
||||
const int64 y_delta = (int)TileY(tile) - (int)TileY(data->centre);
|
||||
|
||||
/* Rotate to new coordinate system */
|
||||
const int64 a_delta = (x_delta * data->cos_fp + y_delta * data->sin_fp) >> 8;
|
||||
const int64 b_delta = (-x_delta * data->sin_fp + y_delta * data->cos_fp) >> 8;
|
||||
|
||||
int max_distance = data->max_distance;
|
||||
if (max_distance >= 6) {
|
||||
/* Vary radius a bit for larger lakes */
|
||||
uint coord = (std::abs(x_delta) > std::abs(y_delta)) ? TileY(tile) : TileX(tile);
|
||||
static const int8 offset_fuzz[4] = { 0, 1, 0, -1 };
|
||||
max_distance += offset_fuzz[(coord / 3) & 3];
|
||||
}
|
||||
|
||||
/* Check if inside ellipse */
|
||||
if ((a_delta * a_delta) + ((data->secondary_axis_scale * b_delta * b_delta) >> 16) > ((int64)(max_distance * max_distance) << 16)) return false;
|
||||
|
||||
for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
|
||||
TileIndex t2 = tile + TileOffsByDiagDir(d);
|
||||
if (IsWaterTile(t2)) {
|
||||
@@ -1280,10 +1308,25 @@ static bool FlowRiver(TileIndex spring, TileIndex begin)
|
||||
CircularTileSearch(&lakeCenter, _settings_game.game_creation.river_tropics_width, RiverModifyDesertZone, nullptr);
|
||||
lakeCenter = end;
|
||||
uint range = RandomRange(_settings_game.game_creation.lake_size) + 3;
|
||||
CircularTileSearch(&lakeCenter, range, MakeLake, &height);
|
||||
|
||||
MakeLakeData data;
|
||||
data.centre = lakeCenter;
|
||||
data.height = height;
|
||||
data.max_distance = range / 2;
|
||||
|
||||
/* Square of ratio of ellipse dimensions: 1 to 5 (16 bit fixed point) */
|
||||
data.secondary_axis_scale = (1 << 16) + RandomRange(1 << 18);
|
||||
|
||||
/* Range from -1 to 1 (16 bit fixed point) */
|
||||
data.sin_fp = RandomRange(1 << 17) - (1 << 16);
|
||||
|
||||
/* sin^2 + cos^2 = 1 */
|
||||
data.cos_fp = IntSqrt64(((int64)1 << 32) - ((int64)data.sin_fp * (int64)data.sin_fp));
|
||||
|
||||
CircularTileSearch(&lakeCenter, range, MakeLake, &data);
|
||||
/* Call the search a second time so artefacts from going circular in one direction get (mostly) hidden. */
|
||||
lakeCenter = end;
|
||||
CircularTileSearch(&lakeCenter, range, MakeLake, &height);
|
||||
CircularTileSearch(&lakeCenter, range, MakeLake, &data);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user