2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 /** @file genworld_gui.cpp GUI to configure and show progress during map generation. */
11 #include "heightmap.h"
14 #include "network/network.h"
15 #include "strings_func.h"
16 #include "window_func.h"
17 #include "timer/timer_game_calendar.h"
18 #include "sound_func.h"
20 #include "string_func.h"
21 #include "dropdown_type.h"
22 #include "dropdown_common_type.h"
23 #include "dropdown_func.h"
24 #include "querystring_gui.h"
26 #include "core/geometry_func.hpp"
27 #include "core/random_func.hpp"
28 #include "saveload/saveload.h"
31 #include "newgrf_townname.h"
32 #include "townname_type.h"
33 #include "video/video_driver.hpp"
34 #include "ai/ai_gui.hpp"
35 #include "game/game_gui.hpp"
38 #include "widgets/genworld_widget.h"
40 #include "safeguards.h"
43 extern void MakeNewgameSettingsLive();
45 /** Enum for the modes we can generate in. */
46 enum GenerateLandscapeWindowMode
{
47 GLWM_GENERATE
, ///< Generate new game.
48 GLWM_HEIGHTMAP
, ///< Load from heightmap.
49 GLWM_SCENARIO
, ///< Generate flat land.
53 * Get the map height limit, or if set to "auto", the absolute limit.
55 static uint
GetMapHeightLimit()
57 if (_settings_newgame
.construction
.map_height_limit
== 0) return MAX_MAP_HEIGHT_LIMIT
;
58 return _settings_newgame
.construction
.map_height_limit
;
62 * Changes landscape type and sets genworld window dirty
63 * @param landscape new landscape type
65 void SetNewLandscapeType(uint8_t landscape
)
67 _settings_newgame
.game_creation
.landscape
= landscape
;
68 InvalidateWindowClassesData(WC_SELECT_GAME
);
69 InvalidateWindowClassesData(WC_GENERATE_LANDSCAPE
);
72 /** Widgets of GenerateLandscapeWindow when generating world */
73 static constexpr NWidgetPart _nested_generate_landscape_widgets
[] = {
74 NWidget(NWID_HORIZONTAL
),
75 NWidget(WWT_CLOSEBOX
, COLOUR_BROWN
),
76 NWidget(WWT_CAPTION
, COLOUR_BROWN
), SetDataTip(STR_MAPGEN_WORLD_GENERATION_CAPTION
, STR_NULL
),
78 NWidget(WWT_PANEL
, COLOUR_BROWN
),
79 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_wide
, 0), SetPadding(WidgetDimensions::unscaled
.sparse
),
80 /* Landscape selection. */
81 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0), SetPIPRatio(1, 1, 1),
82 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TEMPERATE
), SetDataTip(SPR_SELECT_TEMPERATE
, STR_INTRO_TOOLTIP_TEMPERATE
),
83 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_ARCTIC
), SetDataTip(SPR_SELECT_SUB_ARCTIC
, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE
),
84 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TROPICAL
), SetDataTip(SPR_SELECT_SUB_TROPICAL
, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE
),
85 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TOYLAND
), SetDataTip(SPR_SELECT_TOYLAND
, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE
),
88 /* Generation options. */
89 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0),
90 /* Left half (land generation options) */
91 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
92 /* Labels on the left side (global column 1). */
93 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
94 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_MAPSIZE
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
95 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_TERRAIN_TYPE
, STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT
), SetFill(1, 1),
96 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_VARIETY
, STR_CONFIG_SETTING_VARIETY_HELPTEXT
), SetFill(1, 1),
97 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SMOOTHNESS
, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT
), SetFill(1, 1),
98 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_QUANTITY_OF_RIVERS
, STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT
), SetFill(1, 1),
99 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_BORDER_TYPE
, STR_MAPGEN_BORDER_TYPE_TOOLTIP
), SetFill(1, 1),
102 /* Widgets on the right side (global column 2). */
103 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
105 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
106 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_MAPSIZE_X_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
107 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_BY
, STR_NULL
), SetFill(0, 1), SetAlignment(SA_CENTER
),
108 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_MAPSIZE_Y_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
110 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TERRAIN_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT
), SetFill(1, 1),
111 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_VARIETY_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_VARIETY_HELPTEXT
), SetFill(1, 1),
112 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_SMOOTHNESS_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT
), SetFill(1, 1),
113 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_RIVER_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT
), SetFill(1, 1),
114 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_BORDERS_RANDOM
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_BORDER_TYPE_TOOLTIP
), SetFill(1, 1),
118 /* Right half (all other options) */
119 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
120 /* Labels on the left side (global column 3). */
121 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
122 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_GL_CLIMATE_SEL_LABEL
),
123 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SNOW_COVERAGE
, STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT
), SetFill(1, 1),
124 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DESERT_COVERAGE
, STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT
), SetFill(1, 1),
125 NWidget(NWID_SPACER
), SetFill(1, 1),
127 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DATE
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(1, 1),
128 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_TOWN_NAME_LABEL
, STR_MAPGEN_TOWN_NAME_DROPDOWN_TOOLTIP
), SetFill(1, 1),
129 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NUMBER_OF_TOWNS
, STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP
), SetFill(1, 1),
130 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NUMBER_OF_INDUSTRIES
, STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP
), SetFill(1, 1),
131 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SEA_LEVEL
, STR_MAPGEN_SEA_LEVEL_TOOLTIP
), SetFill(1, 1),
134 /* Widgets on the right side (global column 4). */
135 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
136 /* Climate selector. */
137 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_GL_CLIMATE_SEL_SELECTOR
),
139 NWidget(NWID_HORIZONTAL
),
140 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_SNOW_COVERAGE_DOWN
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
141 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_TEXT
), SetDataTip(STR_MAPGEN_SNOW_COVERAGE_TEXT
, STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT
), SetFill(1, 1),
142 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_SNOW_COVERAGE_UP
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
144 /* Desert coverage. */
145 NWidget(NWID_HORIZONTAL
),
146 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_DESERT_COVERAGE_DOWN
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
147 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_TEXT
), SetDataTip(STR_MAPGEN_DESERT_COVERAGE_TEXT
, STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT
), SetFill(1, 1),
148 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_DESERT_COVERAGE_UP
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
150 /* Temperate/Toyland spacer. */
151 NWidget(NWID_SPACER
), SetFill(1, 1),
154 NWidget(NWID_HORIZONTAL
),
155 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_START_DATE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
156 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_START_DATE_TEXT
), SetDataTip(STR_JUST_DATE_LONG
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(1, 1),
157 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_START_DATE_UP
), SetDataTip(SPR_ARROW_UP
, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
159 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TOWNNAME_DROPDOWN
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_TOWN_NAME_DROPDOWN_TOOLTIP
), SetFill(1, 1),
160 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TOWN_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP
), SetFill(1, 1),
161 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_INDUSTRY_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP
), SetFill(1, 1),
162 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_WATER_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_SEA_LEVEL_TOOLTIP
), SetFill(1, 1),
167 /* Map borders buttons for each edge. */
168 NWidget(NWID_VERTICAL
),
169 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
170 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NORTHWEST
, STR_NULL
), SetPadding(0, WidgetDimensions::unscaled
.hsep_normal
, 0, 0), SetFill(1, 1), SetAlignment(SA_RIGHT
| SA_VERT_CENTER
),
171 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_WATER_NW
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_NORTHWEST
), SetFill(1, 1),
172 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_WATER_NE
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_NORTHEAST
), SetFill(1, 1),
173 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NORTHEAST
, STR_NULL
), SetPadding(0, 0, 0, WidgetDimensions::unscaled
.hsep_normal
), SetFill(1, 1),
175 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
176 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SOUTHWEST
, STR_NULL
), SetPadding(0, WidgetDimensions::unscaled
.hsep_normal
, 0, 0), SetFill(1, 1), SetAlignment(SA_RIGHT
| SA_VERT_CENTER
),
177 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_WATER_SW
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_SOUTHWEST
), SetFill(1, 1),
178 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_WATER_SE
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_SOUTHEAST
), SetFill(1, 1),
179 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SOUTHEAST
, STR_NULL
), SetPadding(0, 0, 0, WidgetDimensions::unscaled
.hsep_normal
), SetFill(1, 1),
183 /* AI, GS, and NewGRF settings */
184 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
185 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_AI_BUTTON
), SetMinimalTextLines(2, 0), SetDataTip(STR_MAPGEN_AI_SETTINGS
, STR_MAPGEN_AI_SETTINGS_TOOLTIP
), SetFill(1, 0),
186 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_GS_BUTTON
), SetMinimalTextLines(2, 0), SetDataTip(STR_MAPGEN_GS_SETTINGS
, STR_MAPGEN_GS_SETTINGS_TOOLTIP
), SetFill(1, 0),
187 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_NEWGRF_BUTTON
), SetMinimalTextLines(2, 0), SetDataTip(STR_MAPGEN_NEWGRF_SETTINGS
, STR_MAPGEN_NEWGRF_SETTINGS_TOOLTIP
), SetFill(1, 0),
191 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREEN
, WID_GL_GENERATE_BUTTON
), SetMinimalTextLines(3, 0), SetDataTip(STR_MAPGEN_GENERATE
, STR_MAPGEN_GENERATE_TOOLTIP
), SetFill(1, 1),
196 /** Widgets of GenerateLandscapeWindow when loading heightmap */
197 static constexpr NWidgetPart _nested_heightmap_load_widgets
[] = {
199 NWidget(NWID_HORIZONTAL
),
200 NWidget(WWT_CLOSEBOX
, COLOUR_BROWN
),
201 NWidget(WWT_CAPTION
, COLOUR_BROWN
), SetDataTip(STR_MAPGEN_WORLD_GENERATION_CAPTION
, STR_NULL
),
203 NWidget(WWT_PANEL
, COLOUR_BROWN
),
204 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_wide
, 0), SetPadding(WidgetDimensions::unscaled
.sparse
),
205 /* Landscape selection. */
206 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0), SetPIPRatio(1, 1, 1),
207 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TEMPERATE
), SetDataTip(SPR_SELECT_TEMPERATE
, STR_INTRO_TOOLTIP_TEMPERATE
),
208 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_ARCTIC
), SetDataTip(SPR_SELECT_SUB_ARCTIC
, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE
),
209 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TROPICAL
), SetDataTip(SPR_SELECT_SUB_TROPICAL
, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE
),
210 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TOYLAND
), SetDataTip(SPR_SELECT_TOYLAND
, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE
),
213 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
214 /* Heightmap name label. */
215 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_HEIGHTMAP_NAME
, STR_MAPGEN_HEIGHTMAP_NAME_TOOLTIP
),
216 NWidget(WWT_TEXT
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_NAME_TEXT
), SetTextStyle(TC_ORANGE
), SetDataTip(STR_JUST_RAW_STRING
, STR_MAPGEN_HEIGHTMAP_NAME_TOOLTIP
), SetFill(1, 0),
219 /* Generation options. */
220 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0),
221 /* Left half (land generation options) */
222 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
223 /* Labels on the left side (global column 1). */
224 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
225 /* Land generation option labels. */
226 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_HEIGHTMAP_SIZE_LABEL
, STR_MAPGEN_HEIGHTMAP_SIZE_LABEL_TOOLTIP
), SetFill(1, 1),
227 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_MAPSIZE
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
228 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_HEIGHTMAP_ROTATION
, STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_TOOLTIP
), SetFill(1, 1),
229 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_HEIGHTMAP_HEIGHT
, STR_MAPGEN_HEIGHTMAP_HEIGHT_TOOLTIP
), SetFill(1, 1),
230 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_QUANTITY_OF_RIVERS
, STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT
), SetFill(1, 1),
233 /* Left half widgets (global column 2) */
234 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
235 NWidget(WWT_TEXT
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_SIZE_TEXT
), SetDataTip(STR_MAPGEN_HEIGHTMAP_SIZE
, STR_MAPGEN_HEIGHTMAP_SIZE_LABEL_TOOLTIP
), SetFill(1, 1),
237 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
238 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_MAPSIZE_X_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
239 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_BY
, STR_NULL
), SetFill(0, 1), SetAlignment(SA_CENTER
),
240 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_MAPSIZE_Y_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
242 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_TOOLTIP
), SetFill(1, 1),
243 /* Heightmap highest peak. */
244 NWidget(NWID_HORIZONTAL
),
245 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_HEIGHT_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_HEIGHTMAP_HEIGHT_DOWN
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
246 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_HEIGHT_TEXT
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_HEIGHTMAP_HEIGHT_TOOLTIP
), SetFill(1, 1),
247 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_HEIGHT_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_HEIGHTMAP_HEIGHT_UP
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
249 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_RIVER_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT
), SetFill(1, 1),
253 /* Right half (all other options) */
254 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
255 /* Right half labels (global column 3) */
256 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
257 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_GL_CLIMATE_SEL_LABEL
),
258 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SNOW_COVERAGE
, STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT
), SetFill(1, 1),
259 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DESERT_COVERAGE
, STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT
), SetFill(1, 1),
260 NWidget(NWID_SPACER
), SetFill(1, 1),
262 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DATE
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(1, 1),
263 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_TOWN_NAME_LABEL
, STR_MAPGEN_TOWN_NAME_DROPDOWN_TOOLTIP
), SetFill(1, 1),
264 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NUMBER_OF_TOWNS
, STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP
), SetFill(1, 1),
265 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NUMBER_OF_INDUSTRIES
, STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP
), SetFill(1, 1),
268 /* Right half widgets (global column 4) */
269 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
270 /* Climate selector. */
271 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_GL_CLIMATE_SEL_SELECTOR
),
273 NWidget(NWID_HORIZONTAL
),
274 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_SNOW_COVERAGE_DOWN
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
275 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_TEXT
), SetDataTip(STR_MAPGEN_SNOW_COVERAGE_TEXT
, STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT
), SetFill(1, 1),
276 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_SNOW_COVERAGE_UP
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
278 /* Desert coverage. */
279 NWidget(NWID_HORIZONTAL
),
280 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_DESERT_COVERAGE_DOWN
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
281 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_TEXT
), SetDataTip(STR_MAPGEN_DESERT_COVERAGE_TEXT
, STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT
), SetFill(1, 1),
282 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_DESERT_COVERAGE_UP
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
284 /* Temperate/Toyland spacer. */
285 NWidget(NWID_SPACER
), SetFill(1, 1),
288 NWidget(NWID_HORIZONTAL
),
289 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_START_DATE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
290 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_START_DATE_TEXT
), SetDataTip(STR_JUST_DATE_LONG
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(1, 1),
291 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_START_DATE_UP
), SetDataTip(SPR_ARROW_UP
, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD
), SetFill(0, 1), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
293 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TOWNNAME_DROPDOWN
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_TOWN_NAME_DROPDOWN_TOOLTIP
), SetFill(1, 1),
294 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TOWN_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP
), SetFill(1, 1),
295 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_INDUSTRY_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP
), SetFill(1, 1),
300 /* AI, GS, and NewGRF settings */
301 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
302 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_AI_BUTTON
), SetMinimalTextLines(2, 0), SetDataTip(STR_MAPGEN_AI_SETTINGS
, STR_MAPGEN_AI_SETTINGS_TOOLTIP
), SetFill(1, 0),
303 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_GS_BUTTON
), SetMinimalTextLines(2, 0), SetDataTip(STR_MAPGEN_GS_SETTINGS
, STR_MAPGEN_GS_SETTINGS_TOOLTIP
), SetFill(1, 0),
304 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_NEWGRF_BUTTON
), SetMinimalTextLines(2, 0), SetDataTip(STR_MAPGEN_NEWGRF_SETTINGS
, STR_MAPGEN_NEWGRF_SETTINGS_TOOLTIP
), SetFill(1, 0),
308 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREEN
, WID_GL_GENERATE_BUTTON
), SetMinimalTextLines(3, 0), SetDataTip(STR_MAPGEN_GENERATE
, STR_MAPGEN_GENERATE_TOOLTIP
), SetFill(1, 1),
313 static void StartGeneratingLandscape(GenerateLandscapeWindowMode mode
)
315 CloseAllNonVitalWindows();
316 ClearErrorMessages();
318 /* Copy all XXX_newgame to XXX when coming from outside the editor */
319 MakeNewgameSettingsLive();
320 ResetGRFConfig(true);
322 if (_settings_client
.sound
.confirm
) SndPlayFx(SND_15_BEEP
);
324 case GLWM_GENERATE
: _switch_mode
= (_game_mode
== GM_EDITOR
) ? SM_GENRANDLAND
: SM_NEWGAME
; break;
325 case GLWM_HEIGHTMAP
: _switch_mode
= (_game_mode
== GM_EDITOR
) ? SM_LOAD_HEIGHTMAP
: SM_START_HEIGHTMAP
; break;
326 case GLWM_SCENARIO
: _switch_mode
= SM_EDITOR
; break;
327 default: NOT_REACHED();
331 static void LandscapeGenerationCallback(Window
*w
, bool confirmed
)
333 if (confirmed
) StartGeneratingLandscape((GenerateLandscapeWindowMode
)w
->window_number
);
336 static DropDownList
BuildMapsizeDropDown()
340 for (uint i
= MIN_MAP_SIZE_BITS
; i
<= MAX_MAP_SIZE_BITS
; i
++) {
341 SetDParam(0, 1LL << i
);
342 list
.push_back(MakeDropDownListStringItem(STR_JUST_INT
, i
));
348 static DropDownList
BuildTownNameDropDown()
352 /* Add and sort newgrf townnames generators */
353 const auto &grf_names
= GetGRFTownNameList();
354 for (uint i
= 0; i
< grf_names
.size(); i
++) {
355 list
.push_back(MakeDropDownListStringItem(grf_names
[i
], BUILTIN_TOWNNAME_GENERATOR_COUNT
+ i
));
357 std::sort(list
.begin(), list
.end(), DropDownListStringItem::NatSortFunc
);
359 size_t newgrf_size
= list
.size();
360 /* Insert newgrf_names at the top of the list */
361 if (newgrf_size
> 0) {
362 list
.push_back(MakeDropDownListDividerItem()); // separator line
366 /* Add and sort original townnames generators */
367 for (uint i
= 0; i
< BUILTIN_TOWNNAME_GENERATOR_COUNT
; i
++) {
368 list
.push_back(MakeDropDownListStringItem(STR_MAPGEN_TOWN_NAME_ORIGINAL_ENGLISH
+ i
, i
));
370 std::sort(list
.begin() + newgrf_size
, list
.end(), DropDownListStringItem::NatSortFunc
);
376 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
};
377 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
};
378 static const StringID _rivers
[] = {STR_RIVERS_NONE
, STR_RIVERS_FEW
, STR_RIVERS_MODERATE
, STR_RIVERS_LOT
};
379 static const StringID _smoothness
[] = {STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH
, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH
, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH
, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH
};
380 static const StringID _rotation
[] = {STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE
, STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE
};
381 static const StringID _num_towns
[] = {STR_NUM_VERY_LOW
, STR_NUM_LOW
, STR_NUM_NORMAL
, STR_NUM_HIGH
, STR_NUM_CUSTOM
};
382 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
};
383 static const StringID _variety
[] = {STR_VARIETY_NONE
, STR_VARIETY_VERY_LOW
, STR_VARIETY_LOW
, STR_VARIETY_MEDIUM
, STR_VARIETY_HIGH
, STR_VARIETY_VERY_HIGH
};
385 static_assert(std::size(_num_inds
) == ID_END
);
387 struct GenerateLandscapeWindow
: public Window
{
392 GenerateLandscapeWindowMode mode
;
394 GenerateLandscapeWindow(WindowDesc
&desc
, WindowNumber number
= 0) : Window(desc
)
396 this->InitNested(number
);
398 this->LowerWidget(_settings_newgame
.game_creation
.landscape
+ WID_GL_TEMPERATE
);
400 this->mode
= (GenerateLandscapeWindowMode
)this->window_number
;
402 /* Disable town and industry in SE */
403 this->SetWidgetDisabledState(WID_GL_TOWN_PULLDOWN
, _game_mode
== GM_EDITOR
);
404 this->SetWidgetDisabledState(WID_GL_INDUSTRY_PULLDOWN
, _game_mode
== GM_EDITOR
);
406 /* In case the map_height_limit is changed, clamp heightmap_height and custom_terrain_type. */
407 _settings_newgame
.game_creation
.heightmap_height
= Clamp(_settings_newgame
.game_creation
.heightmap_height
, MIN_HEIGHTMAP_HEIGHT
, GetMapHeightLimit());
408 _settings_newgame
.game_creation
.custom_terrain_type
= Clamp(_settings_newgame
.game_creation
.custom_terrain_type
, MIN_CUSTOM_TERRAIN_TYPE
, GetMapHeightLimit());
410 /* If original landgenerator is selected and alpinist terrain_type was selected, revert to mountainous. */
411 if (_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
) {
412 _settings_newgame
.difficulty
.terrain_type
= Clamp(_settings_newgame
.difficulty
.terrain_type
, 0, 3);
415 this->OnInvalidateData();
419 void SetStringParameters(WidgetID widget
) const override
422 case WID_GL_START_DATE_TEXT
: SetDParam(0, TimerGameCalendar::ConvertYMDToDate(_settings_newgame
.game_creation
.starting_year
, 0, 1)); break;
423 case WID_GL_MAPSIZE_X_PULLDOWN
: SetDParam(0, 1LL << _settings_newgame
.game_creation
.map_x
); break;
424 case WID_GL_MAPSIZE_Y_PULLDOWN
: SetDParam(0, 1LL << _settings_newgame
.game_creation
.map_y
); break;
425 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
: SetDParam(0, _settings_newgame
.game_creation
.heightmap_height
); break;
426 case WID_GL_SNOW_COVERAGE_TEXT
: SetDParam(0, _settings_newgame
.game_creation
.snow_coverage
); break;
427 case WID_GL_DESERT_COVERAGE_TEXT
: SetDParam(0, _settings_newgame
.game_creation
.desert_coverage
); break;
429 case WID_GL_TOWN_PULLDOWN
:
430 if (_game_mode
== GM_EDITOR
) {
431 SetDParam(0, STR_CONFIG_SETTING_OFF
);
432 } else if (_settings_newgame
.difficulty
.number_towns
== CUSTOM_TOWN_NUMBER_DIFFICULTY
) {
433 SetDParam(0, STR_NUM_CUSTOM_NUMBER
);
434 SetDParam(1, _settings_newgame
.game_creation
.custom_town_number
);
436 SetDParam(0, _num_towns
[_settings_newgame
.difficulty
.number_towns
]);
440 case WID_GL_TOWNNAME_DROPDOWN
: {
441 uint gen
= _settings_newgame
.game_creation
.town_name
;
442 StringID name
= gen
< BUILTIN_TOWNNAME_GENERATOR_COUNT
?
443 STR_MAPGEN_TOWN_NAME_ORIGINAL_ENGLISH
+ gen
:
444 GetGRFTownNameName(gen
- BUILTIN_TOWNNAME_GENERATOR_COUNT
);
449 case WID_GL_INDUSTRY_PULLDOWN
:
450 if (_game_mode
== GM_EDITOR
) {
451 SetDParam(0, STR_CONFIG_SETTING_OFF
);
452 } else if (_settings_newgame
.difficulty
.industry_density
== ID_CUSTOM
) {
453 SetDParam(0, STR_NUM_CUSTOM_NUMBER
);
454 SetDParam(1, _settings_newgame
.game_creation
.custom_industry_number
);
456 SetDParam(0, _num_inds
[_settings_newgame
.difficulty
.industry_density
]);
460 case WID_GL_TERRAIN_PULLDOWN
:
461 if (_settings_newgame
.difficulty
.terrain_type
== CUSTOM_TERRAIN_TYPE_NUMBER_DIFFICULTY
) {
462 SetDParam(0, STR_TERRAIN_TYPE_CUSTOM_VALUE
);
463 SetDParam(1, _settings_newgame
.game_creation
.custom_terrain_type
);
465 SetDParam(0, _elevations
[_settings_newgame
.difficulty
.terrain_type
]); break;
469 case WID_GL_WATER_PULLDOWN
:
470 if (_settings_newgame
.difficulty
.quantity_sea_lakes
== CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
) {
471 SetDParam(0, STR_SEA_LEVEL_CUSTOM_PERCENTAGE
);
472 SetDParam(1, _settings_newgame
.game_creation
.custom_sea_level
);
474 SetDParam(0, _sea_lakes
[_settings_newgame
.difficulty
.quantity_sea_lakes
]);
478 case WID_GL_HEIGHTMAP_NAME_TEXT
: SetDParamStr(0, this->name
); break;
479 case WID_GL_RIVER_PULLDOWN
: SetDParam(0, _rivers
[_settings_newgame
.game_creation
.amount_of_rivers
]); break;
480 case WID_GL_SMOOTHNESS_PULLDOWN
: SetDParam(0, _smoothness
[_settings_newgame
.game_creation
.tgen_smoothness
]); break;
481 case WID_GL_VARIETY_PULLDOWN
: SetDParam(0, _variety
[_settings_newgame
.game_creation
.variety
]); break;
482 case WID_GL_BORDERS_RANDOM
: SetDParam(0, (_settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
) ? STR_MAPGEN_BORDER_RANDOMIZE
: STR_MAPGEN_BORDER_MANUAL
); break;
483 case WID_GL_WATER_NE
: SetDParam(0, (_settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
) ? STR_MAPGEN_BORDER_RANDOM
: HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NE
) ? STR_MAPGEN_BORDER_WATER
: STR_MAPGEN_BORDER_FREEFORM
); break;
484 case WID_GL_WATER_NW
: SetDParam(0, (_settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
) ? STR_MAPGEN_BORDER_RANDOM
: HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NW
) ? STR_MAPGEN_BORDER_WATER
: STR_MAPGEN_BORDER_FREEFORM
); break;
485 case WID_GL_WATER_SE
: SetDParam(0, (_settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
) ? STR_MAPGEN_BORDER_RANDOM
: HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SE
) ? STR_MAPGEN_BORDER_WATER
: STR_MAPGEN_BORDER_FREEFORM
); break;
486 case WID_GL_WATER_SW
: SetDParam(0, (_settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
) ? STR_MAPGEN_BORDER_RANDOM
: HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SW
) ? STR_MAPGEN_BORDER_WATER
: STR_MAPGEN_BORDER_FREEFORM
); break;
487 case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
: SetDParam(0, _rotation
[_settings_newgame
.game_creation
.heightmap_rotation
]); break;
489 case WID_GL_HEIGHTMAP_SIZE_TEXT
:
490 if (_settings_newgame
.game_creation
.heightmap_rotation
== HM_CLOCKWISE
) {
491 SetDParam(0, this->y
);
492 SetDParam(1, this->x
);
494 SetDParam(0, this->x
);
495 SetDParam(1, this->y
);
502 * Some data on this window has become invalid.
503 * @param data Information about the changed data.
504 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
506 void OnInvalidateData([[maybe_unused
]] int data
= 0, [[maybe_unused
]] bool gui_scope
= true) override
508 if (!gui_scope
) return;
509 /* Update the climate buttons */
510 this->SetWidgetLoweredState(WID_GL_TEMPERATE
, _settings_newgame
.game_creation
.landscape
== LT_TEMPERATE
);
511 this->SetWidgetLoweredState(WID_GL_ARCTIC
, _settings_newgame
.game_creation
.landscape
== LT_ARCTIC
);
512 this->SetWidgetLoweredState(WID_GL_TROPICAL
, _settings_newgame
.game_creation
.landscape
== LT_TROPIC
);
513 this->SetWidgetLoweredState(WID_GL_TOYLAND
, _settings_newgame
.game_creation
.landscape
== LT_TOYLAND
);
515 /* You can't select smoothness / non-water borders if not terragenesis */
516 if (mode
== GLWM_GENERATE
) {
517 this->SetWidgetDisabledState(WID_GL_SMOOTHNESS_PULLDOWN
, _settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
);
518 this->SetWidgetDisabledState(WID_GL_VARIETY_PULLDOWN
, _settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
);
519 this->SetWidgetDisabledState(WID_GL_BORDERS_RANDOM
, _settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
|| !_settings_newgame
.construction
.freeform_edges
);
520 this->SetWidgetsDisabledState(_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
|| !_settings_newgame
.construction
.freeform_edges
|| _settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
,
521 WID_GL_WATER_NW
, WID_GL_WATER_NE
, WID_GL_WATER_SE
, WID_GL_WATER_SW
);
523 this->SetWidgetLoweredState(WID_GL_BORDERS_RANDOM
, _settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
);
525 this->SetWidgetLoweredState(WID_GL_WATER_NW
, HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NW
));
526 this->SetWidgetLoweredState(WID_GL_WATER_NE
, HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NE
));
527 this->SetWidgetLoweredState(WID_GL_WATER_SE
, HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SE
));
528 this->SetWidgetLoweredState(WID_GL_WATER_SW
, HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SW
));
530 this->SetWidgetsDisabledState(_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
&& (_settings_newgame
.game_creation
.landscape
== LT_ARCTIC
|| _settings_newgame
.game_creation
.landscape
== LT_TROPIC
),
531 WID_GL_TERRAIN_PULLDOWN
, WID_GL_WATER_PULLDOWN
);
534 /* Disable snowline if not arctic */
535 this->SetWidgetDisabledState(WID_GL_SNOW_COVERAGE_TEXT
, _settings_newgame
.game_creation
.landscape
!= LT_ARCTIC
);
536 /* Disable desert if not tropic */
537 this->SetWidgetDisabledState(WID_GL_DESERT_COVERAGE_TEXT
, _settings_newgame
.game_creation
.landscape
!= LT_TROPIC
);
539 /* Set snow/rainforest selections */
540 int climate_plane
= 0;
541 switch (_settings_newgame
.game_creation
.landscape
) {
542 case LT_TEMPERATE
: climate_plane
= 2; break;
543 case LT_ARCTIC
: climate_plane
= 0; break;
544 case LT_TROPIC
: climate_plane
= 1; break;
545 case LT_TOYLAND
: climate_plane
= 2; break;
547 this->GetWidget
<NWidgetStacked
>(WID_GL_CLIMATE_SEL_LABEL
)->SetDisplayedPlane(climate_plane
);
548 this->GetWidget
<NWidgetStacked
>(WID_GL_CLIMATE_SEL_SELECTOR
)->SetDisplayedPlane(climate_plane
);
550 /* Update availability of decreasing / increasing start date and snow level */
551 if (mode
== GLWM_HEIGHTMAP
) {
552 this->SetWidgetDisabledState(WID_GL_HEIGHTMAP_HEIGHT_DOWN
, _settings_newgame
.game_creation
.heightmap_height
<= MIN_HEIGHTMAP_HEIGHT
);
553 this->SetWidgetDisabledState(WID_GL_HEIGHTMAP_HEIGHT_UP
, _settings_newgame
.game_creation
.heightmap_height
>= GetMapHeightLimit());
555 this->SetWidgetDisabledState(WID_GL_START_DATE_DOWN
, _settings_newgame
.game_creation
.starting_year
<= CalendarTime::MIN_YEAR
);
556 this->SetWidgetDisabledState(WID_GL_START_DATE_UP
, _settings_newgame
.game_creation
.starting_year
>= CalendarTime::MAX_YEAR
);
557 this->SetWidgetDisabledState(WID_GL_SNOW_COVERAGE_DOWN
, _settings_newgame
.game_creation
.snow_coverage
<= 0 || _settings_newgame
.game_creation
.landscape
!= LT_ARCTIC
);
558 this->SetWidgetDisabledState(WID_GL_SNOW_COVERAGE_UP
, _settings_newgame
.game_creation
.snow_coverage
>= 100 || _settings_newgame
.game_creation
.landscape
!= LT_ARCTIC
);
559 this->SetWidgetDisabledState(WID_GL_DESERT_COVERAGE_DOWN
, _settings_newgame
.game_creation
.desert_coverage
<= 0 || _settings_newgame
.game_creation
.landscape
!= LT_TROPIC
);
560 this->SetWidgetDisabledState(WID_GL_DESERT_COVERAGE_UP
, _settings_newgame
.game_creation
.desert_coverage
>= 100 || _settings_newgame
.game_creation
.landscape
!= LT_TROPIC
);
562 /* Do not allow a custom sea level or terrain type with the original land generator. */
563 if (_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
) {
564 if (_settings_newgame
.difficulty
.quantity_sea_lakes
== CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
) {
565 _settings_newgame
.difficulty
.quantity_sea_lakes
= 1;
567 if (_settings_newgame
.difficulty
.terrain_type
== CUSTOM_TERRAIN_TYPE_NUMBER_DIFFICULTY
) {
568 _settings_newgame
.difficulty
.terrain_type
= 1;
574 void UpdateWidgetSize(WidgetID widget
, Dimension
&size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
&fill
, [[maybe_unused
]] Dimension
&resize
) override
576 Dimension d
{0, (uint
)GetCharacterHeight(FS_NORMAL
)};
577 std::span
<const StringID
> strs
;
579 case WID_GL_TEMPERATE
: case WID_GL_ARCTIC
:
580 case WID_GL_TROPICAL
: case WID_GL_TOYLAND
:
581 size
.width
+= WidgetDimensions::scaled
.fullbevel
.Horizontal();
582 size
.height
+= WidgetDimensions::scaled
.fullbevel
.Vertical();
585 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
:
586 SetDParam(0, MAX_TILE_HEIGHT
);
587 d
= GetStringBoundingBox(STR_JUST_INT
);
590 case WID_GL_START_DATE_TEXT
:
591 SetDParam(0, TimerGameCalendar::ConvertYMDToDate(CalendarTime::MAX_YEAR
, 0, 1));
592 d
= GetStringBoundingBox(STR_JUST_DATE_LONG
);
595 case WID_GL_MAPSIZE_X_PULLDOWN
:
596 case WID_GL_MAPSIZE_Y_PULLDOWN
:
597 SetDParamMaxValue(0, MAX_MAP_SIZE
);
598 d
= GetStringBoundingBox(STR_JUST_INT
);
601 case WID_GL_SNOW_COVERAGE_TEXT
:
602 SetDParamMaxValue(0, MAX_TILE_HEIGHT
);
603 d
= GetStringBoundingBox(STR_MAPGEN_SNOW_COVERAGE_TEXT
);
606 case WID_GL_DESERT_COVERAGE_TEXT
:
607 SetDParamMaxValue(0, MAX_TILE_HEIGHT
);
608 d
= GetStringBoundingBox(STR_MAPGEN_DESERT_COVERAGE_TEXT
);
611 case WID_GL_HEIGHTMAP_SIZE_TEXT
:
612 SetDParam(0, this->x
);
613 SetDParam(1, this->y
);
614 d
= GetStringBoundingBox(STR_MAPGEN_HEIGHTMAP_SIZE
);
617 case WID_GL_TOWN_PULLDOWN
:
619 SetDParamMaxValue(0, CUSTOM_TOWN_MAX_NUMBER
);
620 d
= GetStringBoundingBox(STR_NUM_CUSTOM_NUMBER
);
623 case WID_GL_INDUSTRY_PULLDOWN
:
625 SetDParamMaxValue(0, IndustryPool::MAX_SIZE
);
626 d
= GetStringBoundingBox(STR_NUM_CUSTOM_NUMBER
);
629 case WID_GL_TERRAIN_PULLDOWN
:
631 SetDParamMaxValue(0, MAX_MAP_HEIGHT_LIMIT
);
632 d
= GetStringBoundingBox(STR_TERRAIN_TYPE_CUSTOM_VALUE
);
635 case WID_GL_WATER_PULLDOWN
:
637 SetDParamMaxValue(0, CUSTOM_SEA_LEVEL_MAX_PERCENTAGE
);
638 d
= GetStringBoundingBox(STR_SEA_LEVEL_CUSTOM_PERCENTAGE
);
641 case WID_GL_RIVER_PULLDOWN
: strs
= _rivers
; break;
642 case WID_GL_SMOOTHNESS_PULLDOWN
: strs
= _smoothness
; break;
643 case WID_GL_VARIETY_PULLDOWN
: strs
= _variety
; break;
644 case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
: strs
= _rotation
; break;
645 case WID_GL_BORDERS_RANDOM
:
646 d
= maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_RANDOMIZE
), GetStringBoundingBox(STR_MAPGEN_BORDER_MANUAL
));
649 case WID_GL_WATER_NE
:
650 case WID_GL_WATER_NW
:
651 case WID_GL_WATER_SE
:
652 case WID_GL_WATER_SW
:
653 d
= maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_RANDOM
), maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_WATER
), GetStringBoundingBox(STR_MAPGEN_BORDER_FREEFORM
)));
656 case WID_GL_HEIGHTMAP_NAME_TEXT
:
663 d
= maxdim(d
, GetStringListBoundingBox(strs
));
664 d
.width
+= padding
.width
;
665 d
.height
+= padding
.height
;
666 size
= maxdim(size
, d
);
669 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
672 case WID_GL_TEMPERATE
:
674 case WID_GL_TROPICAL
:
676 SetNewLandscapeType(widget
- WID_GL_TEMPERATE
);
679 case WID_GL_MAPSIZE_X_PULLDOWN
: // Mapsize X
680 ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame
.game_creation
.map_x
, WID_GL_MAPSIZE_X_PULLDOWN
);
683 case WID_GL_MAPSIZE_Y_PULLDOWN
: // Mapsize Y
684 ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame
.game_creation
.map_y
, WID_GL_MAPSIZE_Y_PULLDOWN
);
687 case WID_GL_TOWN_PULLDOWN
: // Number of towns
688 ShowDropDownMenu(this, _num_towns
, _settings_newgame
.difficulty
.number_towns
, WID_GL_TOWN_PULLDOWN
, 0, 0);
691 case WID_GL_TOWNNAME_DROPDOWN
: // Townname generator
692 ShowDropDownList(this, BuildTownNameDropDown(), _settings_newgame
.game_creation
.town_name
, WID_GL_TOWNNAME_DROPDOWN
);
695 case WID_GL_INDUSTRY_PULLDOWN
: // Number of industries
696 ShowDropDownMenu(this, _num_inds
, _settings_newgame
.difficulty
.industry_density
, WID_GL_INDUSTRY_PULLDOWN
, 0, 0);
699 case WID_GL_GENERATE_BUTTON
: { // Generate
700 /* Get rotated map size. */
703 if (_settings_newgame
.game_creation
.heightmap_rotation
== HM_CLOCKWISE
) {
710 if (mode
== GLWM_HEIGHTMAP
&&
711 (map_x
* 2 < (1U << _settings_newgame
.game_creation
.map_x
) ||
712 map_x
/ 2 > (1U << _settings_newgame
.game_creation
.map_x
) ||
713 map_y
* 2 < (1U << _settings_newgame
.game_creation
.map_y
) ||
714 map_y
/ 2 > (1U << _settings_newgame
.game_creation
.map_y
))) {
716 STR_WARNING_HEIGHTMAP_SCALE_CAPTION
,
717 STR_WARNING_HEIGHTMAP_SCALE_MESSAGE
,
719 LandscapeGenerationCallback
);
721 StartGeneratingLandscape(mode
);
726 case WID_GL_HEIGHTMAP_HEIGHT_DOWN
:
727 case WID_GL_HEIGHTMAP_HEIGHT_UP
: // Height level buttons
728 /* Don't allow too fast scrolling */
729 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
730 this->HandleButtonClick(widget
);
732 _settings_newgame
.game_creation
.heightmap_height
= Clamp(_settings_newgame
.game_creation
.heightmap_height
+ widget
- WID_GL_HEIGHTMAP_HEIGHT_TEXT
, MIN_HEIGHTMAP_HEIGHT
, GetMapHeightLimit());
733 this->InvalidateData();
735 _left_button_clicked
= false;
738 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
: // Height level text
739 this->widget_id
= WID_GL_HEIGHTMAP_HEIGHT_TEXT
;
740 SetDParam(0, _settings_newgame
.game_creation
.heightmap_height
);
741 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_HEIGHTMAP_HEIGHT_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_ENABLE_DEFAULT
);
745 case WID_GL_START_DATE_DOWN
:
746 case WID_GL_START_DATE_UP
: // Year buttons
747 /* Don't allow too fast scrolling */
748 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
749 this->HandleButtonClick(widget
);
751 _settings_newgame
.game_creation
.starting_year
= Clamp(_settings_newgame
.game_creation
.starting_year
+ widget
- WID_GL_START_DATE_TEXT
, CalendarTime::MIN_YEAR
, CalendarTime::MAX_YEAR
);
752 this->InvalidateData();
754 _left_button_clicked
= false;
757 case WID_GL_START_DATE_TEXT
: // Year text
758 this->widget_id
= WID_GL_START_DATE_TEXT
;
759 SetDParam(0, _settings_newgame
.game_creation
.starting_year
);
760 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_START_DATE_QUERY_CAPT
, 8, this, CS_NUMERAL
, QSF_ENABLE_DEFAULT
);
763 case WID_GL_SNOW_COVERAGE_DOWN
:
764 case WID_GL_SNOW_COVERAGE_UP
: // Snow coverage buttons
765 /* Don't allow too fast scrolling */
766 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
767 this->HandleButtonClick(widget
);
769 _settings_newgame
.game_creation
.snow_coverage
= Clamp(_settings_newgame
.game_creation
.snow_coverage
+ (widget
- WID_GL_SNOW_COVERAGE_TEXT
) * 10, 0, 100);
770 this->InvalidateData();
772 _left_button_clicked
= false;
775 case WID_GL_SNOW_COVERAGE_TEXT
: // Snow coverage text
776 this->widget_id
= WID_GL_SNOW_COVERAGE_TEXT
;
777 SetDParam(0, _settings_newgame
.game_creation
.snow_coverage
);
778 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_SNOW_COVERAGE_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_ENABLE_DEFAULT
);
781 case WID_GL_DESERT_COVERAGE_DOWN
:
782 case WID_GL_DESERT_COVERAGE_UP
: // Desert coverage buttons
783 /* Don't allow too fast scrolling */
784 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
785 this->HandleButtonClick(widget
);
787 _settings_newgame
.game_creation
.desert_coverage
= Clamp(_settings_newgame
.game_creation
.desert_coverage
+ (widget
- WID_GL_DESERT_COVERAGE_TEXT
) * 10, 0, 100);
788 this->InvalidateData();
790 _left_button_clicked
= false;
793 case WID_GL_DESERT_COVERAGE_TEXT
: // Desert line text
794 this->widget_id
= WID_GL_DESERT_COVERAGE_TEXT
;
795 SetDParam(0, _settings_newgame
.game_creation
.desert_coverage
);
796 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_DESERT_COVERAGE_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_ENABLE_DEFAULT
);
799 case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
: // Heightmap rotation
800 ShowDropDownMenu(this, _rotation
, _settings_newgame
.game_creation
.heightmap_rotation
, WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
, 0, 0);
803 case WID_GL_TERRAIN_PULLDOWN
: // Terrain type
804 /* For the original map generation only the first four are valid. */
805 ShowDropDownMenu(this, _elevations
, _settings_newgame
.difficulty
.terrain_type
, WID_GL_TERRAIN_PULLDOWN
, 0, _settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
? ~0xF : 0);
808 case WID_GL_WATER_PULLDOWN
: { // Water quantity
809 uint32_t hidden_mask
= 0;
810 /* Disable custom water level when the original map generator is active. */
811 if (_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
) {
812 SetBit(hidden_mask
, CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
);
814 ShowDropDownMenu(this, _sea_lakes
, _settings_newgame
.difficulty
.quantity_sea_lakes
, WID_GL_WATER_PULLDOWN
, 0, hidden_mask
);
818 case WID_GL_RIVER_PULLDOWN
: // Amount of rivers
819 ShowDropDownMenu(this, _rivers
, _settings_newgame
.game_creation
.amount_of_rivers
, WID_GL_RIVER_PULLDOWN
, 0, 0);
822 case WID_GL_SMOOTHNESS_PULLDOWN
: // Map smoothness
823 ShowDropDownMenu(this, _smoothness
, _settings_newgame
.game_creation
.tgen_smoothness
, WID_GL_SMOOTHNESS_PULLDOWN
, 0, 0);
826 case WID_GL_VARIETY_PULLDOWN
: // Map variety
827 ShowDropDownMenu(this, _variety
, _settings_newgame
.game_creation
.variety
, WID_GL_VARIETY_PULLDOWN
, 0, 0);
830 /* Freetype map borders */
831 case WID_GL_WATER_NW
:
832 _settings_newgame
.game_creation
.water_borders
= ToggleBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NW
);
833 this->InvalidateData();
836 case WID_GL_WATER_NE
:
837 _settings_newgame
.game_creation
.water_borders
= ToggleBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NE
);
838 this->InvalidateData();
841 case WID_GL_WATER_SE
:
842 _settings_newgame
.game_creation
.water_borders
= ToggleBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SE
);
843 this->InvalidateData();
846 case WID_GL_WATER_SW
:
847 _settings_newgame
.game_creation
.water_borders
= ToggleBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SW
);
848 this->InvalidateData();
851 case WID_GL_BORDERS_RANDOM
:
852 _settings_newgame
.game_creation
.water_borders
= (_settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
) ? 0 : BORDERS_RANDOM
;
853 this->InvalidateData();
856 case WID_GL_AI_BUTTON
: ///< AI Settings
857 ShowAIConfigWindow();
860 case WID_GL_GS_BUTTON
: ///< Game Script Settings
861 ShowGSConfigWindow();
864 case WID_GL_NEWGRF_BUTTON
: ///< NewGRF Settings
865 ShowNewGRFSettings(true, true, false, &_grfconfig_newgame
);
870 void OnTimeout() override
872 if (mode
== GLWM_HEIGHTMAP
) {
873 this->RaiseWidgetsWhenLowered(WID_GL_HEIGHTMAP_HEIGHT_DOWN
, WID_GL_HEIGHTMAP_HEIGHT_UP
, WID_GL_START_DATE_DOWN
, WID_GL_START_DATE_UP
, WID_GL_SNOW_COVERAGE_UP
, WID_GL_SNOW_COVERAGE_DOWN
, WID_GL_DESERT_COVERAGE_UP
, WID_GL_DESERT_COVERAGE_DOWN
);
875 this->RaiseWidgetsWhenLowered(WID_GL_START_DATE_DOWN
, WID_GL_START_DATE_UP
, WID_GL_SNOW_COVERAGE_UP
, WID_GL_SNOW_COVERAGE_DOWN
, WID_GL_DESERT_COVERAGE_UP
, WID_GL_DESERT_COVERAGE_DOWN
);
879 void OnDropdownSelect(WidgetID widget
, int index
) override
882 case WID_GL_MAPSIZE_X_PULLDOWN
: _settings_newgame
.game_creation
.map_x
= index
; break;
883 case WID_GL_MAPSIZE_Y_PULLDOWN
: _settings_newgame
.game_creation
.map_y
= index
; break;
884 case WID_GL_RIVER_PULLDOWN
: _settings_newgame
.game_creation
.amount_of_rivers
= index
; break;
885 case WID_GL_SMOOTHNESS_PULLDOWN
: _settings_newgame
.game_creation
.tgen_smoothness
= index
; break;
886 case WID_GL_VARIETY_PULLDOWN
: _settings_newgame
.game_creation
.variety
= index
; break;
888 case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
: _settings_newgame
.game_creation
.heightmap_rotation
= index
; break;
890 case WID_GL_TOWN_PULLDOWN
:
891 if ((uint
)index
== CUSTOM_TOWN_NUMBER_DIFFICULTY
) {
892 this->widget_id
= widget
;
893 SetDParam(0, _settings_newgame
.game_creation
.custom_town_number
);
894 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_NUMBER_OF_TOWNS
, 5, this, CS_NUMERAL
, QSF_NONE
);
896 _settings_newgame
.difficulty
.number_towns
= index
;
899 case WID_GL_TOWNNAME_DROPDOWN
: // Town names
900 if (_game_mode
== GM_MENU
|| Town::GetNumItems() == 0) {
901 _settings_newgame
.game_creation
.town_name
= index
;
902 SetWindowDirty(WC_GAME_OPTIONS
, WN_GAME_OPTIONS_GAME_OPTIONS
);
906 case WID_GL_INDUSTRY_PULLDOWN
:
907 if ((uint
)index
== ID_CUSTOM
) {
908 this->widget_id
= widget
;
909 SetDParam(0, _settings_newgame
.game_creation
.custom_industry_number
);
910 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_NUMBER_OF_INDUSTRIES
, 5, this, CS_NUMERAL
, QSF_NONE
);
912 _settings_newgame
.difficulty
.industry_density
= index
;
915 case WID_GL_TERRAIN_PULLDOWN
: {
916 if ((uint
)index
== CUSTOM_TERRAIN_TYPE_NUMBER_DIFFICULTY
) {
917 this->widget_id
= widget
;
918 SetDParam(0, _settings_newgame
.game_creation
.custom_terrain_type
);
919 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_TERRAIN_TYPE_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_NONE
);
921 _settings_newgame
.difficulty
.terrain_type
= index
;
925 case WID_GL_WATER_PULLDOWN
: {
926 if ((uint
)index
== CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
) {
927 this->widget_id
= widget
;
928 SetDParam(0, _settings_newgame
.game_creation
.custom_sea_level
);
929 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_SEA_LEVEL
, 3, this, CS_NUMERAL
, QSF_NONE
);
931 _settings_newgame
.difficulty
.quantity_sea_lakes
= index
;
935 this->InvalidateData();
938 void OnQueryTextFinished(std::optional
<std::string
> str
) override
940 /* Was 'cancel' pressed? */
941 if (!str
.has_value()) return;
945 value
= atoi(str
->c_str());
947 /* An empty string means revert to the default */
948 switch (this->widget_id
) {
949 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
: value
= MAP_HEIGHT_LIMIT_AUTO_MINIMUM
; break;
950 case WID_GL_START_DATE_TEXT
: value
= CalendarTime::DEF_START_YEAR
.base(); break;
951 case WID_GL_SNOW_COVERAGE_TEXT
: value
= DEF_SNOW_COVERAGE
; break;
952 case WID_GL_DESERT_COVERAGE_TEXT
: value
= DEF_DESERT_COVERAGE
; break;
953 case WID_GL_TOWN_PULLDOWN
: value
= 1; break;
954 case WID_GL_INDUSTRY_PULLDOWN
: value
= 1; break;
955 case WID_GL_TERRAIN_PULLDOWN
: value
= MIN_MAP_HEIGHT_LIMIT
; break;
956 case WID_GL_WATER_PULLDOWN
: value
= CUSTOM_SEA_LEVEL_MIN_PERCENTAGE
; break;
957 default: NOT_REACHED();
961 switch (this->widget_id
) {
962 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
:
963 this->SetWidgetDirty(WID_GL_HEIGHTMAP_HEIGHT_TEXT
);
964 _settings_newgame
.game_creation
.heightmap_height
= Clamp(value
, MIN_HEIGHTMAP_HEIGHT
, GetMapHeightLimit());
967 case WID_GL_START_DATE_TEXT
:
968 this->SetWidgetDirty(WID_GL_START_DATE_TEXT
);
969 _settings_newgame
.game_creation
.starting_year
= Clamp(TimerGameCalendar::Year(value
), CalendarTime::MIN_YEAR
, CalendarTime::MAX_YEAR
);
972 case WID_GL_SNOW_COVERAGE_TEXT
:
973 this->SetWidgetDirty(WID_GL_SNOW_COVERAGE_TEXT
);
974 _settings_newgame
.game_creation
.snow_coverage
= Clamp(value
, 0, 100);
977 case WID_GL_DESERT_COVERAGE_TEXT
:
978 this->SetWidgetDirty(WID_GL_DESERT_COVERAGE_TEXT
);
979 _settings_newgame
.game_creation
.desert_coverage
= Clamp(value
, 0, 100);
982 case WID_GL_TOWN_PULLDOWN
:
983 _settings_newgame
.game_creation
.custom_town_number
= Clamp(value
, 1, CUSTOM_TOWN_MAX_NUMBER
);
986 case WID_GL_INDUSTRY_PULLDOWN
:
987 _settings_newgame
.game_creation
.custom_industry_number
= Clamp(value
, 1, IndustryPool::MAX_SIZE
);
990 case WID_GL_TERRAIN_PULLDOWN
:
991 _settings_newgame
.game_creation
.custom_terrain_type
= Clamp(value
, MIN_CUSTOM_TERRAIN_TYPE
, GetMapHeightLimit());
994 case WID_GL_WATER_PULLDOWN
:
995 _settings_newgame
.game_creation
.custom_sea_level
= Clamp(value
, CUSTOM_SEA_LEVEL_MIN_PERCENTAGE
, CUSTOM_SEA_LEVEL_MAX_PERCENTAGE
);
999 this->InvalidateData();
1003 static WindowDesc
_generate_landscape_desc(
1004 WDP_CENTER
, nullptr, 0, 0,
1005 WC_GENERATE_LANDSCAPE
, WC_NONE
,
1007 _nested_generate_landscape_widgets
1010 static WindowDesc
_heightmap_load_desc(
1011 WDP_CENTER
, nullptr, 0, 0,
1012 WC_GENERATE_LANDSCAPE
, WC_NONE
,
1014 _nested_heightmap_load_widgets
1017 static void _ShowGenerateLandscape(GenerateLandscapeWindowMode mode
)
1022 CloseWindowByClass(WC_GENERATE_LANDSCAPE
);
1024 /* Generate a new seed when opening the window */
1025 _settings_newgame
.game_creation
.generation_seed
= InteractiveRandom();
1027 if (mode
== GLWM_HEIGHTMAP
) {
1028 /* If the function returns negative, it means there was a problem loading the heightmap */
1029 if (!GetHeightmapDimensions(_file_to_saveload
.detail_ftype
, _file_to_saveload
.name
.c_str(), &x
, &y
)) return;
1032 WindowDesc
&desc
= (mode
== GLWM_HEIGHTMAP
) ? _heightmap_load_desc
: _generate_landscape_desc
;
1033 GenerateLandscapeWindow
*w
= AllocateWindowDescFront
<GenerateLandscapeWindow
>(desc
, mode
, true);
1035 if (mode
== GLWM_HEIGHTMAP
) {
1038 w
->name
= _file_to_saveload
.title
;
1041 SetWindowDirty(WC_GENERATE_LANDSCAPE
, mode
);
1044 /** Start with a normal game. */
1045 void ShowGenerateLandscape()
1047 _ShowGenerateLandscape(GLWM_GENERATE
);
1050 /** Start with loading a heightmap. */
1051 void ShowHeightmapLoad()
1053 _ShowGenerateLandscape(GLWM_HEIGHTMAP
);
1056 /** Start with a scenario editor. */
1057 void StartScenarioEditor()
1059 StartGeneratingLandscape(GLWM_SCENARIO
);
1063 * Start a normal game without the GUI.
1064 * @param seed The seed of the new game.
1066 void StartNewGameWithoutGUI(uint32_t seed
)
1068 /* GenerateWorld takes care of the possible GENERATE_NEW_SEED value in 'seed' */
1069 _settings_newgame
.game_creation
.generation_seed
= seed
;
1071 StartGeneratingLandscape(GLWM_GENERATE
);
1074 struct CreateScenarioWindow
: public Window
1078 CreateScenarioWindow(WindowDesc
&desc
, WindowNumber window_number
) : Window(desc
)
1080 this->InitNested(window_number
);
1081 this->LowerWidget(_settings_newgame
.game_creation
.landscape
+ WID_CS_TEMPERATE
);
1084 void SetStringParameters(WidgetID widget
) const override
1087 case WID_CS_START_DATE_TEXT
:
1088 SetDParam(0, TimerGameCalendar::ConvertYMDToDate(_settings_newgame
.game_creation
.starting_year
, 0, 1));
1091 case WID_CS_MAPSIZE_X_PULLDOWN
:
1092 SetDParam(0, 1LL << _settings_newgame
.game_creation
.map_x
);
1095 case WID_CS_MAPSIZE_Y_PULLDOWN
:
1096 SetDParam(0, 1LL << _settings_newgame
.game_creation
.map_y
);
1099 case WID_CS_FLAT_LAND_HEIGHT_TEXT
:
1100 SetDParam(0, _settings_newgame
.game_creation
.se_flat_world_height
);
1105 void OnPaint() override
1107 this->SetWidgetDisabledState(WID_CS_START_DATE_DOWN
, _settings_newgame
.game_creation
.starting_year
<= CalendarTime::MIN_YEAR
);
1108 this->SetWidgetDisabledState(WID_CS_START_DATE_UP
, _settings_newgame
.game_creation
.starting_year
>= CalendarTime::MAX_YEAR
);
1109 this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_DOWN
, _settings_newgame
.game_creation
.se_flat_world_height
<= 0);
1110 this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_UP
, _settings_newgame
.game_creation
.se_flat_world_height
>= GetMapHeightLimit());
1112 this->SetWidgetLoweredState(WID_CS_TEMPERATE
, _settings_newgame
.game_creation
.landscape
== LT_TEMPERATE
);
1113 this->SetWidgetLoweredState(WID_CS_ARCTIC
, _settings_newgame
.game_creation
.landscape
== LT_ARCTIC
);
1114 this->SetWidgetLoweredState(WID_CS_TROPICAL
, _settings_newgame
.game_creation
.landscape
== LT_TROPIC
);
1115 this->SetWidgetLoweredState(WID_CS_TOYLAND
, _settings_newgame
.game_creation
.landscape
== LT_TOYLAND
);
1117 this->DrawWidgets();
1120 void UpdateWidgetSize(WidgetID widget
, Dimension
&size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
&fill
, [[maybe_unused
]] Dimension
&resize
) override
1122 StringID str
= STR_JUST_INT
;
1124 case WID_CS_TEMPERATE
: case WID_CS_ARCTIC
:
1125 case WID_CS_TROPICAL
: case WID_CS_TOYLAND
:
1126 size
.width
+= WidgetDimensions::scaled
.fullbevel
.Horizontal();
1127 size
.height
+= WidgetDimensions::scaled
.fullbevel
.Vertical();
1130 case WID_CS_START_DATE_TEXT
:
1131 SetDParam(0, TimerGameCalendar::ConvertYMDToDate(CalendarTime::MAX_YEAR
, 0, 1));
1132 str
= STR_JUST_DATE_LONG
;
1135 case WID_CS_MAPSIZE_X_PULLDOWN
:
1136 case WID_CS_MAPSIZE_Y_PULLDOWN
:
1137 SetDParamMaxValue(0, MAX_MAP_SIZE
);
1140 case WID_CS_FLAT_LAND_HEIGHT_TEXT
:
1141 SetDParamMaxValue(0, MAX_TILE_HEIGHT
);
1147 Dimension d
= GetStringBoundingBox(str
);
1148 d
.width
+= padding
.width
;
1149 d
.height
+= padding
.height
;
1150 size
= maxdim(size
, d
);
1153 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
1156 case WID_CS_TEMPERATE
:
1158 case WID_CS_TROPICAL
:
1159 case WID_CS_TOYLAND
:
1160 this->RaiseWidget(_settings_newgame
.game_creation
.landscape
+ WID_CS_TEMPERATE
);
1161 SetNewLandscapeType(widget
- WID_CS_TEMPERATE
);
1164 case WID_CS_MAPSIZE_X_PULLDOWN
: // Mapsize X
1165 ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame
.game_creation
.map_x
, WID_CS_MAPSIZE_X_PULLDOWN
);
1168 case WID_CS_MAPSIZE_Y_PULLDOWN
: // Mapsize Y
1169 ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame
.game_creation
.map_y
, WID_CS_MAPSIZE_Y_PULLDOWN
);
1172 case WID_CS_EMPTY_WORLD
: // Empty world / flat world
1173 StartGeneratingLandscape(GLWM_SCENARIO
);
1176 case WID_CS_RANDOM_WORLD
: // Generate
1177 ShowGenerateLandscape();
1180 case WID_CS_START_DATE_DOWN
:
1181 case WID_CS_START_DATE_UP
: // Year buttons
1182 /* Don't allow too fast scrolling */
1183 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
1184 this->HandleButtonClick(widget
);
1187 _settings_newgame
.game_creation
.starting_year
= Clamp(_settings_newgame
.game_creation
.starting_year
+ widget
- WID_CS_START_DATE_TEXT
, CalendarTime::MIN_YEAR
, CalendarTime::MAX_YEAR
);
1189 _left_button_clicked
= false;
1192 case WID_CS_START_DATE_TEXT
: // Year text
1193 this->widget_id
= WID_CS_START_DATE_TEXT
;
1194 SetDParam(0, _settings_newgame
.game_creation
.starting_year
);
1195 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_START_DATE_QUERY_CAPT
, 8, this, CS_NUMERAL
, QSF_NONE
);
1198 case WID_CS_FLAT_LAND_HEIGHT_DOWN
:
1199 case WID_CS_FLAT_LAND_HEIGHT_UP
: // Height level buttons
1200 /* Don't allow too fast scrolling */
1201 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
1202 this->HandleButtonClick(widget
);
1205 _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());
1207 _left_button_clicked
= false;
1210 case WID_CS_FLAT_LAND_HEIGHT_TEXT
: // Height level text
1211 this->widget_id
= WID_CS_FLAT_LAND_HEIGHT_TEXT
;
1212 SetDParam(0, _settings_newgame
.game_creation
.se_flat_world_height
);
1213 ShowQueryString(STR_JUST_INT
, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_NONE
);
1218 void OnTimeout() override
1220 this->RaiseWidgetsWhenLowered(WID_CS_START_DATE_DOWN
, WID_CS_START_DATE_UP
, WID_CS_FLAT_LAND_HEIGHT_DOWN
, WID_CS_FLAT_LAND_HEIGHT_UP
);
1223 void OnDropdownSelect(WidgetID widget
, int index
) override
1226 case WID_CS_MAPSIZE_X_PULLDOWN
: _settings_newgame
.game_creation
.map_x
= index
; break;
1227 case WID_CS_MAPSIZE_Y_PULLDOWN
: _settings_newgame
.game_creation
.map_y
= index
; break;
1232 void OnQueryTextFinished(std::optional
<std::string
> str
) override
1234 if (!str
.has_value() || str
->empty()) return;
1236 int32_t value
= atoi(str
->c_str());
1238 switch (this->widget_id
) {
1239 case WID_CS_START_DATE_TEXT
:
1240 this->SetWidgetDirty(WID_CS_START_DATE_TEXT
);
1241 _settings_newgame
.game_creation
.starting_year
= Clamp(TimerGameCalendar::Year(value
), CalendarTime::MIN_YEAR
, CalendarTime::MAX_YEAR
);
1244 case WID_CS_FLAT_LAND_HEIGHT_TEXT
:
1245 this->SetWidgetDirty(WID_CS_FLAT_LAND_HEIGHT_TEXT
);
1246 _settings_newgame
.game_creation
.se_flat_world_height
= Clamp(value
, 0, GetMapHeightLimit());
1254 static constexpr NWidgetPart _nested_create_scenario_widgets
[] = {
1255 NWidget(NWID_HORIZONTAL
),
1256 NWidget(WWT_CLOSEBOX
, COLOUR_BROWN
),
1257 NWidget(WWT_CAPTION
, COLOUR_BROWN
), SetDataTip(STR_SE_MAPGEN_CAPTION
, STR_NULL
),
1259 NWidget(WWT_PANEL
, COLOUR_BROWN
),
1260 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_wide
, 0), SetPadding(WidgetDimensions::unscaled
.sparse
),
1261 /* Landscape style selection. */
1262 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0), SetPIPRatio(1, 1, 1),
1263 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_CS_TEMPERATE
), SetDataTip(SPR_SELECT_TEMPERATE
, STR_INTRO_TOOLTIP_TEMPERATE
),
1264 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_CS_ARCTIC
), SetDataTip(SPR_SELECT_SUB_ARCTIC
, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE
),
1265 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_CS_TROPICAL
), SetDataTip(SPR_SELECT_SUB_TROPICAL
, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE
),
1266 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_CS_TOYLAND
), SetDataTip(SPR_SELECT_TOYLAND
, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE
),
1269 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0),
1270 /* Green generation type buttons: 'Flat land' and 'Random land'. */
1271 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
1272 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREEN
, WID_CS_EMPTY_WORLD
), SetDataTip(STR_SE_MAPGEN_FLAT_WORLD
, STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP
), SetFill(1, 1),
1273 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREEN
, WID_CS_RANDOM_WORLD
), SetDataTip(STR_SE_MAPGEN_RANDOM_LAND
, STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND
), SetFill(1, 1),
1276 /* Labels + setting drop-downs */
1277 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
1279 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
1280 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_MAPSIZE
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(0, 1),
1281 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DATE
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(0, 1),
1282 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_SE_MAPGEN_FLAT_WORLD_HEIGHT
, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_TOOLTIP
), SetFill(0, 1),
1285 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
1287 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
1288 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_CS_MAPSIZE_X_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
1289 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_BY
, STR_NULL
), SetFill(0, 1), SetAlignment(SA_CENTER
),
1290 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_CS_MAPSIZE_Y_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
1294 NWidget(NWID_HORIZONTAL
),
1295 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_CS_START_DATE_DOWN
), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN
, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD
), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
1296 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_CS_START_DATE_TEXT
), SetFill(1, 1), SetDataTip(STR_JUST_DATE_LONG
, STR_MAPGEN_DATE_TOOLTIP
),
1297 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_CS_START_DATE_UP
), SetFill(0, 1), SetDataTip(SPR_ARROW_UP
, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD
), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
1300 /* Flat map height. */
1301 NWidget(NWID_HORIZONTAL
),
1302 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_CS_FLAT_LAND_HEIGHT_DOWN
), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN
, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN
), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
1303 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_CS_FLAT_LAND_HEIGHT_TEXT
), SetFill(1, 1), SetDataTip(STR_JUST_INT
, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_TOOLTIP
),
1304 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_CS_FLAT_LAND_HEIGHT_UP
), SetFill(0, 1), SetDataTip(SPR_ARROW_UP
, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP
), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON
),
1313 static WindowDesc
_create_scenario_desc(
1314 WDP_CENTER
, nullptr, 0, 0,
1315 WC_GENERATE_LANDSCAPE
, WC_NONE
,
1317 _nested_create_scenario_widgets
1320 /** Show the window to create a scenario. */
1321 void ShowCreateScenario()
1323 CloseWindowByClass(WC_GENERATE_LANDSCAPE
);
1324 new CreateScenarioWindow(_create_scenario_desc
, GLWM_SCENARIO
);
1327 static constexpr NWidgetPart _nested_generate_progress_widgets
[] = {
1328 NWidget(WWT_CAPTION
, COLOUR_GREY
), SetDataTip(STR_GENERATION_WORLD
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1329 NWidget(WWT_PANEL
, COLOUR_GREY
),
1330 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_wide
, 0), SetPadding(WidgetDimensions::unscaled
.modalpopup
),
1331 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_GP_PROGRESS_BAR
), SetFill(1, 0),
1332 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_GP_PROGRESS_TEXT
), SetFill(1, 0),
1333 NWidget(WWT_TEXTBTN
, COLOUR_WHITE
, WID_GP_ABORT
), SetDataTip(STR_GENERATION_ABORT
, STR_NULL
), SetFill(1, 0),
1339 static WindowDesc
_generate_progress_desc(
1340 WDP_CENTER
, nullptr, 0, 0,
1341 WC_MODAL_PROGRESS
, WC_NONE
,
1343 _nested_generate_progress_widgets
1346 struct GenWorldStatus
{
1351 std::chrono::steady_clock::time_point next_update
;
1354 static GenWorldStatus _gws
;
1356 static const StringID _generation_class_table
[] = {
1357 STR_GENERATION_WORLD_GENERATION
,
1358 STR_GENERATION_LANDSCAPE_GENERATION
,
1359 STR_GENERATION_RIVER_GENERATION
,
1360 STR_GENERATION_CLEARING_TILES
,
1361 STR_GENERATION_TOWN_GENERATION
,
1362 STR_GENERATION_INDUSTRY_GENERATION
,
1363 STR_GENERATION_OBJECT_GENERATION
,
1364 STR_GENERATION_TREE_GENERATION
,
1365 STR_GENERATION_SETTINGUP_GAME
,
1366 STR_GENERATION_PREPARING_TILELOOP
,
1367 STR_GENERATION_PREPARING_SCRIPT
,
1368 STR_GENERATION_PREPARING_GAME
1370 static_assert(lengthof(_generation_class_table
) == GWP_CLASS_COUNT
);
1373 static void AbortGeneratingWorldCallback(Window
*, bool confirmed
)
1376 AbortGeneratingWorld();
1377 } else if (HasModalProgress() && !IsGeneratingWorldAborted()) {
1378 SetMouseCursor(SPR_CURSOR_ZZZ
, PAL_NONE
);
1382 struct GenerateProgressWindow
: public Window
{
1384 GenerateProgressWindow() : Window(_generate_progress_desc
)
1389 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
1393 SetMouseCursorBusy(false);
1395 STR_GENERATION_ABORT_CAPTION
,
1396 STR_GENERATION_ABORT_MESSAGE
,
1398 AbortGeneratingWorldCallback
1404 void UpdateWidgetSize(WidgetID widget
, Dimension
&size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
&fill
, [[maybe_unused
]] Dimension
&resize
) override
1407 case WID_GP_PROGRESS_BAR
: {
1408 SetDParamMaxValue(0, 100);
1409 size
= GetStringBoundingBox(STR_GENERATION_PROGRESS
);
1410 /* We need some spacing for the 'border' */
1411 size
.height
+= WidgetDimensions::scaled
.frametext
.Horizontal();
1412 size
.width
+= WidgetDimensions::scaled
.frametext
.Vertical();
1416 case WID_GP_PROGRESS_TEXT
:
1417 for (uint i
= 0; i
< GWP_CLASS_COUNT
; i
++) {
1418 size
.width
= std::max(size
.width
, GetStringBoundingBox(_generation_class_table
[i
]).width
+ padding
.width
);
1420 size
.height
= GetCharacterHeight(FS_NORMAL
) * 2 + WidgetDimensions::scaled
.vsep_normal
;
1425 void DrawWidget(const Rect
&r
, WidgetID widget
) const override
1428 case WID_GP_PROGRESS_BAR
: {
1429 /* Draw the % complete with a bar and a text */
1430 DrawFrameRect(r
, COLOUR_GREY
, FR_BORDERONLY
| FR_LOWERED
);
1431 Rect br
= r
.Shrink(WidgetDimensions::scaled
.bevel
);
1432 DrawFrameRect(br
.WithWidth(br
.Width() * _gws
.percent
/ 100, _current_text_dir
== TD_RTL
), COLOUR_MAUVE
, FR_NONE
);
1433 SetDParam(0, _gws
.percent
);
1434 DrawString(br
.left
, br
.right
, CenterBounds(br
.top
, br
.bottom
, GetCharacterHeight(FS_NORMAL
)), STR_GENERATION_PROGRESS
, TC_FROMSTRING
, SA_HOR_CENTER
);
1438 case WID_GP_PROGRESS_TEXT
:
1439 /* Tell which class we are generating */
1440 DrawString(r
.left
, r
.right
, r
.top
, _gws
.cls
, TC_FROMSTRING
, SA_HOR_CENTER
);
1442 /* And say where we are in that class */
1443 SetDParam(0, _gws
.current
);
1444 SetDParam(1, _gws
.total
);
1445 DrawString(r
.left
, r
.right
, r
.top
+ GetCharacterHeight(FS_NORMAL
) + WidgetDimensions::scaled
.vsep_normal
, STR_GENERATION_PROGRESS_NUM
, TC_FROMSTRING
, SA_HOR_CENTER
);
1451 * Initializes the progress counters to the starting point.
1453 void PrepareGenerateWorldProgress()
1455 _gws
.cls
= STR_GENERATION_WORLD_GENERATION
;
1459 _gws
.next_update
= std::chrono::steady_clock::now();
1463 * Show the window where a user can follow the process of the map generation.
1465 void ShowGenerateWorldProgress()
1467 if (BringWindowToFrontById(WC_MODAL_PROGRESS
, 0)) return;
1468 new GenerateProgressWindow();
1471 static void _SetGeneratingWorldProgress(GenWorldProgress cls
, uint progress
, uint total
)
1473 static const int percent_table
[] = {0, 5, 14, 17, 20, 40, 60, 65, 80, 85, 95, 99, 100 };
1474 static_assert(lengthof(percent_table
) == GWP_CLASS_COUNT
+ 1);
1475 assert(cls
< GWP_CLASS_COUNT
);
1477 /* Check if we really are generating the world.
1478 * For example, placing trees via the SE also calls this function, but
1479 * shouldn't try to update the progress.
1481 if (!HasModalProgress()) return;
1483 if (IsGeneratingWorldAborted()) {
1484 HandleGeneratingWorldAbortion();
1489 assert(_gws
.cls
== _generation_class_table
[cls
]);
1490 _gws
.current
+= progress
;
1491 assert(_gws
.current
<= _gws
.total
);
1493 _gws
.cls
= _generation_class_table
[cls
];
1494 _gws
.current
= progress
;
1496 _gws
.percent
= percent_table
[cls
];
1499 /* Percentage is about the number of completed tasks, so 'current - 1' */
1500 _gws
.percent
= percent_table
[cls
] + (percent_table
[cls
+ 1] - percent_table
[cls
]) * (_gws
.current
== 0 ? 0 : _gws
.current
- 1) / _gws
.total
;
1502 if (_network_dedicated
) {
1503 static uint last_percent
= 0;
1505 /* Never display 0% */
1506 if (_gws
.percent
== 0) return;
1507 /* Reset if percent is lower than the last recorded */
1508 if (_gws
.percent
< last_percent
) last_percent
= 0;
1509 /* Display every 5%, but 6% is also very valid.. just not smaller steps than 5% */
1510 if (_gws
.percent
% 5 != 0 && _gws
.percent
<= last_percent
+ 5) return;
1511 /* Never show steps smaller than 2%, even if it is a mod 5% */
1512 if (_gws
.percent
<= last_percent
+ 2) return;
1514 Debug(net
, 3, "Map generation percentage complete: {}", _gws
.percent
);
1515 last_percent
= _gws
.percent
;
1520 SetWindowDirty(WC_MODAL_PROGRESS
, 0);
1522 VideoDriver::GetInstance()->GameLoopPause();
1526 * Set the total of a stage of the world generation.
1527 * @param cls the current class we are in.
1528 * @param total Set the total expected items for this class.
1530 * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always.
1531 * Also, progress works if total is zero, total works if progress is zero.
1533 void SetGeneratingWorldProgress(GenWorldProgress cls
, uint total
)
1535 if (total
== 0) return;
1537 _SetGeneratingWorldProgress(cls
, 0, total
);
1541 * Increases the current stage of the world generation with one.
1542 * @param cls the current class we are in.
1544 * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always.
1545 * Also, progress works if total is zero, total works if progress is zero.
1547 void IncreaseGeneratingWorldProgress(GenWorldProgress cls
)
1549 /* In fact the param 'class' isn't needed.. but for some security reasons, we want it around */
1550 _SetGeneratingWorldProgress(cls
, 1, 0);