1
0
mirror of https://github.com/OpenTTD/OpenTTD synced 2026-01-18 09:52:44 +01:00

Feature: Add worldgen setting for average height (#14989)

This commit is contained in:
Tyler Trahan
2026-01-10 11:53:27 -05:00
committed by GitHub
parent 666073fc7b
commit 7ccfd0a658
9 changed files with 175 additions and 93 deletions

View File

@@ -97,6 +97,7 @@ static constexpr std::initializer_list<NWidgetPart> _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<NWidgetPart> _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<NWidgetPart> _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<NWidgetPart> _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<GenworldAverageHeight>(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<GenworldMaxHeight>(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<TerrainType>(index);
_settings_newgame.difficulty.terrain_type = static_cast<GenworldMaxHeight>(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;

View File

@@ -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<int>(Clamp(_settings_game.difficulty.terrain_type, GenworldMaxHeight::VeryFlat, GenworldMaxHeight::Mountainous)), 0);
}
break;
}

View File

@@ -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:

View File

@@ -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"));

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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<Height>(fheight * (h_max - h_min) + h_min);
if (h < 0) h = I2H(0);
if (h >= h_max) h = h_max - 1;
}

View File

@@ -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'.