diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -35,6 +35,7 @@ #include "engine_func.h" #include "station_base.h" #include "tilehighlight_func.h" +#include "train.h" #include "zoom_func.h" #include "depot_cmd.h" #include "vehicle_cmd.h" @@ -382,6 +383,31 @@ byte GetBestFittingSubType(Vehicle *v_fr return ret_refit_cyc; } +/** + * Get the engine that suffers from the most severe breakdown. + * This means the engine with the lowest breakdown_type. + * If the breakdown types of 2 engines are equal, the one with the lowest breakdown_severity (most severe) is picked. + * @param v The front engine of the train. + * @return The most severly broken engine. + */ +const Vehicle *GetMostSeverelyBrokenEngine(const Train *v) +{ + assert(v->IsFrontEngine()); + const Vehicle *w = v; + byte most_severe_type = 255; + for (const Vehicle *u = v; u != NULL; u = u->Next()) { + if (u->breakdown_ctr == 1) { + if (u->breakdown_type < most_severe_type) { + most_severe_type = u->breakdown_type; + w = u; + } else if (u->breakdown_type == most_severe_type && u->breakdown_severity < w->breakdown_severity) { + w = u; + } + } + } + return w; +} + /** Option to refit a vehicle chain */ struct RefitOption { CargoID cargo; ///< Cargo to refit to @@ -1974,14 +2000,14 @@ public: }; static WindowDesc _vehicle_list_other_desc( - WDP_AUTO, "list_vehicles", 260, 246, + WDP_AUTO, "list_vehicles", 360, 246, WC_INVALID, WC_NONE, 0, _nested_vehicle_list, lengthof(_nested_vehicle_list) ); static WindowDesc _vehicle_list_train_desc( - WDP_AUTO, "list_vehicles_train", 325, 246, + WDP_AUTO, "list_vehicles_train", 425, 246, WC_TRAINS_LIST, WC_NONE, 0, _nested_vehicle_list, lengthof(_nested_vehicle_list) @@ -2347,8 +2373,25 @@ struct VehicleDetailsWindow : Window { y += FONT_HEIGHT_NORMAL; /* Draw breakdown & reliability */ - SetDParam(0, ToPercent16(v->reliability)); - SetDParam(1, v->breakdowns_since_last_service); + byte total_engines = 0; + if (v->type == VEH_TRAIN) { + /* we want to draw the average reliability and total number of breakdowns */ + uint32 total_reliability = 0; + uint16 total_breakdowns = 0; + for (const Vehicle *w = v; w != NULL; w = w->Next()) { + if (Train::From(w)->IsEngine() || Train::From(w)->IsMultiheaded()) { + total_reliability += w->reliability; + total_breakdowns += w->breakdowns_since_last_service; + } + } + total_engines = Train::From(v)->tcache.cached_num_engines; + assert(total_engines > 0); + SetDParam(0, ToPercent16(total_reliability / total_engines)); + SetDParam(1, total_breakdowns); + } else { + SetDParam(0, ToPercent16(v->reliability)); + SetDParam(1, v->breakdowns_since_last_service); + } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS); break; } @@ -2644,6 +2687,13 @@ void StartStopVehicle(const Vehicle *v, Command::Post(_vehicle_msg_translation_table[VCT_CMD_START_STOP][v->type], texteffect ? CcStartStopVehicle : nullptr, v->tile, v->index, false); } +/** Strings for aircraft breakdown types */ +static const StringID _aircraft_breakdown_strings[] = { + STR_BREAKDOWN_TYPE_LOW_SPEED, + STR_BREAKDOWN_TYPE_DEPOT, + STR_BREAKDOWN_TYPE_LANDING, +}; + /** Checks whether the vehicle may be refitted at the moment.*/ static bool IsVehicleRefitable(const Vehicle *v) { @@ -2820,8 +2870,33 @@ public: TextColour text_colour = TC_FROMSTRING; if (v->vehstatus & VS_CRASHED) { str = STR_VEHICLE_STATUS_CRASHED; - } else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary? - str = STR_VEHICLE_STATUS_BROKEN_DOWN; + } else if ( v->breakdown_ctr == 1 || ( v->type == VEH_TRAIN && Train::From( v )->flags & VRF_IS_BROKEN ) ) { + if ( _settings_game.vehicle.improved_breakdowns ) { + str = STR_VEHICLE_STATUS_BROKEN_DOWN_VEL; + SetDParam( 2, v->GetDisplaySpeed( ) ); + } else + str = STR_VEHICLE_STATUS_BROKEN_DOWN; + + if ( v->type == VEH_AIRCRAFT ) { + SetDParam( 0, _aircraft_breakdown_strings[v->breakdown_type] ); + if ( v->breakdown_type == BREAKDOWN_AIRCRAFT_SPEED ) { + uint percentage_speed_limit = v->breakdown_severity; + uint cached_max_speed = v->vcache.cached_max_speed; + uint broken_down_max_speed = ((cached_max_speed * percentage_speed_limit) + 99) / 100; + SetDParam( 1, broken_down_max_speed); + } else { + SetDParam( 1, v->current_order.GetDestination( ) ); + } + } else { + const Vehicle *w = ( v->type == VEH_TRAIN ) ? GetMostSeverelyBrokenEngine( Train::From( v ) ) : v; + SetDParam( 0, STR_BREAKDOWN_TYPE_CRITICAL + w->breakdown_type ); + + if ( w->breakdown_type == BREAKDOWN_LOW_SPEED ) { + SetDParam( 1, std::min( w->First()->GetDisplayMaxSpeed( ), w->breakdown_severity >> ( v->type == VEH_TRAIN ? 0 : 1 ) ) ); + } else if ( w->breakdown_type == BREAKDOWN_LOW_POWER ) { + SetDParam( 1, w->breakdown_severity * 100 / 256 ); + } + } } else if (v->vehstatus & VS_STOPPED && (!mouse_over_start_stop || v->IsStoppedInDepot())) { if (v->type == VEH_TRAIN) { if (v->cur_speed == 0) {