diff --git a/src/openrct2/util/Util.cpp b/src/openrct2/util/Util.cpp index e4b9b7c6b7..5f8884fc38 100644 --- a/src/openrct2/util/Util.cpp +++ b/src/openrct2/util/Util.cpp @@ -423,6 +423,15 @@ uint32_t util_rand() return _prng(); } +// Returns a random floating point number from the Standard Normal Distribution; mean of 0 and standard deviation of 1. +// TODO: In C++20 this can be templated, where the standard deviation is passed as a value template argument. +float util_rand_normal_distributed() +{ + thread_local std::mt19937 _prng{ std::random_device{}() }; + thread_local std::normal_distribution _distributor{ 0.0f, 1.0f }; + return _distributor(_prng); +} + constexpr size_t CHUNK = 128 * 1024; // Compress the source to gzip-compatible stream, write to dest. diff --git a/src/openrct2/util/Util.h b/src/openrct2/util/Util.h index 01290233b4..c41de0cc5a 100644 --- a/src/openrct2/util/Util.h +++ b/src/openrct2/util/Util.h @@ -42,6 +42,7 @@ char* strcasestr(const char* haystack, const char* needle); bool str_is_null_or_empty(const char* str); uint32_t util_rand(); +float util_rand_normal_distributed(); bool util_gzip_compress(FILE* source, FILE* dest); std::vector Gzip(const void* data, const size_t dataLen); diff --git a/src/openrct2/world/MapGen.cpp b/src/openrct2/world/MapGen.cpp index 206fdc82c7..4ff88f0d50 100644 --- a/src/openrct2/world/MapGen.cpp +++ b/src/openrct2/world/MapGen.cpp @@ -338,8 +338,10 @@ static void mapgen_place_trees() continue; // Use fractal noise to group tiles that are likely to spawn trees together - float noiseValue = std::clamp(fractal_noise(x, y, 0.025f, 8, 2.0f, 0.65f), -1.0f, 1.0f); - if (noiseValue < 0.0f) + float noiseValue = fractal_noise(x, y, 0.025f, 2, 2.0f, 0.65f); + // Reduces the range to rarely stray further than 0.5 from the mean. + float noiseOffset = util_rand_normal_distributed() * 0.25f; + if (noiseValue < noiseOffset) continue; ObjectEntryIndex treeObjectEntryIndex = OBJECT_ENTRY_INDEX_NULL;