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 "widgets/dropdown_type.h"
22 #include "widgets/dropdown_func.h"
23 #include "querystring_gui.h"
25 #include "core/geometry_func.hpp"
26 #include "core/random_func.hpp"
27 #include "saveload/saveload.h"
30 #include "newgrf_townname.h"
31 #include "townname_type.h"
32 #include "video/video_driver.hpp"
33 #include "ai/ai_gui.hpp"
34 #include "game/game_gui.hpp"
37 #include "widgets/genworld_widget.h"
39 #include "safeguards.h"
42 extern void MakeNewgameSettingsLive();
44 /** Enum for the modes we can generate in. */
45 enum GenerateLandscapeWindowMode
{
46 GLWM_GENERATE
, ///< Generate new game.
47 GLWM_HEIGHTMAP
, ///< Load from heightmap.
48 GLWM_SCENARIO
, ///< Generate flat land.
52 * Get the map height limit, or if set to "auto", the absolute limit.
54 static uint
GetMapHeightLimit()
56 if (_settings_newgame
.construction
.map_height_limit
== 0) return MAX_MAP_HEIGHT_LIMIT
;
57 return _settings_newgame
.construction
.map_height_limit
;
61 * Changes landscape type and sets genworld window dirty
62 * @param landscape new landscape type
64 void SetNewLandscapeType(byte landscape
)
66 _settings_newgame
.game_creation
.landscape
= landscape
;
67 InvalidateWindowClassesData(WC_SELECT_GAME
);
68 InvalidateWindowClassesData(WC_GENERATE_LANDSCAPE
);
71 /** Widgets of GenerateLandscapeWindow when generating world */
72 static constexpr NWidgetPart _nested_generate_landscape_widgets
[] = {
73 NWidget(NWID_HORIZONTAL
),
74 NWidget(WWT_CLOSEBOX
, COLOUR_BROWN
),
75 NWidget(WWT_CAPTION
, COLOUR_BROWN
), SetDataTip(STR_MAPGEN_WORLD_GENERATION_CAPTION
, STR_NULL
),
77 NWidget(WWT_PANEL
, COLOUR_BROWN
),
78 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_wide
, 0), SetPadding(WidgetDimensions::unscaled
.sparse
),
79 /* Landscape selection. */
80 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0), SetPIPRatio(1, 1, 1),
81 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TEMPERATE
), SetDataTip(SPR_SELECT_TEMPERATE
, STR_INTRO_TOOLTIP_TEMPERATE
),
82 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_ARCTIC
), SetDataTip(SPR_SELECT_SUB_ARCTIC
, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE
),
83 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TROPICAL
), SetDataTip(SPR_SELECT_SUB_TROPICAL
, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE
),
84 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TOYLAND
), SetDataTip(SPR_SELECT_TOYLAND
, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE
),
87 /* Generation options. */
88 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0),
89 /* Left half (land generation options) */
90 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
91 /* Labels on the left side (global column 1). */
92 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
93 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_MAPSIZE
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
94 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_TERRAIN_TYPE
, STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT
), SetFill(1, 1),
95 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_VARIETY
, STR_CONFIG_SETTING_VARIETY_HELPTEXT
), SetFill(1, 1),
96 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SMOOTHNESS
, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT
), SetFill(1, 1),
97 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_QUANTITY_OF_RIVERS
, STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT
), SetFill(1, 1),
98 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_BORDER_TYPE
, STR_MAPGEN_BORDER_TYPE_TOOLTIP
), SetFill(1, 1),
101 /* Widgets on the right side (global column 2). */
102 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
104 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
105 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_MAPSIZE_X_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
106 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_BY
, STR_NULL
), SetFill(0, 1), SetAlignment(SA_CENTER
),
107 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_MAPSIZE_Y_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
109 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TERRAIN_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT
), SetFill(1, 1),
110 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_VARIETY_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_VARIETY_HELPTEXT
), SetFill(1, 1),
111 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_SMOOTHNESS_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT
), SetFill(1, 1),
112 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_RIVER_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT
), SetFill(1, 1),
113 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_BORDERS_RANDOM
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_BORDER_TYPE_TOOLTIP
), SetFill(1, 1),
117 /* Right half (all other options) */
118 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
119 /* Labels on the left side (global column 3). */
120 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
121 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_GL_CLIMATE_SEL_LABEL
),
122 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SNOW_COVERAGE
, STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT
), SetFill(1, 1),
123 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DESERT_COVERAGE
, STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT
), SetFill(1, 1),
124 NWidget(NWID_SPACER
), SetFill(1, 1),
126 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DATE
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(1, 1),
127 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_TOWN_NAME_LABEL
, STR_MAPGEN_TOWN_NAME_DROPDOWN_TOOLTIP
), SetFill(1, 1),
128 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NUMBER_OF_TOWNS
, STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP
), SetFill(1, 1),
129 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NUMBER_OF_INDUSTRIES
, STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP
), SetFill(1, 1),
130 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SEA_LEVEL
, STR_MAPGEN_SEA_LEVEL_TOOLTIP
), SetFill(1, 1),
133 /* Widgets on the right side (global column 4). */
134 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
135 /* Climate selector. */
136 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_GL_CLIMATE_SEL_SELECTOR
),
138 NWidget(NWID_HORIZONTAL
),
139 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_SNOW_COVERAGE_DOWN
), SetFill(0, 1),
140 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),
141 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_SNOW_COVERAGE_UP
), SetFill(0, 1),
143 /* Desert coverage. */
144 NWidget(NWID_HORIZONTAL
),
145 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_DESERT_COVERAGE_DOWN
), SetFill(0, 1),
146 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),
147 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_DESERT_COVERAGE_UP
), SetFill(0, 1),
149 /* Temperate/Toyland spacer. */
150 NWidget(NWID_SPACER
), SetFill(1, 1),
153 NWidget(NWID_HORIZONTAL
),
154 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),
155 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_START_DATE_TEXT
), SetDataTip(STR_JUST_DATE_LONG
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(1, 1),
156 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),
158 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TOWNNAME_DROPDOWN
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_TOWN_NAME_DROPDOWN_TOOLTIP
), SetFill(1, 1),
159 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TOWN_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP
), SetFill(1, 1),
160 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_INDUSTRY_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP
), SetFill(1, 1),
161 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_WATER_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_SEA_LEVEL_TOOLTIP
), SetFill(1, 1),
166 /* Map borders buttons for each edge. */
167 NWidget(NWID_VERTICAL
),
168 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
169 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
),
170 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_WATER_NW
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_NORTHWEST
), SetFill(1, 1),
171 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_WATER_NE
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_NORTHEAST
), SetFill(1, 1),
172 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NORTHEAST
, STR_NULL
), SetPadding(0, 0, 0, WidgetDimensions::unscaled
.hsep_normal
), SetFill(1, 1),
174 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
175 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
),
176 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_WATER_SW
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_SOUTHWEST
), SetFill(1, 1),
177 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_WATER_SE
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_SOUTHEAST
), SetFill(1, 1),
178 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SOUTHEAST
, STR_NULL
), SetPadding(0, 0, 0, WidgetDimensions::unscaled
.hsep_normal
), SetFill(1, 1),
182 /* AI, GS, and NewGRF settings */
183 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
184 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),
185 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),
186 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),
190 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREEN
, WID_GL_GENERATE_BUTTON
), SetMinimalTextLines(3, 0), SetDataTip(STR_MAPGEN_GENERATE
, STR_MAPGEN_GENERATE_TOOLTIP
), SetFill(1, 1),
195 /** Widgets of GenerateLandscapeWindow when loading heightmap */
196 static constexpr NWidgetPart _nested_heightmap_load_widgets
[] = {
198 NWidget(NWID_HORIZONTAL
),
199 NWidget(WWT_CLOSEBOX
, COLOUR_BROWN
),
200 NWidget(WWT_CAPTION
, COLOUR_BROWN
), SetDataTip(STR_MAPGEN_WORLD_GENERATION_CAPTION
, STR_NULL
),
202 NWidget(WWT_PANEL
, COLOUR_BROWN
),
203 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_wide
, 0), SetPadding(WidgetDimensions::unscaled
.sparse
),
204 /* Landscape selection. */
205 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0), SetPIPRatio(1, 1, 1),
206 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TEMPERATE
), SetDataTip(SPR_SELECT_TEMPERATE
, STR_INTRO_TOOLTIP_TEMPERATE
),
207 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_ARCTIC
), SetDataTip(SPR_SELECT_SUB_ARCTIC
, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE
),
208 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TROPICAL
), SetDataTip(SPR_SELECT_SUB_TROPICAL
, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE
),
209 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_GL_TOYLAND
), SetDataTip(SPR_SELECT_TOYLAND
, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE
),
212 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
213 /* Heightmap name label. */
214 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_HEIGHTMAP_NAME
, STR_MAPGEN_HEIGHTMAP_NAME_TOOLTIP
),
215 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),
218 /* Generation options. */
219 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0),
220 /* Left half (land generation options) */
221 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
222 /* Labels on the left side (global column 1). */
223 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
224 /* Land generation option labels. */
225 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_HEIGHTMAP_SIZE_LABEL
, STR_MAPGEN_HEIGHTMAP_SIZE_LABEL_TOOLTIP
), SetFill(1, 1),
226 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_MAPSIZE
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
227 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_HEIGHTMAP_ROTATION
, STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_TOOLTIP
), SetFill(1, 1),
228 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_HEIGHTMAP_HEIGHT
, STR_MAPGEN_HEIGHTMAP_HEIGHT_TOOLTIP
), SetFill(1, 1),
229 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_QUANTITY_OF_RIVERS
, STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT
), SetFill(1, 1),
232 /* Left half widgets (global column 2) */
233 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
234 NWidget(WWT_TEXT
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_SIZE_TEXT
), SetDataTip(STR_MAPGEN_HEIGHTMAP_SIZE
, STR_MAPGEN_HEIGHTMAP_SIZE_LABEL_TOOLTIP
), SetFill(1, 1),
236 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
237 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_MAPSIZE_X_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
238 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_BY
, STR_NULL
), SetFill(0, 1), SetAlignment(SA_CENTER
),
239 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_MAPSIZE_Y_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
241 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_TOOLTIP
), SetFill(1, 1),
242 /* Heightmap highest peak. */
243 NWidget(NWID_HORIZONTAL
),
244 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_HEIGHT_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_HEIGHTMAP_HEIGHT_DOWN
), SetFill(0, 1),
245 NWidget(WWT_TEXTBTN
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_HEIGHT_TEXT
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_HEIGHTMAP_HEIGHT_TOOLTIP
), SetFill(1, 1),
246 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_HEIGHTMAP_HEIGHT_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_HEIGHTMAP_HEIGHT_UP
), SetFill(0, 1),
248 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_RIVER_PULLDOWN
), SetDataTip(STR_JUST_STRING
, STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT
), SetFill(1, 1),
252 /* Right half (all other options) */
253 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
254 /* Right half labels (global column 3) */
255 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
256 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_GL_CLIMATE_SEL_LABEL
),
257 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_SNOW_COVERAGE
, STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT
), SetFill(1, 1),
258 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DESERT_COVERAGE
, STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT
), SetFill(1, 1),
259 NWidget(NWID_SPACER
), SetFill(1, 1),
261 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DATE
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(1, 1),
262 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_TOWN_NAME_LABEL
, STR_MAPGEN_TOWN_NAME_DROPDOWN_TOOLTIP
), SetFill(1, 1),
263 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NUMBER_OF_TOWNS
, STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP
), SetFill(1, 1),
264 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_NUMBER_OF_INDUSTRIES
, STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP
), SetFill(1, 1),
267 /* Right half widgets (global column 4) */
268 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
269 /* Climate selector. */
270 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_GL_CLIMATE_SEL_SELECTOR
),
272 NWidget(NWID_HORIZONTAL
),
273 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_SNOW_COVERAGE_DOWN
), SetFill(0, 1),
274 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),
275 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_SNOW_COVERAGE_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_SNOW_COVERAGE_UP
), SetFill(0, 1),
277 /* Desert coverage. */
278 NWidget(NWID_HORIZONTAL
),
279 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_DOWN
), SetDataTip(SPR_ARROW_DOWN
, STR_MAPGEN_DESERT_COVERAGE_DOWN
), SetFill(0, 1),
280 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),
281 NWidget(WWT_IMGBTN
, COLOUR_ORANGE
, WID_GL_DESERT_COVERAGE_UP
), SetDataTip(SPR_ARROW_UP
, STR_MAPGEN_DESERT_COVERAGE_UP
), SetFill(0, 1),
283 /* Temperate/Toyland spacer. */
284 NWidget(NWID_SPACER
), SetFill(1, 1),
287 NWidget(NWID_HORIZONTAL
),
288 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),
289 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_GL_START_DATE_TEXT
), SetDataTip(STR_JUST_DATE_LONG
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(1, 1),
290 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),
292 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TOWNNAME_DROPDOWN
), SetDataTip(STR_JUST_STRING
, STR_MAPGEN_TOWN_NAME_DROPDOWN_TOOLTIP
), SetFill(1, 1),
293 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_TOWN_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_NUMBER_OF_TOWNS_TOOLTIP
), SetFill(1, 1),
294 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_GL_INDUSTRY_PULLDOWN
), SetDataTip(STR_JUST_STRING1
, STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP
), SetFill(1, 1),
299 /* AI, GS, and NewGRF settings */
300 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
301 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),
302 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),
303 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),
307 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREEN
, WID_GL_GENERATE_BUTTON
), SetMinimalTextLines(3, 0), SetDataTip(STR_MAPGEN_GENERATE
, STR_MAPGEN_GENERATE_TOOLTIP
), SetFill(1, 1),
312 static void StartGeneratingLandscape(GenerateLandscapeWindowMode mode
)
314 CloseAllNonVitalWindows();
315 ClearErrorMessages();
317 /* Copy all XXX_newgame to XXX when coming from outside the editor */
318 MakeNewgameSettingsLive();
319 ResetGRFConfig(true);
321 if (_settings_client
.sound
.confirm
) SndPlayFx(SND_15_BEEP
);
323 case GLWM_GENERATE
: _switch_mode
= (_game_mode
== GM_EDITOR
) ? SM_GENRANDLAND
: SM_NEWGAME
; break;
324 case GLWM_HEIGHTMAP
: _switch_mode
= (_game_mode
== GM_EDITOR
) ? SM_LOAD_HEIGHTMAP
: SM_START_HEIGHTMAP
; break;
325 case GLWM_SCENARIO
: _switch_mode
= SM_EDITOR
; break;
326 default: NOT_REACHED();
330 static void LandscapeGenerationCallback(Window
*w
, bool confirmed
)
332 if (confirmed
) StartGeneratingLandscape((GenerateLandscapeWindowMode
)w
->window_number
);
335 static DropDownList
BuildMapsizeDropDown()
339 for (uint i
= MIN_MAP_SIZE_BITS
; i
<= MAX_MAP_SIZE_BITS
; i
++) {
340 SetDParam(0, 1LL << i
);
341 list
.push_back(std::make_unique
<DropDownListStringItem
>(STR_JUST_INT
, i
, false));
347 static DropDownList
BuildTownNameDropDown()
351 /* Add and sort newgrf townnames generators */
352 const auto &grf_names
= GetGRFTownNameList();
353 for (uint i
= 0; i
< grf_names
.size(); i
++) {
354 list
.push_back(std::make_unique
<DropDownListStringItem
>(grf_names
[i
], BUILTIN_TOWNNAME_GENERATOR_COUNT
+ i
, false));
356 std::sort(list
.begin(), list
.end(), DropDownListStringItem::NatSortFunc
);
358 size_t newgrf_size
= list
.size();
359 /* Insert newgrf_names at the top of the list */
360 if (newgrf_size
> 0) {
361 list
.push_back(std::make_unique
<DropDownListDividerItem
>(-1, false)); // separator line
365 /* Add and sort original townnames generators */
366 for (uint i
= 0; i
< BUILTIN_TOWNNAME_GENERATOR_COUNT
; i
++) {
367 list
.push_back(std::make_unique
<DropDownListStringItem
>(STR_MAPGEN_TOWN_NAME_ORIGINAL_ENGLISH
+ i
, i
, false));
369 std::sort(list
.begin() + newgrf_size
, list
.end(), DropDownListStringItem::NatSortFunc
);
375 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
, INVALID_STRING_ID
};
376 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
, INVALID_STRING_ID
};
377 static const StringID _rivers
[] = {STR_RIVERS_NONE
, STR_RIVERS_FEW
, STR_RIVERS_MODERATE
, STR_RIVERS_LOT
, INVALID_STRING_ID
};
378 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
, INVALID_STRING_ID
};
379 static const StringID _rotation
[] = {STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE
, STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE
, INVALID_STRING_ID
};
380 static const StringID _num_towns
[] = {STR_NUM_VERY_LOW
, STR_NUM_LOW
, STR_NUM_NORMAL
, STR_NUM_HIGH
, STR_NUM_CUSTOM
, INVALID_STRING_ID
};
381 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
, INVALID_STRING_ID
};
382 static const StringID _variety
[] = {STR_VARIETY_NONE
, STR_VARIETY_VERY_LOW
, STR_VARIETY_LOW
, STR_VARIETY_MEDIUM
, STR_VARIETY_HIGH
, STR_VARIETY_VERY_HIGH
, INVALID_STRING_ID
};
384 static_assert(lengthof(_num_inds
) == ID_END
+ 1);
386 struct GenerateLandscapeWindow
: public Window
{
391 GenerateLandscapeWindowMode mode
;
393 GenerateLandscapeWindow(WindowDesc
*desc
, WindowNumber number
= 0) : Window(desc
)
395 this->InitNested(number
);
397 this->LowerWidget(_settings_newgame
.game_creation
.landscape
+ WID_GL_TEMPERATE
);
399 this->mode
= (GenerateLandscapeWindowMode
)this->window_number
;
401 /* Disable town and industry in SE */
402 this->SetWidgetDisabledState(WID_GL_TOWN_PULLDOWN
, _game_mode
== GM_EDITOR
);
403 this->SetWidgetDisabledState(WID_GL_INDUSTRY_PULLDOWN
, _game_mode
== GM_EDITOR
);
405 /* In case the map_height_limit is changed, clamp heightmap_height and custom_terrain_type. */
406 _settings_newgame
.game_creation
.heightmap_height
= Clamp(_settings_newgame
.game_creation
.heightmap_height
, MIN_HEIGHTMAP_HEIGHT
, GetMapHeightLimit());
407 _settings_newgame
.game_creation
.custom_terrain_type
= Clamp(_settings_newgame
.game_creation
.custom_terrain_type
, MIN_CUSTOM_TERRAIN_TYPE
, GetMapHeightLimit());
409 /* If original landgenerator is selected and alpinist terrain_type was selected, revert to mountainous. */
410 if (_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
) {
411 _settings_newgame
.difficulty
.terrain_type
= Clamp(_settings_newgame
.difficulty
.terrain_type
, 0, 3);
414 this->OnInvalidateData();
418 void SetStringParameters(WidgetID widget
) const override
421 case WID_GL_START_DATE_TEXT
: SetDParam(0, TimerGameCalendar::ConvertYMDToDate(_settings_newgame
.game_creation
.starting_year
, 0, 1)); break;
422 case WID_GL_MAPSIZE_X_PULLDOWN
: SetDParam(0, 1LL << _settings_newgame
.game_creation
.map_x
); break;
423 case WID_GL_MAPSIZE_Y_PULLDOWN
: SetDParam(0, 1LL << _settings_newgame
.game_creation
.map_y
); break;
424 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
: SetDParam(0, _settings_newgame
.game_creation
.heightmap_height
); break;
425 case WID_GL_SNOW_COVERAGE_TEXT
: SetDParam(0, _settings_newgame
.game_creation
.snow_coverage
); break;
426 case WID_GL_DESERT_COVERAGE_TEXT
: SetDParam(0, _settings_newgame
.game_creation
.desert_coverage
); break;
428 case WID_GL_TOWN_PULLDOWN
:
429 if (_game_mode
== GM_EDITOR
) {
430 SetDParam(0, STR_CONFIG_SETTING_OFF
);
431 } else if (_settings_newgame
.difficulty
.number_towns
== CUSTOM_TOWN_NUMBER_DIFFICULTY
) {
432 SetDParam(0, STR_NUM_CUSTOM_NUMBER
);
433 SetDParam(1, _settings_newgame
.game_creation
.custom_town_number
);
435 SetDParam(0, _num_towns
[_settings_newgame
.difficulty
.number_towns
]);
439 case WID_GL_TOWNNAME_DROPDOWN
: {
440 uint gen
= _settings_newgame
.game_creation
.town_name
;
441 StringID name
= gen
< BUILTIN_TOWNNAME_GENERATOR_COUNT
?
442 STR_MAPGEN_TOWN_NAME_ORIGINAL_ENGLISH
+ gen
:
443 GetGRFTownNameName(gen
- BUILTIN_TOWNNAME_GENERATOR_COUNT
);
448 case WID_GL_INDUSTRY_PULLDOWN
:
449 if (_game_mode
== GM_EDITOR
) {
450 SetDParam(0, STR_CONFIG_SETTING_OFF
);
451 } else if (_settings_newgame
.difficulty
.industry_density
== ID_CUSTOM
) {
452 SetDParam(0, STR_NUM_CUSTOM_NUMBER
);
453 SetDParam(1, _settings_newgame
.game_creation
.custom_industry_number
);
455 SetDParam(0, _num_inds
[_settings_newgame
.difficulty
.industry_density
]);
459 case WID_GL_TERRAIN_PULLDOWN
:
460 if (_settings_newgame
.difficulty
.terrain_type
== CUSTOM_TERRAIN_TYPE_NUMBER_DIFFICULTY
) {
461 SetDParam(0, STR_TERRAIN_TYPE_CUSTOM_VALUE
);
462 SetDParam(1, _settings_newgame
.game_creation
.custom_terrain_type
);
464 SetDParam(0, _elevations
[_settings_newgame
.difficulty
.terrain_type
]); break;
468 case WID_GL_WATER_PULLDOWN
:
469 if (_settings_newgame
.difficulty
.quantity_sea_lakes
== CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
) {
470 SetDParam(0, STR_SEA_LEVEL_CUSTOM_PERCENTAGE
);
471 SetDParam(1, _settings_newgame
.game_creation
.custom_sea_level
);
473 SetDParam(0, _sea_lakes
[_settings_newgame
.difficulty
.quantity_sea_lakes
]);
477 case WID_GL_HEIGHTMAP_NAME_TEXT
: SetDParamStr(0, this->name
); break;
478 case WID_GL_RIVER_PULLDOWN
: SetDParam(0, _rivers
[_settings_newgame
.game_creation
.amount_of_rivers
]); break;
479 case WID_GL_SMOOTHNESS_PULLDOWN
: SetDParam(0, _smoothness
[_settings_newgame
.game_creation
.tgen_smoothness
]); break;
480 case WID_GL_VARIETY_PULLDOWN
: SetDParam(0, _variety
[_settings_newgame
.game_creation
.variety
]); break;
481 case WID_GL_BORDERS_RANDOM
: SetDParam(0, (_settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
) ? STR_MAPGEN_BORDER_RANDOMIZE
: STR_MAPGEN_BORDER_MANUAL
); break;
482 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;
483 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;
484 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;
485 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;
486 case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
: SetDParam(0, _rotation
[_settings_newgame
.game_creation
.heightmap_rotation
]); break;
488 case WID_GL_HEIGHTMAP_SIZE_TEXT
:
489 if (_settings_newgame
.game_creation
.heightmap_rotation
== HM_CLOCKWISE
) {
490 SetDParam(0, this->y
);
491 SetDParam(1, this->x
);
493 SetDParam(0, this->x
);
494 SetDParam(1, this->y
);
501 * Some data on this window has become invalid.
502 * @param data Information about the changed data.
503 * @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.
505 void OnInvalidateData([[maybe_unused
]] int data
= 0, [[maybe_unused
]] bool gui_scope
= true) override
507 if (!gui_scope
) return;
508 /* Update the climate buttons */
509 this->SetWidgetLoweredState(WID_GL_TEMPERATE
, _settings_newgame
.game_creation
.landscape
== LT_TEMPERATE
);
510 this->SetWidgetLoweredState(WID_GL_ARCTIC
, _settings_newgame
.game_creation
.landscape
== LT_ARCTIC
);
511 this->SetWidgetLoweredState(WID_GL_TROPICAL
, _settings_newgame
.game_creation
.landscape
== LT_TROPIC
);
512 this->SetWidgetLoweredState(WID_GL_TOYLAND
, _settings_newgame
.game_creation
.landscape
== LT_TOYLAND
);
514 /* You can't select smoothness / non-water borders if not terragenesis */
515 if (mode
== GLWM_GENERATE
) {
516 this->SetWidgetDisabledState(WID_GL_SMOOTHNESS_PULLDOWN
, _settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
);
517 this->SetWidgetDisabledState(WID_GL_VARIETY_PULLDOWN
, _settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
);
518 this->SetWidgetDisabledState(WID_GL_BORDERS_RANDOM
, _settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
|| !_settings_newgame
.construction
.freeform_edges
);
519 this->SetWidgetsDisabledState(_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
|| !_settings_newgame
.construction
.freeform_edges
|| _settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
,
520 WID_GL_WATER_NW
, WID_GL_WATER_NE
, WID_GL_WATER_SE
, WID_GL_WATER_SW
);
522 this->SetWidgetLoweredState(WID_GL_BORDERS_RANDOM
, _settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
);
524 this->SetWidgetLoweredState(WID_GL_WATER_NW
, HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NW
));
525 this->SetWidgetLoweredState(WID_GL_WATER_NE
, HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NE
));
526 this->SetWidgetLoweredState(WID_GL_WATER_SE
, HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SE
));
527 this->SetWidgetLoweredState(WID_GL_WATER_SW
, HasBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SW
));
529 this->SetWidgetsDisabledState(_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
&& (_settings_newgame
.game_creation
.landscape
== LT_ARCTIC
|| _settings_newgame
.game_creation
.landscape
== LT_TROPIC
),
530 WID_GL_TERRAIN_PULLDOWN
, WID_GL_WATER_PULLDOWN
);
533 /* Disable snowline if not arctic */
534 this->SetWidgetDisabledState(WID_GL_SNOW_COVERAGE_TEXT
, _settings_newgame
.game_creation
.landscape
!= LT_ARCTIC
);
535 /* Disable desert if not tropic */
536 this->SetWidgetDisabledState(WID_GL_DESERT_COVERAGE_TEXT
, _settings_newgame
.game_creation
.landscape
!= LT_TROPIC
);
538 /* Set snow/rainforest selections */
539 int climate_plane
= 0;
540 switch (_settings_newgame
.game_creation
.landscape
) {
541 case LT_TEMPERATE
: climate_plane
= 2; break;
542 case LT_ARCTIC
: climate_plane
= 0; break;
543 case LT_TROPIC
: climate_plane
= 1; break;
544 case LT_TOYLAND
: climate_plane
= 2; break;
546 this->GetWidget
<NWidgetStacked
>(WID_GL_CLIMATE_SEL_LABEL
)->SetDisplayedPlane(climate_plane
);
547 this->GetWidget
<NWidgetStacked
>(WID_GL_CLIMATE_SEL_SELECTOR
)->SetDisplayedPlane(climate_plane
);
549 /* Update availability of decreasing / increasing start date and snow level */
550 if (mode
== GLWM_HEIGHTMAP
) {
551 this->SetWidgetDisabledState(WID_GL_HEIGHTMAP_HEIGHT_DOWN
, _settings_newgame
.game_creation
.heightmap_height
<= MIN_HEIGHTMAP_HEIGHT
);
552 this->SetWidgetDisabledState(WID_GL_HEIGHTMAP_HEIGHT_UP
, _settings_newgame
.game_creation
.heightmap_height
>= GetMapHeightLimit());
554 this->SetWidgetDisabledState(WID_GL_START_DATE_DOWN
, _settings_newgame
.game_creation
.starting_year
<= CalendarTime::MIN_YEAR
);
555 this->SetWidgetDisabledState(WID_GL_START_DATE_UP
, _settings_newgame
.game_creation
.starting_year
>= CalendarTime::MAX_YEAR
);
556 this->SetWidgetDisabledState(WID_GL_SNOW_COVERAGE_DOWN
, _settings_newgame
.game_creation
.snow_coverage
<= 0 || _settings_newgame
.game_creation
.landscape
!= LT_ARCTIC
);
557 this->SetWidgetDisabledState(WID_GL_SNOW_COVERAGE_UP
, _settings_newgame
.game_creation
.snow_coverage
>= 100 || _settings_newgame
.game_creation
.landscape
!= LT_ARCTIC
);
558 this->SetWidgetDisabledState(WID_GL_DESERT_COVERAGE_DOWN
, _settings_newgame
.game_creation
.desert_coverage
<= 0 || _settings_newgame
.game_creation
.landscape
!= LT_TROPIC
);
559 this->SetWidgetDisabledState(WID_GL_DESERT_COVERAGE_UP
, _settings_newgame
.game_creation
.desert_coverage
>= 100 || _settings_newgame
.game_creation
.landscape
!= LT_TROPIC
);
561 /* Do not allow a custom sea level or terrain type with the original land generator. */
562 if (_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
) {
563 if (_settings_newgame
.difficulty
.quantity_sea_lakes
== CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
) {
564 _settings_newgame
.difficulty
.quantity_sea_lakes
= 1;
566 if (_settings_newgame
.difficulty
.terrain_type
== CUSTOM_TERRAIN_TYPE_NUMBER_DIFFICULTY
) {
567 _settings_newgame
.difficulty
.terrain_type
= 1;
573 void UpdateWidgetSize(WidgetID widget
, Dimension
*size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
*fill
, [[maybe_unused
]] Dimension
*resize
) override
575 Dimension d
{0, (uint
)GetCharacterHeight(FS_NORMAL
)};
576 const StringID
*strs
= nullptr;
578 case WID_GL_TEMPERATE
: case WID_GL_ARCTIC
:
579 case WID_GL_TROPICAL
: case WID_GL_TOYLAND
:
580 size
->width
+= WidgetDimensions::scaled
.fullbevel
.Horizontal();
581 size
->height
+= WidgetDimensions::scaled
.fullbevel
.Vertical();
584 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
:
585 SetDParam(0, MAX_TILE_HEIGHT
);
586 d
= GetStringBoundingBox(STR_JUST_INT
);
589 case WID_GL_START_DATE_TEXT
:
590 SetDParam(0, TimerGameCalendar::ConvertYMDToDate(CalendarTime::MAX_YEAR
, 0, 1));
591 d
= GetStringBoundingBox(STR_JUST_DATE_LONG
);
594 case WID_GL_MAPSIZE_X_PULLDOWN
:
595 case WID_GL_MAPSIZE_Y_PULLDOWN
:
596 SetDParamMaxValue(0, MAX_MAP_SIZE
);
597 d
= GetStringBoundingBox(STR_JUST_INT
);
600 case WID_GL_SNOW_COVERAGE_TEXT
:
601 SetDParamMaxValue(0, MAX_TILE_HEIGHT
);
602 d
= GetStringBoundingBox(STR_MAPGEN_SNOW_COVERAGE_TEXT
);
605 case WID_GL_DESERT_COVERAGE_TEXT
:
606 SetDParamMaxValue(0, MAX_TILE_HEIGHT
);
607 d
= GetStringBoundingBox(STR_MAPGEN_DESERT_COVERAGE_TEXT
);
610 case WID_GL_HEIGHTMAP_SIZE_TEXT
:
611 SetDParam(0, this->x
);
612 SetDParam(1, this->y
);
613 d
= GetStringBoundingBox(STR_MAPGEN_HEIGHTMAP_SIZE
);
616 case WID_GL_TOWN_PULLDOWN
:
618 SetDParamMaxValue(0, CUSTOM_TOWN_MAX_NUMBER
);
619 d
= GetStringBoundingBox(STR_NUM_CUSTOM_NUMBER
);
622 case WID_GL_INDUSTRY_PULLDOWN
:
624 SetDParamMaxValue(0, IndustryPool::MAX_SIZE
);
625 d
= GetStringBoundingBox(STR_NUM_CUSTOM_NUMBER
);
628 case WID_GL_TERRAIN_PULLDOWN
:
630 SetDParamMaxValue(0, MAX_MAP_HEIGHT_LIMIT
);
631 d
= GetStringBoundingBox(STR_TERRAIN_TYPE_CUSTOM_VALUE
);
634 case WID_GL_WATER_PULLDOWN
:
636 SetDParamMaxValue(0, CUSTOM_SEA_LEVEL_MAX_PERCENTAGE
);
637 d
= GetStringBoundingBox(STR_SEA_LEVEL_CUSTOM_PERCENTAGE
);
640 case WID_GL_RIVER_PULLDOWN
: strs
= _rivers
; break;
641 case WID_GL_SMOOTHNESS_PULLDOWN
: strs
= _smoothness
; break;
642 case WID_GL_VARIETY_PULLDOWN
: strs
= _variety
; break;
643 case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
: strs
= _rotation
; break;
644 case WID_GL_BORDERS_RANDOM
:
645 d
= maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_RANDOMIZE
), GetStringBoundingBox(STR_MAPGEN_BORDER_MANUAL
));
648 case WID_GL_WATER_NE
:
649 case WID_GL_WATER_NW
:
650 case WID_GL_WATER_SE
:
651 case WID_GL_WATER_SW
:
652 d
= maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_RANDOM
), maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_WATER
), GetStringBoundingBox(STR_MAPGEN_BORDER_FREEFORM
)));
655 case WID_GL_HEIGHTMAP_NAME_TEXT
:
662 if (strs
!= nullptr) {
663 while (*strs
!= INVALID_STRING_ID
) {
664 d
= maxdim(d
, GetStringBoundingBox(*strs
++));
667 d
.width
+= padding
.width
;
668 d
.height
+= padding
.height
;
669 *size
= maxdim(*size
, d
);
672 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
675 case WID_GL_TEMPERATE
:
677 case WID_GL_TROPICAL
:
679 SetNewLandscapeType(widget
- WID_GL_TEMPERATE
);
682 case WID_GL_MAPSIZE_X_PULLDOWN
: // Mapsize X
683 ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame
.game_creation
.map_x
, WID_GL_MAPSIZE_X_PULLDOWN
);
686 case WID_GL_MAPSIZE_Y_PULLDOWN
: // Mapsize Y
687 ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame
.game_creation
.map_y
, WID_GL_MAPSIZE_Y_PULLDOWN
);
690 case WID_GL_TOWN_PULLDOWN
: // Number of towns
691 ShowDropDownMenu(this, _num_towns
, _settings_newgame
.difficulty
.number_towns
, WID_GL_TOWN_PULLDOWN
, 0, 0);
694 case WID_GL_TOWNNAME_DROPDOWN
: // Townname generator
695 ShowDropDownList(this, BuildTownNameDropDown(), _settings_newgame
.game_creation
.town_name
, WID_GL_TOWNNAME_DROPDOWN
);
698 case WID_GL_INDUSTRY_PULLDOWN
: // Number of industries
699 ShowDropDownMenu(this, _num_inds
, _settings_newgame
.difficulty
.industry_density
, WID_GL_INDUSTRY_PULLDOWN
, 0, 0);
702 case WID_GL_GENERATE_BUTTON
: { // Generate
703 /* Get rotated map size. */
706 if (_settings_newgame
.game_creation
.heightmap_rotation
== HM_CLOCKWISE
) {
713 if (mode
== GLWM_HEIGHTMAP
&&
714 (map_x
* 2 < (1U << _settings_newgame
.game_creation
.map_x
) ||
715 map_x
/ 2 > (1U << _settings_newgame
.game_creation
.map_x
) ||
716 map_y
* 2 < (1U << _settings_newgame
.game_creation
.map_y
) ||
717 map_y
/ 2 > (1U << _settings_newgame
.game_creation
.map_y
))) {
719 STR_WARNING_HEIGHTMAP_SCALE_CAPTION
,
720 STR_WARNING_HEIGHTMAP_SCALE_MESSAGE
,
722 LandscapeGenerationCallback
);
724 StartGeneratingLandscape(mode
);
729 case WID_GL_HEIGHTMAP_HEIGHT_DOWN
:
730 case WID_GL_HEIGHTMAP_HEIGHT_UP
: // Height level buttons
731 /* Don't allow too fast scrolling */
732 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
733 this->HandleButtonClick(widget
);
735 _settings_newgame
.game_creation
.heightmap_height
= Clamp(_settings_newgame
.game_creation
.heightmap_height
+ widget
- WID_GL_HEIGHTMAP_HEIGHT_TEXT
, MIN_HEIGHTMAP_HEIGHT
, GetMapHeightLimit());
736 this->InvalidateData();
738 _left_button_clicked
= false;
741 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
: // Height level text
742 this->widget_id
= WID_GL_HEIGHTMAP_HEIGHT_TEXT
;
743 SetDParam(0, _settings_newgame
.game_creation
.heightmap_height
);
744 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_HEIGHTMAP_HEIGHT_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_ENABLE_DEFAULT
);
748 case WID_GL_START_DATE_DOWN
:
749 case WID_GL_START_DATE_UP
: // Year buttons
750 /* Don't allow too fast scrolling */
751 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
752 this->HandleButtonClick(widget
);
754 _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
);
755 this->InvalidateData();
757 _left_button_clicked
= false;
760 case WID_GL_START_DATE_TEXT
: // Year text
761 this->widget_id
= WID_GL_START_DATE_TEXT
;
762 SetDParam(0, _settings_newgame
.game_creation
.starting_year
);
763 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_START_DATE_QUERY_CAPT
, 8, this, CS_NUMERAL
, QSF_ENABLE_DEFAULT
);
766 case WID_GL_SNOW_COVERAGE_DOWN
:
767 case WID_GL_SNOW_COVERAGE_UP
: // Snow coverage buttons
768 /* Don't allow too fast scrolling */
769 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
770 this->HandleButtonClick(widget
);
772 _settings_newgame
.game_creation
.snow_coverage
= Clamp(_settings_newgame
.game_creation
.snow_coverage
+ (widget
- WID_GL_SNOW_COVERAGE_TEXT
) * 10, 0, 100);
773 this->InvalidateData();
775 _left_button_clicked
= false;
778 case WID_GL_SNOW_COVERAGE_TEXT
: // Snow coverage text
779 this->widget_id
= WID_GL_SNOW_COVERAGE_TEXT
;
780 SetDParam(0, _settings_newgame
.game_creation
.snow_coverage
);
781 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_SNOW_COVERAGE_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_ENABLE_DEFAULT
);
784 case WID_GL_DESERT_COVERAGE_DOWN
:
785 case WID_GL_DESERT_COVERAGE_UP
: // Desert coverage buttons
786 /* Don't allow too fast scrolling */
787 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
788 this->HandleButtonClick(widget
);
790 _settings_newgame
.game_creation
.desert_coverage
= Clamp(_settings_newgame
.game_creation
.desert_coverage
+ (widget
- WID_GL_DESERT_COVERAGE_TEXT
) * 10, 0, 100);
791 this->InvalidateData();
793 _left_button_clicked
= false;
796 case WID_GL_DESERT_COVERAGE_TEXT
: // Desert line text
797 this->widget_id
= WID_GL_DESERT_COVERAGE_TEXT
;
798 SetDParam(0, _settings_newgame
.game_creation
.desert_coverage
);
799 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_DESERT_COVERAGE_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_ENABLE_DEFAULT
);
802 case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
: // Heightmap rotation
803 ShowDropDownMenu(this, _rotation
, _settings_newgame
.game_creation
.heightmap_rotation
, WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
, 0, 0);
806 case WID_GL_TERRAIN_PULLDOWN
: // Terrain type
807 /* For the original map generation only the first four are valid. */
808 ShowDropDownMenu(this, _elevations
, _settings_newgame
.difficulty
.terrain_type
, WID_GL_TERRAIN_PULLDOWN
, 0, _settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
? ~0xF : 0);
811 case WID_GL_WATER_PULLDOWN
: { // Water quantity
812 uint32_t hidden_mask
= 0;
813 /* Disable custom water level when the original map generator is active. */
814 if (_settings_newgame
.game_creation
.land_generator
== LG_ORIGINAL
) {
815 SetBit(hidden_mask
, CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
);
817 ShowDropDownMenu(this, _sea_lakes
, _settings_newgame
.difficulty
.quantity_sea_lakes
, WID_GL_WATER_PULLDOWN
, 0, hidden_mask
);
821 case WID_GL_RIVER_PULLDOWN
: // Amount of rivers
822 ShowDropDownMenu(this, _rivers
, _settings_newgame
.game_creation
.amount_of_rivers
, WID_GL_RIVER_PULLDOWN
, 0, 0);
825 case WID_GL_SMOOTHNESS_PULLDOWN
: // Map smoothness
826 ShowDropDownMenu(this, _smoothness
, _settings_newgame
.game_creation
.tgen_smoothness
, WID_GL_SMOOTHNESS_PULLDOWN
, 0, 0);
829 case WID_GL_VARIETY_PULLDOWN
: // Map variety
830 ShowDropDownMenu(this, _variety
, _settings_newgame
.game_creation
.variety
, WID_GL_VARIETY_PULLDOWN
, 0, 0);
833 /* Freetype map borders */
834 case WID_GL_WATER_NW
:
835 _settings_newgame
.game_creation
.water_borders
= ToggleBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NW
);
836 this->InvalidateData();
839 case WID_GL_WATER_NE
:
840 _settings_newgame
.game_creation
.water_borders
= ToggleBit(_settings_newgame
.game_creation
.water_borders
, BORDER_NE
);
841 this->InvalidateData();
844 case WID_GL_WATER_SE
:
845 _settings_newgame
.game_creation
.water_borders
= ToggleBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SE
);
846 this->InvalidateData();
849 case WID_GL_WATER_SW
:
850 _settings_newgame
.game_creation
.water_borders
= ToggleBit(_settings_newgame
.game_creation
.water_borders
, BORDER_SW
);
851 this->InvalidateData();
854 case WID_GL_BORDERS_RANDOM
:
855 _settings_newgame
.game_creation
.water_borders
= (_settings_newgame
.game_creation
.water_borders
== BORDERS_RANDOM
) ? 0 : BORDERS_RANDOM
;
856 this->InvalidateData();
859 case WID_GL_AI_BUTTON
: ///< AI Settings
860 ShowAIConfigWindow();
863 case WID_GL_GS_BUTTON
: ///< Game Script Settings
864 ShowGSConfigWindow();
867 case WID_GL_NEWGRF_BUTTON
: ///< NewGRF Settings
868 ShowNewGRFSettings(true, true, false, &_grfconfig_newgame
);
873 void OnTimeout() override
875 if (mode
== GLWM_HEIGHTMAP
) {
876 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
);
878 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
);
882 void OnDropdownSelect(WidgetID widget
, int index
) override
885 case WID_GL_MAPSIZE_X_PULLDOWN
: _settings_newgame
.game_creation
.map_x
= index
; break;
886 case WID_GL_MAPSIZE_Y_PULLDOWN
: _settings_newgame
.game_creation
.map_y
= index
; break;
887 case WID_GL_RIVER_PULLDOWN
: _settings_newgame
.game_creation
.amount_of_rivers
= index
; break;
888 case WID_GL_SMOOTHNESS_PULLDOWN
: _settings_newgame
.game_creation
.tgen_smoothness
= index
; break;
889 case WID_GL_VARIETY_PULLDOWN
: _settings_newgame
.game_creation
.variety
= index
; break;
891 case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN
: _settings_newgame
.game_creation
.heightmap_rotation
= index
; break;
893 case WID_GL_TOWN_PULLDOWN
:
894 if ((uint
)index
== CUSTOM_TOWN_NUMBER_DIFFICULTY
) {
895 this->widget_id
= widget
;
896 SetDParam(0, _settings_newgame
.game_creation
.custom_town_number
);
897 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_NUMBER_OF_TOWNS
, 5, this, CS_NUMERAL
, QSF_NONE
);
899 _settings_newgame
.difficulty
.number_towns
= index
;
902 case WID_GL_TOWNNAME_DROPDOWN
: // Town names
903 if (_game_mode
== GM_MENU
|| Town::GetNumItems() == 0) {
904 _settings_newgame
.game_creation
.town_name
= index
;
905 SetWindowDirty(WC_GAME_OPTIONS
, WN_GAME_OPTIONS_GAME_OPTIONS
);
909 case WID_GL_INDUSTRY_PULLDOWN
:
910 if ((uint
)index
== ID_CUSTOM
) {
911 this->widget_id
= widget
;
912 SetDParam(0, _settings_newgame
.game_creation
.custom_industry_number
);
913 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_NUMBER_OF_INDUSTRIES
, 5, this, CS_NUMERAL
, QSF_NONE
);
915 _settings_newgame
.difficulty
.industry_density
= index
;
918 case WID_GL_TERRAIN_PULLDOWN
: {
919 if ((uint
)index
== CUSTOM_TERRAIN_TYPE_NUMBER_DIFFICULTY
) {
920 this->widget_id
= widget
;
921 SetDParam(0, _settings_newgame
.game_creation
.custom_terrain_type
);
922 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_TERRAIN_TYPE_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_NONE
);
924 _settings_newgame
.difficulty
.terrain_type
= index
;
928 case WID_GL_WATER_PULLDOWN
: {
929 if ((uint
)index
== CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
) {
930 this->widget_id
= widget
;
931 SetDParam(0, _settings_newgame
.game_creation
.custom_sea_level
);
932 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_SEA_LEVEL
, 3, this, CS_NUMERAL
, QSF_NONE
);
934 _settings_newgame
.difficulty
.quantity_sea_lakes
= index
;
938 this->InvalidateData();
941 void OnQueryTextFinished(char *str
) override
943 /* Was 'cancel' pressed? */
944 if (str
== nullptr) return;
947 if (!StrEmpty(str
)) {
950 /* An empty string means revert to the default */
951 switch (this->widget_id
) {
952 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
: value
= MAP_HEIGHT_LIMIT_AUTO_MINIMUM
; break;
953 case WID_GL_START_DATE_TEXT
: value
= CalendarTime::DEF_START_YEAR
.base(); break;
954 case WID_GL_SNOW_COVERAGE_TEXT
: value
= DEF_SNOW_COVERAGE
; break;
955 case WID_GL_DESERT_COVERAGE_TEXT
: value
= DEF_DESERT_COVERAGE
; break;
956 case WID_GL_TOWN_PULLDOWN
: value
= 1; break;
957 case WID_GL_INDUSTRY_PULLDOWN
: value
= 1; break;
958 case WID_GL_TERRAIN_PULLDOWN
: value
= MIN_MAP_HEIGHT_LIMIT
; break;
959 case WID_GL_WATER_PULLDOWN
: value
= CUSTOM_SEA_LEVEL_MIN_PERCENTAGE
; break;
960 default: NOT_REACHED();
964 switch (this->widget_id
) {
965 case WID_GL_HEIGHTMAP_HEIGHT_TEXT
:
966 this->SetWidgetDirty(WID_GL_HEIGHTMAP_HEIGHT_TEXT
);
967 _settings_newgame
.game_creation
.heightmap_height
= Clamp(value
, MIN_HEIGHTMAP_HEIGHT
, GetMapHeightLimit());
970 case WID_GL_START_DATE_TEXT
:
971 this->SetWidgetDirty(WID_GL_START_DATE_TEXT
);
972 _settings_newgame
.game_creation
.starting_year
= Clamp(TimerGameCalendar::Year(value
), CalendarTime::MIN_YEAR
, CalendarTime::MAX_YEAR
);
975 case WID_GL_SNOW_COVERAGE_TEXT
:
976 this->SetWidgetDirty(WID_GL_SNOW_COVERAGE_TEXT
);
977 _settings_newgame
.game_creation
.snow_coverage
= Clamp(value
, 0, 100);
980 case WID_GL_DESERT_COVERAGE_TEXT
:
981 this->SetWidgetDirty(WID_GL_DESERT_COVERAGE_TEXT
);
982 _settings_newgame
.game_creation
.desert_coverage
= Clamp(value
, 0, 100);
985 case WID_GL_TOWN_PULLDOWN
:
986 _settings_newgame
.game_creation
.custom_town_number
= Clamp(value
, 1, CUSTOM_TOWN_MAX_NUMBER
);
989 case WID_GL_INDUSTRY_PULLDOWN
:
990 _settings_newgame
.game_creation
.custom_industry_number
= Clamp(value
, 1, IndustryPool::MAX_SIZE
);
993 case WID_GL_TERRAIN_PULLDOWN
:
994 _settings_newgame
.game_creation
.custom_terrain_type
= Clamp(value
, MIN_CUSTOM_TERRAIN_TYPE
, GetMapHeightLimit());
997 case WID_GL_WATER_PULLDOWN
:
998 _settings_newgame
.game_creation
.custom_sea_level
= Clamp(value
, CUSTOM_SEA_LEVEL_MIN_PERCENTAGE
, CUSTOM_SEA_LEVEL_MAX_PERCENTAGE
);
1002 this->InvalidateData();
1006 static WindowDesc
_generate_landscape_desc(__FILE__
, __LINE__
,
1007 WDP_CENTER
, nullptr, 0, 0,
1008 WC_GENERATE_LANDSCAPE
, WC_NONE
,
1010 std::begin(_nested_generate_landscape_widgets
), std::end(_nested_generate_landscape_widgets
)
1013 static WindowDesc
_heightmap_load_desc(__FILE__
, __LINE__
,
1014 WDP_CENTER
, nullptr, 0, 0,
1015 WC_GENERATE_LANDSCAPE
, WC_NONE
,
1017 std::begin(_nested_heightmap_load_widgets
), std::end(_nested_heightmap_load_widgets
)
1020 static void _ShowGenerateLandscape(GenerateLandscapeWindowMode mode
)
1025 CloseWindowByClass(WC_GENERATE_LANDSCAPE
);
1027 /* Generate a new seed when opening the window */
1028 _settings_newgame
.game_creation
.generation_seed
= InteractiveRandom();
1030 if (mode
== GLWM_HEIGHTMAP
) {
1031 /* If the function returns negative, it means there was a problem loading the heightmap */
1032 if (!GetHeightmapDimensions(_file_to_saveload
.detail_ftype
, _file_to_saveload
.name
.c_str(), &x
, &y
)) return;
1035 WindowDesc
*desc
= (mode
== GLWM_HEIGHTMAP
) ? &_heightmap_load_desc
: &_generate_landscape_desc
;
1036 GenerateLandscapeWindow
*w
= AllocateWindowDescFront
<GenerateLandscapeWindow
>(desc
, mode
, true);
1038 if (mode
== GLWM_HEIGHTMAP
) {
1041 w
->name
= _file_to_saveload
.title
;
1044 SetWindowDirty(WC_GENERATE_LANDSCAPE
, mode
);
1047 /** Start with a normal game. */
1048 void ShowGenerateLandscape()
1050 _ShowGenerateLandscape(GLWM_GENERATE
);
1053 /** Start with loading a heightmap. */
1054 void ShowHeightmapLoad()
1056 _ShowGenerateLandscape(GLWM_HEIGHTMAP
);
1059 /** Start with a scenario editor. */
1060 void StartScenarioEditor()
1062 StartGeneratingLandscape(GLWM_SCENARIO
);
1066 * Start a normal game without the GUI.
1067 * @param seed The seed of the new game.
1069 void StartNewGameWithoutGUI(uint32_t seed
)
1071 /* GenerateWorld takes care of the possible GENERATE_NEW_SEED value in 'seed' */
1072 _settings_newgame
.game_creation
.generation_seed
= seed
;
1074 StartGeneratingLandscape(GLWM_GENERATE
);
1077 struct CreateScenarioWindow
: public Window
1081 CreateScenarioWindow(WindowDesc
*desc
, WindowNumber window_number
) : Window(desc
)
1083 this->InitNested(window_number
);
1084 this->LowerWidget(_settings_newgame
.game_creation
.landscape
+ WID_CS_TEMPERATE
);
1087 void SetStringParameters(WidgetID widget
) const override
1090 case WID_CS_START_DATE_TEXT
:
1091 SetDParam(0, TimerGameCalendar::ConvertYMDToDate(_settings_newgame
.game_creation
.starting_year
, 0, 1));
1094 case WID_CS_MAPSIZE_X_PULLDOWN
:
1095 SetDParam(0, 1LL << _settings_newgame
.game_creation
.map_x
);
1098 case WID_CS_MAPSIZE_Y_PULLDOWN
:
1099 SetDParam(0, 1LL << _settings_newgame
.game_creation
.map_y
);
1102 case WID_CS_FLAT_LAND_HEIGHT_TEXT
:
1103 SetDParam(0, _settings_newgame
.game_creation
.se_flat_world_height
);
1108 void OnPaint() override
1110 this->SetWidgetDisabledState(WID_CS_START_DATE_DOWN
, _settings_newgame
.game_creation
.starting_year
<= CalendarTime::MIN_YEAR
);
1111 this->SetWidgetDisabledState(WID_CS_START_DATE_UP
, _settings_newgame
.game_creation
.starting_year
>= CalendarTime::MAX_YEAR
);
1112 this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_DOWN
, _settings_newgame
.game_creation
.se_flat_world_height
<= 0);
1113 this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_UP
, _settings_newgame
.game_creation
.se_flat_world_height
>= GetMapHeightLimit());
1115 this->SetWidgetLoweredState(WID_CS_TEMPERATE
, _settings_newgame
.game_creation
.landscape
== LT_TEMPERATE
);
1116 this->SetWidgetLoweredState(WID_CS_ARCTIC
, _settings_newgame
.game_creation
.landscape
== LT_ARCTIC
);
1117 this->SetWidgetLoweredState(WID_CS_TROPICAL
, _settings_newgame
.game_creation
.landscape
== LT_TROPIC
);
1118 this->SetWidgetLoweredState(WID_CS_TOYLAND
, _settings_newgame
.game_creation
.landscape
== LT_TOYLAND
);
1120 this->DrawWidgets();
1123 void UpdateWidgetSize(WidgetID widget
, Dimension
*size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
*fill
, [[maybe_unused
]] Dimension
*resize
) override
1125 StringID str
= STR_JUST_INT
;
1127 case WID_CS_TEMPERATE
: case WID_CS_ARCTIC
:
1128 case WID_CS_TROPICAL
: case WID_CS_TOYLAND
:
1129 size
->width
+= WidgetDimensions::scaled
.fullbevel
.Horizontal();
1130 size
->height
+= WidgetDimensions::scaled
.fullbevel
.Vertical();
1133 case WID_CS_START_DATE_TEXT
:
1134 SetDParam(0, TimerGameCalendar::ConvertYMDToDate(CalendarTime::MAX_YEAR
, 0, 1));
1135 str
= STR_JUST_DATE_LONG
;
1138 case WID_CS_MAPSIZE_X_PULLDOWN
:
1139 case WID_CS_MAPSIZE_Y_PULLDOWN
:
1140 SetDParamMaxValue(0, MAX_MAP_SIZE
);
1143 case WID_CS_FLAT_LAND_HEIGHT_TEXT
:
1144 SetDParamMaxValue(0, MAX_TILE_HEIGHT
);
1150 Dimension d
= GetStringBoundingBox(str
);
1151 d
.width
+= padding
.width
;
1152 d
.height
+= padding
.height
;
1153 *size
= maxdim(*size
, d
);
1156 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
1159 case WID_CS_TEMPERATE
:
1161 case WID_CS_TROPICAL
:
1162 case WID_CS_TOYLAND
:
1163 this->RaiseWidget(_settings_newgame
.game_creation
.landscape
+ WID_CS_TEMPERATE
);
1164 SetNewLandscapeType(widget
- WID_CS_TEMPERATE
);
1167 case WID_CS_MAPSIZE_X_PULLDOWN
: // Mapsize X
1168 ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame
.game_creation
.map_x
, WID_CS_MAPSIZE_X_PULLDOWN
);
1171 case WID_CS_MAPSIZE_Y_PULLDOWN
: // Mapsize Y
1172 ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame
.game_creation
.map_y
, WID_CS_MAPSIZE_Y_PULLDOWN
);
1175 case WID_CS_EMPTY_WORLD
: // Empty world / flat world
1176 StartGeneratingLandscape(GLWM_SCENARIO
);
1179 case WID_CS_RANDOM_WORLD
: // Generate
1180 ShowGenerateLandscape();
1183 case WID_CS_START_DATE_DOWN
:
1184 case WID_CS_START_DATE_UP
: // Year buttons
1185 /* Don't allow too fast scrolling */
1186 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
1187 this->HandleButtonClick(widget
);
1190 _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
);
1192 _left_button_clicked
= false;
1195 case WID_CS_START_DATE_TEXT
: // Year text
1196 this->widget_id
= WID_CS_START_DATE_TEXT
;
1197 SetDParam(0, _settings_newgame
.game_creation
.starting_year
);
1198 ShowQueryString(STR_JUST_INT
, STR_MAPGEN_START_DATE_QUERY_CAPT
, 8, this, CS_NUMERAL
, QSF_NONE
);
1201 case WID_CS_FLAT_LAND_HEIGHT_DOWN
:
1202 case WID_CS_FLAT_LAND_HEIGHT_UP
: // Height level buttons
1203 /* Don't allow too fast scrolling */
1204 if (!(this->flags
& WF_TIMEOUT
) || this->timeout_timer
<= 1) {
1205 this->HandleButtonClick(widget
);
1208 _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());
1210 _left_button_clicked
= false;
1213 case WID_CS_FLAT_LAND_HEIGHT_TEXT
: // Height level text
1214 this->widget_id
= WID_CS_FLAT_LAND_HEIGHT_TEXT
;
1215 SetDParam(0, _settings_newgame
.game_creation
.se_flat_world_height
);
1216 ShowQueryString(STR_JUST_INT
, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT
, 4, this, CS_NUMERAL
, QSF_NONE
);
1221 void OnTimeout() override
1223 this->RaiseWidgetsWhenLowered(WID_CS_START_DATE_DOWN
, WID_CS_START_DATE_UP
, WID_CS_FLAT_LAND_HEIGHT_DOWN
, WID_CS_FLAT_LAND_HEIGHT_UP
);
1226 void OnDropdownSelect(WidgetID widget
, int index
) override
1229 case WID_CS_MAPSIZE_X_PULLDOWN
: _settings_newgame
.game_creation
.map_x
= index
; break;
1230 case WID_CS_MAPSIZE_Y_PULLDOWN
: _settings_newgame
.game_creation
.map_y
= index
; break;
1235 void OnQueryTextFinished(char *str
) override
1237 if (!StrEmpty(str
)) {
1238 int32_t value
= atoi(str
);
1240 switch (this->widget_id
) {
1241 case WID_CS_START_DATE_TEXT
:
1242 this->SetWidgetDirty(WID_CS_START_DATE_TEXT
);
1243 _settings_newgame
.game_creation
.starting_year
= Clamp(TimerGameCalendar::Year(value
), CalendarTime::MIN_YEAR
, CalendarTime::MAX_YEAR
);
1246 case WID_CS_FLAT_LAND_HEIGHT_TEXT
:
1247 this->SetWidgetDirty(WID_CS_FLAT_LAND_HEIGHT_TEXT
);
1248 _settings_newgame
.game_creation
.se_flat_world_height
= Clamp(value
, 0, GetMapHeightLimit());
1257 static constexpr NWidgetPart _nested_create_scenario_widgets
[] = {
1258 NWidget(NWID_HORIZONTAL
),
1259 NWidget(WWT_CLOSEBOX
, COLOUR_BROWN
),
1260 NWidget(WWT_CAPTION
, COLOUR_BROWN
), SetDataTip(STR_SE_MAPGEN_CAPTION
, STR_NULL
),
1262 NWidget(WWT_PANEL
, COLOUR_BROWN
),
1263 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_wide
, 0), SetPadding(WidgetDimensions::unscaled
.sparse
),
1264 /* Landscape style selection. */
1265 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0), SetPIPRatio(1, 1, 1),
1266 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_CS_TEMPERATE
), SetDataTip(SPR_SELECT_TEMPERATE
, STR_INTRO_TOOLTIP_TEMPERATE
),
1267 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_CS_ARCTIC
), SetDataTip(SPR_SELECT_SUB_ARCTIC
, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE
),
1268 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_CS_TROPICAL
), SetDataTip(SPR_SELECT_SUB_TROPICAL
, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE
),
1269 NWidget(WWT_IMGBTN_2
, COLOUR_ORANGE
, WID_CS_TOYLAND
), SetDataTip(SPR_SELECT_TOYLAND
, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE
),
1272 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_wide
, 0),
1273 /* Green generation type buttons: 'Flat land' and 'Random land'. */
1274 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
1275 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREEN
, WID_CS_EMPTY_WORLD
), SetDataTip(STR_SE_MAPGEN_FLAT_WORLD
, STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP
), SetFill(1, 1),
1276 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREEN
, WID_CS_RANDOM_WORLD
), SetDataTip(STR_SE_MAPGEN_RANDOM_LAND
, STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND
), SetFill(1, 1),
1279 /* Labels + setting drop-downs */
1280 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
1282 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
1283 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_MAPSIZE
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(0, 1),
1284 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_DATE
, STR_MAPGEN_DATE_TOOLTIP
), SetFill(0, 1),
1285 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_SE_MAPGEN_FLAT_WORLD_HEIGHT
, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_TOOLTIP
), SetFill(0, 1),
1288 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
), SetPIP(0, WidgetDimensions::unscaled
.vsep_sparse
, 0),
1290 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
1291 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_CS_MAPSIZE_X_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
1292 NWidget(WWT_TEXT
, COLOUR_ORANGE
), SetDataTip(STR_MAPGEN_BY
, STR_NULL
), SetFill(0, 1), SetAlignment(SA_CENTER
),
1293 NWidget(WWT_DROPDOWN
, COLOUR_ORANGE
, WID_CS_MAPSIZE_Y_PULLDOWN
), SetDataTip(STR_JUST_INT
, STR_MAPGEN_MAPSIZE_TOOLTIP
), SetFill(1, 1),
1297 NWidget(NWID_HORIZONTAL
),
1298 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
),
1299 NWidget(WWT_PUSHTXTBTN
, COLOUR_ORANGE
, WID_CS_START_DATE_TEXT
), SetFill(1, 1), SetDataTip(STR_JUST_DATE_LONG
, STR_MAPGEN_DATE_TOOLTIP
),
1300 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
),
1303 /* Flat map height. */
1304 NWidget(NWID_HORIZONTAL
),
1305 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
),
1306 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
),
1307 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
),
1316 static WindowDesc
_create_scenario_desc(__FILE__
, __LINE__
,
1317 WDP_CENTER
, nullptr, 0, 0,
1318 WC_GENERATE_LANDSCAPE
, WC_NONE
,
1320 std::begin(_nested_create_scenario_widgets
), std::end(_nested_create_scenario_widgets
)
1323 /** Show the window to create a scenario. */
1324 void ShowCreateScenario()
1326 CloseWindowByClass(WC_GENERATE_LANDSCAPE
);
1327 new CreateScenarioWindow(&_create_scenario_desc
, GLWM_SCENARIO
);
1330 static constexpr NWidgetPart _nested_generate_progress_widgets
[] = {
1331 NWidget(WWT_CAPTION
, COLOUR_GREY
), SetDataTip(STR_GENERATION_WORLD
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1332 NWidget(WWT_PANEL
, COLOUR_GREY
),
1333 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_wide
, 0), SetPadding(WidgetDimensions::unscaled
.modalpopup
),
1334 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_GP_PROGRESS_BAR
), SetFill(1, 0),
1335 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_GP_PROGRESS_TEXT
), SetFill(1, 0),
1336 NWidget(WWT_TEXTBTN
, COLOUR_WHITE
, WID_GP_ABORT
), SetDataTip(STR_GENERATION_ABORT
, STR_NULL
), SetFill(1, 0),
1342 static WindowDesc
_generate_progress_desc(__FILE__
, __LINE__
,
1343 WDP_CENTER
, nullptr, 0, 0,
1344 WC_MODAL_PROGRESS
, WC_NONE
,
1346 std::begin(_nested_generate_progress_widgets
), std::end(_nested_generate_progress_widgets
)
1349 struct GenWorldStatus
{
1354 std::chrono::steady_clock::time_point next_update
;
1357 static GenWorldStatus _gws
;
1359 static const StringID _generation_class_table
[] = {
1360 STR_GENERATION_WORLD_GENERATION
,
1361 STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION
,
1362 STR_GENERATION_RIVER_GENERATION
,
1363 STR_GENERATION_CLEARING_TILES
,
1364 STR_SCENEDIT_TOOLBAR_TOWN_GENERATION
,
1365 STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION
,
1366 STR_GENERATION_OBJECT_GENERATION
,
1367 STR_GENERATION_TREE_GENERATION
,
1368 STR_GENERATION_SETTINGUP_GAME
,
1369 STR_GENERATION_PREPARING_TILELOOP
,
1370 STR_GENERATION_PREPARING_SCRIPT
,
1371 STR_GENERATION_PREPARING_GAME
1373 static_assert(lengthof(_generation_class_table
) == GWP_CLASS_COUNT
);
1376 static void AbortGeneratingWorldCallback(Window
*, bool confirmed
)
1379 AbortGeneratingWorld();
1380 } else if (HasModalProgress() && !IsGeneratingWorldAborted()) {
1381 SetMouseCursor(SPR_CURSOR_ZZZ
, PAL_NONE
);
1385 struct GenerateProgressWindow
: public Window
{
1387 GenerateProgressWindow() : Window(&_generate_progress_desc
)
1392 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
1396 SetMouseCursorBusy(false);
1398 STR_GENERATION_ABORT_CAPTION
,
1399 STR_GENERATION_ABORT_MESSAGE
,
1401 AbortGeneratingWorldCallback
1407 void UpdateWidgetSize(WidgetID widget
, Dimension
*size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
*fill
, [[maybe_unused
]] Dimension
*resize
) override
1410 case WID_GP_PROGRESS_BAR
: {
1411 SetDParamMaxValue(0, 100);
1412 *size
= GetStringBoundingBox(STR_GENERATION_PROGRESS
);
1413 /* We need some spacing for the 'border' */
1414 size
->height
+= WidgetDimensions::scaled
.frametext
.Horizontal();
1415 size
->width
+= WidgetDimensions::scaled
.frametext
.Vertical();
1419 case WID_GP_PROGRESS_TEXT
:
1420 for (uint i
= 0; i
< GWP_CLASS_COUNT
; i
++) {
1421 size
->width
= std::max(size
->width
, GetStringBoundingBox(_generation_class_table
[i
]).width
+ padding
.width
);
1423 size
->height
= GetCharacterHeight(FS_NORMAL
) * 2 + WidgetDimensions::scaled
.vsep_normal
;
1428 void DrawWidget(const Rect
&r
, WidgetID widget
) const override
1431 case WID_GP_PROGRESS_BAR
: {
1432 /* Draw the % complete with a bar and a text */
1433 DrawFrameRect(r
, COLOUR_GREY
, FR_BORDERONLY
| FR_LOWERED
);
1434 Rect br
= r
.Shrink(WidgetDimensions::scaled
.bevel
);
1435 DrawFrameRect(br
.WithWidth(br
.Width() * _gws
.percent
/ 100, false), COLOUR_MAUVE
, FR_NONE
);
1436 SetDParam(0, _gws
.percent
);
1437 DrawString(br
.left
, br
.right
, CenterBounds(br
.top
, br
.bottom
, GetCharacterHeight(FS_NORMAL
)), STR_GENERATION_PROGRESS
, TC_FROMSTRING
, SA_HOR_CENTER
);
1441 case WID_GP_PROGRESS_TEXT
:
1442 /* Tell which class we are generating */
1443 DrawString(r
.left
, r
.right
, r
.top
, _gws
.cls
, TC_FROMSTRING
, SA_HOR_CENTER
);
1445 /* And say where we are in that class */
1446 SetDParam(0, _gws
.current
);
1447 SetDParam(1, _gws
.total
);
1448 DrawString(r
.left
, r
.right
, r
.top
+ GetCharacterHeight(FS_NORMAL
) + WidgetDimensions::scaled
.vsep_normal
, STR_GENERATION_PROGRESS_NUM
, TC_FROMSTRING
, SA_HOR_CENTER
);
1454 * Initializes the progress counters to the starting point.
1456 void PrepareGenerateWorldProgress()
1458 _gws
.cls
= STR_GENERATION_WORLD_GENERATION
;
1462 _gws
.next_update
= std::chrono::steady_clock::now();
1466 * Show the window where a user can follow the process of the map generation.
1468 void ShowGenerateWorldProgress()
1470 if (BringWindowToFrontById(WC_MODAL_PROGRESS
, 0)) return;
1471 new GenerateProgressWindow();
1474 static void _SetGeneratingWorldProgress(GenWorldProgress cls
, uint progress
, uint total
)
1476 static const int percent_table
[] = {0, 5, 14, 17, 20, 40, 60, 65, 80, 85, 95, 99, 100 };
1477 static_assert(lengthof(percent_table
) == GWP_CLASS_COUNT
+ 1);
1478 assert(cls
< GWP_CLASS_COUNT
);
1480 /* Check if we really are generating the world.
1481 * For example, placing trees via the SE also calls this function, but
1482 * shouldn't try to update the progress.
1484 if (!HasModalProgress()) return;
1486 if (IsGeneratingWorldAborted()) {
1487 HandleGeneratingWorldAbortion();
1492 assert(_gws
.cls
== _generation_class_table
[cls
]);
1493 _gws
.current
+= progress
;
1494 assert(_gws
.current
<= _gws
.total
);
1496 _gws
.cls
= _generation_class_table
[cls
];
1497 _gws
.current
= progress
;
1499 _gws
.percent
= percent_table
[cls
];
1502 /* Percentage is about the number of completed tasks, so 'current - 1' */
1503 _gws
.percent
= percent_table
[cls
] + (percent_table
[cls
+ 1] - percent_table
[cls
]) * (_gws
.current
== 0 ? 0 : _gws
.current
- 1) / _gws
.total
;
1505 if (_network_dedicated
) {
1506 static uint last_percent
= 0;
1508 /* Never display 0% */
1509 if (_gws
.percent
== 0) return;
1510 /* Reset if percent is lower than the last recorded */
1511 if (_gws
.percent
< last_percent
) last_percent
= 0;
1512 /* Display every 5%, but 6% is also very valid.. just not smaller steps than 5% */
1513 if (_gws
.percent
% 5 != 0 && _gws
.percent
<= last_percent
+ 5) return;
1514 /* Never show steps smaller than 2%, even if it is a mod 5% */
1515 if (_gws
.percent
<= last_percent
+ 2) return;
1517 Debug(net
, 3, "Map generation percentage complete: {}", _gws
.percent
);
1518 last_percent
= _gws
.percent
;
1523 SetWindowDirty(WC_MODAL_PROGRESS
, 0);
1525 VideoDriver::GetInstance()->GameLoopPause();
1529 * Set the total of a stage of the world generation.
1530 * @param cls the current class we are in.
1531 * @param total Set the total expected items for this class.
1533 * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always.
1534 * Also, progress works if total is zero, total works if progress is zero.
1536 void SetGeneratingWorldProgress(GenWorldProgress cls
, uint total
)
1538 if (total
== 0) return;
1540 _SetGeneratingWorldProgress(cls
, 0, total
);
1544 * Increases the current stage of the world generation with one.
1545 * @param cls the current class we are in.
1547 * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always.
1548 * Also, progress works if total is zero, total works if progress is zero.
1550 void IncreaseGeneratingWorldProgress(GenWorldProgress cls
)
1552 /* In fact the param 'class' isn't needed.. but for some security reasons, we want it around */
1553 _SetGeneratingWorldProgress(cls
, 1, 0);