diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index 8944d77af6..feedb47d20 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -97,6 +97,7 @@ static constexpr std::initializer_list _nested_generate_landscape_w NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0), NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_MAPSIZE, STR_MAPGEN_MAPSIZE_TOOLTIP), SetFill(1, 1), NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_TERRAIN_TYPE, STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT), SetFill(1, 1), + NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_AVERAGE_HEIGHT, STR_CONFIG_SETTING_AVERAGE_HEIGHT_HELPTEXT), SetFill(1, 1), NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_VARIETY, STR_CONFIG_SETTING_VARIETY_HELPTEXT), SetFill(1, 1), NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_SMOOTHNESS, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT), SetFill(1, 1), NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_QUANTITY_OF_RIVERS, STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT), SetFill(1, 1), @@ -111,7 +112,8 @@ static constexpr std::initializer_list _nested_generate_landscape_w NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_BY), SetFill(0, 1), SetAlignment(SA_CENTER), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_MAPSIZE_Y_PULLDOWN), SetToolTip(STR_MAPGEN_MAPSIZE_TOOLTIP), SetFill(1, 1), EndContainer(), - NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_TERRAIN_PULLDOWN), SetToolTip(STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT), SetFill(1, 1), + NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_MAX_HEIGHT_PULLDOWN), SetToolTip(STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT), SetFill(1, 1), + NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_AVERAGE_HEIGHT_PULLDOWN), SetToolTip(STR_CONFIG_SETTING_AVERAGE_HEIGHT_HELPTEXT), SetFill(1, 1), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_VARIETY_PULLDOWN), SetToolTip(STR_CONFIG_SETTING_VARIETY_HELPTEXT), SetFill(1, 1), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_SMOOTHNESS_PULLDOWN), SetToolTip(STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT), SetFill(1, 1), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_RIVER_PULLDOWN), SetToolTip(STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT), SetFill(1, 1), @@ -133,6 +135,8 @@ static constexpr std::initializer_list _nested_generate_landscape_w NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_NUMBER_OF_TOWNS, STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP), SetFill(1, 1), NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_NUMBER_OF_INDUSTRIES, STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP), SetFill(1, 1), NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_MAPGEN_SEA_LEVEL, STR_MAPGEN_SEA_LEVEL_TOOLTIP), SetFill(1, 1), + /* Spacer due to fewer items in columns 3-4 than in 1-2. */ + NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), /* Widgets on the right side (global column 4). */ @@ -164,6 +168,8 @@ static constexpr std::initializer_list _nested_generate_landscape_w NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_TOWN_PULLDOWN), SetToolTip(STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP), SetFill(1, 1), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_INDUSTRY_PULLDOWN), SetToolTip(STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP), SetFill(1, 1), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_WATER_PULLDOWN), SetToolTip(STR_MAPGEN_SEA_LEVEL_TOOLTIP), SetFill(1, 1), + /* Spacer due to fewer items in columns 3-4 than in 1-2. */ + NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), EndContainer(), EndContainer(), @@ -376,7 +382,7 @@ static DropDownList BuildTownNameDropDown() } -static const StringID _elevations[] = {STR_TERRAIN_TYPE_VERY_FLAT, STR_TERRAIN_TYPE_FLAT, STR_TERRAIN_TYPE_HILLY, STR_TERRAIN_TYPE_MOUNTAINOUS, STR_TERRAIN_TYPE_ALPINIST, STR_TERRAIN_TYPE_CUSTOM}; +static const StringID _max_height[] = {STR_TERRAIN_TYPE_VERY_FLAT, STR_TERRAIN_TYPE_FLAT, STR_TERRAIN_TYPE_HILLY, STR_TERRAIN_TYPE_MOUNTAINOUS, STR_TERRAIN_TYPE_ALPINIST, STR_TERRAIN_TYPE_CUSTOM}; static const StringID _sea_lakes[] = {STR_SEA_LEVEL_VERY_LOW, STR_SEA_LEVEL_LOW, STR_SEA_LEVEL_MEDIUM, STR_SEA_LEVEL_HIGH, STR_SEA_LEVEL_CUSTOM}; static const StringID _rivers[] = {STR_RIVERS_NONE, STR_RIVERS_FEW, STR_RIVERS_MODERATE, STR_RIVERS_LOT}; static const StringID _borders[] = {STR_MAPGEN_BORDER_RANDOMIZE, STR_MAPGEN_BORDER_MANUAL, STR_MAPGEN_BORDER_INFINITE_WATER}; @@ -385,6 +391,7 @@ static const StringID _rotation[] = {STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CO static const StringID _num_towns[] = {STR_NUM_VERY_LOW, STR_NUM_LOW, STR_NUM_NORMAL, STR_NUM_HIGH, STR_NUM_CUSTOM}; static const StringID _num_inds[] = {STR_FUNDING_ONLY, STR_MINIMAL, STR_NUM_VERY_LOW, STR_NUM_LOW, STR_NUM_NORMAL, STR_NUM_HIGH, STR_NUM_CUSTOM}; static const StringID _variety[] = {STR_VARIETY_NONE, STR_VARIETY_VERY_LOW, STR_VARIETY_LOW, STR_VARIETY_MEDIUM, STR_VARIETY_HIGH, STR_VARIETY_VERY_HIGH}; +static const StringID _average_height[] = {STR_CONFIG_SETTING_AVERAGE_HEIGHT_AUTO, STR_CONFIG_SETTING_AVERAGE_HEIGHT_LOWLANDS, STR_CONFIG_SETTING_AVERAGE_HEIGHT_NORMAL, STR_CONFIG_SETTING_AVERAGE_HEIGHT_PLATEAUS}; static_assert(std::size(_num_inds) == ID_END); @@ -413,7 +420,7 @@ struct GenerateLandscapeWindow : public Window { /* If original landgenerator is selected and alpinist terrain_type was selected, revert to mountainous. */ if (_settings_newgame.game_creation.land_generator == LG_ORIGINAL) { - _settings_newgame.difficulty.terrain_type = Clamp(_settings_newgame.difficulty.terrain_type, TT_VERY_FLAT, TT_MOUNTAINOUS); + _settings_newgame.difficulty.terrain_type = Clamp(_settings_newgame.difficulty.terrain_type, GenworldMaxHeight::VeryFlat, GenworldMaxHeight::Mountainous); } this->OnInvalidateData(); @@ -456,11 +463,11 @@ struct GenerateLandscapeWindow : public Window { } return GetString(_num_inds[_settings_newgame.difficulty.industry_density]); - case WID_GL_TERRAIN_PULLDOWN: - if (_settings_newgame.difficulty.terrain_type == TT_CUSTOM) { + case WID_GL_MAX_HEIGHT_PULLDOWN: + if (_settings_newgame.difficulty.terrain_type == GenworldMaxHeight::Custom) { return GetString(STR_TERRAIN_TYPE_CUSTOM_VALUE, _settings_newgame.game_creation.custom_terrain_type); } - return GetString(_elevations[_settings_newgame.difficulty.terrain_type]); + return GetString(_max_height[to_underlying(_settings_newgame.difficulty.terrain_type)]); case WID_GL_WATER_PULLDOWN: if (_settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) { @@ -472,6 +479,7 @@ struct GenerateLandscapeWindow : public Window { case WID_GL_RIVER_PULLDOWN: return GetString(_rivers[_settings_newgame.game_creation.amount_of_rivers]); case WID_GL_SMOOTHNESS_PULLDOWN: return GetString(_smoothness[_settings_newgame.game_creation.tgen_smoothness]); case WID_GL_VARIETY_PULLDOWN: return GetString(_variety[_settings_newgame.game_creation.variety]); + case WID_GL_AVERAGE_HEIGHT_PULLDOWN: return GetString(_average_height[to_underlying(_settings_newgame.game_creation.average_height)]); case WID_GL_BORDERS_PULLDOWN: return GetString(_borders[_settings_newgame.game_creation.water_border_presets]); case WID_GL_WATER_NE: return GetString((_settings_newgame.game_creation.water_borders == BorderFlag::Random) ? STR_MAPGEN_BORDER_RANDOM : _settings_newgame.game_creation.water_borders.Test(BorderFlag::NorthEast) ? STR_MAPGEN_BORDER_WATER : STR_MAPGEN_BORDER_FREEFORM); case WID_GL_WATER_NW: return GetString((_settings_newgame.game_creation.water_borders == BorderFlag::Random) ? STR_MAPGEN_BORDER_RANDOM : _settings_newgame.game_creation.water_borders.Test(BorderFlag::NorthWest) ? STR_MAPGEN_BORDER_WATER : STR_MAPGEN_BORDER_FREEFORM); @@ -518,7 +526,7 @@ struct GenerateLandscapeWindow : public Window { this->SetWidgetLoweredState(WID_GL_WATER_SW, _settings_newgame.game_creation.water_borders.Test(BorderFlag::SouthWest)); this->SetWidgetsDisabledState(_settings_newgame.game_creation.land_generator == LG_ORIGINAL && (_settings_newgame.game_creation.landscape == LandscapeType::Arctic || _settings_newgame.game_creation.landscape == LandscapeType::Tropic), - WID_GL_TERRAIN_PULLDOWN, WID_GL_WATER_PULLDOWN); + WID_GL_MAX_HEIGHT_PULLDOWN, WID_GL_WATER_PULLDOWN); } /* Disable snowline if not arctic */ @@ -554,8 +562,8 @@ struct GenerateLandscapeWindow : public Window { if (_settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) { _settings_newgame.difficulty.quantity_sea_lakes = 1; } - if (_settings_newgame.difficulty.terrain_type == TT_CUSTOM) { - _settings_newgame.difficulty.terrain_type = TT_FLAT; + if (_settings_newgame.difficulty.terrain_type == GenworldMaxHeight::Custom) { + _settings_newgame.difficulty.terrain_type = GenworldMaxHeight::Flat; } } @@ -607,8 +615,8 @@ struct GenerateLandscapeWindow : public Window { d = GetStringBoundingBox(GetString(STR_NUM_CUSTOM_NUMBER, GetParamMaxValue(IndustryPool::MAX_SIZE))); break; - case WID_GL_TERRAIN_PULLDOWN: - strs = _elevations; + case WID_GL_MAX_HEIGHT_PULLDOWN: + strs = _max_height; d = GetStringBoundingBox(GetString(STR_TERRAIN_TYPE_CUSTOM_VALUE, GetParamMaxValue(MAX_MAP_HEIGHT_LIMIT))); break; @@ -619,6 +627,7 @@ struct GenerateLandscapeWindow : public Window { case WID_GL_RIVER_PULLDOWN: strs = _rivers; break; case WID_GL_SMOOTHNESS_PULLDOWN: strs = _smoothness; break; + case WID_GL_AVERAGE_HEIGHT_PULLDOWN: strs = _variety; break; case WID_GL_VARIETY_PULLDOWN: strs = _variety; break; case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN: strs = _rotation; break; case WID_GL_BORDERS_PULLDOWN: strs = _borders; break; @@ -776,9 +785,9 @@ struct GenerateLandscapeWindow : public Window { ShowDropDownMenu(this, _rotation, _settings_newgame.game_creation.heightmap_rotation, WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, 0, 0); break; - case WID_GL_TERRAIN_PULLDOWN: // Terrain type + case WID_GL_MAX_HEIGHT_PULLDOWN: // Max height /* For the original map generation only the first four are valid. */ - ShowDropDownMenu(this, _elevations, _settings_newgame.difficulty.terrain_type, WID_GL_TERRAIN_PULLDOWN, 0, _settings_newgame.game_creation.land_generator == LG_ORIGINAL ? ~0xF : 0); + ShowDropDownMenu(this, _max_height, to_underlying(_settings_newgame.difficulty.terrain_type), WID_GL_MAX_HEIGHT_PULLDOWN, 0, _settings_newgame.game_creation.land_generator == LG_ORIGINAL ? ~0xF : 0); break; case WID_GL_WATER_PULLDOWN: { // Water quantity @@ -803,6 +812,10 @@ struct GenerateLandscapeWindow : public Window { ShowDropDownMenu(this, _variety, _settings_newgame.game_creation.variety, WID_GL_VARIETY_PULLDOWN, 0, 0); break; + case WID_GL_AVERAGE_HEIGHT_PULLDOWN: // Average height + ShowDropDownMenu(this, _average_height, to_underlying(_settings_newgame.game_creation.average_height), WID_GL_AVERAGE_HEIGHT_PULLDOWN, 0, 0); + break; + /* Map borders */ case WID_GL_BORDERS_PULLDOWN: ShowDropDownMenu(this, _borders, _settings_newgame.game_creation.water_border_presets, WID_GL_BORDERS_PULLDOWN, 0, 0); @@ -863,6 +876,7 @@ struct GenerateLandscapeWindow : public Window { case WID_GL_RIVER_PULLDOWN: _settings_newgame.game_creation.amount_of_rivers = index; break; case WID_GL_SMOOTHNESS_PULLDOWN: _settings_newgame.game_creation.tgen_smoothness = index; break; case WID_GL_VARIETY_PULLDOWN: _settings_newgame.game_creation.variety = index; break; + case WID_GL_AVERAGE_HEIGHT_PULLDOWN: _settings_newgame.game_creation.average_height = static_cast(index); break; case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN: _settings_newgame.game_creation.heightmap_rotation = index; break; @@ -889,12 +903,12 @@ struct GenerateLandscapeWindow : public Window { _settings_newgame.difficulty.industry_density = index; break; - case WID_GL_TERRAIN_PULLDOWN: { - if ((uint)index == TT_CUSTOM) { + case WID_GL_MAX_HEIGHT_PULLDOWN: { + if (static_cast(index) == GenworldMaxHeight::Custom) { this->widget_id = widget; ShowQueryString(GetString(STR_JUST_INT, _settings_newgame.game_creation.custom_terrain_type), STR_MAPGEN_TERRAIN_TYPE_QUERY_CAPT, 4, this, CS_NUMERAL, {}); } - _settings_newgame.difficulty.terrain_type = static_cast(index); + _settings_newgame.difficulty.terrain_type = static_cast(index); break; } @@ -948,7 +962,7 @@ struct GenerateLandscapeWindow : public Window { case WID_GL_DESERT_COVERAGE_TEXT: value = DEF_DESERT_COVERAGE; break; case WID_GL_TOWN_PULLDOWN: value = 1; break; case WID_GL_INDUSTRY_PULLDOWN: value = 1; break; - case WID_GL_TERRAIN_PULLDOWN: value = MIN_MAP_HEIGHT_LIMIT; break; + case WID_GL_MAX_HEIGHT_PULLDOWN: value = MIN_MAP_HEIGHT_LIMIT; break; case WID_GL_WATER_PULLDOWN: value = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE; break; default: NOT_REACHED(); } @@ -983,7 +997,7 @@ struct GenerateLandscapeWindow : public Window { _settings_newgame.game_creation.custom_industry_number = Clamp(value, 1, IndustryPool::MAX_SIZE); break; - case WID_GL_TERRAIN_PULLDOWN: + case WID_GL_MAX_HEIGHT_PULLDOWN: _settings_newgame.game_creation.custom_terrain_type = Clamp(value, MIN_CUSTOM_TERRAIN_TYPE, GetMapHeightLimit()); break; diff --git a/src/landscape.cpp b/src/landscape.cpp index 7bad6138e1..1a4e35c678 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -1034,7 +1034,7 @@ static bool FindSpring(TileIndex tile) uint required_num_hills = 3; /* If we don't have many hills, loosen the standards so we still get rivers. */ - if (_settings_game.difficulty.terrain_type < TT_HILLY) { + if (_settings_game.difficulty.terrain_type < GenworldMaxHeight::Hilly) { max_hill_distance = 3; required_num_hills = 1; }; @@ -1676,7 +1676,7 @@ bool GenerateLandscape(uint8_t mode) uint i = Map::ScaleBySize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100); for (; i != 0; --i) { /* Make sure we do not overflow. */ - GenerateTerrain(Clamp(_settings_game.difficulty.terrain_type, TT_VERY_FLAT, TT_MOUNTAINOUS), 0); + GenerateTerrain(static_cast(Clamp(_settings_game.difficulty.terrain_type, GenworldMaxHeight::VeryFlat, GenworldMaxHeight::Mountainous)), 0); } break; } diff --git a/src/lang/english.txt b/src/lang/english.txt index b6f1f0d893..c71eaaa9be 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1598,7 +1598,7 @@ STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT :The original ge STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Original STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis -STR_CONFIG_SETTING_TERRAIN_TYPE :Terrain type: {STRING2} +STR_CONFIG_SETTING_TERRAIN_TYPE :Maximum height preset: {STRING2} STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :Choose the height of hills and mountains of the landscape STR_CONFIG_SETTING_INDUSTRY_DENSITY :Industry density: {STRING2} @@ -1626,6 +1626,14 @@ STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Smooth STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Rough STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Very Rough +STR_CONFIG_SETTING_AVERAGE_HEIGHT :Average height: {STRING2} +STR_CONFIG_SETTING_AVERAGE_HEIGHT_HELPTEXT :Choose the average height of land. 'Automatic' uses the default based on the selected climate: 'Lowlands' for Subtropical, 'Normal' for Temperate and Toyland, and 'Plateaus' for Subarctic. +###length 4 +STR_CONFIG_SETTING_AVERAGE_HEIGHT_AUTO :Automatic +STR_CONFIG_SETTING_AVERAGE_HEIGHT_LOWLANDS :Lowlands +STR_CONFIG_SETTING_AVERAGE_HEIGHT_NORMAL :Normal +STR_CONFIG_SETTING_AVERAGE_HEIGHT_PLATEAUS :Plateaus + STR_CONFIG_SETTING_VARIETY :Variety distribution: {STRING2} STR_CONFIG_SETTING_VARIETY_HELPTEXT :Choose if the map contains both mountains and flat areas. The higher the variety, the more differences in elevation between mountainous and flat areas @@ -3386,7 +3394,8 @@ STR_MAPGEN_DESERT_COVERAGE :{BLACK}Desert c STR_MAPGEN_DESERT_COVERAGE_UP_TOOLTIP :{BLACK}Increase desert coverage by ten percent STR_MAPGEN_DESERT_COVERAGE_DOWN_TOOLTIP :{BLACK}Decrease desert coverage by ten percent STR_MAPGEN_DESERT_COVERAGE_TEXT :{BLACK}{NUM}% -STR_MAPGEN_TERRAIN_TYPE :{BLACK}Terrain type: +STR_MAPGEN_TERRAIN_TYPE :{BLACK}Maximum height: +STR_MAPGEN_AVERAGE_HEIGHT :{BLACK}Average height: STR_MAPGEN_SEA_LEVEL :{BLACK}Sea level: STR_MAPGEN_SEA_LEVEL_TOOLTIP :{BLACK}Select the sea level STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Rivers: diff --git a/src/settingentry_gui.cpp b/src/settingentry_gui.cpp index 031fb1989f..d9ac6134b0 100644 --- a/src/settingentry_gui.cpp +++ b/src/settingentry_gui.cpp @@ -841,6 +841,7 @@ SettingsContainer &GetSettingsTree() genworld->Add(new SettingEntry("game_creation.landscape")); genworld->Add(new SettingEntry("game_creation.land_generator")); genworld->Add(new SettingEntry("difficulty.terrain_type")); + genworld->Add(new SettingEntry("game_creation.average_height")); genworld->Add(new SettingEntry("game_creation.tgen_smoothness")); genworld->Add(new SettingEntry("game_creation.variety")); genworld->Add(new SettingEntry("game_creation.snow_coverage")); diff --git a/src/settings_type.h b/src/settings_type.h index fd484e4799..32b0fba43d 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -51,16 +51,6 @@ enum SettingsProfile : uint8_t { SP_HIGHSCORE_END, ///< End of highscore tables. }; -/** Available terrain types (heights). */ -enum TerrainType : uint8_t { - TT_VERY_FLAT, - TT_FLAT, - TT_HILLY, - TT_MOUNTAINOUS, - TT_ALPINIST, - TT_CUSTOM, -}; - /** Available industry map generation densities. */ enum IndustryDensity : uint8_t { ID_FUND_ONLY, ///< The game does not build industries. @@ -75,6 +65,24 @@ enum IndustryDensity : uint8_t { ID_END, ///< Number of industry density settings. }; +/** Possible options for the Maximum Height pulldown in the Genworld GUI. */ +enum class GenworldMaxHeight : uint8_t { + VeryFlat, + Flat, + Hilly, + Mountainous, + Alpinist, + Custom, +}; + +/** Possible options for the Average Height pulldown in the Genworld GUI. */ +enum class GenworldAverageHeight : uint8_t { + Auto, + Lowlands, + Normal, + Plateaus, +}; + /** Possible options for the Borders pulldown in the Genworld GUI. */ enum BorderFlagPresets : uint8_t { BFP_RANDOM = 0, @@ -151,7 +159,7 @@ struct DifficultySettings { uint8_t subsidy_multiplier; ///< payment multiplier for subsidized deliveries uint16_t subsidy_duration; ///< duration of subsidies uint8_t construction_cost; ///< how expensive is building - TerrainType terrain_type; ///< the mountainousness of the landscape + GenworldMaxHeight terrain_type; ///< the mountainousness of the landscape uint8_t quantity_sea_lakes; ///< the amount of seas/lakes bool economy; ///< how volatile is the economy bool line_reverse_mode; ///< reversing at stations or not @@ -415,6 +423,7 @@ struct GameCreationSettings { uint16_t custom_town_number; ///< manually entered number of towns uint16_t custom_industry_number; ///< manually entered number of industries uint8_t variety; ///< variety level applied to TGP + GenworldAverageHeight average_height; ///< adjustment applied to TGP based on climate, or manually set by the player. uint8_t custom_terrain_type; ///< manually entered height for TGP to aim for uint8_t custom_sea_level; ///< manually entered percentage of water in the map uint8_t min_river_length; ///< the minimum river length diff --git a/src/table/settings/difficulty_settings.ini b/src/table/settings/difficulty_settings.ini index 71bed256c1..e8be630f07 100644 --- a/src/table/settings/difficulty_settings.ini +++ b/src/table/settings/difficulty_settings.ini @@ -231,9 +231,9 @@ var = difficulty.terrain_type type = SLE_UINT8 from = SLV_97 flags = SettingFlag::GuiDropdown, SettingFlag::NewgameOnly -def = TT_FLAT -min = TT_VERY_FLAT -max = TT_CUSTOM +def = GenworldMaxHeight::Flat +min = GenworldMaxHeight::VeryFlat +max = GenworldMaxHeight::Custom str = STR_CONFIG_SETTING_TERRAIN_TYPE strhelp = STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT strval = STR_TERRAIN_TYPE_VERY_FLAT diff --git a/src/table/settings/world_settings.ini b/src/table/settings/world_settings.ini index 30aaec5f6f..1cbacba67c 100644 --- a/src/table/settings/world_settings.ini +++ b/src/table/settings/world_settings.ini @@ -185,6 +185,18 @@ strhelp = STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT strval = STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH cat = SC_BASIC +[SDT_VAR] +var = game_creation.average_height +type = SLE_UINT8 +flags = SettingFlag::GuiDropdown, SettingFlag::NewgameOnly +def = GenworldAverageHeight::Auto +min = GenworldAverageHeight::Auto +max = GenworldAverageHeight::Plateaus +str = STR_CONFIG_SETTING_AVERAGE_HEIGHT +strhelp = STR_CONFIG_SETTING_AVERAGE_HEIGHT_HELPTEXT +strval = STR_CONFIG_SETTING_AVERAGE_HEIGHT_AUTO +cat = SC_BASIC + [SDT_VAR] var = game_creation.variety type = SLE_UINT8 diff --git a/src/tgp.cpp b/src/tgp.cpp index 3287ed8ed6..a48147a910 100644 --- a/src/tgp.cpp +++ b/src/tgp.cpp @@ -215,7 +215,7 @@ static const int64_t _water_percent[4] = {70, 170, 270, 420}; */ static Height TGPGetMaxHeight() { - if (_settings_game.difficulty.terrain_type == TT_CUSTOM) { + if (_settings_game.difficulty.terrain_type == GenworldMaxHeight::Custom) { /* TGP never reaches this height; this means that if a user inputs "2", * it would create a flat map without the "+ 1". But that would * overflow on "255". So we reduce it by 1 to get back in range. */ @@ -242,7 +242,7 @@ static Height TGPGetMaxHeight() }; int map_size_bucket = std::min(Map::LogX(), Map::LogY()) - MIN_MAP_SIZE_BITS; - int max_height_from_table = max_height[_settings_game.difficulty.terrain_type][map_size_bucket]; + int max_height_from_table = max_height[to_underlying(_settings_game.difficulty.terrain_type)][map_size_bucket]; /* If there is a manual map height limit, clamp to it. */ if (_settings_game.construction.map_height_limit != 0) { @@ -455,6 +455,81 @@ static int *HeightMapMakeHistogram(Height h_min, [[maybe_unused]] Height h_max, return hist; } +/** + * Adjust the landscape to create lowlands on average (tropic landscape). + * @param fheight The height to adjust. + * @return The adjusted height. + */ +static double SineTransformLowlands(double fheight) +{ + double height = fheight; + + /* Half of tiles should be at lowest (0..25%) heights */ + double sine_lower_limit = 0.5; + double linear_compression = 2; + if (height <= sine_lower_limit) { + /* Under the limit we do linear compression down */ + height = height / linear_compression; + } else { + double m = sine_lower_limit / linear_compression; + /* Get sine_lower_limit..1 into -1..1 */ + height = 2.0 * ((height - sine_lower_limit) / (1.0 - sine_lower_limit)) - 1.0; + /* Sine wave transform */ + height = sin(height * M_PI_2); + /* Get -1..1 back to (sine_lower_limit / linear_compression)..1.0 */ + height = 0.5 * ((1.0 - m) * height + (1.0 + m)); + } + + return height; +} + +/** + * Adjust the landscape to create normal average height (temperate and toyland landscapes). + * @param fheight The height to adjust. + * @return The adjusted height. + */ +static double SineTransformNormal(double &fheight) +{ + double height = fheight; + + /* Move and scale 0..1 into -1..+1 */ + height = 2 * height - 1; + /* Sine transform */ + height = sin(height * M_PI_2); + /* Transform it back from -1..1 into 0..1 space */ + height = 0.5 * (height + 1); + + return height; +} + +/** + * Adjust the landscape to create plateaus on average (arctic landscape). + * @param fheight The height to adjust. + * @return The adjusted height. + */ +static double SineTransformPlateaus(double &fheight) +{ + double height = fheight; + + /* Redistribute heights to have more tiles at highest (75%..100%) range */ + double sine_upper_limit = 0.75; + double linear_compression = 2; + if (height >= sine_upper_limit) { + /* Over the limit we do linear compression up */ + height = 1.0 - (1.0 - height) / linear_compression; + } else { + double m = 1.0 - (1.0 - sine_upper_limit) / linear_compression; + /* Get 0..sine_upper_limit into -1..1 */ + height = 2.0 * height / sine_upper_limit - 1.0; + /* Sine wave transform */ + height = sin(height * M_PI_2); + /* Get -1..1 back to 0..(1 - (1 - sine_upper_limit) / linear_compression) == 0.0..m */ + height = 0.5 * (height + 1.0) * m; + } + + return height; +} + /** Applies sine wave redistribution onto height map */ static void HeightMapSineTransform(Height h_min, Height h_max) { @@ -465,66 +540,27 @@ static void HeightMapSineTransform(Height h_min, Height h_max) /* Transform height into 0..1 space */ fheight = (double)(h - h_min) / (double)(h_max - h_min); - /* Apply sine transform depending on landscape type */ - switch (_settings_game.game_creation.landscape) { - case LandscapeType::Toyland: - case LandscapeType::Temperate: - /* Move and scale 0..1 into -1..+1 */ - fheight = 2 * fheight - 1; - /* Sine transform */ - fheight = sin(fheight * M_PI_2); - /* Transform it back from -1..1 into 0..1 space */ - fheight = 0.5 * (fheight + 1); - break; - case LandscapeType::Arctic: - { - /* Arctic terrain needs special height distribution. - * Redistribute heights to have more tiles at highest (75%..100%) range */ - double sine_upper_limit = 0.75; - double linear_compression = 2; - if (fheight >= sine_upper_limit) { - /* Over the limit we do linear compression up */ - fheight = 1.0 - (1.0 - fheight) / linear_compression; - } else { - double m = 1.0 - (1.0 - sine_upper_limit) / linear_compression; - /* Get 0..sine_upper_limit into -1..1 */ - fheight = 2.0 * fheight / sine_upper_limit - 1.0; - /* Sine wave transform */ - fheight = sin(fheight * M_PI_2); - /* Get -1..1 back to 0..(1 - (1 - sine_upper_limit) / linear_compression) == 0.0..m */ - fheight = 0.5 * (fheight + 1.0) * m; - } + switch (_settings_game.game_creation.average_height) { + case GenworldAverageHeight::Auto: + /* Apply sine transform depending on landscape type */ + switch (_settings_game.game_creation.landscape) { + case LandscapeType::Temperate: fheight = SineTransformNormal(fheight); break; + case LandscapeType::Tropic: fheight = SineTransformLowlands(fheight); break; + case LandscapeType::Arctic: fheight = SineTransformPlateaus(fheight); break; + case LandscapeType::Toyland: fheight = SineTransformNormal(fheight); break; + default: NOT_REACHED(); } break; - case LandscapeType::Tropic: - { - /* Desert terrain needs special height distribution. - * Half of tiles should be at lowest (0..25%) heights */ - double sine_lower_limit = 0.5; - double linear_compression = 2; - if (fheight <= sine_lower_limit) { - /* Under the limit we do linear compression down */ - fheight = fheight / linear_compression; - } else { - double m = sine_lower_limit / linear_compression; - /* Get sine_lower_limit..1 into -1..1 */ - fheight = 2.0 * ((fheight - sine_lower_limit) / (1.0 - sine_lower_limit)) - 1.0; - /* Sine wave transform */ - fheight = sin(fheight * M_PI_2); - /* Get -1..1 back to (sine_lower_limit / linear_compression)..1.0 */ - fheight = 0.5 * ((1.0 - m) * fheight + (1.0 + m)); - } - } - break; - - default: - NOT_REACHED(); - break; + case GenworldAverageHeight::Lowlands: fheight = SineTransformLowlands(fheight); break; + case GenworldAverageHeight::Normal: fheight = SineTransformNormal(fheight); break; + case GenworldAverageHeight::Plateaus: fheight = SineTransformPlateaus(fheight); break; + default: NOT_REACHED(); } + /* Transform it back into h_min..h_max space */ - h = (Height)(fheight * (h_max - h_min) + h_min); + h = static_cast(fheight * (h_max - h_min) + h_min); if (h < 0) h = I2H(0); if (h >= h_max) h = h_max - 1; } diff --git a/src/widgets/genworld_widget.h b/src/widgets/genworld_widget.h index 7180863f9c..106415b74d 100644 --- a/src/widgets/genworld_widget.h +++ b/src/widgets/genworld_widget.h @@ -48,11 +48,12 @@ enum GenerateLandscapeWidgets : WidgetID { WID_GL_HEIGHTMAP_SIZE_TEXT, ///< Size of heightmap. WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, ///< Dropdown 'Heightmap rotation'. - WID_GL_TERRAIN_PULLDOWN, ///< Dropdown 'Terrain type'. + WID_GL_MAX_HEIGHT_PULLDOWN, ///< Dropdown 'Maximum height'. WID_GL_WATER_PULLDOWN, ///< Dropdown 'Sea level'. WID_GL_RIVER_PULLDOWN, ///< Dropdown 'Rivers'. WID_GL_SMOOTHNESS_PULLDOWN, ///< Dropdown 'Smoothness'. WID_GL_VARIETY_PULLDOWN, ///< Dropdown 'Variety distribution'. + WID_GL_AVERAGE_HEIGHT_PULLDOWN, ///< Dropdown 'Average height'. WID_GL_BORDERS_PULLDOWN, ///< Dropdown 'Map edges'. WID_GL_WATER_NW, ///< NW 'Water'/'Freeform'.