Index: src/settings.cpp =================================================================== --- src/settings.cpp (revision 11959) +++ src/settings.cpp (working copy) @@ -56,6 +56,7 @@ #include "sound/sound_driver.hpp" #include "music/music_driver.hpp" #include "blitter/factory.hpp" +#include "map_type.h" #include "table/strings.h" @@ -1366,8 +1367,8 @@ SDT_VAR(Patches, window_snap_radius, SLE_UINT8, S,D0, 10, 1, 32, 0, STR_CONFIG_PATCHES_SNAP_RADIUS, NULL), SDT_BOOL(Patches, invisible_trees, S, 0, false, STR_CONFIG_PATCHES_INVISIBLE_TREES, RedrawScreen), SDT_BOOL(Patches, population_in_label, S, 0, true, STR_CONFIG_PATCHES_POPULATION_IN_LABEL, PopulationInLabelActive), - SDT_VAR(Patches, map_x, SLE_UINT8, S, 0, 8, 6, 11, 0, STR_CONFIG_PATCHES_MAP_X, NULL), - SDT_VAR(Patches, map_y, SLE_UINT8, S, 0, 8, 6, 11, 0, STR_CONFIG_PATCHES_MAP_Y, NULL), + SDT_VAR(Patches, map_x, SLE_UINT8, S, 0, 8, MIN_MAP_SIZE_BITS, MAX_MAP_SIZE_BITS, 0, STR_CONFIG_PATCHES_MAP_X, NULL), + SDT_VAR(Patches, map_y, SLE_UINT8, S, 0, 8, MIN_MAP_SIZE_BITS, MAX_MAP_SIZE_BITS, 0, STR_CONFIG_PATCHES_MAP_Y, NULL), SDT_BOOL(Patches, link_terraform_toolbar, S, 0, false, STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR,NULL), SDT_VAR(Patches, liveries, SLE_UINT8, S,MS, 2, 0, 2, 0, STR_CONFIG_PATCHES_LIVERIES, RedrawScreen), SDT_BOOL(Patches, prefer_teamchat, S, 0, false, STR_CONFIG_PATCHES_PREFER_TEAMCHAT, NULL), Index: src/lang/english.txt =================================================================== --- src/lang/english.txt (revision 11959) +++ src/lang/english.txt (working copy) @@ -3246,6 +3246,9 @@ STR_NUM_1 :{BLACK}{SKIP}{NUM} STR_NUM_2 :{BLACK}{SKIP}{SKIP}{NUM} STR_NUM_3 :{BLACK}{SKIP}{SKIP}{SKIP}{NUM} +STR_RED_NUM_1 :{RED}{SKIP}{NUM} +STR_RED_NUM_2 :{RED}{SKIP}{SKIP}{NUM} +STR_RED_NUM_3 :{RED}{SKIP}{SKIP}{SKIP}{NUM} ########### String for New Landscape Generator @@ -3274,6 +3277,7 @@ STR_HEIGHTMAP_SCALE_WARNING_MESSAGE :{YELLOW}Resizing source map too much is not recommended. Continue with the generation? STR_TOWN_LAYOUT_WARNING_CAPTION :{WHITE}Town layout warning STR_TOWN_LAYOUT_WARNING_MESSAGE :{YELLOW}The town layout "no more roads" is not recommended. Continue with the generation? +STR_MAP_TOO_MANY_TILES_MESSAGE :{YELLOW}Too many tiles in map. Maximum number of tiles is {NUM}, you have selected {NUM} STR_HEIGHTMAP_NAME :{BLACK}Heightmap name: STR_HEIGHTMAP_SIZE :{BLACK}Size: {ORANGE}{NUM} x {NUM} STR_GENERATION_WORLD :{WHITE}Generating world... Index: src/genworld_gui.cpp =================================================================== --- src/genworld_gui.cpp (revision 11959) +++ src/genworld_gui.cpp (working copy) @@ -24,6 +24,7 @@ #include "fios.h" #include "string_func.h" #include "gfx_func.h" +#include "map_type.h" #include "settings_type.h" #include "widgets/dropdown_type.h" #include "widgets/dropdown_func.h" @@ -228,11 +229,33 @@ if (confirmed) StartGeneratingLandscape((glwp_modes)w->window_number); } +/** + Check if map size set lies in allowed boundaries. + @param printWarning If set to true, messagebox with warning is printed out if size is outside limits. + @return true if size is ok, false otherwise. +*/ +static bool CheckMapSize(bool printWarning = true) +{ + uint64 map_x = 1U << _patches_newgame.map_x; + uint64 map_y = 1U << _patches_newgame.map_y; + uint64 tiles = map_x * map_y; + + if (_patches_newgame.map_x + _patches_newgame.map_y > MAX_MAP_TILES_BITS) { + if (printWarning) { + SetDParam(0, MAX_MAP_TILES); + SetDParam(1, tiles); + ShowErrorMessage(INVALID_STRING_ID, STR_MAP_TOO_MANY_TILES_MESSAGE, 0, 0); + } + return false; + } + return true; +} + static DropDownList *BuildMapsizeDropDown() { DropDownList *list = new DropDownList(); - for (uint i = 6; i <= 11; i++) { + for (uint i = MIN_MAP_SIZE_BITS; i <= MAX_MAP_SIZE_BITS; i++) { DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false); item->SetParam(0, 1 << i); list->push_back(item); @@ -256,6 +279,7 @@ static querystr_d _genseed_query; static char _genseed_buffer[11]; + bool mapsize_valid = CheckMapSize(false); glwp_modes mode = (glwp_modes)w->window_number; switch (e->event) { @@ -315,6 +339,9 @@ SetDParam(2, 1 << _patches_newgame.map_y); // GLAND_MAPSIZE_Y_PULLDOWN SetDParam(3, _patches_newgame.snow_line_height); // GLAND_SNOW_LEVEL_TEXT + w->widget[GLAND_MAPSIZE_X_PULLDOWN].data = mapsize_valid ? STR_NUM_1 : STR_RED_NUM_1; + w->widget[GLAND_MAPSIZE_Y_PULLDOWN].data = mapsize_valid ? STR_NUM_2 : STR_RED_NUM_2; + DrawWindowWidgets(w); DrawEditBox(w, &_genseed_query, GLAND_RANDOM_EDITBOX); @@ -375,6 +402,8 @@ case GLAND_GENERATE_BUTTON: // Generate + if (!CheckMapSize()) break; + UpdatePatches(); if (_patches.town_layout == TL_NO_ROADS) { @@ -635,6 +664,8 @@ static void CreateScenarioWndProc(Window *w, WindowEvent *e) { + bool mapsize_valid = CheckMapSize(false); + switch (e->event) { case WE_CREATE: w->LowerWidget(_opt_newgame.landscape + CSCEN_TEMPERATE); @@ -657,6 +688,9 @@ SetDParam(2, 1 << _patches_newgame.map_y); // CSCEN_MAPSIZE_Y_PULLDOWN SetDParam(3, _patches_newgame.se_flat_world_height); // CSCEN_FLAT_LAND_HEIGHT_TEXT + w->widget[CSCEN_MAPSIZE_X_PULLDOWN].data = mapsize_valid ? STR_NUM_1 : STR_RED_NUM_1; + w->widget[CSCEN_MAPSIZE_Y_PULLDOWN].data = mapsize_valid ? STR_NUM_2 : STR_RED_NUM_2; + DrawWindowWidgets(w); break; @@ -680,10 +714,12 @@ break; case CSCEN_EMPTY_WORLD: // Empty world / flat world + if (!CheckMapSize()) break; StartGeneratingLandscape(GLWP_SCENARIO); break; case CSCEN_RANDOM_WORLD: // Generate + if (!CheckMapSize()) break; ShowGenerateLandscape(); break; Index: src/saveload.cpp =================================================================== --- src/saveload.cpp (revision 11959) +++ src/saveload.cpp (working copy) @@ -1117,8 +1117,11 @@ CursorID cursor; }; -/* A maximum size of of 128K * 500 = 64.000KB savegames */ -STATIC_OLD_POOL(Savegame, byte, 17, 500, NULL, NULL) +/* + * A maximum size of of 128K * 500 * N = 64000 KiB savegames + * N = 1 for 2048*2048 or appropriately more for larger sizes + */ +STATIC_OLD_POOL(Savegame, byte, 17, 500 * (MAX_MAP_TILES / 2048) / 2048, NULL, NULL) static ThreadedSave _ts; static bool InitMem() Index: src/map_type.h =================================================================== --- src/map_type.h (revision 11959) +++ src/map_type.h (working copy) @@ -5,6 +5,19 @@ #ifndef MAP_TYPE_H #define MAP_TYPE_H +/** Minimal size of map is equal to 2 ^ MIN_MAP_SIZE_BITS */ +#define MIN_MAP_SIZE_BITS 6 +/** Maximal size of map is equal to 2 ^ MAX_MAP_SIZE_BITS */ +#define MAX_MAP_SIZE_BITS 13 +/** Maximal number of tiles in a map is equal to 2 ^ MAX_MAP_TILES_BITS. */ +#define MAX_MAP_TILES_BITS 22 +/** Minimal map size. */ +#define MIN_MAP_SIZE (1 << MIN_MAP_SIZE_BITS) // = 64 +/** Maximal map size. */ +#define MAX_MAP_SIZE (1 << MAX_MAP_SIZE_BITS) // = 8192 +/** Maximal number of tiles in a map. */ +#define MAX_MAP_TILES (1 << MAX_MAP_TILES_BITS) // = 2048 * 2048 + /** * Data that is stored per tile. Also used TileExtended for this. * Look at docs/landscape.html for the exact meaning of the members. Index: src/map.cpp =================================================================== --- src/map.cpp (revision 11959) +++ src/map.cpp (working copy) @@ -32,16 +32,18 @@ */ void AllocateMap(uint size_x, uint size_y) { + DEBUG(map, 2, "Min/max map size %d/%d, max map tiles %d", MIN_MAP_SIZE, MAX_MAP_SIZE, MAX_MAP_TILES); + DEBUG(map, 1, "Allocating map of size %dx%d", size_x, size_y); + /* Make sure that the map size is within the limits and that * the x axis size is a power of 2. */ - if (size_x < 64 || size_x > 2048 || - size_y < 64 || size_y > 2048 || + if (size_x < MIN_MAP_SIZE || + size_x * size_y > MAX_MAP_TILES || + size_y < MIN_MAP_SIZE || (size_x & (size_x - 1)) != 0 || (size_y & (size_y - 1)) != 0) error("Invalid map size"); - DEBUG(map, 1, "Allocating map of size %dx%d", size_x, size_y); - _map_log_x = FindFirstBit(size_x); _map_size_x = size_x; _map_size_y = size_y; Index: src/openttd.cpp =================================================================== --- src/openttd.cpp (revision 11959) +++ src/openttd.cpp (working copy) @@ -741,7 +741,20 @@ ResetGRFConfig(true); GenerateWorldSetCallback(&MakeNewEditorWorldDone); - GenerateWorld(GW_EMPTY, 1 << _patches.map_x, 1 << _patches.map_y); + + /* + * Too large size may be stored in config. + * Check the size and fall back to minimal size if the size is invalid + */ + uint64 map_x = 1U << _patches.map_x; + uint64 map_y = 1U << _patches.map_y; + + if (_patches.map_x + _patches.map_y > MAX_MAP_TILES_BITS) { + map_x = MIN_MAP_SIZE; + map_y = MIN_MAP_SIZE; + } + + GenerateWorld(GW_EMPTY, map_x, map_y); } void StartupPlayers();