diff --git a/src/aircraft.h b/src/aircraft.h index f47febd62d..9e342f4a57 100644 --- a/src/aircraft.h +++ b/src/aircraft.h @@ -77,7 +77,13 @@ struct Aircraft FINAL : public SpecializedVehicle { int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } int GetSpeedOldUnits() const { return this->vcache.cached_max_speed * 10 / 128; } Money GetRunningCost() const; - bool IsInDepot() const { return (this->vehstatus & VS_HIDDEN) != 0 && IsHangarTile(this->tile); } + + bool IsInDepot() const + { + assert(this->IsPrimaryVehicle()); + return (this->vehstatus & VS_HIDDEN) != 0 && IsHangarTile(this->tile); + } + bool Tick(); void OnNewDay(); uint Crash(bool flooded = false); diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 7bdba7deaa..9b4959e58d 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -365,7 +365,7 @@ bool Aircraft::FindClosestDepot(TileIndex *location, DestinationID *destination, static void CheckIfAircraftNeedsService(Aircraft *v) { if (Company::Get(v->owner)->settings.vehicle.servint_aircraft == 0 || !v->NeedsAutomaticServicing()) return; - if (v->IsInDepot()) { + if (v->IsChainInDepot()) { VehicleServiceInDepot(v); return; } diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 10b1684e11..1f7a1fa60d 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -662,7 +662,7 @@ CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1 CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; - if (!v->IsInDepot()) return CMD_ERROR; + if (!v->IsChainInDepot()) return CMD_ERROR; if (v->vehstatus & VS_CRASHED) return CMD_ERROR; bool free_wagon = false; @@ -699,7 +699,7 @@ CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1 if (!was_stopped) cost.AddCost(CmdStartStopVehicle(v, true)); if (cost.Failed()) return cost; - assert(v->IsStoppedInDepot()); + assert(free_wagon || v->IsStoppedInDepot()); /* We have to construct the new vehicle chain to test whether it is valid. * Vehicle construction needs random bits, so we have to save the random seeds diff --git a/src/error.h b/src/error.h index eeb90557d3..34fb3fb2c3 100644 --- a/src/error.h +++ b/src/error.h @@ -48,6 +48,8 @@ public: void CopyOutDParams(); }; +void ScheduleErrorMessage(const ErrorMessageData &data); + void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x = 0, int y = 0, uint textref_stack_size = 0, const uint32 *textref_stack = NULL); void ClearErrorMessages(); void ShowFirstError(); diff --git a/src/error_gui.cpp b/src/error_gui.cpp index b054f8834b..6c4c2e9c64 100644 --- a/src/error_gui.cpp +++ b/src/error_gui.cpp @@ -417,3 +417,13 @@ void ScheduleErrorMessage(ErrorList &datas) { _error_list.splice(_error_list.end(), datas); } + +/** + * Schedule an error. + * Note: This does not try to display the error now. This is useful if the window system is not yet running. + * @param data Error message data; cleared afterwards + */ +void ScheduleErrorMessage(const ErrorMessageData &data) +{ + _error_list.push_back(data); +} diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index 27e9776b9a..5712b28f96 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -12,6 +12,7 @@ #include "stdafx.h" #include "train.h" #include "roadveh.h" +#include "depot_map.h" /** * Recalculates the cached total power of a vehicle. Should be called when the consist is changed. @@ -164,6 +165,27 @@ int GroundVehicle::GetAcceleration() const } } +/** + * Check whether the whole vehicle chain is in the depot. + * @return true if and only if the whole chain is in the depot. + */ +template +bool GroundVehicle::IsChainInDepot() const +{ + const T *v = this->First(); + /* Is the front engine stationary in the depot? */ + assert_compile((int)TRANSPORT_RAIL == (int)VEH_TRAIN); + assert_compile((int)TRANSPORT_ROAD == (int)VEH_ROAD); + if (!IsDepotTypeTile(v->tile, (TransportType)Type) || v->cur_speed != 0) return false; + + /* Check whether the rest is also already trying to enter the depot. */ + for (; v != NULL; v = v->Next()) { + if (!v->T::IsInDepot() || v->tile != this->tile) return false; + } + + return true; +} + /* Instantiation for Train */ template struct GroundVehicle; /* Instantiation for RoadVehicle */ diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp index a06d6c71b9..65c8562950 100644 --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -92,6 +92,7 @@ struct GroundVehicle : public SpecializedVehicle { void PowerChanged(); void CargoChanged(); int GetAcceleration() const; + bool IsChainInDepot() const; /** * Common code executed for crashed ground vehicles diff --git a/src/lang/english.txt b/src/lang/english.txt index e8d5630d84..26c01bc640 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1393,6 +1393,9 @@ STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :incompatible to STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :unknown STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... compression level '{RAW_STRING}' is not valid STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... savegame format '{RAW_STRING}' is not available. Reverting to '{RAW_STRING}' +STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ignoring Base Graphics set '{RAW_STRING}': not found +STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignoring Base Sounds set '{RAW_STRING}': not found +STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignoring Base Music set '{RAW_STRING}': not found # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 8ac9c7bf6c..e1ea5b94e3 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -93,6 +93,12 @@ public: break; } + case WID_BO_OBJECT_NAME: + case WID_BO_OBJECT_SIZE: + /* We do not want the window to resize when selecting objects; better clip texts */ + size->width = 0; + break; + case WID_BO_OBJECT_MATRIX: { /* Get the right amount of buttons based on the current spec. */ const ObjectSpec *spec = ObjectClass::Get(_selected_object_class, _selected_object_index); diff --git a/src/openttd.cpp b/src/openttd.cpp index e29336bf0d..7df58fabe4 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -722,8 +722,14 @@ int ttd_main(int argc, char *argv[]) BaseGraphics::FindSets(); if (graphics_set == NULL && BaseGraphics::ini_set != NULL) graphics_set = strdup(BaseGraphics::ini_set); - if (!BaseGraphics::SetSet(graphics_set) && !StrEmpty(graphics_set)) { - usererror("Failed to select requested graphics set '%s'", graphics_set); + if (!BaseGraphics::SetSet(graphics_set)) { + if (!StrEmpty(graphics_set)) { + BaseGraphics::SetSet(NULL); + + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND); + msg.SetDParamStr(0, graphics_set); + ScheduleErrorMessage(msg); + } } free(graphics_set); @@ -782,18 +788,26 @@ int ttd_main(int argc, char *argv[]) BaseSounds::FindSets(); if (sounds_set == NULL && BaseSounds::ini_set != NULL) sounds_set = strdup(BaseSounds::ini_set); if (!BaseSounds::SetSet(sounds_set)) { - StrEmpty(sounds_set) ? - usererror("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 4.1 of readme.txt.") : - usererror("Failed to select requested sounds set '%s'", sounds_set); + if (StrEmpty(sounds_set) || !BaseSounds::SetSet(NULL)) { + usererror("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 4.1 of readme.txt."); + } else { + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND); + msg.SetDParamStr(0, sounds_set); + ScheduleErrorMessage(msg); + } } free(sounds_set); BaseMusic::FindSets(); if (music_set == NULL && BaseMusic::ini_set != NULL) music_set = strdup(BaseMusic::ini_set); if (!BaseMusic::SetSet(music_set)) { - StrEmpty(music_set) ? - usererror("Failed to find a music set. Please acquire a music set for OpenTTD. See section 4.1 of readme.txt.") : - usererror("Failed to select requested music set '%s'", music_set); + if (StrEmpty(music_set) || !BaseMusic::SetSet(NULL)) { + usererror("Failed to find a music set. Please acquire a music set for OpenTTD. See section 4.1 of readme.txt."); + } else { + ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND); + msg.SetDParamStr(0, music_set); + ScheduleErrorMessage(msg); + } } free(music_set); diff --git a/src/roadveh.h b/src/roadveh.h index 6358cef7f5..956cc00a66 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -113,7 +113,6 @@ struct RoadVehicle FINAL : public GroundVehicle { Money GetRunningCost() const; int GetDisplayImageWidth(Point *offset = NULL) const; bool IsInDepot() const { return this->state == RVSB_IN_DEPOT; } - bool IsStoppedInDepot() const; bool Tick(); void OnNewDay(); uint Crash(bool flooded = false); diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 6a82250502..eeac274000 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -306,19 +306,6 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin return CommandCost(); } -bool RoadVehicle::IsStoppedInDepot() const -{ - TileIndex tile = this->tile; - - if (!IsRoadDepotTile(tile)) return false; - if (this->IsFrontEngine() && !(this->vehstatus & VS_STOPPED)) return false; - - for (const RoadVehicle *v = this; v != NULL; v = v->Next()) { - if (v->state != RVSB_IN_DEPOT || v->tile != tile) return false; - } - return true; -} - static FindDepotData FindClosestRoadDepot(const RoadVehicle *v, int max_distance) { if (IsRoadDepotTile(v->tile)) return FindDepotData(v->tile, 0); @@ -356,6 +343,8 @@ CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 RoadVehicle *v = RoadVehicle::GetIfValid(p1); if (v == NULL) return CMD_ERROR; + if (!v->IsPrimaryVehicle()) return CMD_ERROR; + CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -1576,7 +1565,7 @@ static void CheckIfRoadVehNeedsService(RoadVehicle *v) { /* If we already got a slot at a stop, use that FIRST, and go to a depot later */ if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return; - if (v->IsInDepot()) { + if (v->IsChainInDepot()) { VehicleServiceInDepot(v); return; } diff --git a/src/script/api/script_vehicle.cpp b/src/script/api/script_vehicle.cpp index c4c6ca5905..639b42f4b7 100644 --- a/src/script/api/script_vehicle.cpp +++ b/src/script/api/script_vehicle.cpp @@ -182,7 +182,7 @@ /* static */ bool ScriptVehicle::IsInDepot(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return false; - return ::Vehicle::Get(vehicle_id)->IsInDepot(); + return ::Vehicle::Get(vehicle_id)->IsChainInDepot(); } /* static */ bool ScriptVehicle::IsStoppedInDepot(VehicleID vehicle_id) diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index ebb6d9bfff..edcb96a781 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -142,7 +142,7 @@ static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance) static void CheckIfShipNeedsService(Vehicle *v) { if (Company::Get(v->owner)->settings.vehicle.servint_ships == 0 || !v->NeedsAutomaticServicing()) return; - if (v->IsInDepot()) { + if (v->IsChainInDepot()) { VehicleServiceInDepot(v); return; } @@ -299,7 +299,7 @@ static const TileIndexDiffC _ship_leave_depot_offs[] = { static bool CheckShipLeaveDepot(Ship *v) { - if (!v->IsInDepot()) return false; + if (!v->IsChainInDepot()) return false; /* We are leaving a depot, but have to go to the exact same one; re-enter */ if (v->current_order.IsType(OT_GOTO_DEPOT) && diff --git a/src/train.h b/src/train.h index 80e8b34944..85c9edf67f 100644 --- a/src/train.h +++ b/src/train.h @@ -101,8 +101,7 @@ struct Train FINAL : public GroundVehicle { int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } Money GetRunningCost() const; int GetDisplayImageWidth(Point *offset = NULL) const; - bool IsInDepot() const; - bool IsStoppedInDepot() const; + bool IsInDepot() const { return this->track == TRACK_BIT_DEPOT; } bool Tick(); void OnNewDay(); uint Crash(bool flooded = false); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 2de9dd5e87..5bdb3ea2b7 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -730,34 +730,6 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin return CommandCost(); } -/** - * Is the whole consist the in a depot? - * @return \c true iff all vehicles of the train are in a depot. - */ -bool Train::IsInDepot() const -{ - /* Is the front engine stationary in the depot? */ - if (!IsRailDepotTile(this->tile) || this->cur_speed != 0) return false; - - /* Check whether the rest is also already trying to enter the depot. */ - for (const Train *v = this; v != NULL; v = v->Next()) { - if (v->track != TRACK_BIT_DEPOT || v->tile != this->tile) return false; - } - - return true; -} - -/** - * Is the train stopped in a depot? - * @return True if the train is stopped in a depot, else false. - */ -bool Train::IsStoppedInDepot() const -{ - /* Are we stopped? Of course wagons don't really care... */ - if (this->IsFrontEngine() && !(this->vehstatus & VS_STOPPED)) return false; - return this->IsInDepot(); -} - static Train *FindGoodVehiclePos(const Train *src) { EngineID eng = src->engine_type; @@ -1932,6 +1904,8 @@ CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, Train *t = Train::GetIfValid(p1); if (t == NULL) return CMD_ERROR; + if (!t->IsPrimaryVehicle()) return CMD_ERROR; + CommandCost ret = CheckOwnership(t->owner); if (ret.Failed()) return ret; @@ -1942,7 +1916,7 @@ CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, * to proceed to the next signal. In the other cases we * would like to pass the signal at danger and run till the * next signal we encounter. */ - t->force_proceed = t->force_proceed == TFP_SIGNAL ? TFP_NONE : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsInDepot() ? TFP_STUCK : TFP_SIGNAL; + t->force_proceed = t->force_proceed == TFP_SIGNAL ? TFP_NONE : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsChainInDepot() ? TFP_STUCK : TFP_SIGNAL; SetWindowDirty(WC_VEHICLE_VIEW, t->index); } @@ -3900,7 +3874,7 @@ bool Train::Tick() static void CheckIfTrainNeedsService(Train *v) { if (Company::Get(v->owner)->settings.vehicle.servint_trains == 0 || !v->NeedsAutomaticServicing()) return; - if (v->IsInDepot()) { + if (v->IsChainInDepot()) { VehicleServiceInDepot(v); return; } diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 852442e2e7..b3cb466b7d 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -410,11 +410,23 @@ public: */ virtual bool IsInDepot() const { return false; } + /** + * Check whether the whole vehicle chain is in the depot. + * @return true if and only if the whole chain is in the depot. + */ + virtual bool IsChainInDepot() const { return this->IsInDepot(); } + /** * Check whether the vehicle is in the depot *and* stopped. * @return true if and only if the vehicle is in the depot and stopped. */ - virtual bool IsStoppedInDepot() const { return this->IsInDepot() && (this->vehstatus & VS_STOPPED) != 0; } + bool IsStoppedInDepot() const + { + assert(this == this->First()); + /* Free wagons have no VS_STOPPED state */ + if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false; + return this->IsChainInDepot(); + } /** * Calls the tick handler of the vehicle diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 8899b5f32e..bfcdb68621 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -601,13 +601,7 @@ CommandCost CmdMassStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 if (!!(v->vehstatus & VS_STOPPED) != do_start) continue; - if (!vehicle_list_window) { - if (vli.vtype == VEH_TRAIN) { - if (!Train::From(v)->IsInDepot()) continue; - } else { - if (!(v->vehstatus & VS_HIDDEN)) continue; - } - } + if (!vehicle_list_window && !v->IsChainInDepot()) continue; /* Just try and don't care if some vehicle's can't be stopped. */ DoCommand(tile, v->index, 0, flags, CMD_START_STOP_VEHICLE); @@ -679,7 +673,7 @@ CommandCost CmdDepotMassAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 const Vehicle *v = list[i]; /* Ensure that the vehicle completely in the depot */ - if (!v->IsInDepot()) continue; + if (!v->IsChainInDepot()) continue; CommandCost ret = DoCommand(0, v->index, 0, flags, CMD_AUTOREPLACE_VEHICLE); @@ -991,6 +985,7 @@ CommandCost CmdSendVehicleToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1 Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20)); if (v == NULL) return CMD_ERROR; + if (!v->IsPrimaryVehicle()) return CMD_ERROR; return v->SendToDepot(flags, (DepotCommand)(p1 & DEPOT_COMMAND_MASK)); } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 353d710b05..be36c01693 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1292,7 +1292,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int if (show_orderlist) DrawSmallOrderList(v, orderlist_left, orderlist_right, y, v->cur_real_order_index); - if (v->IsInDepot()) { + if (v->IsChainInDepot()) { str = STR_BLUE_COMMA; } else { str = (v->age > v->max_age - DAYS_IN_LEAP_YEAR) ? STR_RED_COMMA : STR_BLACK_COMMA; @@ -1544,7 +1544,7 @@ public: switch (index) { case ADI_REPLACE: // Replace window - ShowReplaceGroupVehicleWindow(DEFAULT_GROUP, this->vli.vtype); + ShowReplaceGroupVehicleWindow(ALL_GROUP, this->vli.vtype); break; case ADI_SERVICE: // Send for servicing case ADI_DEPOT: // Send to Depots