diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index aad7bae547..2e608af550 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -94,16 +94,19 @@ static void BuildDocksClick_Demolish(Window *w) static void BuildDocksClick_Depot(Window *w) { + if (!CanBuildVehicleInfrastructure(VEH_SHIP)) return; if (HandlePlacePushButton(w, DTW_DEPOT, SPR_CURSOR_SHIP_DEPOT, 1, PlaceDocks_Depot)) ShowBuildDocksDepotPicker(); } static void BuildDocksClick_Dock(Window *w) { + if (!CanBuildVehicleInfrastructure(VEH_SHIP)) return; if (HandlePlacePushButton(w, DTW_STATION, SPR_CURSOR_DOCK, 3, PlaceDocks_Dock)) ShowBuildDockStationPicker(); } static void BuildDocksClick_Buoy(Window *w) { + if (!CanBuildVehicleInfrastructure(VEH_SHIP)) return; HandlePlacePushButton(w, DTW_BUOY, SPR_CURSOR_BOUY, 1, PlaceDocks_Buoy); } @@ -124,6 +127,7 @@ static void BuildDocksToolbWndProc(Window *w, WindowEvent *e) switch (e->event) { case WE_PAINT: DrawWindowWidgets(w); + SetWindowWidgetsDisabledState(w, !CanBuildVehicleInfrastructure(VEH_SHIP), 7, 8, 9, WIDGET_LIST_END); break; case WE_CLICK: diff --git a/src/lang/english.txt b/src/lang/english.txt index 3b6ce37430..68800d65de 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1115,6 +1115,7 @@ STR_CONFIG_PATCHES_DEFAULT_RAIL_TYPE_FIRST :First available STR_CONFIG_PATCHES_DEFAULT_RAIL_TYPE_LAST :Last available STR_CONFIG_PATCHES_DEFAULT_RAIL_TYPE_MOST_USED :Most used +STR_CONFIG_PATCHES_ALWAYS_BUILD_INFRASTRUCTURE :{LTBLUE}Show building tools when no suitable vehicles are available: {ORANGE}{STRING1} STR_CONFIG_PATCHES_MAX_TRAINS :{LTBLUE}Max trains per player: {ORANGE}{STRING1} STR_CONFIG_PATCHES_MAX_ROADVEH :{LTBLUE}Max road vehicles per player: {ORANGE}{STRING1} STR_CONFIG_PATCHES_MAX_AIRCRAFT :{LTBLUE}Max aircraft per player: {ORANGE}{STRING1} diff --git a/src/main_gui.cpp b/src/main_gui.cpp index e5bbe934df..69a8a649b5 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -1867,6 +1867,9 @@ static void MainToolbarWndProc(Window *w, WindowEvent *e) /* disable company list drop downs, if there are no companies */ SetWindowWidgetsDisabledState(w, ActivePlayerCount() == 0, 7, 8, 13, 14, 15, 16, WIDGET_LIST_END); + SetWindowWidgetDisabledState(w, 19, !CanBuildVehicleInfrastructure(VEH_TRAIN)); + SetWindowWidgetDisabledState(w, 22, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)); + DrawWindowWidgets(w); break; @@ -1895,16 +1898,16 @@ static void MainToolbarWndProc(Window *w, WindowEvent *e) case WKC_SHIFT | WKC_F4: ShowVehicleListWindow(_local_player, VEH_AIRCRAFT); break; case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break; case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break; - case WKC_SHIFT | WKC_F7: ShowBuildRailToolbar(_last_built_railtype, -1); break; + case WKC_SHIFT | WKC_F7: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, -1); break; case WKC_SHIFT | WKC_F8: ShowBuildRoadToolbar(_last_built_roadtype); break; case WKC_SHIFT | WKC_F9: ShowBuildDocksToolbar(); break; - case WKC_SHIFT | WKC_F10: ShowBuildAirToolbar(); break; + case WKC_SHIFT | WKC_F10: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break; case WKC_SHIFT | WKC_F11: ShowBuildTreesToolbar(); break; case WKC_SHIFT | WKC_F12: ShowMusicWindow(); break; case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break; case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break; case WKC_CTRL | WKC_ALT | 'C': if (!_networking) ShowCheatWindow(); break; - case 'A': ShowBuildRailToolbar(_last_built_railtype, 4); break; /* Invoke Autorail */ + case 'A': if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, 4); break; /* Invoke Autorail */ case 'L': ShowTerraformToolbar(); break; default: return; } diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 66e566ad19..405f7a4dcf 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -213,19 +213,19 @@ static void BuildRoadClick_Demolish(Window *w) static void BuildRoadClick_Depot(Window *w) { - if (_game_mode == GM_EDITOR) return; + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; if (HandlePlacePushButton(w, RTW_DEPOT, SPR_CURSOR_ROAD_DEPOT, 1, PlaceRoad_Depot)) ShowRoadDepotPicker(); } static void BuildRoadClick_BusStation(Window *w) { - if (_game_mode == GM_EDITOR) return; + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; if (HandlePlacePushButton(w, RTW_BUS_STATION, SPR_CURSOR_BUS_STATION, 1, PlaceRoad_BusStation)) ShowRVStationPicker(RoadStop::BUS); } static void BuildRoadClick_TruckStation(Window *w) { - if (_game_mode == GM_EDITOR) return; + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; if (HandlePlacePushButton(w, RTW_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, 1, PlaceRoad_TruckStation)) ShowRVStationPicker(RoadStop::TRUCK); } @@ -270,6 +270,7 @@ static void BuildRoadToolbWndProc(Window *w, WindowEvent *e) if (IsWindowWidgetLowered(w, RTW_ROAD_X) || IsWindowWidgetLowered(w, RTW_ROAD_Y) || IsWindowWidgetLowered(w, RTW_BUS_STATION) || IsWindowWidgetLowered(w, RTW_TRUCK_STATION)) { EnableWindowWidget(w, RTW_REMOVE); } + SetWindowWidgetsDisabledState(w, !CanBuildVehicleInfrastructure(VEH_ROAD), 6, 7, 8, WIDGET_LIST_END); DrawWindowWidgets(w); break; diff --git a/src/settings.cpp b/src/settings.cpp index e7db267435..b68aa49a00 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1384,10 +1384,11 @@ const SettingDesc _patch_settings[] = { SDT_BOOL(Patches, autorenew, S, 0, false, STR_CONFIG_PATCHES_AUTORENEW_VEHICLE, EngineRenewUpdate), SDT_VAR(Patches, autorenew_months, SLE_INT16, S, 0, 6, -12, 12, 0, STR_CONFIG_PATCHES_AUTORENEW_MONTHS, EngineRenewMonthsUpdate), SDT_VAR(Patches, autorenew_money, SLE_UINT, S,CR,100000, 0, 2000000, 0, STR_CONFIG_PATCHES_AUTORENEW_MONEY, EngineRenewMoneyUpdate), - SDT_VAR(Patches, max_trains, SLE_UINT16, 0, 0, 500, 0, 5000, 0, STR_CONFIG_PATCHES_MAX_TRAINS, NULL), - SDT_VAR(Patches, max_roadveh, SLE_UINT16, 0, 0, 500, 0, 5000, 0, STR_CONFIG_PATCHES_MAX_ROADVEH, NULL), - SDT_VAR(Patches, max_aircraft, SLE_UINT16, 0, 0, 200, 0, 5000, 0, STR_CONFIG_PATCHES_MAX_AIRCRAFT, NULL), - SDT_VAR(Patches, max_ships, SLE_UINT16, 0, 0, 300, 0, 5000, 0, STR_CONFIG_PATCHES_MAX_SHIPS, NULL), + SDT_BOOL(Patches, always_build_infrastructure, S, 0, false, STR_CONFIG_PATCHES_ALWAYS_BUILD_INFRASTRUCTURE, RedrawScreen), + SDT_VAR(Patches, max_trains, SLE_UINT16, 0, 0, 500, 0, 5000, 0, STR_CONFIG_PATCHES_MAX_TRAINS, RedrawScreen), + SDT_VAR(Patches, max_roadveh, SLE_UINT16, 0, 0, 500, 0, 5000, 0, STR_CONFIG_PATCHES_MAX_ROADVEH, RedrawScreen), + SDT_VAR(Patches, max_aircraft, SLE_UINT16, 0, 0, 200, 0, 5000, 0, STR_CONFIG_PATCHES_MAX_AIRCRAFT, RedrawScreen), + SDT_VAR(Patches, max_ships, SLE_UINT16, 0, 0, 300, 0, 5000, 0, STR_CONFIG_PATCHES_MAX_SHIPS, RedrawScreen), SDT_BOOL(Patches, servint_ispercent, 0, 0, false, STR_CONFIG_PATCHES_SERVINT_ISPERCENT, CheckInterval), SDT_VAR(Patches, servint_trains, SLE_UINT16, 0,D0, 150, 5, 800, 0, STR_CONFIG_PATCHES_SERVINT_TRAINS, InValidateDetailsWindow), SDT_VAR(Patches, servint_roadveh, SLE_UINT16, 0,D0, 150, 5, 800, 0, STR_CONFIG_PATCHES_SERVINT_ROADVEH, InValidateDetailsWindow), diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index e134a35409..3546fe3cda 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -655,6 +655,7 @@ static const char *_patches_ui[] = { "loading_indicators", "timetable_in_ticks", "default_rail_type", + "always_build_infrastructure", }; static const char *_patches_construction[] = { diff --git a/src/variables.h b/src/variables.h index 7ee345be54..704e58996c 100644 --- a/src/variables.h +++ b/src/variables.h @@ -139,6 +139,7 @@ struct Patches { uint8 toolbar_pos; // position of toolbars, 0=left, 1=center, 2=right uint8 window_snap_radius; // Windows snap at each other if closer than this + bool always_build_infrastructure; ///< Always allow building of infrastructure, even when you do not have the vehicles for it UnitID max_trains; // max trains in game per player (these are 16bit because the unitnumber field can't hold more) UnitID max_roadveh; // max trucks in game per player UnitID max_aircraft; // max planes in game per player diff --git a/src/vehicle.cpp b/src/vehicle.cpp index a97c027d23..9ed457f18b 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2615,6 +2615,50 @@ UnitID GetFreeUnitNumber(VehicleType type) } +/** + * Check whether we can build infrastructure for the given + * vehicle type. This to disable building stations etc. when + * you are not allowed/able to have the vehicle type yet. + * @param type the vehicle type to check this for + * @return true if there is any reason why you may build + * the infrastructure for the given vehicle type + */ +bool CanBuildVehicleInfrastructure(VehicleType type) +{ + assert(IsPlayerBuildableVehicleType(type)); + + if (_patches.always_build_infrastructure) return true; + + UnitID max; + switch (type) { + case VEH_TRAIN: max = _patches.max_trains; break; + case VEH_ROAD: max = _patches.max_roadveh; break; + case VEH_SHIP: max = _patches.max_ships; break; + case VEH_AIRCRAFT: max = _patches.max_aircraft; break; + default: NOT_REACHED(); + } + + /* We can build vehicle infrastructure when we may build the vehicle type */ + if (max > 0) { + + /* Can we actually build the vehicle type? */ + EngineID e; + FOR_ALL_ENGINEIDS_OF_TYPE(e, type) { + if (HASBIT(GetEngine(e)->player_avail, _local_player)) return true; + } + return false; + } + + /* We should be able to build infrastructure when we have the actual vehicle type */ + const Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->owner == _local_player && v->type == type) return true; + } + + return false; +} + + const Livery *GetEngineLivery(EngineID engine_type, PlayerID player, EngineID parent_engine_type, const Vehicle *v) { const Player *p = GetPlayer(player); diff --git a/src/vehicle.h b/src/vehicle.h index 7b2b5cebc4..c51b49f058 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -77,6 +77,7 @@ enum VehicleType { VEH_END, VEH_INVALID = 0xFF, }; +DECLARE_POSTFIX_INCREMENT(VehicleType); template <> struct EnumPropsT : MakeEnumPropsT {}; typedef TinyEnumT VehicleTypeByte; @@ -569,6 +570,7 @@ void VehicleEnterDepot(Vehicle *v); void InvalidateAutoreplaceWindow(EngineID e); CommandCost MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs); +bool CanBuildVehicleInfrastructure(VehicleType type); /* Flags to add to p2 for goto depot commands */ /* Note: bits 8-10 are used for VLW flags */