Index: src/settings.cpp =================================================================== --- src/settings.cpp (revision 11910) +++ 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" @@ -1364,8 +1365,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 11910) +++ src/lang/english.txt (working copy) @@ -3267,6 +3267,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_SNOW_LINE_HEIGHT_NUM :{NUM} STR_HEIGHTMAP_NAME :{BLACK}Heightmap name: STR_HEIGHTMAP_SIZE :{BLACK}Size: {ORANGE}{NUM} x {NUM} Index: src/genworld_gui.cpp =================================================================== --- src/genworld_gui.cpp (revision 11910) +++ 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]; + uint16 mapsize_color = CheckMapSize(false) ? TC_BLACK : TC_RED; glwp_modes mode = (glwp_modes)w->window_number; uint y; @@ -315,10 +339,10 @@ y = (mode == GLWP_HEIGHTMAP) ? 22 : 0; SetDParam(0, 1 << _patches_newgame.map_x); - DrawString(119, 91 + y, STR_JUST_INT, TC_BLACK); + DrawString(119, 91 + y, STR_JUST_INT, mapsize_color); SetDParam(0, 1 << _patches_newgame.map_y); - DrawString(182, 91 + y, STR_JUST_INT, TC_BLACK); + DrawString(182, 91 + y, STR_JUST_INT, mapsize_color); DrawEditBox(w, &_genseed_query, GLAND_RANDOM_EDITBOX); @@ -376,6 +400,7 @@ UpdatePatches(); + if (!CheckMapSize()) break; if (_patches.town_layout == TL_NO_ROADS) { ShowQuery( STR_TOWN_LAYOUT_WARNING_CAPTION, @@ -618,6 +643,8 @@ static void CreateScenarioWndProc(Window *w, WindowEvent *e) { + uint16 mapsize_color = CheckMapSize(false) ? TC_BLACK : TC_RED; + switch (e->event) { case WE_CREATE: w->LowerWidget(_opt_newgame.landscape + CSCEN_TEMPERATE); break; @@ -634,11 +661,12 @@ DrawWindowWidgets(w); DrawStringRightAligned(211, 97, STR_MAPSIZE, TC_FROMSTRING); + SetDParam(0, 1 << _patches_newgame.map_x); - DrawString( 221, 97, STR_JUST_INT, TC_BLACK); + DrawString( 221, 97, STR_JUST_INT, mapsize_color); DrawStringCentered( 272, 97, STR_BY, TC_FROMSTRING); SetDParam(0, 1 << _patches_newgame.map_y); - DrawString( 284, 97, STR_JUST_INT, TC_BLACK); + DrawString( 284, 97, STR_JUST_INT, mapsize_color); DrawStringRightAligned(211, 115, STR_DATE, TC_FROMSTRING); SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1)); @@ -662,9 +690,11 @@ ShowDropDownList(w, BuildMapsizeDropDown(), _patches_newgame.map_y, CSCEN_MAPSIZE_Y_PULLDOWN); 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; case CSCEN_START_DATE_DOWN: case CSCEN_START_DATE_UP: // Year buttons Index: src/saveload.cpp =================================================================== --- src/saveload.cpp (revision 11910) +++ 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 11910) +++ 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 11910) +++ 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 11910) +++ 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();