diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index d3d57e6313..1954b938a0 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -172,6 +172,7 @@ struct BuildDocksToolbarWindow : Window { BuildDocksToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window() { this->InitNested(desc, window_number); + this->OnInvalidateData(); if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); } @@ -180,9 +181,17 @@ struct BuildDocksToolbarWindow : Window { if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } + void OnInvalidateData(int data = 0) + { + this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_SHIP), + DTW_DEPOT, + DTW_STATION, + DTW_BUOY, + WIDGET_LIST_END); + } + virtual void OnPaint() { - this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_SHIP), DTW_DEPOT, DTW_STATION, DTW_BUOY, WIDGET_LIST_END); this->DrawWidgets(); } diff --git a/src/engine.cpp b/src/engine.cpp index ec09133113..b95cafe6dd 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -581,6 +581,10 @@ static void AcceptEnginePreview(EngineID eid, CompanyID company) if (company == _local_company) { AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); } + + /* Update the toolbar. */ + if (e->type == VEH_ROAD) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_ROAD); + if (e->type == VEH_SHIP) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_WATER); } static CompanyID GetBestCompany(uint8 pp) @@ -713,6 +717,10 @@ static void NewVehicleAvailable(Engine *e) SetDParam(0, GetEngineCategoryName(index)); SetDParam(1, index); AddNewsItem(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NS_NEW_VEHICLES, NR_ENGINE, index); + + /* Update the toolbar. */ + if (e->type == VEH_ROAD) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_ROAD); + if (e->type == VEH_SHIP) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_WATER); } void EnginesMonthlyLoop() diff --git a/src/genworld.cpp b/src/genworld.cpp index 6303cca710..b15d031c5a 100644 --- a/src/genworld.cpp +++ b/src/genworld.cpp @@ -88,7 +88,6 @@ static void CleanupGeneration() DeleteWindowById(WC_GENERATE_PROGRESS_WINDOW, 0); MarkWholeScreenDirty(); - _genworld_mapgen_mutex->EndCritical(); } /** @@ -172,6 +171,7 @@ static void _GenerateWorld(void *) IncreaseGeneratingWorldProgress(GWP_GAME_START); CleanupGeneration(); + _genworld_mapgen_mutex->EndCritical(); ShowNewGRFError(); diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 3c75ccc877..4bec0e0a32 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -413,11 +413,7 @@ struct BuildRoadToolbarWindow : Window { RTW_ONE_WAY, WIDGET_LIST_END); - this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD), - RTW_DEPOT, - RTW_BUS_STATION, - RTW_TRUCK_STATION, - WIDGET_LIST_END); + this->OnInvalidateData(); if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); } @@ -427,6 +423,15 @@ struct BuildRoadToolbarWindow : Window { if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } + void OnInvalidateData(int data = 0) + { + this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD), + RTW_DEPOT, + RTW_BUS_STATION, + RTW_TRUCK_STATION, + WIDGET_LIST_END); + } + /** * Update the remove button lowered state of the road toolbar * diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index fb4a578ffb..5fd66a7885 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -81,7 +81,7 @@ void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_wate SetWaterClass(t, WATER_CLASS_INVALID); return; } else { - NOT_REACHED(); + SlErrorCorrupt("Invalid water class for dry tile"); } } @@ -110,7 +110,7 @@ void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_wate case WATER_CLASS_SEA: has_water = true; break; case WATER_CLASS_CANAL: has_canal = true; break; case WATER_CLASS_RIVER: has_river = true; break; - default: NOT_REACHED(); + default: SlErrorCorrupt("Invalid water class for tile"); } } break; @@ -338,33 +338,43 @@ static void CDECL HandleSavegameLoadCrash(int signum) char buffer[8192]; char *p = buffer; - p += seprintf(p, lastof(buffer), - "Loading your savegame caused OpenTTD to crash.\n" - "This is most likely caused by a missing NewGRF or a NewGRF that has been\n" - "loaded as replacement for a missing NewGRF. OpenTTD cannot easily\n" - "determine whether a replacement NewGRF is of a newer or older version.\n" - "It will load a NewGRF with the same GRF ID as the missing NewGRF. This\n" - "means that if the author makes incompatible NewGRFs with the same GRF ID\n" - "OpenTTD cannot magically do the right thing. In most cases OpenTTD will\n" - "load the savegame and not crash, but this is an exception.\n" - "Please load the savegame with the appropriate NewGRFs. When loading a\n" - "savegame still crashes when all NewGRFs are found you should file a\n" - "bug report. The missing NewGRFs are:\n"); + p += seprintf(p, lastof(buffer), "Loading your savegame caused OpenTTD to crash.\n"); - for (const GRFConfig *c = _grfconfig; c != NULL; c = c->next) { - if (HasBit(c->flags, GCF_COMPATIBLE)) { - const GRFIdentifier *replaced = GetOverriddenIdentifier(c); - char buf[40]; - md5sumToString(buf, lastof(buf), replaced->md5sum); - p += seprintf(p, lastof(buffer), "NewGRF %08X (checksum %s) not found.\n Loaded NewGRF \"%s\" with same GRF ID instead.\n", BSWAP32(c->grfid), buf, c->filename); - _saveload_crash_with_missing_newgrfs = true; - } - if (c->status == GCS_NOT_FOUND) { - char buf[40]; - md5sumToString(buf, lastof(buf), c->md5sum); - p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s.\n", BSWAP32(c->grfid), c->filename, buf); - _saveload_crash_with_missing_newgrfs = true; + for (const GRFConfig *c = _grfconfig; !_saveload_crash_with_missing_newgrfs && c != NULL; c = c->next) { + _saveload_crash_with_missing_newgrfs = HasBit(c->flags, GCF_COMPATIBLE) || c->status == GCS_NOT_FOUND; + } + + if (_saveload_crash_with_missing_newgrfs) { + p += seprintf(p, lastof(buffer), + "This is most likely caused by a missing NewGRF or a NewGRF that\n" + "has been loaded as replacement for a missing NewGRF. OpenTTD\n" + "cannot easily determine whether a replacement NewGRF is of a newer\n" + "or older version.\n" + "It will load a NewGRF with the same GRF ID as the missing NewGRF.\n" + "This means that if the author makes incompatible NewGRFs with the\n" + "same GRF ID OpenTTD cannot magically do the right thing. In most\n" + "cases OpenTTD will load the savegame and not crash, but this is an\n" + "exception.\n" + "Please load the savegame with the appropriate NewGRFs installed.\n" + "The missing/compatible NewGRFs are:\n"); + + for (const GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + if (HasBit(c->flags, GCF_COMPATIBLE)) { + const GRFIdentifier *replaced = GetOverriddenIdentifier(c); + char buf[40]; + md5sumToString(buf, lastof(buf), replaced->md5sum); + p += seprintf(p, lastof(buffer), "NewGRF %08X (checksum %s) not found.\n Loaded NewGRF \"%s\" with same GRF ID instead.\n", BSWAP32(c->grfid), buf, c->filename); + } + if (c->status == GCS_NOT_FOUND) { + char buf[40]; + md5sumToString(buf, lastof(buf), c->md5sum); + p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s.\n", BSWAP32(c->grfid), c->filename, buf); + } } + } else { + p += seprintf(p, lastof(buffer), + "This is probably caused by a corruption in the savegame.\n" + "Please file a bug report and attach this savegame.\n"); } ShowInfo(buffer); @@ -840,7 +850,7 @@ bool AfterLoadGame() case MP_ROAD: SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2)); switch (GetRoadTileType(t)) { - default: NOT_REACHED(); + default: SlErrorCorrupt("Invalid road tile type"); case ROAD_TILE_NORMAL: SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4)); SB(_m[t].m4, 4, 4, 0); @@ -881,7 +891,7 @@ bool AfterLoadGame() if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_me[t].m7, 5, 3)); SB(_me[t].m7, 5, 1, GB(_m[t].m3, 7, 1)); // snow/desert switch (GetRoadTileType(t)) { - default: NOT_REACHED(); + default: SlErrorCorrupt("Invalid road tile type"); case ROAD_TILE_NORMAL: SB(_me[t].m7, 0, 4, GB(_m[t].m3, 0, 4)); // road works SB(_m[t].m6, 3, 3, GB(_m[t].m3, 4, 3)); // ground @@ -1000,7 +1010,7 @@ bool AfterLoadGame() if (dir != DirToDiagDir(v->direction)) continue; switch (dir) { - default: NOT_REACHED(); + default: SlErrorCorrupt("Invalid vehicle direction"); case DIAGDIR_NE: if ((v->x_pos & 0xF) != 0) continue; break; case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break; case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break; diff --git a/src/saveload/ai_sl.cpp b/src/saveload/ai_sl.cpp index 6a8fb2b1a3..5d6827d379 100644 --- a/src/saveload/ai_sl.cpp +++ b/src/saveload/ai_sl.cpp @@ -178,7 +178,7 @@ static bool LoadObjects() case SQSL_ARRAY_TABLE_END: return false; - default: NOT_REACHED(); + default: SlErrorCorrupt("Invalid AI data type"); } } diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 777fa25899..4266707f35 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -1098,7 +1098,7 @@ static bool LoadOldVehicleUnion(LoadgameState *ls, int num) res = LoadChunk(ls, NULL, vehicle_empty_chunk); } else { switch (v->type) { - default: NOT_REACHED(); + default: SlErrorCorrupt("Invalid vehicle type"); case VEH_TRAIN : res = LoadChunk(ls, v, vehicle_train_chunk); break; case VEH_ROAD : res = LoadChunk(ls, v, vehicle_road_chunk); break; case VEH_SHIP : res = LoadChunk(ls, v, vehicle_ship_chunk); break; @@ -1298,7 +1298,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num) } else { /* Read the vehicle type and allocate the right vehicle */ switch (ReadByte(ls)) { - default: NOT_REACHED(); + default: SlErrorCorrupt("Invalid vehicle type"); case 0x00 /* VEH_INVALID */: v = NULL; break; case 0x10 /* VEH_TRAIN */: v = new (_current_vehicle_id) Train(); break; case 0x11 /* VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break; diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 0b35f8492b..8b87233897 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -203,6 +203,18 @@ static void NORETURN SlError(StringID string, const char *extra_msg = NULL) throw std::exception(); } +/** + * Error handler for corrupt savegames. Sets everything up to show the + * error message and to clean up the mess of a partial savegame load. + * @param msg Location the corruption has been spotted. + * @note This function does never return as it throws an exception to + * break out of all the saveload code. + */ +void NORETURN SlErrorCorrupt(const char *msg) +{ + SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg); +} + typedef void (*AsyncSaveFinishProc)(); static AsyncSaveFinishProc _async_save_finish = NULL; static ThreadObject *_save_thread; @@ -242,7 +254,7 @@ void ProcessAsyncSaveFinish() static void SlReadFill() { size_t len = _sl.read_bytes(); - if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk"); + if (len == 0) SlErrorCorrupt("Unexpected end of chunk"); _sl.bufp = _sl.buf; _sl.bufe = _sl.buf + len; @@ -390,7 +402,7 @@ static uint SlReadSimpleGamma() if (HasBit(i, 5)) { i &= ~0x20; if (HasBit(i, 4)) - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unsupported gamma"); + SlErrorCorrupt("Unsupported gamma"); i = (i << 8) | SlReadByte(); } i = (i << 8) | SlReadByte(); @@ -462,7 +474,7 @@ int SlIterateArray() /* After reading in the whole array inside the loop * we must have read in all the data, so we must be at end of current block. */ - if (_next_offs != 0 && SlGetOffs() != _next_offs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size"); + if (_next_offs != 0 && SlGetOffs() != _next_offs) SlErrorCorrupt("Invalid chunk size"); while (true) { uint length = SlReadArrayLength(); @@ -1098,7 +1110,7 @@ void SlAutolength(AutolengthProc *proc, void *arg) /* And write the stuff */ proc(arg); - if (offs != SlGetOffs()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size"); + if (offs != SlGetOffs()) SlErrorCorrupt("Invalid chunk size"); } /** @@ -1130,9 +1142,9 @@ static void SlLoadChunk(const ChunkHandler *ch) _sl.obj_len = len; endoffs = SlGetOffs() + len; ch->load_proc(); - if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size"); + if (SlGetOffs() != endoffs) SlErrorCorrupt("Invalid chunk size"); } else { - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type"); + SlErrorCorrupt("Invalid chunk type"); } break; } @@ -1216,7 +1228,7 @@ static void SlLoadChunks() DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id); ch = SlFindChunkHandler(id); - if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type"); + if (ch == NULL) SlErrorCorrupt("Unknown chunk type"); SlLoadChunk(ch); } } @@ -1269,13 +1281,13 @@ static size_t ReadLZO() size = TO_BE32(size); } - if (size >= sizeof(out)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Inconsistent size"); + if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size"); /* Read block */ if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE); /* Verify checksum */ - if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Bad checksum"); + if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum"); /* Decompress */ lzo1x_decompress(out + sizeof(uint32) * 1, size, _sl.buf, &len, NULL); @@ -1564,38 +1576,38 @@ static void *IntToReference(size_t index, SLRefType rt) switch (rt) { case REF_ORDERLIST: if (OrderList::IsValidID(index)) return OrderList::Get(index); - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid OrderList"); + SlErrorCorrupt("Referencing invalid OrderList"); case REF_ORDER: if (Order::IsValidID(index)) return Order::Get(index); /* in old versions, invalid order was used to mark end of order list */ if (CheckSavegameVersionOldStyle(5, 2)) return NULL; - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Order"); + SlErrorCorrupt("Referencing invalid Order"); case REF_VEHICLE_OLD: case REF_VEHICLE: if (Vehicle::IsValidID(index)) return Vehicle::Get(index); - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Vehicle"); + SlErrorCorrupt("Referencing invalid Vehicle"); case REF_STATION: if (Station::IsValidID(index)) return Station::Get(index); - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Station"); + SlErrorCorrupt("Referencing invalid Station"); case REF_TOWN: if (Town::IsValidID(index)) return Town::Get(index); - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid Town"); + SlErrorCorrupt("Referencing invalid Town"); case REF_ROADSTOPS: if (RoadStop::IsValidID(index)) return RoadStop::Get(index); - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid RoadStop"); + SlErrorCorrupt("Referencing invalid RoadStop"); case REF_ENGINE_RENEWS: if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index); - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid EngineRenew"); + SlErrorCorrupt("Referencing invalid EngineRenew"); case REF_CARGO_PACKET: if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index); - SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Referencing invalid CargoPacket"); + SlErrorCorrupt("Referencing invalid CargoPacket"); default: NOT_REACHED(); } @@ -1766,7 +1778,7 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded) { uint i; - if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk"); + if (_ts.count != _sl.offs_base) SlErrorCorrupt("Unexpected size of chunk"); for (i = 0; i != _memory_savegame.Length() - 1; i++) { _sl.buf = _memory_savegame[i]; fmt->writer(MEMORY_CHUNK_SIZE); @@ -1779,7 +1791,7 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded) } fmt->uninit_write(); - if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk"); + if (_ts.count != _sl.offs_base) SlErrorCorrupt("Unexpected size of chunk"); UnInitMem(); fclose(_sl.fh); diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 0914a50ea8..5b752d4ac4 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -333,6 +333,7 @@ void SlGlobList(const SaveLoadGlobVarList *sldg); void SlArray(void *array, size_t length, VarType conv); void SlObject(void *object, const SaveLoad *sld); bool SlObjectMember(void *object, const SaveLoad *sld); +void NORETURN SlErrorCorrupt(const char *msg); bool SaveloadCrashWithMissingNewGRFs(); diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 70ce2e1f35..48f7fa9051 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -151,7 +151,7 @@ void ConvertOldMultiheadToNew() u->SetWagon(); u->SetFreeWagon(); break; - default: NOT_REACHED(); + default: SlErrorCorrupt("Invalid train subtype"); } } } @@ -716,7 +716,7 @@ void Load_VEHS() case VEH_EFFECT: v = new (index) EffectVehicle(); break; case VEH_DISASTER: v = new (index) DisasterVehicle(); break; case VEH_INVALID: // Savegame shouldn't contain invalid vehicles - default: NOT_REACHED(); + default: SlErrorCorrupt("Invalid vehicle type"); } SlObject(v, GetVehicleDescription(vtype)); diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 77784e0480..e4589a7d02 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1424,19 +1424,29 @@ static const NWidgetPart _nested_smallmap_bar[] = { NWidget(NWID_VERTICAL), /* Top button row. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), - NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), - NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR), SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), - NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES), SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), - NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES), SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), + NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_IN), + SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP), + SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR), + SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES), + SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES), + SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1), EndContainer(), /* Bottom button row. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), - NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME), SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), - NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES), SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), - NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION), SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), - NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), + NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_OUT), + SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME), + SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES), + SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION), + SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1), + NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS), + SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1), EndContainer(), NWidget(NWID_SPACER), SetResize(0, 1), EndContainer(),