diff --git a/src/openrct2-ui/windows/MapGen.cpp b/src/openrct2-ui/windows/MapGen.cpp index 6ab3212989..4ffd9bba73 100644 --- a/src/openrct2-ui/windows/MapGen.cpp +++ b/src/openrct2-ui/windows/MapGen.cpp @@ -378,7 +378,7 @@ static void WindowMapgenSetPage(rct_window* w, int32_t page); static void WindowMapgenSetPressedTab(rct_window* w); static void WindowMapgenDrawTabImages(rct_drawpixelinfo* dpi, rct_window* w); -static int32_t _mapSize = 150; +static TileCoordsXY _mapSize{ 150, 150 }; static int32_t _baseHeight = 12; static int32_t _waterLevel = 6; static int32_t _floorTexture = 0; @@ -470,7 +470,13 @@ static void WindowMapgenBaseMouseup(rct_window* w, rct_widgetindex widgetIndex) ft.Add(MINIMUM_MAP_SIZE_PRACTICAL); ft.Add(MAXIMUM_MAP_SIZE_PRACTICAL); // Practical map size is 2 lower than the technical map size - WindowTextInputOpen(w, WIDX_MAP_SIZE_Y, STR_MAP_SIZE_2, STR_ENTER_MAP_SIZE, ft, STR_FORMAT_INTEGER, _mapSize - 2, 4); + WindowTextInputOpen(w, WIDX_MAP_SIZE_Y, STR_MAP_SIZE_2, STR_ENTER_MAP_SIZE, ft, STR_FORMAT_INTEGER, _mapSize.y - 2, 4); + break; + case WIDX_MAP_SIZE_X: // TODO: Dedupe code - handle similar to Map.cpp + ft.Add(MINIMUM_MAP_SIZE_PRACTICAL); + ft.Add(MAXIMUM_MAP_SIZE_PRACTICAL); + // Practical map size is 2 lower than the technical map size + WindowTextInputOpen(w, WIDX_MAP_SIZE_X, STR_MAP_SIZE_2, STR_ENTER_MAP_SIZE, ft, STR_FORMAT_INTEGER, _mapSize.x - 2, 4); break; case WIDX_BASE_HEIGHT: ft.Add((BASESIZE_MIN - 12) / 2); @@ -492,11 +498,19 @@ static void WindowMapgenBaseMousedown(rct_window* w, rct_widgetindex widgetIndex switch (widgetIndex) { case WIDX_MAP_SIZE_Y_UP: - _mapSize = std::min(_mapSize + 1, MAXIMUM_MAP_SIZE_TECHNICAL); + _mapSize.y = std::min(_mapSize.y + 1, MAXIMUM_MAP_SIZE_TECHNICAL); w->Invalidate(); break; case WIDX_MAP_SIZE_Y_DOWN: - _mapSize = std::max(_mapSize - 1, MINIMUM_MAP_SIZE_TECHNICAL); + _mapSize.y = std::max(_mapSize.y - 1, MINIMUM_MAP_SIZE_TECHNICAL); + w->Invalidate(); + break; + case WIDX_MAP_SIZE_X_UP: + _mapSize.x = std::min(_mapSize.x + 1, MAXIMUM_MAP_SIZE_TECHNICAL); + w->Invalidate(); + break; + case WIDX_MAP_SIZE_X_DOWN: + _mapSize.x = std::max(_mapSize.x - 1, MINIMUM_MAP_SIZE_TECHNICAL); w->Invalidate(); break; case WIDX_BASE_HEIGHT_UP: @@ -596,7 +610,13 @@ static void WindowMapgenTextinput(rct_window* w, rct_widgetindex widgetIndex, ch case WIDX_SIMPLEX_MAP_SIZE_Y: // The practical size is 2 lower than the technical size value += 2; - _mapSize = std::clamp(value, MINIMUM_MAP_SIZE_TECHNICAL, MAXIMUM_MAP_SIZE_TECHNICAL); + _mapSize.y = std::clamp(value, MINIMUM_MAP_SIZE_TECHNICAL, MAXIMUM_MAP_SIZE_TECHNICAL); + break; + case WIDX_MAP_SIZE_X: + case WIDX_SIMPLEX_MAP_SIZE_X: + // The practical size is 2 lower than the technical size + value += 2; + _mapSize.x = std::clamp(value, MINIMUM_MAP_SIZE_TECHNICAL, MAXIMUM_MAP_SIZE_TECHNICAL); break; case WIDX_BASE_HEIGHT: _baseHeight = std::clamp((value * 2) + 12, BASESIZE_MIN, BASESIZE_MAX); @@ -691,8 +711,8 @@ static void WindowMapgenBasePaint(rct_window* w, rct_drawpixelinfo* dpi) // The practical map size is 2 lower than the technical map size // This needs to be cast down to a uint16_t because that's what the STR_RESOLUTION_X_BY_Y string takes. auto ft = Formatter(); - ft.Add(static_cast(_mapSize - 2)); - ft.Add(static_cast(_mapSize - 2)); + ft.Add(static_cast(_mapSize.y - 2)); + ft.Add(static_cast(_mapSize.x - 2)); DrawTextBasic( dpi, w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_MAP_SIZE_Y].left + 1, w->widgets[WIDX_MAP_SIZE_Y].top + 1 }, STR_RESOLUTION_X_BY_Y, ft, { w->colours[1] }); @@ -801,7 +821,17 @@ static void WindowMapgenSimplexMouseup(rct_window* w, rct_widgetindex widgetInde ft.Add(MAXIMUM_MAP_SIZE_PRACTICAL); // Practical map size is 2 lower than the technical map size WindowTextInputOpen( - w, WIDX_SIMPLEX_MAP_SIZE_Y, STR_MAP_SIZE_2, STR_ENTER_MAP_SIZE, ft, STR_FORMAT_INTEGER, _mapSize - 2, 4); + w, WIDX_SIMPLEX_MAP_SIZE_Y, STR_MAP_SIZE_2, STR_ENTER_MAP_SIZE, ft, STR_FORMAT_INTEGER, _mapSize.y - 2, 4); + break; + } + case WIDX_SIMPLEX_MAP_SIZE_X: // TODO: Dedupe code - handle similar to Map.cpp + { + Formatter ft; + ft.Add(MINIMUM_MAP_SIZE_PRACTICAL); + ft.Add(MAXIMUM_MAP_SIZE_PRACTICAL); + // Practical map size is 2 lower than the technical map size + WindowTextInputOpen( + w, WIDX_SIMPLEX_MAP_SIZE_X, STR_MAP_SIZE_2, STR_ENTER_MAP_SIZE, ft, STR_FORMAT_INTEGER, _mapSize.x - 2, 4); break; } case WIDX_SIMPLEX_GENERATE: @@ -861,11 +891,19 @@ static void WindowMapgenSimplexMousedown(rct_window* w, rct_widgetindex widgetIn w->Invalidate(); break; case WIDX_SIMPLEX_MAP_SIZE_Y_UP: - _mapSize = std::min(_mapSize + 1, MAXIMUM_MAP_SIZE_TECHNICAL); + _mapSize.y = std::min(_mapSize.y + 1, MAXIMUM_MAP_SIZE_TECHNICAL); w->Invalidate(); break; case WIDX_SIMPLEX_MAP_SIZE_Y_DOWN: - _mapSize = std::max(_mapSize - 1, MINIMUM_MAP_SIZE_TECHNICAL); + _mapSize.y = std::max(_mapSize.y - 1, MINIMUM_MAP_SIZE_TECHNICAL); + w->Invalidate(); + break; + case WIDX_SIMPLEX_MAP_SIZE_X_UP: // TODO: Dedupe code - handle similar to Map.cpp + _mapSize.x = std::min(_mapSize.x + 1, MAXIMUM_MAP_SIZE_TECHNICAL); + w->Invalidate(); + break; + case WIDX_SIMPLEX_MAP_SIZE_X_DOWN: // TODO: Dedupe code - handle similar to Map.cpp + _mapSize.x = std::max(_mapSize.x - 1, MINIMUM_MAP_SIZE_TECHNICAL); w->Invalidate(); break; case WIDX_SIMPLEX_WATER_LEVEL_UP: @@ -952,6 +990,9 @@ static void WindowMapgenSimplexInvalidate(rct_window* w) WindowInitScrollWidgets(w); } + // Only allow linking the map size when X and Y are the same + WidgetSetDisabled(w, WIDX_SIMPLEX_MAP_SIZE_LINK, gMapSize.x != gMapSize.y); + WidgetSetCheckboxValue(w, WIDX_SIMPLEX_RANDOM_TERRAIN_CHECKBOX, _randomTerrain != 0); WidgetSetCheckboxValue(w, WIDX_SIMPLEX_PLACE_TREES_CHECKBOX, _placeTrees != 0); @@ -1029,8 +1070,8 @@ static void WindowMapgenSimplexPaint(rct_window* w, rct_drawpixelinfo* dpi) // The practical map size is 2 lower than the technical map size. // This needs to be cast down to a uint16_t because that's what the STR_RESOLUTION_X_BY_Y string takes. ft = Formatter(); - ft.Add(static_cast(_mapSize - 2)); - ft.Add(static_cast(_mapSize - 2)); + ft.Add(static_cast(_mapSize.y - 2)); + ft.Add(static_cast(_mapSize.x - 2)); DrawTextBasic( dpi, w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_SIMPLEX_MAP_SIZE_Y].left + 1, w->widgets[WIDX_SIMPLEX_MAP_SIZE_Y].top + 1 }, diff --git a/src/openrct2/world/MapGen.cpp b/src/openrct2/world/MapGen.cpp index d99ffbc12c..8f2700d083 100644 --- a/src/openrct2/world/MapGen.cpp +++ b/src/openrct2/world/MapGen.cpp @@ -98,21 +98,21 @@ static void mapgen_set_height(mapgen_settings* settings); static float fractal_noise(int32_t x, int32_t y, float frequency, int32_t octaves, float lacunarity, float persistence); static void mapgen_simplex(mapgen_settings* settings); -static int32_t _heightSize; +static TileCoordsXY _heightSize; static uint8_t* _height; static int32_t get_height(int32_t x, int32_t y) { - if (x >= 0 && y >= 0 && x < _heightSize && y < _heightSize) - return _height[x + y * _heightSize]; + if (x >= 0 && y >= 0 && x < _heightSize.x && y < _heightSize.y) + return _height[x + y * _heightSize.x]; return 0; } static void set_height(int32_t x, int32_t y, int32_t height) { - if (x >= 0 && y >= 0 && x < _heightSize && y < _heightSize) - _height[x + y * _heightSize] = height; + if (x >= 0 && y >= 0 && x < _heightSize.x && y < _heightSize.y) + _height[x + y * _heightSize.x] = height; } void mapgen_generate_blank(mapgen_settings* settings) @@ -120,10 +120,10 @@ void mapgen_generate_blank(mapgen_settings* settings) int32_t x, y; map_clear_all_elements(); - map_init({ settings->mapSize, settings->mapSize }); - for (y = 1; y < settings->mapSize - 1; y++) + map_init(settings->mapSize); + for (y = 1; y < settings->mapSize.y - 1; y++) { - for (x = 1; x < settings->mapSize - 1; x++) + for (x = 1; x < settings->mapSize.x - 1; x++) { auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); if (surfaceElement != nullptr) @@ -141,7 +141,7 @@ void mapgen_generate_blank(mapgen_settings* settings) void mapgen_generate(mapgen_settings* settings) { - auto mapSize = settings->mapSize; + const auto& mapSize = settings->mapSize; auto waterLevel = settings->water_level; const auto selectedFloor = TerrainSurfaceObject::GetById(settings->floor); std::string_view floorTexture = selectedFloor != nullptr ? selectedFloor->GetIdentifier() : ""; @@ -184,10 +184,10 @@ void mapgen_generate(mapgen_settings* settings) map_clear_all_elements(); // Initialise the base map - map_init({ mapSize, mapSize }); - for (auto y = 1; y < mapSize - 1; y++) + map_init(mapSize); + for (auto y = 1; y < mapSize.y - 1; y++) { - for (auto x = 1; x < mapSize - 1; x++) + for (auto x = 1; x < mapSize.x - 1; x++) { auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); if (surfaceElement != nullptr) @@ -201,9 +201,9 @@ void mapgen_generate(mapgen_settings* settings) } // Create the temporary height map and initialise - _heightSize = mapSize * 2; - _height = new uint8_t[_heightSize * _heightSize]; - std::fill_n(_height, _heightSize * _heightSize, 0x00); + _heightSize = { mapSize.x * 2, mapSize.y * 2 }; + _height = new uint8_t[_heightSize.y * _heightSize.x]; + std::fill_n(_height, _heightSize.y * _heightSize.x, 0x00); mapgen_simplex(settings); mapgen_smooth_height(2 + (util_rand() % 6)); @@ -213,7 +213,7 @@ void mapgen_generate(mapgen_settings* settings) delete[] _height; // Set the tile slopes so that there are no cliffs - while (map_smooth(1, 1, mapSize - 1, mapSize - 1)) + while (map_smooth(1, 1, mapSize.x - 1, mapSize.y - 1)) { } @@ -235,9 +235,9 @@ void mapgen_generate(mapgen_settings* settings) } auto beachTextureId = objectManager.GetLoadedObjectEntryIndex(ObjectEntryDescriptor(beachTexture)); - for (auto y = 1; y < mapSize - 1; y++) + for (auto y = 1; y < mapSize.y - 1; y++) { - for (auto x = 1; x < mapSize - 1; x++) + for (auto x = 1; x < mapSize.x - 1; x++) { auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY()); @@ -431,22 +431,22 @@ static void mapgen_set_water_level(int32_t waterLevel) static void mapgen_smooth_height(int32_t iterations) { int32_t i, x, y, xx, yy, avg; - int32_t arraySize = _heightSize * _heightSize * sizeof(uint8_t); + int32_t arraySize = _heightSize.y * _heightSize.x * sizeof(uint8_t); uint8_t* copyHeight = new uint8_t[arraySize]; for (i = 0; i < iterations; i++) { std::memcpy(copyHeight, _height, arraySize); - for (y = 1; y < _heightSize - 1; y++) + for (y = 1; y < _heightSize.y - 1; y++) { - for (x = 1; x < _heightSize - 1; x++) + for (x = 1; x < _heightSize.x - 1; x++) { avg = 0; for (yy = -1; yy <= 1; yy++) { for (xx = -1; xx <= 1; xx++) { - avg += copyHeight[(y + yy) * _heightSize + (x + xx)]; + avg += copyHeight[(y + yy) * _heightSize.x + (x + xx)]; } } avg /= 9; @@ -463,12 +463,11 @@ static void mapgen_smooth_height(int32_t iterations) */ static void mapgen_set_height(mapgen_settings* settings) { - int32_t x, y, heightX, heightY, mapSize; + int32_t x, y, heightX, heightY; - mapSize = _heightSize / 2; - for (y = 1; y < mapSize - 1; y++) + for (y = 1; y < _heightSize.y / 2 - 1; y++) { - for (x = 1; x < mapSize - 1; x++) + for (x = 1; x < _heightSize.x / 2 - 1; x++) { heightX = x * 2; heightY = y * 2; @@ -646,16 +645,16 @@ static void mapgen_simplex(mapgen_settings* settings) { int32_t x, y; - float freq = settings->simplex_base_freq * (1.0f / _heightSize); + float freq = settings->simplex_base_freq * (1.0f / _heightSize.x); int32_t octaves = settings->simplex_octaves; int32_t low = settings->simplex_low; int32_t high = settings->simplex_high; noise_rand(); - for (y = 0; y < _heightSize; y++) + for (y = 0; y < _heightSize.y; y++) { - for (x = 0; x < _heightSize; x++) + for (x = 0; x < _heightSize.x; x++) { float noiseValue = std::clamp(fractal_noise(x, y, freq, octaves, 2.0f, 0.65f), -1.0f, 1.0f); float normalisedNoiseValue = (noiseValue + 1.0f) / 2.0f; diff --git a/src/openrct2/world/MapGen.h b/src/openrct2/world/MapGen.h index cd8bfbfec9..61036adb81 100644 --- a/src/openrct2/world/MapGen.h +++ b/src/openrct2/world/MapGen.h @@ -11,11 +11,12 @@ #include "../common.h" #include "../core/String.hpp" +#include "Location.hpp" struct mapgen_settings { // Base - int32_t mapSize; + TileCoordsXY mapSize; int32_t height; int32_t water_level; int32_t floor;