From 422e132845255264314cd79aa14361d0df0905d7 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Wed, 24 Mar 2021 10:29:01 +0100 Subject: [PATCH] Feature: auto-detect map height limit based on generated map This opens up the true power of the TGP terrain generator, as it is no longer constrainted by an arbitrary low map height limit, especially for extreme terrain types. In other words: on a 1kx1k map with "Alpinist" terrain type, the map is now really hilly with default settings. People can still manually limit the map height if they so wish, and after the terrain generation the limit is stored in the savegame as if the user set it. Cheats still allow you to change this value. --- src/genworld.cpp | 15 +++++++++++++++ src/genworld.h | 3 +++ src/genworld_gui.cpp | 15 ++++++++++++--- src/lang/english.txt | 4 +++- src/table/settings.ini | 8 ++++---- src/tgp.cpp | 15 ++++++++++++++- src/tgp.h | 1 + src/tile_type.h | 1 - 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/genworld.cpp b/src/genworld.cpp index 0bd64f8965..d357a15161 100644 --- a/src/genworld.cpp +++ b/src/genworld.cpp @@ -33,6 +33,7 @@ #include "game/game_instance.hpp" #include "string_func.h" #include "thread.h" +#include "tgp.h" #include "safeguards.h" @@ -285,6 +286,20 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti InitializeGame(_gw.size_x, _gw.size_y, true, reset_settings); PrepareGenerateWorldProgress(); + if (_settings_game.construction.map_height_limit == 0) { + uint estimated_height = 0; + + if (_gw.mode == GWM_EMPTY && _game_mode != GM_MENU) { + estimated_height = _settings_game.game_creation.se_flat_world_height; + } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) { + estimated_height = GetEstimationTGPMapHeight(); + } else { + estimated_height = 0; + } + + _settings_game.construction.map_height_limit = std::max(MAP_HEIGHT_LIMIT_AUTO_MINIMUM, std::min(MAX_MAP_HEIGHT_LIMIT, estimated_height + MAP_HEIGHT_LIMIT_AUTO_CEILING_ROOM)); + } + /* Load the right landscape stuff, and the NewGRFs! */ GfxLoadSprites(); LoadStringWidthTable(); diff --git a/src/genworld.h b/src/genworld.h index e780ed1694..71dae3f365 100644 --- a/src/genworld.h +++ b/src/genworld.h @@ -46,6 +46,9 @@ static const uint CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY = 4; ///< Value for custom static const uint CUSTOM_SEA_LEVEL_MIN_PERCENTAGE = 1; ///< Minimum percentage a user can specify for custom sea level. static const uint CUSTOM_SEA_LEVEL_MAX_PERCENTAGE = 90; ///< Maximum percentage a user can specify for custom sea level. +static const uint MAP_HEIGHT_LIMIT_AUTO_MINIMUM = 30; ///< When map height limit is auto, make this the lowest possible map height limit. +static const uint MAP_HEIGHT_LIMIT_AUTO_CEILING_ROOM = 15; ///< When map height limit is auto, the map height limit will be the higest peak plus this value. + typedef void GWDoneProc(); ///< Procedure called when the genworld process finishes typedef void GWAbortProc(); ///< Called when genworld is aborted diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index 0ca4543f2c..5e1fac685b 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -45,6 +45,15 @@ enum GenerateLandscapeWindowMode { GLWM_SCENARIO, ///< Generate flat land. }; +/** + * Get the map height limit, or if set to "auto", the absolute limit. + */ +static uint GetMapHeightLimit() +{ + if (_settings_newgame.construction.map_height_limit == 0) return MAX_MAP_HEIGHT_LIMIT; + return _settings_newgame.construction.map_height_limit; +} + /** * Changes landscape type and sets genworld window dirty * @param landscape new landscape type @@ -974,7 +983,7 @@ struct CreateScenarioWindow : public Window this->SetWidgetDisabledState(WID_CS_START_DATE_DOWN, _settings_newgame.game_creation.starting_year <= MIN_YEAR); this->SetWidgetDisabledState(WID_CS_START_DATE_UP, _settings_newgame.game_creation.starting_year >= MAX_YEAR); this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_DOWN, _settings_newgame.game_creation.se_flat_world_height <= 0); - this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_UP, _settings_newgame.game_creation.se_flat_world_height >= MAX_TILE_HEIGHT); + this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_UP, _settings_newgame.game_creation.se_flat_world_height >= GetMapHeightLimit()); this->SetWidgetLoweredState(WID_CS_TEMPERATE, _settings_newgame.game_creation.landscape == LT_TEMPERATE); this->SetWidgetLoweredState(WID_CS_ARCTIC, _settings_newgame.game_creation.landscape == LT_ARCTIC); @@ -1062,7 +1071,7 @@ struct CreateScenarioWindow : public Window this->HandleButtonClick(widget); this->SetDirty(); - _settings_newgame.game_creation.se_flat_world_height = Clamp(_settings_newgame.game_creation.se_flat_world_height + widget - WID_CS_FLAT_LAND_HEIGHT_TEXT, 0, _settings_game.construction.map_height_limit); + _settings_newgame.game_creation.se_flat_world_height = Clamp(_settings_newgame.game_creation.se_flat_world_height + widget - WID_CS_FLAT_LAND_HEIGHT_TEXT, 0, GetMapHeightLimit()); } _left_button_clicked = false; break; @@ -1108,7 +1117,7 @@ struct CreateScenarioWindow : public Window case WID_CS_FLAT_LAND_HEIGHT_TEXT: this->SetWidgetDirty(WID_CS_FLAT_LAND_HEIGHT_TEXT); - _settings_newgame.game_creation.se_flat_world_height = Clamp(value, 0, _settings_game.construction.map_height_limit); + _settings_newgame.game_creation.se_flat_world_height = Clamp(value, 0, GetMapHeightLimit()); break; } diff --git a/src/lang/english.txt b/src/lang/english.txt index bc38876e4d..94dbba787c 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1206,7 +1206,9 @@ STR_CONFIG_SETTING_CITY_APPROVAL :Town council's STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Choose how much noise and environmental damage by companies affect their town rating and further construction actions in their area STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT :Map height limit: {STRING2} -STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_HELPTEXT :Set the maximum allowed height of the map; neither the terrain generator nor you can build higher than this limit +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_HELPTEXT :Set the maximum allowed height of the map; neither the terrain generator nor you can build higher than this limit. On (auto) it will pick a good value after terrain generation +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_VALUE :{NUM} +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_AUTO :(auto) STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}You can't set the map height limit to this value. At least one mountain on the map is higher STR_CONFIG_SETTING_AUTOSLOPE :Allow landscaping under buildings, tracks, etc.: {STRING2} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Allow landscaping under buildings and tracks without removing them diff --git a/src/table/settings.ini b/src/table/settings.ini index 67403a3bf1..ae6a40e9fd 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -394,16 +394,16 @@ base = GameSettings var = construction.map_height_limit type = SLE_UINT8 from = SLV_194 -guiflags = SGF_NEWGAME_ONLY | SGF_SCENEDIT_TOO -def = DEF_MAP_HEIGHT_LIMIT +guiflags = SGF_NEWGAME_ONLY | SGF_SCENEDIT_TOO | SGF_0ISDISABLED +def = 0 min = MIN_MAP_HEIGHT_LIMIT max = MAX_MAP_HEIGHT_LIMIT interval = 1 str = STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT strhelp = STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_HELPTEXT -strval = STR_JUST_INT +strval = STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_VALUE proc = ChangeMaxHeightLevel -cat = SC_BASIC +cat = SC_ADVANCED [SDT_BOOL] base = GameSettings diff --git a/src/tgp.cpp b/src/tgp.cpp index 92e714d9bf..3ced2a1b06 100644 --- a/src/tgp.cpp +++ b/src/tgp.cpp @@ -237,7 +237,20 @@ static height_t TGPGetMaxHeight() int map_size_bucket = std::min(MapLogX(), MapLogY()) - MIN_MAP_SIZE_BITS; int max_height_from_table = max_height[_settings_game.difficulty.terrain_type][map_size_bucket]; - return I2H(std::min(max_height_from_table, _settings_game.construction.map_height_limit)); + /* If there is a manual map height limit, clamp to it. */ + if (_settings_game.construction.map_height_limit != 0) { + max_height_from_table = std::min(max_height_from_table, _settings_game.construction.map_height_limit); + } + + return I2H(max_height_from_table); +} + +/** + * Get an overestimation of the highest peak TGP wants to generate. + */ +uint GetEstimationTGPMapHeight() +{ + return H2I(TGPGetMaxHeight()); } /** diff --git a/src/tgp.h b/src/tgp.h index 8d8d974892..e773c6ff25 100644 --- a/src/tgp.h +++ b/src/tgp.h @@ -11,5 +11,6 @@ #define TGP_H void GenerateTerrainPerlin(); +uint GetEstimationTGPMapHeight(); #endif /* TGP_H */ diff --git a/src/tile_type.h b/src/tile_type.h index ad3d1b5635..17b4ad2067 100644 --- a/src/tile_type.h +++ b/src/tile_type.h @@ -22,7 +22,6 @@ static const int MAX_VEHICLE_PIXEL_Y = 96; ///< Maximum heig static const uint MAX_TILE_HEIGHT = 255; ///< Maximum allowed tile height static const uint MIN_MAP_HEIGHT_LIMIT = 15; ///< Lower bound of maximum allowed heightlevel (in the construction settings) -static const uint DEF_MAP_HEIGHT_LIMIT = 30; ///< Default maximum allowed heightlevel (in the construction settings) static const uint MAX_MAP_HEIGHT_LIMIT = MAX_TILE_HEIGHT; ///< Upper bound of maximum allowed heightlevel (in the construction settings) static const uint MIN_SNOWLINE_HEIGHT = 2; ///< Minimum snowline height