From 7ffd65c3e60cd8717f905c9dfe0fa49c245ed3e5 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Sun, 20 Jun 2021 13:00:28 +0200 Subject: [PATCH 01/17] Add initial implementation --- src/build_vehicle_gui.cpp | 1371 +++++++++++++++++++++++++++- src/lang/english.txt | 13 + src/widgets/build_vehicle_widget.h | 26 + 3 files changed, 1406 insertions(+), 4 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index a3e6c4c170..17445952f9 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -49,6 +49,9 @@ uint GetEngineListHeight(VehicleType type) return std::max(FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM, GetVehicleImageCellSize(type, EIT_PURCHASE).height); } +/** + * Normal layout for roadvehicles, ships and airplanes. +*/ static const NWidgetPart _nested_build_vehicle_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), @@ -87,17 +90,115 @@ static const NWidgetPart _nested_build_vehicle_widgets[] = { EndContainer(), }; +/* Advanced layout for trains. */ +static const NWidgetPart _nested_build_vehicle_widgets_train_advanced[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + + NWidget(NWID_HORIZONTAL), + /* First half of the window contains locomotives. */ + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 0), + NWidget(WWT_LABEL, COLOUR_GREY, WID_BV_CAPTION_LOCO), SetDataTip(STR_WHITE_STRING, STR_NULL), SetResize(1, 0), SetFill(1, 0), + EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASSENDING_DESCENDING_LOCO), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN_LOCO), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDDEN_LOCOS), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN_LOCO), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), + EndContainer(), + EndContainer(), + EndContainer(), + /* Vehicle list for locomotives. */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_BV_LIST_LOCO), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_BV_SCROLLBAR_LOCO), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BV_SCROLLBAR_LOCO), + EndContainer(), + /* Panel with details for locomotives. */ + NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL_LOCO), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + /* Build/rename buttons, resize button for locomotives. */ + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL_LOCO), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD_LOCO), SetMinimalSize(50, 1), SetResize(1, 0), SetFill(1, 0), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDE_LOCO), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME_LOCO), SetResize(1, 0), SetFill(1, 0), + EndContainer(), + + EndContainer(), + /* Second half of the window contains wagons. */ + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 0), + NWidget(WWT_LABEL, COLOUR_GREY, WID_BV_CAPTION_WAGON), SetDataTip(STR_WHITE_STRING, STR_NULL), SetResize(1, 0), SetFill(1, 0), + EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASSENDING_DESCENDING_WAGON), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN_WAGON), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDDEN_WAGONS), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN_WAGON), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), + EndContainer(), + EndContainer(), + EndContainer(), + /* Vehicle list for wagons. */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_BV_LIST_WAGON), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_BV_SCROLLBAR_WAGON), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BV_SCROLLBAR_WAGON), + EndContainer(), + /* Panel with details for wagons. */ + NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL_WAGON), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + /* Build/rename buttons, resize button for wagons. */ + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL_WAGON), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD_WAGON), SetMinimalSize(50, 1), SetResize(1, 0), SetFill(1, 0), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDE_WAGON), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME_WAGON), SetResize(1, 0), SetFill(1, 0), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), + EndContainer(), + EndContainer(), +}; + /** Special cargo filter criteria */ static const CargoID CF_ANY = CT_NO_REFIT; ///< Show all vehicles independent of carried cargo (i.e. no filtering) static const CargoID CF_NONE = CT_INVALID; ///< Show only vehicles which do not carry cargo (e.g. train engines) static const CargoID CF_ENGINES = CT_AUTO_REFIT; ///< Show only engines (for rail vehicles only) -bool _engine_sort_direction; ///< \c false = descending, \c true = ascending. +bool _engine_sort_direction; ///< \c false = descending, \c true = ascending. byte _engine_sort_last_criteria[] = {0, 0, 0, 0}; ///< Last set sort criteria, for each vehicle type. bool _engine_sort_last_order[] = {false, false, false, false}; ///< Last set direction of the sort order, for each vehicle type. bool _engine_sort_show_hidden_engines[] = {false, false, false, false}; ///< Last set 'show hidden engines' setting for each vehicle type. +bool _engine_sort_show_hidden_locos = false; ///< Last set 'show hidden locos' setting. +bool _engine_sort_show_hidden_wagons = false; ///< Last set 'show hidden wagons' setting. static CargoID _engine_sort_last_cargo_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ANY}; ///< Last set filter criteria, for each vehicle type. +static bool _internal_sort_order_loco; ///< false = descending, true = ascending +static byte _last_sort_criteria_loco = 0; +static bool _last_sort_order_loco = false; +static CargoID _last_filter_criteria_loco = CF_ANY; + +static bool _internal_sort_order_wagon; ///< false = descending, true = ascending +static byte _last_sort_criteria_wagon = 0; +static bool _last_sort_order_wagon = false; +static CargoID _last_filter_criteria_wagon = CF_ANY; + /** * Determines order of engines by engineID * @param a first engine to compare @@ -446,6 +547,354 @@ static bool AircraftRangeSorter(const EngineID &a, const EngineID &b) return _engine_sort_direction ? r > 0 : r < 0; } +/* Locomotive sorting functions. */ +/** + * Determines order of locomotives by engineID + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineNumberSorterLoco(const EngineID &a, const EngineID &b) +{ + int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; + + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of locomotives by introduction date + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineIntroDateSorterLoco(const EngineID &a, const EngineID &b) +{ + const int va = Engine::Get(a)->intro_date; + const int vb = Engine::Get(b)->intro_date; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of locomotives by name + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineNameSorterLoco(const EngineID &a, const EngineID &b) +{ + static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; + static char last_name[2][64] = { "\0", "\0" }; + + const EngineID va = a; + const EngineID vb = b; + + if (va != last_engine[0]) { + last_engine[0] = va; + SetDParam(0, va); + GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); + } + + if (vb != last_engine[1]) { + last_engine[1] = vb; + SetDParam(0, vb); + GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of locomotives by reliability + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineReliabilitySorterLoco(const EngineID &a, const EngineID &b) +{ + const int va = Engine::Get(a)->reliability; + const int vb = Engine::Get(b)->reliability; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of locomotives by purchase cost + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineCostSorterLoco(const EngineID &a, const EngineID &b) +{ + Money va = Engine::Get(a)->GetCost(); + Money vb = Engine::Get(b)->GetCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of locomotives by speed + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineSpeedSorterLoco(const EngineID &a, const EngineID &b) +{ + int va = Engine::Get(a)->GetDisplayMaxSpeed(); + int vb = Engine::Get(b)->GetDisplayMaxSpeed(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of locomotives by power + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EnginePowerSorterLoco(const EngineID &a, const EngineID &b) +{ + int va = Engine::Get(a)->GetPower(); + int vb = Engine::Get(b)->GetPower(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of locomotives by tractive effort + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineTractiveEffortSorterLoco(const EngineID &a, const EngineID &b) +{ + int va = Engine::Get(a)->GetDisplayMaxTractiveEffort(); + int vb = Engine::Get(b)->GetDisplayMaxTractiveEffort(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of locomotives by running costs + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineRunningCostSorterLoco(const EngineID &a, const EngineID &b) +{ + Money va = Engine::Get(a)->GetRunningCost(); + Money vb = Engine::Get(b)->GetRunningCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of locomotives by running costs + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EnginePowerVsRunningCostSorterLoco(const EngineID &a, const EngineID &b) +{ + const Engine *e_a = Engine::Get(a); + const Engine *e_b = Engine::Get(b); + + /* Here we are using a few tricks to get the right sort. + * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int, + * we will actually calculate cunning cost/power (to make it more than 1). + * Because of this, the return value have to be reversed as well and we return b - a instead of a - b. + * Another thing is that both power and running costs should be doubled for multiheaded engines. + * Since it would be multiplying with 2 in both numerator and denominator, it will even themselves out and we skip checking for multiheaded. */ + Money va = (e_a->GetRunningCost()) / std::max(1U, (uint)e_a->GetPower()); + Money vb = (e_b->GetRunningCost()) / std::max(1U, (uint)e_b->GetPower()); + int r = ClampToI32(vb - va); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/** + * Determines order of train locomotives by capacity + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool TrainEngineCapacitySorterLoco(const EngineID &a, const EngineID &b) +{ + const RailVehicleInfo *rvi_a = RailVehInfo(a); + const RailVehicleInfo *rvi_b = RailVehInfo(b); + + int va = GetTotalCapacityOfArticulatedParts(a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int vb = GetTotalCapacityOfArticulatedParts(b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? -r : r; +} + +/* Wagon sorting functions. */ + +/** + * Determines order of wagons by engineID + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineNumberSorterWagon(const EngineID &a, const EngineID &b) +{ + int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; + + return _internal_sort_order_wagon ? -r : r; +} + +/** + * Determines order of wagons by introduction date + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineIntroDateSorterWagon(const EngineID &a, const EngineID &b) +{ + const int va = Engine::Get(a)->intro_date; + const int vb = Engine::Get(b)->intro_date; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? -r : r; +} + +/** + * Determines order of wagons by name + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineNameSorterWagon(const EngineID &a, const EngineID &b) +{ + static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; + static char last_name[2][64] = { "\0", "\0" }; + + const EngineID va = a; + const EngineID vb = b; + + if (va != last_engine[0]) { + last_engine[0] = va; + SetDParam(0, va); + GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); + } + + if (vb != last_engine[1]) { + last_engine[1] = vb; + SetDParam(0, vb); + GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? -r : r; +} + +/** + * Determines order of wagons by purchase cost + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineCostSorterWagon(const EngineID &a, const EngineID &b) +{ + Money va = Engine::Get(a)->GetCost(); + Money vb = Engine::Get(b)->GetCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? -r : r; +} + +/** + * Determines order of wagons by speed + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineSpeedSorterWagon(const EngineID &a, const EngineID &b) +{ + int va = Engine::Get(a)->GetDisplayMaxSpeed(); + int vb = Engine::Get(b)->GetDisplayMaxSpeed(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? -r : r; +} + +/** + * Determines order of wagons by running costs + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineRunningCostSorterWagon(const EngineID &a, const EngineID &b) +{ + Money va = Engine::Get(a)->GetRunningCost(); + Money vb = Engine::Get(b)->GetRunningCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? -r : r; +} + +/** + * Determines order of train wagons by capacity + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool TrainEngineCapacitySorterWagon(const EngineID &a, const EngineID &b) +{ + const RailVehicleInfo *rvi_a = RailVehInfo(a); + const RailVehicleInfo *rvi_b = RailVehInfo(b); + + int va = GetTotalCapacityOfArticulatedParts(a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int vb = GetTotalCapacityOfArticulatedParts(b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? -r : r; +} + /** Sort functions for the vehicle sort criteria, for each vehicle type. */ EngList_SortTypeFunction * const _engine_sort_functions[][12] = {{ /* Trains */ @@ -558,6 +1007,60 @@ const StringID _engine_sort_listing[][13] = {{ INVALID_STRING_ID }}; +static EngList_SortTypeFunction * const _sorter_loco[12] = { + /* Locomotives */ + &EngineNumberSorterLoco, + &EngineCostSorterLoco, + &EngineSpeedSorterLoco, + &EnginePowerSorterLoco, + &EngineTractiveEffortSorterLoco, + &EngineIntroDateSorterLoco, + &EngineNameSorterLoco, + &EngineRunningCostSorterLoco, + &EnginePowerVsRunningCostSorterLoco, + &EngineReliabilitySorter, + &TrainEngineCapacitySorter +}; + +static EngList_SortTypeFunction * const _sorter_wagon[7] = { + /* Wagons */ + &EngineNumberSorterWagon, + &EngineCostSorterWagon, + &EngineSpeedSorterWagon, + &EngineIntroDateSorterWagon, + &EngineNameSorterWagon, + &EngineRunningCostSorterWagon, + &TrainEngineCapacitySorterWagon +}; + +static const StringID _sort_listing_loco[12] = { + /* Locomotives */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_POWER, + STR_SORT_BY_TRACTIVE_EFFORT, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_POWER_VS_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}; + +static const StringID _sort_listing_wagon[8] = { + /* Wagons */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}; + /** Filters vehicles by cargo and engine (in case of rail vehicle). */ static bool CDECL CargoAndEngineFilter(const EngineID *eid, const CargoID cid) { @@ -1730,6 +2233,855 @@ struct BuildVehicleWindow : Window { } }; +/** Advanced window for trains. It is divided into two parts, one for locomotives and one for wagons. */ +struct BuildVehicleWindowTrainAdvanced : Window { + + /* Locomotives and wagons */ + + VehicleType vehicle_type; ///< Type of vehicles shown in the window. + RailType railtype; ///< Filter to apply. + bool listview_mode; ///< If set, only display the available vehicles and do not show a 'build' button. + + + /* Locomotives */ + + bool descending_sort_order_loco; ///< Sort direction, @see _engine_sort_direction + byte sort_criteria_loco; ///< Current sort criterium for locomotives. + EngineID sel_engine_loco; ///< Currently selected engine, or #INVALID_ENGINE + EngineID rename_engine_loco; ///< Engine being renamed. + GUIEngineList eng_list_loco; + Scrollbar *vscroll_loco; + byte cargo_filter_criteria_loco; ///< Selected cargo filter + bool show_hidden_locos; ///< State of the 'show hidden locomotives' button. + int details_height_loco; ///< Minimal needed height of the details panels (found so far). + CargoID cargo_filter_loco[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE + StringID cargo_filter_texts_loco[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID + + + /* Wagons */ + + bool descending_sort_order_wagon; ///< Sort direction, @see _engine_sort_direction + byte sort_criteria_wagon; ///< Current sort criterium for wagons. + EngineID sel_engine_wagon; ///< Currently selected engine, or #INVALID_ENGINE + EngineID rename_engine_wagon; ///< Engine being renamed. + GUIEngineList eng_list_wagon; + Scrollbar *vscroll_wagon; + byte cargo_filter_criteria_wagon; ///< Selected cargo filter + bool show_hidden_wagons; ///< State of the 'show hidden wagons' button. + int details_height_wagon; ///< Minimal needed height of the details panels (found so far). + CargoID cargo_filter_wagon[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE + StringID cargo_filter_texts_wagon[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID + + + bool virtual_train_mode; ///< Are we building a virtual train? + Train **virtual_train_out; ///< Virtual train ptr + + TestedEngineDetails te; ///< Tested cost and capacity after refit. + + BuildVehicleWindowTrainAdvanced(WindowDesc *desc, TileIndex tile, Train **virtual_train_out) : Window(desc) + { + this->vehicle_type = VEH_TRAIN; + this->window_number = tile == INVALID_TILE ? (int)VEH_TRAIN : tile; + + this->virtual_train_out = virtual_train_out; + this->virtual_train_mode = (virtual_train_out != nullptr); + if (this->virtual_train_mode) this->window_number = 0; + + this->sel_engine_loco = INVALID_ENGINE; + this->sort_criteria_loco = _last_sort_criteria_loco; + this->descending_sort_order_loco = _last_sort_order_loco; + this->show_hidden_wagons = _engine_sort_show_hidden_wagons; + + this->sel_engine_wagon = INVALID_ENGINE; + this->sort_criteria_wagon = _last_sort_criteria_wagon; + this->descending_sort_order_wagon = _last_sort_order_wagon; + this->show_hidden_locos = _engine_sort_show_hidden_locos; + + this->railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile); + this->listview_mode = (tile == INVALID_TILE) && !virtual_train_mode; + + this->CreateNestedTree(); + + this->vscroll_loco = this->GetScrollbar(WID_BV_SCROLLBAR_LOCO); + this->vscroll_wagon = this->GetScrollbar(WID_BV_SCROLLBAR_WAGON); + + /* If we are just viewing the list of vehicles, we do not need the Build button. + * So we just hide it, and enlarge the Rename button by the now vacant place. */ + if (this->listview_mode) this->GetWidget(WID_BV_BUILD_SEL_LOCO)->SetDisplayedPlane(SZSP_NONE); + if (this->listview_mode) this->GetWidget(WID_BV_BUILD_SEL_WAGON)->SetDisplayedPlane(SZSP_NONE); + + /* Locomotives */ + + NWidgetCore *widget_loco = this->GetWidget(WID_BV_LIST_LOCO); + widget_loco->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + VEH_TRAIN; + + widget_loco = this->GetWidget(WID_BV_SHOW_HIDE_LOCO); + widget_loco->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + VEH_TRAIN; + + widget_loco = this->GetWidget(WID_BV_BUILD_LOCO); + if (this->virtual_train_mode) { + widget_loco->widget_data = STR_TMPL_CONFIRM; + widget_loco->tool_tip = STR_TMPL_CONFIRM; + } + else { + widget_loco->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_LOCOMOTIVE_BUTTON; + widget_loco->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_LOCOMOTIVE_TOOLTIP; + } + + widget_loco = this->GetWidget(WID_BV_RENAME_LOCO); + widget_loco->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_BUTTON; + widget_loco->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_TOOLTIP; + + widget_loco = this->GetWidget(WID_BV_SHOW_HIDDEN_LOCOS); + widget_loco->widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + VEH_TRAIN; + widget_loco->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + VEH_TRAIN; + widget_loco->SetLowered(this->show_hidden_locos); + + /* Wagons */ + + NWidgetCore *widget_wagon = this->GetWidget(WID_BV_LIST_WAGON); + widget_wagon->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + VEH_TRAIN; + + widget_wagon = this->GetWidget(WID_BV_SHOW_HIDE_WAGON); + widget_wagon->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + VEH_TRAIN; + + widget_wagon = this->GetWidget(WID_BV_BUILD_WAGON); + if (this->virtual_train_mode) { + widget_wagon->widget_data = STR_TMPL_CONFIRM; + widget_wagon->tool_tip = STR_TMPL_CONFIRM; + } else { + widget_wagon->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_WAGON_BUTTON; + widget_wagon->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_WAGON_TOOLTIP; + } + + widget_wagon = this->GetWidget(WID_BV_RENAME_WAGON); + widget_wagon->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_BUTTON; + widget_wagon->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_TOOLTIP; + + widget_wagon = this->GetWidget(WID_BV_SHOW_HIDDEN_WAGONS); + widget_wagon->widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + VEH_TRAIN; + widget_wagon->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + VEH_TRAIN; + widget_wagon->SetLowered(this->show_hidden_wagons); + + + this->details_height_loco = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + this->details_height_wagon = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + + this->FinishInitNested(this->window_number); + + this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company; + + this->eng_list_loco.ForceRebuild(); + this->eng_list_wagon.ForceRebuild(); + + this->GenerateBuildList(); // generate the list, since we need it in the next line + /* Select the first engine in the list as default when opening the window */ + + if (!this->eng_list_loco.empty()) this->sel_engine_loco = this->eng_list_loco[0]; + if (!this->eng_list_wagon.empty()) this->sel_engine_wagon = this->eng_list_wagon[0]; + } + + /** Set the filter type according to the depot type */ + void UpdateFilterByTile() + { + if (this->listview_mode || this->virtual_train_mode) { + this->railtype = INVALID_RAILTYPE; + } else { + this->railtype = GetRailType(this->window_number); + } + } + + /** Populate the filter list and set the cargo filter criteria. */ + void SetCargoFilterArray() + { + /* Locomotives */ + + uint filter_items_loco = 0; + + /* Add item for disabling filtering. */ + this->cargo_filter_loco[filter_items_loco] = CF_ANY; + this->cargo_filter_texts_loco[filter_items_loco] = STR_PURCHASE_INFO_ALL_TYPES; + filter_items_loco++; + + /* Add item for vehicles not carrying anything, e.g. train engines. */ + this->cargo_filter_loco[filter_items_loco] = CF_NONE; + this->cargo_filter_texts_loco[filter_items_loco] = STR_PURCHASE_INFO_NONE; + filter_items_loco++; + + /* Collect available cargo types for filtering. */ + const CargoSpec *cs_loco; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs_loco) { + this->cargo_filter_loco[filter_items_loco] = cs_loco->Index(); + this->cargo_filter_texts_loco[filter_items_loco] = cs_loco->name; + filter_items_loco++; + } + + /* Terminate the filter list. */ + this->cargo_filter_texts_loco[filter_items_loco] = INVALID_STRING_ID; + + /* If not found, the cargo criteria will be set to all cargoes. */ + this->cargo_filter_criteria_loco = 0; + + /* Find the last cargo filter criteria. */ + for (uint i = 0; i < filter_items_loco; i++) { + if (this->cargo_filter_loco[i] == _last_filter_criteria_loco) { + this->cargo_filter_criteria_loco = i; + break; + } + } + + this->eng_list_loco.SetFilterFuncs(_filter_funcs); + this->eng_list_loco.SetFilterState(this->cargo_filter_loco[this->cargo_filter_criteria_loco] != CF_ANY); + + + /* Wagons */ + + uint filter_items_wagon = 0; + + /* Add item for disabling filtering. */ + this->cargo_filter_wagon[filter_items_wagon] = CF_ANY; + this->cargo_filter_texts_wagon[filter_items_wagon] = STR_PURCHASE_INFO_ALL_TYPES; + filter_items_wagon++; + + /* Add item for vehicles not carrying anything, e.g. train engines. + * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */ + + this->cargo_filter_wagon[filter_items_wagon] = CF_NONE; + this->cargo_filter_texts_wagon[filter_items_wagon] = STR_PURCHASE_INFO_NONE; + filter_items_wagon++; + + + /* Collect available cargo types for filtering. */ + + const CargoSpec *cs_wagon; + + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs_wagon) { + this->cargo_filter_wagon[filter_items_wagon] = cs_wagon->Index(); + this->cargo_filter_texts_wagon[filter_items_wagon] = cs_wagon->name; + filter_items_wagon++; + } + + /* Terminate the filter list. */ + this->cargo_filter_texts_wagon[filter_items_wagon] = INVALID_STRING_ID; + + /* If not found, the cargo criteria will be set to all cargoes. */ + this->cargo_filter_criteria_wagon = 0; + + /* Find the last cargo filter criteria. */ + for (uint i = 0; i < filter_items_wagon; i++) { + if (this->cargo_filter_wagon[i] == _last_filter_criteria_wagon) { + this->cargo_filter_criteria_wagon = i; + break; + } + } + this->eng_list_wagon.SetFilterFuncs(_filter_funcs); + this->eng_list_wagon.SetFilterState(this->cargo_filter_wagon[this->cargo_filter_criteria_wagon] != CF_ANY); + } + + void OnInit() + { + this->SetCargoFilterArray(); + } + + /** Filter the engine list against the currently selected cargo filter */ + void FilterEngineList() + { + this->eng_list_loco.Filter(this->cargo_filter_loco[this->cargo_filter_criteria_loco]); + if (this->eng_list_loco.empty()) { + // no engine passed through the filter, invalidate the previously selected engine + this->sel_engine_loco = INVALID_ENGINE; + } else if (std::find(this->eng_list_loco.begin(), this->eng_list_loco.end(), this->sel_engine_loco) == this->eng_list_loco.end()) { + // previously selected engine didn't pass the filter, select the first engine of the list + this->sel_engine_loco = this->eng_list_loco[0]; + } + this->eng_list_wagon.Filter(this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]); + if (this->eng_list_wagon.empty()) { + // no engine passed through the filter, invalidate the previously selected engine + this->sel_engine_wagon = INVALID_ENGINE; + } else if (std::find(this->eng_list_wagon.begin(), this->eng_list_wagon.end(), this->sel_engine_wagon) == this->eng_list_wagon.end()) { + // previously selected engine didn't pass the filter, select the first engine of the list + this->sel_engine_wagon = this->eng_list_wagon[0]; + } + } + + /* Filter a single locomotive */ + bool FilterSingleEngineLoco(EngineID eid) + { + const CargoID filter_type = this->cargo_filter_loco[this->cargo_filter_criteria_loco]; + return (filter_type == CF_ANY || CargoAndEngineFilter(&eid, filter_type)); + } + + /* Filter a single wagon */ + bool FilterSingleEngineWagon(EngineID eid) + { + const CargoID filter_type = this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]; + return (filter_type == CF_ANY || CargoAndEngineFilter(&eid, filter_type)); + } + + /* Figure out what train EngineIDs to put in the list */ + void GenerateBuildTrainList() + { + this->railtype = (this->listview_mode || this->virtual_train_mode) ? RAILTYPE_END : GetRailType(this->window_number); + + /* Locomotives */ + + EngineID sel_id_loco = INVALID_ENGINE; + + int num_engines_loco = 0; + + this->eng_list_loco.clear(); + + /* Make list of all available train engines and wagons. + * Also check to see if the previously selected engine is still available, + * and if not, reset selection to INVALID_ENGINE. This could be the case + * when engines become obsolete and are removed */ + for (const Engine *e : Engine::IterateType(VEH_TRAIN)) { + if (!this->show_hidden_locos && e->IsHidden(_local_company)) continue; + EngineID eid = e->index; + const RailVehicleInfo *rvi = &e->u.rail; + + if (this->railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->railtype)) continue; + if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; + + /* Filter now! So num_engines and num_wagons is valid */ + if (!FilterSingleEngineLoco(eid)) continue; + + if (rvi->railveh_type != RAILVEH_WAGON) { + num_engines_loco++; + this->eng_list_loco.push_back(eid); + } + + if (eid == this->sel_engine_loco) sel_id_loco = eid; + } + + this->sel_engine_loco = sel_id_loco; + + + /* Wagons */ + + EngineID sel_id_wagon = INVALID_ENGINE; + + int num_engines_wagon = 0; + int num_wagons_wagon = 0; + + this->eng_list_wagon.clear(); + + /* Make list of all available train engines and wagons. + * Also check to see if the previously selected engine is still available, + * and if not, reset selection to INVALID_ENGINE. This could be the case + * when engines become obsolete and are removed */ + for (const Engine *e : Engine::IterateType(VEH_TRAIN)) { + if (!this->show_hidden_wagons && e->IsHidden(_local_company)) continue; + EngineID eid = e->index; + const RailVehicleInfo *rvi = &e->u.rail; + + if (this->railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->railtype)) continue; + if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; + + /* Filter now! So num_engines and num_wagons is valid */ + if (!FilterSingleEngineWagon(eid)) continue; + + + if (rvi->railveh_type == RAILVEH_WAGON) { + this->eng_list_wagon.push_back(eid); + num_wagons_wagon++; + } + + if (eid == this->sel_engine_wagon) sel_id_wagon = eid; + } + + this->sel_engine_wagon = sel_id_wagon; + + /* Sort locomotives */ + _internal_sort_order_loco = this->descending_sort_order_loco; + EngList_SortPartial(&this->eng_list_loco, _sorter_loco[this->sort_criteria_loco], 0, num_engines_loco); + + /* Sort wagons */ + _internal_sort_order_wagon = this->descending_sort_order_wagon; + EngList_SortPartial(&this->eng_list_wagon, _sorter_wagon[this->sort_criteria_wagon], num_engines_wagon, num_wagons_wagon); + + } + + /* Generate the list of vehicles */ + void GenerateBuildList() + { + if (!this->eng_list_loco.NeedRebuild() && !this->eng_list_wagon.NeedRebuild()) return; + + this->GenerateBuildTrainList(); + this->eng_list_loco.RebuildDone(); + this->eng_list_wagon.RebuildDone(); + } + + void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + + /* Locomotives */ + + + case WID_BV_SORT_ASSENDING_DESCENDING_LOCO: { + this->descending_sort_order_loco ^= true; + _last_sort_order_loco = this->descending_sort_order_loco; + this->eng_list_loco.ForceRebuild(); + this->SetDirty(); + break; + } + + case WID_BV_SHOW_HIDDEN_LOCOS: { + this->show_hidden_locos ^= true; + _engine_sort_show_hidden_locos = this->show_hidden_locos; + this->eng_list_loco.ForceRebuild(); + this->SetWidgetLoweredState(widget, this->show_hidden_locos); + this->SetDirty(); + break; + } + + case WID_BV_LIST_LOCO: { + uint i = this->vscroll_loco->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST_LOCO); + size_t num_items = this->eng_list_loco.size(); + this->sel_engine_loco = (i < num_items) ? this->eng_list_loco[i] : INVALID_ENGINE; + this->SetDirty(); + + if (_ctrl_pressed) { + this->OnClick(pt, WID_BV_SHOW_HIDE_LOCO, 1); + } + else if (click_count > 1 && !this->listview_mode) { + this->OnClick(pt, WID_BV_BUILD_LOCO, 1); + } + break; + } + + case WID_BV_SORT_DROPDOWN_LOCO: { // Select sorting criteria dropdown menu + uint32 hidden_mask = 0; + /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ + if (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { + SetBit(hidden_mask, 4); // tractive effort + } + ShowDropDownMenu(this, _sort_listing_loco, this->sort_criteria_loco, WID_BV_SORT_DROPDOWN_LOCO, 0, hidden_mask); + break; + } + + case WID_BV_CARGO_FILTER_DROPDOWN_LOCO: { // Select cargo filtering criteria dropdown menu + ShowDropDownMenu(this, this->cargo_filter_texts_loco, this->cargo_filter_criteria_loco, WID_BV_CARGO_FILTER_DROPDOWN_LOCO, 0, 0); + break; + } + + case WID_BV_SHOW_HIDE_LOCO: { + const Engine *e = (this->sel_engine_loco == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_loco); + if (e != nullptr) { + DoCommandP(0, 0, this->sel_engine_loco | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY); + } + break; + } + + case WID_BV_BUILD_LOCO: { + EngineID sel_eng = this->sel_engine_loco; + if (sel_eng != INVALID_ENGINE) { + if (this->virtual_train_mode) { + DoCommandP(0, sel_eng, 0, CMD_BUILD_VIRTUAL_RAIL_VEHICLE, CcAddVirtualEngine); + } + else { + CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle; + DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback); + } + } + break; + } + + case WID_BV_RENAME_LOCO: { + EngineID sel_eng = this->sel_engine_loco; + if (sel_eng != INVALID_ENGINE) { + this->rename_engine_loco = sel_eng; + this->rename_engine_wagon = INVALID_ENGINE; + SetDParam(0, sel_eng); + ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_LOCOMOTIVE_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + } + break; + } + + + /* Wagons */ + + case WID_BV_SORT_ASSENDING_DESCENDING_WAGON: { + this->descending_sort_order_wagon ^= true; + _last_sort_order_wagon = this->descending_sort_order_wagon; + this->eng_list_wagon.ForceRebuild(); + this->SetDirty(); + break; + } + + case WID_BV_SHOW_HIDDEN_WAGONS: { + this->show_hidden_wagons ^= true; + _engine_sort_show_hidden_wagons = this->show_hidden_wagons; + this->eng_list_wagon.ForceRebuild(); + this->SetWidgetLoweredState(widget, this->show_hidden_wagons); + this->SetDirty(); + break; + } + + case WID_BV_LIST_WAGON: { + uint i = this->vscroll_wagon->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST_WAGON); + size_t num_items = this->eng_list_wagon.size(); + this->sel_engine_wagon = (i < num_items) ? this->eng_list_wagon[i] : INVALID_ENGINE; + this->SetDirty(); + + if (_ctrl_pressed) { + this->OnClick(pt, WID_BV_SHOW_HIDE_WAGON, 1); + } + else if (click_count > 1 && !this->listview_mode) { + this->OnClick(pt, WID_BV_BUILD_WAGON, 1); + } + break; + } + + case WID_BV_SORT_DROPDOWN_WAGON: { // Select sorting criteria dropdown menu + uint32 hidden_mask = 0; + /* Disable sorting by maximum speed when wagon speed is disabled. */ + if (!_settings_game.vehicle.wagon_speed_limits) { + SetBit(hidden_mask, 2); // maximum speed + } + ShowDropDownMenu(this, _sort_listing_wagon, this->sort_criteria_wagon, WID_BV_SORT_DROPDOWN_WAGON, 0, hidden_mask); + break; + } + + case WID_BV_CARGO_FILTER_DROPDOWN_WAGON: { // Select cargo filtering criteria dropdown menu + ShowDropDownMenu(this, this->cargo_filter_texts_wagon, this->cargo_filter_criteria_wagon, WID_BV_CARGO_FILTER_DROPDOWN_WAGON, 0, 0); + break; + } + + case WID_BV_SHOW_HIDE_WAGON: { + const Engine *e = (this->sel_engine_wagon == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_wagon); + if (e != nullptr) { + DoCommandP(0, 0, this->sel_engine_wagon | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY); + } + break; + } + + case WID_BV_BUILD_WAGON: { + EngineID sel_eng = this->sel_engine_wagon; + if (sel_eng != INVALID_ENGINE) { + if (this->virtual_train_mode) { + DoCommandP(0, sel_eng, 0, CMD_BUILD_VIRTUAL_RAIL_VEHICLE, CcAddVirtualEngine); + } + else { + CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle; + DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback); + } + } + break; + } + + case WID_BV_RENAME_WAGON: { + EngineID sel_eng = this->sel_engine_wagon; + if (sel_eng != INVALID_ENGINE) { + this->rename_engine_loco = INVALID_ENGINE; + this->rename_engine_wagon = sel_eng; + SetDParam(0, sel_eng); + ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_WAGON_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + } + break; + } + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + + /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ + this->eng_list_loco.ForceRebuild(); + this->eng_list_wagon.ForceRebuild(); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_BV_CAPTION: { + if (this->vehicle_type == VEH_TRAIN && !this->listview_mode && !this->virtual_train_mode) { + const RailtypeInfo *rti = GetRailTypeInfo(this->railtype); + SetDParam(0, rti->strings.build_caption); + } else { + SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type); + } + break; + } + + case WID_BV_CAPTION_LOCO: { + SetDParam(0, STR_BUY_VEHICLE_TRAIN_LOCOMOTIVES); + break; + } + + case WID_BV_SHOW_HIDE_LOCO: { + const Engine *e = (this->sel_engine_loco == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_loco); + if (e != nullptr && e->IsHidden(_local_company)) { + SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type); + } + else { + SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); + } + break; + } + + case WID_BV_CAPTION_WAGON: { + SetDParam(0, STR_BUY_VEHICLE_TRAIN_WAGONS); + break; + } + + case WID_BV_SORT_DROPDOWN_LOCO: { + SetDParam(0, _sort_listing_loco[this->sort_criteria_loco]); + break; + } + + case WID_BV_CARGO_FILTER_DROPDOWN_LOCO: { + SetDParam(0, this->cargo_filter_texts_loco[this->cargo_filter_criteria_loco]); + break; + } + + case WID_BV_SORT_DROPDOWN_WAGON: { + SetDParam(0, _sort_listing_wagon[this->sort_criteria_wagon]); + break; + } + + case WID_BV_CARGO_FILTER_DROPDOWN_WAGON: { + SetDParam(0, this->cargo_filter_texts_wagon[this->cargo_filter_criteria_wagon]); + break; + } + + case WID_BV_SHOW_HIDE_WAGON: { + const Engine *e = (this->sel_engine_wagon == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_wagon); + if (e != nullptr && e->IsHidden(_local_company)) { + SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type); + } + else { + SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); + } + break; + } + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_BV_LIST_LOCO: { + resize->height = GetEngineListHeight(this->vehicle_type); + size->height = 3 * resize->height; + break; + } + + case WID_BV_PANEL_LOCO: { + size->height = this->details_height_loco; + break; + } + + case WID_BV_SORT_ASSENDING_DESCENDING_LOCO: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_BV_LIST_WAGON: { + resize->height = GetEngineListHeight(this->vehicle_type); + size->height = 3 * resize->height; + break; + } + + case WID_BV_PANEL_WAGON: { + size->height = this->details_height_wagon; + break; + } + + case WID_BV_SORT_ASSENDING_DESCENDING_WAGON: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_BV_SHOW_HIDE_LOCO: { + *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); + *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type)); + size->width += padding.width; + size->height += padding.height; + break; + } + + case WID_BV_SHOW_HIDE_WAGON: { + *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); + *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type)); + size->width += padding.width; + size->height += padding.height; + break; + } + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_BV_LIST_LOCO: { + DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list_loco, this->vscroll_loco->GetPosition(), std::min(this->vscroll_loco->GetPosition() + this->vscroll_loco->GetCapacity(), this->eng_list_loco.size()), this->sel_engine_loco, false, DEFAULT_GROUP); + break; + } + + case WID_BV_SORT_ASSENDING_DESCENDING_LOCO: { + this->DrawSortButtonState(WID_BV_SORT_ASSENDING_DESCENDING_LOCO, this->descending_sort_order_loco ? SBS_DOWN : SBS_UP); + break; + } + + case WID_BV_LIST_WAGON: { + DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list_wagon, this->vscroll_wagon->GetPosition(), std::min(this->vscroll_wagon->GetPosition() + this->vscroll_wagon->GetCapacity(), this->eng_list_wagon.size()), this->sel_engine_wagon, false, DEFAULT_GROUP); + break; + } + + case WID_BV_SORT_ASSENDING_DESCENDING_WAGON: { + this->DrawSortButtonState(WID_BV_SORT_ASSENDING_DESCENDING_WAGON, this->descending_sort_order_wagon ? SBS_DOWN : SBS_UP); + break; + } + } + } + + virtual void OnPaint() + { + this->GenerateBuildList(); + this->vscroll_loco->SetCount(this->eng_list_loco.size()); + this->vscroll_wagon->SetCount(this->eng_list_wagon.size()); + + this->SetWidgetDisabledState(WID_BV_SHOW_HIDE_LOCO, this->sel_engine_loco == INVALID_ENGINE); + this->SetWidgetDisabledState(WID_BV_SHOW_HIDE_WAGON, this->sel_engine_wagon == INVALID_ENGINE); + + /* disable renaming engines in network games if you are not the server */ + this->SetWidgetDisabledState(WID_BV_RENAME_LOCO, (this->sel_engine_loco == INVALID_ENGINE) || (_networking && !_network_server)); + this->SetWidgetDisabledState(WID_BV_BUILD_LOCO, this->sel_engine_loco == INVALID_ENGINE); + + /* disable renaming engines in network games if you are not the server */ + this->SetWidgetDisabledState(WID_BV_RENAME_WAGON, (this->sel_engine_wagon == INVALID_ENGINE) || (_networking && !_network_server)); + this->SetWidgetDisabledState(WID_BV_BUILD_WAGON, this->sel_engine_wagon == INVALID_ENGINE); + + this->DrawWidgets(); + + if (!this->IsShaded()) { + int needed_height_loco = this->details_height_loco; + /* Draw details panels. */ + if (this->sel_engine_loco != INVALID_ENGINE) { + NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL_LOCO); + int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, + nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine_loco, this->te); + needed_height_loco = std::max(needed_height_loco, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + } + if (needed_height_loco != this->details_height_loco) { // Details window are not high enough, enlarge them. + int resize = needed_height_loco - this->details_height_loco; + this->details_height_loco = needed_height_loco; + this->ReInit(0, resize); + return; + } + + int needed_height_wagon = this->details_height_wagon; + if (this->sel_engine_wagon != INVALID_ENGINE) { + NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL_WAGON); + int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, + nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine_wagon, this->te); + needed_height_wagon = std::max(needed_height_wagon, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + } + if (needed_height_wagon != this->details_height_wagon) { // Details window are not high enough, enlarge them. + int resize = needed_height_wagon - this->details_height_wagon; + this->details_height_wagon = needed_height_wagon; + this->ReInit(0, resize); + return; + } + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == nullptr) return; + if(this->rename_engine_loco != INVALID_ENGINE) + { + DoCommandP(0, this->rename_engine_loco, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), nullptr, str); + } + else + { + DoCommandP(0, this->rename_engine_wagon, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), nullptr, str); + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_BV_SORT_DROPDOWN_LOCO: { + if (this->sort_criteria_loco != index) { + this->sort_criteria_loco = index; + _last_sort_criteria_loco = this->sort_criteria_loco; + this->eng_list_loco.ForceRebuild(); + } + break; + } + + case WID_BV_CARGO_FILTER_DROPDOWN_LOCO: { // Select a cargo filter criteria + if (this->cargo_filter_criteria_loco != index) { + this->cargo_filter_criteria_loco = index; + _last_filter_criteria_loco = this->cargo_filter_loco[this->cargo_filter_criteria_loco]; + /* deactivate filter if criteria is 'Show All', activate it otherwise */ + this->eng_list_loco.SetFilterState(this->cargo_filter_loco[this->cargo_filter_criteria_loco] != CF_ANY); + this->eng_list_loco.ForceRebuild(); + } + break; + } + + case WID_BV_SORT_DROPDOWN_WAGON: { + if (this->sort_criteria_wagon != index) { + this->sort_criteria_wagon = index; + _last_sort_criteria_wagon = this->sort_criteria_wagon; + this->eng_list_wagon.ForceRebuild(); + } + break; + } + + case WID_BV_CARGO_FILTER_DROPDOWN_WAGON: { // Select a cargo filter criteria + if (this->cargo_filter_criteria_wagon != index) { + this->cargo_filter_criteria_wagon = index; + _last_filter_criteria_wagon = this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]; + /* deactivate filter if criteria is 'Show All', activate it otherwise */ + this->eng_list_wagon.SetFilterState(this->cargo_filter_wagon[this->cargo_filter_criteria_wagon] != CF_ANY); + this->eng_list_wagon.ForceRebuild(); + } + break; + } + } + + this->SetDirty(); + } + + virtual void OnResize() + { + this->vscroll_loco->SetCapacityFromWidget(this, WID_BV_LIST_LOCO); + this->vscroll_wagon->SetCapacityFromWidget(this, WID_BV_LIST_WAGON); + } + + void AddVirtualEngine(Train *toadd) + { + if (this->virtual_train_out == nullptr) return; + + if (*(this->virtual_train_out) == nullptr) { + *(this->virtual_train_out) = toadd; + } else { + VehicleID target = (*(this->virtual_train_out))->GetLastUnit()->index; + + DoCommandP(0, (1 << 21) | toadd->index, target, CMD_MOVE_RAIL_VEHICLE); + } + InvalidateWindowClassesData(WC_CREATE_TEMPLATE); + InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN); + } +}; + void CcAddVirtualEngine(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd) { if (result.Failed()) return; @@ -1764,11 +3116,18 @@ static WindowDesc _build_vehicle_desc( _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) ); +static WindowDesc _build_vehicle_desc_train_advanced( + WDP_AUTO, "build_vehicle", 480, 268, + WC_BUILD_VEHICLE, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_vehicle_widgets_train_advanced, lengthof(_nested_build_vehicle_widgets_train_advanced) +); + static WindowDesc _build_template_vehicle_desc( WDP_AUTO, "build_vehicle", 240, 268, WC_BUILD_VIRTUAL_TRAIN, WC_CREATE_TEMPLATE, WDF_CONSTRUCTION, - _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) + _nested_build_vehicle_widgets_train_advanced, lengthof(_nested_build_vehicle_widgets_train_advanced) ); void ShowBuildVehicleWindow(TileIndex tile, VehicleType type) @@ -1783,7 +3142,11 @@ void ShowBuildVehicleWindow(TileIndex tile, VehicleType type) DeleteWindowById(WC_BUILD_VEHICLE, num); - new BuildVehicleWindow(&_build_vehicle_desc, tile, type, nullptr); + if(type == VEH_TRAIN) { + new BuildVehicleWindowTrainAdvanced(&_build_vehicle_desc_train_advanced, tile, nullptr); + } else { + new BuildVehicleWindow(&_build_vehicle_desc, tile, type, nullptr); + } } void ShowTemplateTrainBuildVehicleWindow(Train **virtual_train) @@ -1792,5 +3155,5 @@ void ShowTemplateTrainBuildVehicleWindow(Train **virtual_train) DeleteWindowById(WC_BUILD_VIRTUAL_TRAIN, 0); - new BuildVehicleWindow(&_build_template_vehicle_desc, INVALID_TILE, VEH_TRAIN, virtual_train); + new BuildVehicleWindowTrainAdvanced(&_build_template_vehicle_desc, INVALID_TILE, virtual_train); } diff --git a/src/lang/english.txt b/src/lang/english.txt index eba78574a4..9a1b5886de 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4569,6 +4569,9 @@ STR_BUY_VEHICLE_SHIP_CAPTION :New Ships STR_BUY_VEHICLE_AIRCRAFT_CAPTION :New Aircraft ############ range for vehicle availability ends +STR_BUY_VEHICLE_TRAIN_LOCOMOTIVES :Locomotives and Power Cars +STR_BUY_VEHICLE_TRAIN_WAGONS :Wagons + STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Weight: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} (Refit Cost: {GOLD}{CURRENCY_LONG}{BLACK}) Weight: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Speed: {GOLD}{VELOCITY}{BLACK} Power: {GOLD}{POWER} @@ -4610,6 +4613,8 @@ STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehi STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehicle STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Buy Ship STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Buy Aircraft +STR_BUY_VEHICLE_TRAIN_BUY_LOCOMOTIVE_BUTTON :{BLACK}Buy Locomotive +STR_BUY_VEHICLE_TRAIN_BUY_WAGON_BUTTON :{BLACK}Buy Wagon STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Vehicle STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Vehicle @@ -4620,6 +4625,8 @@ STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted road vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted ship. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted aircraft. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_TRAIN_BUY_LOCOMOTIVE_TOOLTIP :{BLACK}Buy the highlighted locomotive or power car. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_TRAIN_BUY_WAGON_TOOLTIP :{BLACK}Buy the highlighted wagon. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted train vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted road vehicle. Shift+Click shows estimated cost without purchase @@ -4630,11 +4637,15 @@ STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Rename +STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_BUTTON :{BLACK}Rename Locomotive +STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_BUTTON :{BLACK}Rename Wagon STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Rename train vehicle type STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Rename road vehicle type STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Rename ship type STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Rename aircraft type +STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_TOOLTIP :{BLACK}Rename locomotive or power car +STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_TOOLTIP :{BLACK}Rename wagon STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON :{BLACK}Hide STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_TOGGLE_BUTTON :{BLACK}Hide @@ -4655,6 +4666,8 @@ STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Rename t STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Rename road vehicle type STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Rename ship type STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Rename aircraft type +STR_QUERY_RENAME_TRAIN_TYPE_LOCOMOTIVE_CAPTION :{WHITE}Rename locomotive type +STR_QUERY_RENAME_TRAIN_TYPE_WAGON_CAPTION :{WHITE}Rename wagon type # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} diff --git a/src/widgets/build_vehicle_widget.h b/src/widgets/build_vehicle_widget.h index 861c01f680..201be32fe1 100644 --- a/src/widgets/build_vehicle_widget.h +++ b/src/widgets/build_vehicle_widget.h @@ -24,6 +24,32 @@ enum BuildVehicleWidgets { WID_BV_SHOW_HIDE, ///< Button to hide or show the selected engine. WID_BV_BUILD_SEL, ///< Build button. WID_BV_RENAME, ///< Rename button. + + WID_BV_CAPTION_LOCO, ///< Caption of locomotive half of the window. + WID_BV_SORT_ASSENDING_DESCENDING_LOCO, ///< Sort direction. + WID_BV_SORT_DROPDOWN_LOCO, ///< Criteria of sorting dropdown. + WID_BV_CARGO_FILTER_DROPDOWN_LOCO, ///< Cargo filter dropdown. + WID_BV_SHOW_HIDDEN_LOCOS, ///< Toggle whether to display the hidden locomotives. + WID_BV_LIST_LOCO, ///< List of vehicles. + WID_BV_SCROLLBAR_LOCO, ///< Scrollbar of list. + WID_BV_PANEL_LOCO, ///< Button panel. + WID_BV_SHOW_HIDE_LOCO, ///< Button to hide or show the selected locomotives. + WID_BV_BUILD_LOCO, ///< Build panel. + WID_BV_BUILD_SEL_LOCO, ///< Build button. + WID_BV_RENAME_LOCO, ///< Rename button. + + WID_BV_CAPTION_WAGON, ///< Caption of wagon half of the window. + WID_BV_SORT_ASSENDING_DESCENDING_WAGON, ///< Sort direction. + WID_BV_SORT_DROPDOWN_WAGON, ///< Criteria of sorting dropdown. + WID_BV_CARGO_FILTER_DROPDOWN_WAGON, ///< Cargo filter dropdown. + WID_BV_SHOW_HIDDEN_WAGONS, ///< Toggle whether to display the hidden wagons. + WID_BV_LIST_WAGON, ///< List of vehicles. + WID_BV_SCROLLBAR_WAGON, ///< Scrollbar of list. + WID_BV_PANEL_WAGON, ///< Button panel. + WID_BV_SHOW_HIDE_WAGON, ///< Button to hide or show the selected wagons. + WID_BV_BUILD_WAGON, ///< Build panel. + WID_BV_BUILD_SEL_WAGON, ///< Build button. + WID_BV_RENAME_WAGON, ///< Rename button. }; #endif /* WIDGETS_BUILD_VEHICLE_WIDGET_H */ From 40c9be0c0242143ec5e0a560222c26ff3d8f7a44 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Sun, 20 Jun 2021 19:22:31 +0200 Subject: [PATCH 02/17] Fix sorter functions --- src/build_vehicle_gui.cpp | 145 +++++++++++++++----------------------- 1 file changed, 57 insertions(+), 88 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 17445952f9..7d7078ccff 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -558,7 +558,7 @@ static bool EngineNumberSorterLoco(const EngineID &a, const EngineID &b) { int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; - return _internal_sort_order_loco ? -r : r; + return _internal_sort_order_loco ? r > 0 : r < 0; } /** @@ -575,7 +575,7 @@ static bool EngineIntroDateSorterLoco(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; + return _internal_sort_order_loco ? r > 0 : r < 0; } /** @@ -586,21 +586,17 @@ static bool EngineIntroDateSorterLoco(const EngineID &a, const EngineID &b) */ static bool EngineNameSorterLoco(const EngineID &a, const EngineID &b) { - static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; - static char last_name[2][64] = { "\0", "\0" }; + static char last_name[2][64] = { "", "" }; - const EngineID va = a; - const EngineID vb = b; - - if (va != last_engine[0]) { - last_engine[0] = va; - SetDParam(0, va); + if (a != _last_engine[0]) { + _last_engine[0] = a; + SetDParam(0, a); GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); } - if (vb != last_engine[1]) { - last_engine[1] = vb; - SetDParam(0, vb); + if (b != _last_engine[1]) { + _last_engine[1] = b; + SetDParam(0, b); GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); } @@ -608,24 +604,7 @@ static bool EngineNameSorterLoco(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; -} - -/** - * Determines order of locomotives by reliability - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineReliabilitySorterLoco(const EngineID &a, const EngineID &b) -{ - const int va = Engine::Get(a)->reliability; - const int vb = Engine::Get(b)->reliability; - const int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; + return _internal_sort_order_loco ? r > 0 : r < 0; } /** @@ -642,7 +621,7 @@ static bool EngineCostSorterLoco(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; + return _internal_sort_order_loco ? r > 0 : r < 0; } /** @@ -659,7 +638,7 @@ static bool EngineSpeedSorterLoco(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; + return _internal_sort_order_loco ? r > 0 : r < 0; } /** @@ -676,7 +655,7 @@ static bool EnginePowerSorterLoco(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; + return _internal_sort_order_loco ? r > 0 : r < 0; } /** @@ -693,7 +672,7 @@ static bool EngineTractiveEffortSorterLoco(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; + return _internal_sort_order_loco ? r > 0 : r < 0; } /** @@ -710,7 +689,7 @@ static bool EngineRunningCostSorterLoco(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; + return _internal_sort_order_loco ? r > 0 : r < 0; } /** @@ -723,40 +702,34 @@ static bool EnginePowerVsRunningCostSorterLoco(const EngineID &a, const EngineID { const Engine *e_a = Engine::Get(a); const Engine *e_b = Engine::Get(b); - - /* Here we are using a few tricks to get the right sort. - * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int, - * we will actually calculate cunning cost/power (to make it more than 1). - * Because of this, the return value have to be reversed as well and we return b - a instead of a - b. - * Another thing is that both power and running costs should be doubled for multiheaded engines. - * Since it would be multiplying with 2 in both numerator and denominator, it will even themselves out and we skip checking for multiheaded. */ - Money va = (e_a->GetRunningCost()) / std::max(1U, (uint)e_a->GetPower()); - Money vb = (e_b->GetRunningCost()) / std::max(1U, (uint)e_b->GetPower()); - int r = ClampToI32(vb - va); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; -} - -/** - * Determines order of train locomotives by capacity - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool TrainEngineCapacitySorterLoco(const EngineID &a, const EngineID &b) -{ - const RailVehicleInfo *rvi_a = RailVehInfo(a); - const RailVehicleInfo *rvi_b = RailVehInfo(b); - - int va = GetTotalCapacityOfArticulatedParts(a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); - int vb = GetTotalCapacityOfArticulatedParts(b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? -r : r; + uint p_a = e_a->GetPower(); + uint p_b = e_b->GetPower(); + Money r_a = e_a->GetRunningCost(); + Money r_b = e_b->GetRunningCost(); + /* Check if running cost is zero in one or both engines. + * If only one of them is zero then that one has higher value, + * else if both have zero cost then compare powers. */ + if (r_a == 0) { + if (r_b == 0) { + /* If it is ambiguous which to return go with their ID */ + if (p_a == p_b) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco != (p_a < p_b); + } + return !_internal_sort_order_loco; + } + if (r_b == 0) return _internal_sort_order_loco; + /* Using double for more precision when comparing close values. + * This shouldn't have any major effects in performance nor in keeping + * the game in sync between players since it's used in GUI only in client side */ + double v_a = (double)p_a / (double)r_a; + double v_b = (double)p_b / (double)r_b; + /* Use EngineID to sort if both have same power/running cost, + * since we want consistent sorting. + * Also if both have no power then sort with reverse of running cost to simulate + * previous sorting behaviour for wagons. */ + if (v_a == 0 && v_b == 0) return !EngineRunningCostSorterLoco(a, b); + if (v_a == v_b) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco != (v_a < v_b); } /* Wagon sorting functions. */ @@ -771,7 +744,7 @@ static bool EngineNumberSorterWagon(const EngineID &a, const EngineID &b) { int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; - return _internal_sort_order_wagon ? -r : r; + return _internal_sort_order_wagon ? r > 0 : r < 0; } /** @@ -788,7 +761,7 @@ static bool EngineIntroDateSorterWagon(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? -r : r; + return _internal_sort_order_wagon ? r > 0 : r < 0; } /** @@ -799,21 +772,17 @@ static bool EngineIntroDateSorterWagon(const EngineID &a, const EngineID &b) */ static bool EngineNameSorterWagon(const EngineID &a, const EngineID &b) { - static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; - static char last_name[2][64] = { "\0", "\0" }; + static char last_name[2][64] = { "", "" }; - const EngineID va = a; - const EngineID vb = b; - - if (va != last_engine[0]) { - last_engine[0] = va; - SetDParam(0, va); + if (a != _last_engine[0]) { + _last_engine[0] = a; + SetDParam(0, a); GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); } - if (vb != last_engine[1]) { - last_engine[1] = vb; - SetDParam(0, vb); + if (b != _last_engine[1]) { + _last_engine[1] = b; + SetDParam(0, b); GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); } @@ -821,7 +790,7 @@ static bool EngineNameSorterWagon(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? -r : r; + return _internal_sort_order_wagon ? r > 0 : r < 0; } /** @@ -838,7 +807,7 @@ static bool EngineCostSorterWagon(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? -r : r; + return _internal_sort_order_wagon ? r > 0 : r < 0; } /** @@ -855,7 +824,7 @@ static bool EngineSpeedSorterWagon(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? -r : r; + return _internal_sort_order_wagon ? r > 0 : r < 0; } /** @@ -872,7 +841,7 @@ static bool EngineRunningCostSorterWagon(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? -r : r; + return _internal_sort_order_wagon ? r > 0 : r < 0; } /** @@ -892,7 +861,7 @@ static bool TrainEngineCapacitySorterWagon(const EngineID &a, const EngineID &b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? -r : r; + return _internal_sort_order_wagon ? r > 0 : r < 0; } /** Sort functions for the vehicle sort criteria, for each vehicle type. */ From 92276518ddad14d5ff4b08929933ea2098c83dd3 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Sun, 20 Jun 2021 19:48:47 +0200 Subject: [PATCH 03/17] Adjust further to new API --- src/build_vehicle_gui.cpp | 168 +++++++++++++++++++++++++++++++------- src/lang/english.txt | 4 + 2 files changed, 143 insertions(+), 29 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 7d7078ccff..4d680dd48a 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -2247,6 +2247,48 @@ struct BuildVehicleWindowTrainAdvanced : Window { TestedEngineDetails te; ///< Tested cost and capacity after refit. + void SetBuyLocomotiveText() + { + const auto widget = this->GetWidget(WID_BV_BUILD_LOCO); + + bool refit = this->sel_engine_loco != INVALID_ENGINE && this->cargo_filter_loco[this->cargo_filter_criteria_loco] != CF_ANY && this->cargo_filter_loco[this->cargo_filter_criteria_loco] != CF_NONE; + if (refit) refit = Engine::Get(this->sel_engine_loco)->GetDefaultCargoType() != this->cargo_filter_loco[this->cargo_filter_criteria_loco]; + + if (this->virtual_train_mode) { + widget->widget_data = STR_TMPL_CONFIRM; + widget->tool_tip = STR_TMPL_CONFIRM; + } else { + if (refit) { + widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_LOCOMOTIVE_BUTTON; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_LOCOMOTIVE_TOOLTIP; + } else { + widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_LOCOMOTIVE_BUTTON; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_LOCOMOTIVE_TOOLTIP; + } + } + } + + void SetBuyWagonText() + { + const auto widget = this->GetWidget(WID_BV_BUILD_WAGON); + + bool refit = this->sel_engine_wagon != INVALID_ENGINE && this->cargo_filter_wagon[this->cargo_filter_criteria_wagon] != CF_ANY && this->cargo_filter_wagon[this->cargo_filter_criteria_wagon] != CF_NONE; + if (refit) refit = Engine::Get(this->sel_engine_wagon)->GetDefaultCargoType() != this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]; + + if (this->virtual_train_mode) { + widget->widget_data = STR_TMPL_CONFIRM; + widget->tool_tip = STR_TMPL_CONFIRM; + } else { + if (refit) { + widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_WAGON_BUTTON; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_WAGON_TOOLTIP; + } else { + widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_WAGON_BUTTON; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_WAGON_TOOLTIP; + } + } + } + BuildVehicleWindowTrainAdvanced(WindowDesc *desc, TileIndex tile, Train **virtual_train_out) : Window(desc) { this->vehicle_type = VEH_TRAIN; @@ -2269,6 +2311,8 @@ struct BuildVehicleWindowTrainAdvanced : Window { this->railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile); this->listview_mode = (tile == INVALID_TILE) && !virtual_train_mode; + this->UpdateFilterByTile(); + this->CreateNestedTree(); this->vscroll_loco = this->GetScrollbar(WID_BV_SCROLLBAR_LOCO); @@ -2287,16 +2331,6 @@ struct BuildVehicleWindowTrainAdvanced : Window { widget_loco = this->GetWidget(WID_BV_SHOW_HIDE_LOCO); widget_loco->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + VEH_TRAIN; - widget_loco = this->GetWidget(WID_BV_BUILD_LOCO); - if (this->virtual_train_mode) { - widget_loco->widget_data = STR_TMPL_CONFIRM; - widget_loco->tool_tip = STR_TMPL_CONFIRM; - } - else { - widget_loco->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_LOCOMOTIVE_BUTTON; - widget_loco->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_LOCOMOTIVE_TOOLTIP; - } - widget_loco = this->GetWidget(WID_BV_RENAME_LOCO); widget_loco->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_BUTTON; widget_loco->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_TOOLTIP; @@ -2314,15 +2348,6 @@ struct BuildVehicleWindowTrainAdvanced : Window { widget_wagon = this->GetWidget(WID_BV_SHOW_HIDE_WAGON); widget_wagon->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + VEH_TRAIN; - widget_wagon = this->GetWidget(WID_BV_BUILD_WAGON); - if (this->virtual_train_mode) { - widget_wagon->widget_data = STR_TMPL_CONFIRM; - widget_wagon->tool_tip = STR_TMPL_CONFIRM; - } else { - widget_wagon->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_WAGON_BUTTON; - widget_wagon->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_WAGON_TOOLTIP; - } - widget_wagon = this->GetWidget(WID_BV_RENAME_WAGON); widget_wagon->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_BUTTON; widget_wagon->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_TOOLTIP; @@ -2344,10 +2369,19 @@ struct BuildVehicleWindowTrainAdvanced : Window { this->eng_list_wagon.ForceRebuild(); this->GenerateBuildList(); // generate the list, since we need it in the next line - /* Select the first engine in the list as default when opening the window */ - if (!this->eng_list_loco.empty()) this->sel_engine_loco = this->eng_list_loco[0]; - if (!this->eng_list_wagon.empty()) this->sel_engine_wagon = this->eng_list_wagon[0]; + /* Select the first engine in the list as default when opening the window */ + if (this->eng_list_loco.empty()) { + this->SelectLocomotive(INVALID_ENGINE); + } else { + this->SelectLocomotive(this->eng_list_loco[0]); + } + + if (this->eng_list_wagon.empty()) { + this->SelectWagon(INVALID_ENGINE); + } else { + this->SelectWagon(this->eng_list_wagon[0]); + } } /** Set the filter type according to the depot type */ @@ -2447,7 +2481,77 @@ struct BuildVehicleWindowTrainAdvanced : Window { this->eng_list_wagon.SetFilterState(this->cargo_filter_wagon[this->cargo_filter_criteria_wagon] != CF_ANY); } - void OnInit() + void SelectLocomotive(const EngineID engine) + { + CargoID cargo = this->cargo_filter_loco[this->cargo_filter_criteria_loco]; + if (cargo == CF_ANY) cargo = CF_NONE; + + this->sel_engine_loco = engine; + this->SetBuyLocomotiveText(); + + if (this->sel_engine_loco == INVALID_ENGINE) return; + + const Engine *e = Engine::Get(this->sel_engine_loco); + if (!e->CanCarryCargo()) { + this->te.cost = 0; + this->te.cargo = CT_INVALID; + return; + } + + if (!this->listview_mode) { + /* Query for cost and refitted capacity */ + const CommandCost ret = DoCommand(this->window_number, this->sel_engine_loco | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr); + if (ret.Succeeded()) { + this->te.cost = ret.GetCost() - e->GetCost(); + this->te.capacity = _returned_refit_capacity; + this->te.mail_capacity = _returned_mail_refit_capacity; + this->te.cargo = (cargo == CT_INVALID) ? e->GetDefaultCargoType() : cargo; + return; + } + } + + /* Purchase test was not possible or failed, fill in the defaults instead. */ + this->te.cost = 0; + this->te.capacity = e->GetDisplayDefaultCapacity(&this->te.mail_capacity); + this->te.cargo = e->GetDefaultCargoType(); + } + + void SelectWagon(const EngineID engine) + { + CargoID cargo = this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]; + if (cargo == CF_ANY) cargo = CF_NONE; + + this->sel_engine_wagon = engine; + this->SetBuyWagonText(); + + if (this->sel_engine_wagon == INVALID_ENGINE) return; + + const Engine *e = Engine::Get(this->sel_engine_wagon); + if (!e->CanCarryCargo()) { + this->te.cost = 0; + this->te.cargo = CT_INVALID; + return; + } + + if (!this->listview_mode) { + /* Query for cost and refitted capacity */ + const CommandCost ret = DoCommand(this->window_number, this->sel_engine_wagon | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr); + if (ret.Succeeded()) { + this->te.cost = ret.GetCost() - e->GetCost(); + this->te.capacity = _returned_refit_capacity; + this->te.mail_capacity = _returned_mail_refit_capacity; + this->te.cargo = (cargo == CT_INVALID) ? e->GetDefaultCargoType() : cargo; + return; + } + } + + /* Purchase test was not possible or failed, fill in the defaults instead. */ + this->te.cost = 0; + this->te.capacity = e->GetDisplayDefaultCapacity(&this->te.mail_capacity); + this->te.cargo = e->GetDefaultCargoType(); + } + + void OnInit() override { this->SetCargoFilterArray(); } @@ -2523,14 +2627,13 @@ struct BuildVehicleWindowTrainAdvanced : Window { if (eid == this->sel_engine_loco) sel_id_loco = eid; } - this->sel_engine_loco = sel_id_loco; + this->SelectLocomotive(sel_id_loco); /* Wagons */ EngineID sel_id_wagon = INVALID_ENGINE; - int num_engines_wagon = 0; int num_wagons_wagon = 0; this->eng_list_wagon.clear(); @@ -2559,7 +2662,10 @@ struct BuildVehicleWindowTrainAdvanced : Window { if (eid == this->sel_engine_wagon) sel_id_wagon = eid; } - this->sel_engine_wagon = sel_id_wagon; + this->SelectWagon(sel_id_wagon); + + /* invalidate cached values for name sorter - engine names could change */ + _last_engine[0] = _last_engine[1] = INVALID_ENGINE; /* Sort locomotives */ _internal_sort_order_loco = this->descending_sort_order_loco; @@ -2567,7 +2673,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { /* Sort wagons */ _internal_sort_order_wagon = this->descending_sort_order_wagon; - EngList_SortPartial(&this->eng_list_wagon, _sorter_wagon[this->sort_criteria_wagon], num_engines_wagon, num_wagons_wagon); + EngList_SortPartial(&this->eng_list_wagon, _sorter_wagon[this->sort_criteria_wagon], 0, num_wagons_wagon); } @@ -2576,8 +2682,14 @@ struct BuildVehicleWindowTrainAdvanced : Window { { if (!this->eng_list_loco.NeedRebuild() && !this->eng_list_wagon.NeedRebuild()) return; + /* Update filter type in case the rail type of the depot got converted */ + this->UpdateFilterByTile(); this->GenerateBuildTrainList(); + + this->eng_list_loco.shrink_to_fit(); this->eng_list_loco.RebuildDone(); + + this->eng_list_wagon.shrink_to_fit(); this->eng_list_wagon.RebuildDone(); } @@ -2587,7 +2699,6 @@ struct BuildVehicleWindowTrainAdvanced : Window { /* Locomotives */ - case WID_BV_SORT_ASSENDING_DESCENDING_LOCO: { this->descending_sort_order_loco ^= true; _last_sort_order_loco = this->descending_sort_order_loco; @@ -2668,7 +2779,6 @@ struct BuildVehicleWindowTrainAdvanced : Window { break; } - /* Wagons */ case WID_BV_SORT_ASSENDING_DESCENDING_WAGON: { diff --git a/src/lang/english.txt b/src/lang/english.txt index 9a1b5886de..24ffc38470 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4620,6 +4620,8 @@ STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Vehicle STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Ship STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Aircraft +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_LOCOMOTIVE_BUTTON :{BLACK}Buy and Refit Locomotive +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_WAGON_BUTTON :{BLACK}Buy and Refit Wagon STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted train vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted road vehicle. Shift+Click shows estimated cost without purchase @@ -4632,6 +4634,8 @@ STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted road vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted ship. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted aircraft. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_LOCOMOTIVE_TOOLTIP :{BLACK}Buy and refit the highlighted locomotive or power car. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_WAGON_TOOLTIP :{BLACK}Buy and refit the highlighted wagon. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Rename From 790b73ea3d6209a4b1b77a6084ea7e9c18466540 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Sun, 20 Jun 2021 19:56:35 +0200 Subject: [PATCH 04/17] Cleanup some code --- src/build_vehicle_gui.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 4d680dd48a..7baaa6e930 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -3165,10 +3165,11 @@ void CcAddVirtualEngine(const CommandCost &result, TileIndex tile, uint32 p1, ui { if (result.Failed()) return; - Window* window = FindWindowById(WC_BUILD_VIRTUAL_TRAIN, 0); - if (window) { - Train* train = Train::From(Vehicle::Get(_new_vehicle_id)); - ((BuildVehicleWindow*) window)->AddVirtualEngine(train); + Window *window = FindWindowById(WC_BUILD_VIRTUAL_TRAIN, 0); + + if (window != nullptr) { + Train *train = Train::From(Vehicle::Get(_new_vehicle_id)); + dynamic_cast(window)->AddVirtualEngine(train); } else { DoCommandP(0, _new_vehicle_id | (1 << 21), 0, CMD_SELL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_SELL_TRAIN)); } @@ -3178,13 +3179,15 @@ void CcMoveNewVirtualEngine(const CommandCost &result, TileIndex tile, uint32 p1 { if (result.Failed()) return; - Window* window = FindWindowById(WC_BUILD_VIRTUAL_TRAIN, 0); - if (window) { + Window *window = FindWindowById(WC_BUILD_VIRTUAL_TRAIN, 0); + + if (window != nullptr) { if (result.IsSuccessWithMessage()) { - CommandCost res = result.UnwrapSuccessWithMessage(); + const CommandCost res = result.UnwrapSuccessWithMessage(); ShowErrorMessage(STR_ERROR_CAN_T_MOVE_VEHICLE, res.GetErrorMessage(), WL_INFO, 0, 0, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack(), res.GetExtraErrorMessage()); } } + InvalidateWindowClassesData(WC_CREATE_TEMPLATE); } @@ -3209,13 +3212,13 @@ static WindowDesc _build_template_vehicle_desc( _nested_build_vehicle_widgets_train_advanced, lengthof(_nested_build_vehicle_widgets_train_advanced) ); -void ShowBuildVehicleWindow(TileIndex tile, VehicleType type) +void ShowBuildVehicleWindow(const TileIndex tile, const VehicleType type) { /* We want to be able to open both Available Train as Available Ships, * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number. * As it always is a low value, it won't collide with any real tile * number. */ - uint num = (tile == INVALID_TILE) ? (int)type : tile; + const uint num = (tile == INVALID_TILE) ? static_cast(type) : tile; assert(IsCompanyBuildableVehicleType(type)); From 58c00d169e32b552882a4d87ea63affac8b8f52c Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Sun, 20 Jun 2021 20:12:42 +0200 Subject: [PATCH 05/17] Adjust OnClick --- src/build_vehicle_gui.cpp | 126 +++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 48 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 7baaa6e930..58b6c0c53a 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1517,10 +1517,10 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList * * Display the dropdown for the vehicle sort criteria. * @param w Parent window (holds the dropdown button). * @param vehicle_type %Vehicle type being sorted. - * @param selected Currently selected sort criterium. + * @param selected Currently selected sort criterion. * @param button Widget button. */ -void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, int button) +void DisplayVehicleSortDropDown(Window *w, const VehicleType vehicle_type, const int selected, const int button) { uint32 hidden_mask = 0; /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */ @@ -1536,6 +1536,34 @@ void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selecte ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask); } +/** + * Display the dropdown for the locomotive sort criteria. + * @param w Parent window (holds the dropdown button). + * @param selected Currently selected sort criterion. + */ +void DisplayLocomotiveSortDropDown(Window *w, int selected) +{ + uint32 hidden_mask = 0; + /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ + SetBit(hidden_mask, 4); // tractive effort + ShowDropDownMenu(w, _sort_listing_loco, selected, WID_BV_SORT_DROPDOWN_LOCO, 0, hidden_mask); +} + +/** + * Display the dropdown for the wagon sort criteria. + * @param w Parent window (holds the dropdown button). + * @param selected Currently selected sort criterion. + */ +void DisplayWagonSortDropDown(Window *w, int selected) +{ + uint32 hidden_mask = 0; + /* Disable sorting by maximum speed when wagon speed is disabled. */ + if (!_settings_game.vehicle.wagon_speed_limits) { + SetBit(hidden_mask, 2); // maximum speed + } + ShowDropDownMenu(w, _sort_listing_wagon, selected, WID_BV_SORT_DROPDOWN_WAGON, 0, hidden_mask); +} + /** GUI for building vehicles. */ struct BuildVehicleWindow : Window { VehicleType vehicle_type; ///< Type of vehicles shown in the window. @@ -2717,8 +2745,8 @@ struct BuildVehicleWindowTrainAdvanced : Window { } case WID_BV_LIST_LOCO: { - uint i = this->vscroll_loco->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST_LOCO); - size_t num_items = this->eng_list_loco.size(); + const uint i = this->vscroll_loco->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST_LOCO); + const size_t num_items = this->eng_list_loco.size(); this->sel_engine_loco = (i < num_items) ? this->eng_list_loco[i] : INVALID_ENGINE; this->SetDirty(); @@ -2731,13 +2759,8 @@ struct BuildVehicleWindowTrainAdvanced : Window { break; } - case WID_BV_SORT_DROPDOWN_LOCO: { // Select sorting criteria dropdown menu - uint32 hidden_mask = 0; - /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ - if (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { - SetBit(hidden_mask, 4); // tractive effort - } - ShowDropDownMenu(this, _sort_listing_loco, this->sort_criteria_loco, WID_BV_SORT_DROPDOWN_LOCO, 0, hidden_mask); + case WID_BV_SORT_DROPDOWN_LOCO: { + DisplayLocomotiveSortDropDown(this, this->sort_criteria_loco); break; } @@ -2747,33 +2770,39 @@ struct BuildVehicleWindowTrainAdvanced : Window { } case WID_BV_SHOW_HIDE_LOCO: { - const Engine *e = (this->sel_engine_loco == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_loco); - if (e != nullptr) { - DoCommandP(0, 0, this->sel_engine_loco | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY); + const Engine *engine = (this->sel_engine_loco == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_loco); + if (engine != nullptr) { + DoCommandP(0, 0, this->sel_engine_loco | (engine->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY); } break; } case WID_BV_BUILD_LOCO: { - EngineID sel_eng = this->sel_engine_loco; - if (sel_eng != INVALID_ENGINE) { + const EngineID selected_loco = this->sel_engine_loco; + if (selected_loco != INVALID_ENGINE) { + CommandCallback *callback; + uint32 cmd; if (this->virtual_train_mode) { - DoCommandP(0, sel_eng, 0, CMD_BUILD_VIRTUAL_RAIL_VEHICLE, CcAddVirtualEngine); - } - else { - CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle; - DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback); + callback = CcAddVirtualEngine; + cmd = CMD_BUILD_VIRTUAL_RAIL_VEHICLE; + } else { + callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(selected_loco)->railveh_type == RAILVEH_WAGON) + ? CcBuildWagon : CcBuildPrimaryVehicle; + cmd = GetCmdBuildVeh(this->vehicle_type); } + CargoID cargo = this->cargo_filter_loco[this->cargo_filter_criteria_loco]; + if (cargo == CF_ANY || cargo == CF_ENGINES) cargo = CF_NONE; + DoCommandP(this->window_number, selected_loco | (cargo << 24), 0, cmd, callback); } break; } case WID_BV_RENAME_LOCO: { - EngineID sel_eng = this->sel_engine_loco; - if (sel_eng != INVALID_ENGINE) { - this->rename_engine_loco = sel_eng; + const EngineID selected_loco = this->sel_engine_loco; + if (selected_loco != INVALID_ENGINE) { + this->rename_engine_loco = selected_loco; this->rename_engine_wagon = INVALID_ENGINE; - SetDParam(0, sel_eng); + SetDParam(0, selected_loco); ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_LOCOMOTIVE_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); } break; @@ -2799,8 +2828,8 @@ struct BuildVehicleWindowTrainAdvanced : Window { } case WID_BV_LIST_WAGON: { - uint i = this->vscroll_wagon->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST_WAGON); - size_t num_items = this->eng_list_wagon.size(); + const uint i = this->vscroll_wagon->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST_WAGON); + const size_t num_items = this->eng_list_wagon.size(); this->sel_engine_wagon = (i < num_items) ? this->eng_list_wagon[i] : INVALID_ENGINE; this->SetDirty(); @@ -2813,13 +2842,8 @@ struct BuildVehicleWindowTrainAdvanced : Window { break; } - case WID_BV_SORT_DROPDOWN_WAGON: { // Select sorting criteria dropdown menu - uint32 hidden_mask = 0; - /* Disable sorting by maximum speed when wagon speed is disabled. */ - if (!_settings_game.vehicle.wagon_speed_limits) { - SetBit(hidden_mask, 2); // maximum speed - } - ShowDropDownMenu(this, _sort_listing_wagon, this->sort_criteria_wagon, WID_BV_SORT_DROPDOWN_WAGON, 0, hidden_mask); + case WID_BV_SORT_DROPDOWN_WAGON: { + DisplayWagonSortDropDown(this, this->sort_criteria_wagon); break; } @@ -2829,33 +2853,39 @@ struct BuildVehicleWindowTrainAdvanced : Window { } case WID_BV_SHOW_HIDE_WAGON: { - const Engine *e = (this->sel_engine_wagon == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_wagon); - if (e != nullptr) { - DoCommandP(0, 0, this->sel_engine_wagon | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY); + const Engine *engine = (this->sel_engine_wagon == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_wagon); + if (engine != nullptr) { + DoCommandP(0, 0, this->sel_engine_wagon | (engine->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY); } break; } case WID_BV_BUILD_WAGON: { - EngineID sel_eng = this->sel_engine_wagon; - if (sel_eng != INVALID_ENGINE) { + const EngineID selected_wagon = this->sel_engine_loco; + if (selected_wagon != INVALID_ENGINE) { + CommandCallback *callback; + uint32 cmd; if (this->virtual_train_mode) { - DoCommandP(0, sel_eng, 0, CMD_BUILD_VIRTUAL_RAIL_VEHICLE, CcAddVirtualEngine); - } - else { - CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle; - DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback); + callback = CcAddVirtualEngine; + cmd = CMD_BUILD_VIRTUAL_RAIL_VEHICLE; + } else { + callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(selected_wagon)->railveh_type == RAILVEH_WAGON) + ? CcBuildWagon : CcBuildPrimaryVehicle; + cmd = GetCmdBuildVeh(this->vehicle_type); } + CargoID cargo = this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]; + if (cargo == CF_ANY || cargo == CF_ENGINES) cargo = CF_NONE; + DoCommandP(this->window_number, selected_wagon | (cargo << 24), 0, cmd, callback); } break; } case WID_BV_RENAME_WAGON: { - EngineID sel_eng = this->sel_engine_wagon; - if (sel_eng != INVALID_ENGINE) { + const EngineID selected_wagon = this->sel_engine_wagon; + if (selected_wagon != INVALID_ENGINE) { this->rename_engine_loco = INVALID_ENGINE; - this->rename_engine_wagon = sel_eng; - SetDParam(0, sel_eng); + this->rename_engine_wagon = selected_wagon; + SetDParam(0, selected_wagon); ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_WAGON_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); } break; From 081131c29876a6bbc2e356e8c1ff343f408dc94f Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Sun, 20 Jun 2021 20:30:07 +0200 Subject: [PATCH 06/17] Make final adjustments and cleanup --- src/build_vehicle_gui.cpp | 180 ++++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 86 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 58b6c0c53a..398c117553 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -2231,7 +2231,7 @@ struct BuildVehicleWindow : Window { }; /** Advanced window for trains. It is divided into two parts, one for locomotives and one for wagons. */ -struct BuildVehicleWindowTrainAdvanced : Window { +struct BuildVehicleWindowTrainAdvanced final : Window { /* Locomotives and wagons */ @@ -2242,38 +2242,38 @@ struct BuildVehicleWindowTrainAdvanced : Window { /* Locomotives */ - bool descending_sort_order_loco; ///< Sort direction, @see _engine_sort_direction - byte sort_criteria_loco; ///< Current sort criterium for locomotives. - EngineID sel_engine_loco; ///< Currently selected engine, or #INVALID_ENGINE - EngineID rename_engine_loco; ///< Engine being renamed. + bool descending_sort_order_loco; ///< Sort direction, @see _engine_sort_direction + byte sort_criteria_loco; ///< Current sort criterium for locomotives. + EngineID sel_engine_loco; ///< Currently selected engine, or #INVALID_ENGINE + EngineID rename_engine_loco {}; ///< Engine being renamed. GUIEngineList eng_list_loco; Scrollbar *vscroll_loco; - byte cargo_filter_criteria_loco; ///< Selected cargo filter - bool show_hidden_locos; ///< State of the 'show hidden locomotives' button. - int details_height_loco; ///< Minimal needed height of the details panels (found so far). - CargoID cargo_filter_loco[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE - StringID cargo_filter_texts_loco[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID + byte cargo_filter_criteria_loco {}; ///< Selected cargo filter + bool show_hidden_locos; ///< State of the 'show hidden locomotives' button. + int details_height_loco; ///< Minimal needed height of the details panels (found so far). + CargoID cargo_filter_loco[NUM_CARGO + 2] {}; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE + StringID cargo_filter_texts_loco[NUM_CARGO + 3] {}; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID /* Wagons */ - bool descending_sort_order_wagon; ///< Sort direction, @see _engine_sort_direction - byte sort_criteria_wagon; ///< Current sort criterium for wagons. - EngineID sel_engine_wagon; ///< Currently selected engine, or #INVALID_ENGINE - EngineID rename_engine_wagon; ///< Engine being renamed. + bool descending_sort_order_wagon; ///< Sort direction, @see _engine_sort_direction + byte sort_criteria_wagon; ///< Current sort criterion for wagons. + EngineID sel_engine_wagon; ///< Currently selected engine, or #INVALID_ENGINE + EngineID rename_engine_wagon {}; ///< Engine being renamed. GUIEngineList eng_list_wagon; Scrollbar *vscroll_wagon; - byte cargo_filter_criteria_wagon; ///< Selected cargo filter - bool show_hidden_wagons; ///< State of the 'show hidden wagons' button. - int details_height_wagon; ///< Minimal needed height of the details panels (found so far). - CargoID cargo_filter_wagon[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE - StringID cargo_filter_texts_wagon[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID + byte cargo_filter_criteria_wagon {}; ///< Selected cargo filter + bool show_hidden_wagons; ///< State of the 'show hidden wagons' button. + int details_height_wagon; ///< Minimal needed height of the details panels (found so far). + CargoID cargo_filter_wagon[NUM_CARGO + 2] {}; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE + StringID cargo_filter_texts_wagon[NUM_CARGO + 3] {}; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID - bool virtual_train_mode; ///< Are we building a virtual train? - Train **virtual_train_out; ///< Virtual train ptr + bool virtual_train_mode; ///< Are we building a virtual train? + Train **virtual_train_out; ///< Virtual train ptr - TestedEngineDetails te; ///< Tested cost and capacity after refit. + TestedEngineDetails te; ///< Tested cost and capacity after refit. void SetBuyLocomotiveText() { @@ -2320,7 +2320,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { BuildVehicleWindowTrainAdvanced(WindowDesc *desc, TileIndex tile, Train **virtual_train_out) : Window(desc) { this->vehicle_type = VEH_TRAIN; - this->window_number = tile == INVALID_TILE ? (int)VEH_TRAIN : tile; + this->window_number = tile == INVALID_TILE ? static_cast(VEH_TRAIN) : tile; this->virtual_train_out = virtual_train_out; this->virtual_train_mode = (virtual_train_out != nullptr); @@ -2353,7 +2353,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { /* Locomotives */ - NWidgetCore *widget_loco = this->GetWidget(WID_BV_LIST_LOCO); + auto widget_loco = this->GetWidget(WID_BV_LIST_LOCO); widget_loco->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + VEH_TRAIN; widget_loco = this->GetWidget(WID_BV_SHOW_HIDE_LOCO); @@ -2370,7 +2370,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { /* Wagons */ - NWidgetCore *widget_wagon = this->GetWidget(WID_BV_LIST_WAGON); + auto widget_wagon = this->GetWidget(WID_BV_LIST_WAGON); widget_wagon->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + VEH_TRAIN; widget_wagon = this->GetWidget(WID_BV_SHOW_HIDE_WAGON); @@ -2475,7 +2475,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { filter_items_wagon++; /* Add item for vehicles not carrying anything, e.g. train engines. - * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */ + * This could also be useful for eye candy vehicles of other types, but is likely too confusing for joe, */ this->cargo_filter_wagon[filter_items_wagon] = CF_NONE; this->cargo_filter_texts_wagon[filter_items_wagon] = STR_PURCHASE_INFO_NONE; @@ -2544,18 +2544,18 @@ struct BuildVehicleWindowTrainAdvanced : Window { this->te.cargo = e->GetDefaultCargoType(); } - void SelectWagon(const EngineID engine) + void SelectWagon(const EngineID eid) { CargoID cargo = this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]; if (cargo == CF_ANY) cargo = CF_NONE; - this->sel_engine_wagon = engine; + this->sel_engine_wagon = eid; this->SetBuyWagonText(); if (this->sel_engine_wagon == INVALID_ENGINE) return; - const Engine *e = Engine::Get(this->sel_engine_wagon); - if (!e->CanCarryCargo()) { + const Engine *engine = Engine::Get(this->sel_engine_wagon); + if (!engine->CanCarryCargo()) { this->te.cost = 0; this->te.cargo = CT_INVALID; return; @@ -2565,18 +2565,18 @@ struct BuildVehicleWindowTrainAdvanced : Window { /* Query for cost and refitted capacity */ const CommandCost ret = DoCommand(this->window_number, this->sel_engine_wagon | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr); if (ret.Succeeded()) { - this->te.cost = ret.GetCost() - e->GetCost(); + this->te.cost = ret.GetCost() - engine->GetCost(); this->te.capacity = _returned_refit_capacity; this->te.mail_capacity = _returned_mail_refit_capacity; - this->te.cargo = (cargo == CT_INVALID) ? e->GetDefaultCargoType() : cargo; + this->te.cargo = (cargo == CT_INVALID) ? engine->GetDefaultCargoType() : cargo; return; } } /* Purchase test was not possible or failed, fill in the defaults instead. */ this->te.cost = 0; - this->te.capacity = e->GetDisplayDefaultCapacity(&this->te.mail_capacity); - this->te.cargo = e->GetDefaultCargoType(); + this->te.capacity = engine->GetDisplayDefaultCapacity(&this->te.mail_capacity); + this->te.cargo = engine->GetDefaultCargoType(); } void OnInit() override @@ -2636,10 +2636,10 @@ struct BuildVehicleWindowTrainAdvanced : Window { * Also check to see if the previously selected engine is still available, * and if not, reset selection to INVALID_ENGINE. This could be the case * when engines become obsolete and are removed */ - for (const Engine *e : Engine::IterateType(VEH_TRAIN)) { - if (!this->show_hidden_locos && e->IsHidden(_local_company)) continue; - EngineID eid = e->index; - const RailVehicleInfo *rvi = &e->u.rail; + for (const Engine *engine : Engine::IterateType(VEH_TRAIN)) { + if (!this->show_hidden_locos && engine->IsHidden(_local_company)) continue; + EngineID eid = engine->index; + const RailVehicleInfo *rvi = &engine->u.rail; if (this->railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->railtype)) continue; if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; @@ -2670,10 +2670,10 @@ struct BuildVehicleWindowTrainAdvanced : Window { * Also check to see if the previously selected engine is still available, * and if not, reset selection to INVALID_ENGINE. This could be the case * when engines become obsolete and are removed */ - for (const Engine *e : Engine::IterateType(VEH_TRAIN)) { - if (!this->show_hidden_wagons && e->IsHidden(_local_company)) continue; - EngineID eid = e->index; - const RailVehicleInfo *rvi = &e->u.rail; + for (const Engine *engine : Engine::IterateType(VEH_TRAIN)) { + if (!this->show_hidden_wagons && engine->IsHidden(_local_company)) continue; + EngineID eid = engine->index; + const RailVehicleInfo *rvi = &engine->u.rail; if (this->railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->railtype)) continue; if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; @@ -2721,7 +2721,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { this->eng_list_wagon.RebuildDone(); } - void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { @@ -2898,7 +2898,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { * @param data Information about the changed data. * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. */ - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; @@ -2907,11 +2907,11 @@ struct BuildVehicleWindowTrainAdvanced : Window { this->eng_list_wagon.ForceRebuild(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_BV_CAPTION: { - if (this->vehicle_type == VEH_TRAIN && !this->listview_mode && !this->virtual_train_mode) { + if (!this->listview_mode && !this->virtual_train_mode) { const RailtypeInfo *rti = GetRailTypeInfo(this->railtype); SetDParam(0, rti->strings.build_caption); } else { @@ -2926,8 +2926,8 @@ struct BuildVehicleWindowTrainAdvanced : Window { } case WID_BV_SHOW_HIDE_LOCO: { - const Engine *e = (this->sel_engine_loco == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_loco); - if (e != nullptr && e->IsHidden(_local_company)) { + const Engine *engine = (this->sel_engine_loco == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_loco); + if (engine != nullptr && engine->IsHidden(_local_company)) { SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type); } else { @@ -2962,8 +2962,8 @@ struct BuildVehicleWindowTrainAdvanced : Window { } case WID_BV_SHOW_HIDE_WAGON: { - const Engine *e = (this->sel_engine_wagon == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_wagon); - if (e != nullptr && e->IsHidden(_local_company)) { + const Engine *engine = (this->sel_engine_wagon == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_wagon); + if (engine != nullptr && engine->IsHidden(_local_company)) { SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type); } else { @@ -2974,7 +2974,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BV_LIST_LOCO: { @@ -3015,14 +3015,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { break; } - case WID_BV_SHOW_HIDE_LOCO: { - *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); - *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type)); - size->width += padding.width; - size->height += padding.height; - break; - } - + case WID_BV_SHOW_HIDE_LOCO: // Fallthrough case WID_BV_SHOW_HIDE_WAGON: { *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type)); @@ -3033,11 +3026,15 @@ struct BuildVehicleWindowTrainAdvanced : Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_BV_LIST_LOCO: { - DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list_loco, this->vscroll_loco->GetPosition(), std::min(this->vscroll_loco->GetPosition() + this->vscroll_loco->GetCapacity(), this->eng_list_loco.size()), this->sel_engine_loco, false, DEFAULT_GROUP); + DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, + r.top + WD_FRAMERECT_TOP, &this->eng_list_loco, this->vscroll_loco->GetPosition(), + std::min(this->vscroll_loco->GetPosition() + this->vscroll_loco->GetCapacity(), + static_cast(this->eng_list_loco.size())), this->sel_engine_loco, false, + DEFAULT_GROUP); break; } @@ -3047,7 +3044,11 @@ struct BuildVehicleWindowTrainAdvanced : Window { } case WID_BV_LIST_WAGON: { - DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list_wagon, this->vscroll_wagon->GetPosition(), std::min(this->vscroll_wagon->GetPosition() + this->vscroll_wagon->GetCapacity(), this->eng_list_wagon.size()), this->sel_engine_wagon, false, DEFAULT_GROUP); + DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, + r.top + WD_FRAMERECT_TOP, &this->eng_list_wagon, this->vscroll_wagon->GetPosition(), + std::min(this->vscroll_wagon->GetPosition() + this->vscroll_wagon->GetCapacity(), + static_cast(this->eng_list_wagon.size())), this->sel_engine_wagon, false, + DEFAULT_GROUP); break; } @@ -3058,11 +3059,11 @@ struct BuildVehicleWindowTrainAdvanced : Window { } } - virtual void OnPaint() + void OnPaint() override { this->GenerateBuildList(); - this->vscroll_loco->SetCount(this->eng_list_loco.size()); - this->vscroll_wagon->SetCount(this->eng_list_wagon.size()); + this->vscroll_loco->SetCount(static_cast(this->eng_list_loco.size())); + this->vscroll_wagon->SetCount(static_cast(this->eng_list_wagon.size())); this->SetWidgetDisabledState(WID_BV_SHOW_HIDE_LOCO, this->sel_engine_loco == INVALID_ENGINE); this->SetWidgetDisabledState(WID_BV_SHOW_HIDE_WAGON, this->sel_engine_wagon == INVALID_ENGINE); @@ -3081,13 +3082,16 @@ struct BuildVehicleWindowTrainAdvanced : Window { int needed_height_loco = this->details_height_loco; /* Draw details panels. */ if (this->sel_engine_loco != INVALID_ENGINE) { - NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL_LOCO); - int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, - nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine_loco, this->te); - needed_height_loco = std::max(needed_height_loco, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + const auto widget = this->GetWidget(WID_BV_PANEL_LOCO); + const int text_end = DrawVehiclePurchaseInfo(widget->pos_x + WD_FRAMETEXT_LEFT, + static_cast( + widget->pos_x + widget->current_x - + WD_FRAMETEXT_RIGHT), widget->pos_y + WD_FRAMERECT_TOP, + this->sel_engine_loco, this->te); + needed_height_loco = std::max(needed_height_loco, text_end - widget->pos_y + WD_FRAMERECT_BOTTOM); } if (needed_height_loco != this->details_height_loco) { // Details window are not high enough, enlarge them. - int resize = needed_height_loco - this->details_height_loco; + const int resize = needed_height_loco - this->details_height_loco; this->details_height_loco = needed_height_loco; this->ReInit(0, resize); return; @@ -3095,13 +3099,16 @@ struct BuildVehicleWindowTrainAdvanced : Window { int needed_height_wagon = this->details_height_wagon; if (this->sel_engine_wagon != INVALID_ENGINE) { - NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL_WAGON); - int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, - nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine_wagon, this->te); - needed_height_wagon = std::max(needed_height_wagon, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + const auto widget = this->GetWidget(WID_BV_PANEL_WAGON); + const int text_end = DrawVehiclePurchaseInfo(widget->pos_x + WD_FRAMETEXT_LEFT, + static_cast( + widget->pos_x + widget->current_x - + WD_FRAMETEXT_RIGHT), widget->pos_y + WD_FRAMERECT_TOP, + this->sel_engine_wagon, this->te); + needed_height_wagon = std::max(needed_height_wagon, text_end - widget->pos_y + WD_FRAMERECT_BOTTOM); } if (needed_height_wagon != this->details_height_wagon) { // Details window are not high enough, enlarge them. - int resize = needed_height_wagon - this->details_height_wagon; + const int resize = needed_height_wagon - this->details_height_wagon; this->details_height_wagon = needed_height_wagon; this->ReInit(0, resize); return; @@ -3109,9 +3116,10 @@ struct BuildVehicleWindowTrainAdvanced : Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (str == nullptr) return; + if(this->rename_engine_loco != INVALID_ENGINE) { DoCommandP(0, this->rename_engine_loco, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), nullptr, str); @@ -3122,12 +3130,12 @@ struct BuildVehicleWindowTrainAdvanced : Window { } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_BV_SORT_DROPDOWN_LOCO: { if (this->sort_criteria_loco != index) { - this->sort_criteria_loco = index; + this->sort_criteria_loco = static_cast(index); _last_sort_criteria_loco = this->sort_criteria_loco; this->eng_list_loco.ForceRebuild(); } @@ -3136,7 +3144,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { case WID_BV_CARGO_FILTER_DROPDOWN_LOCO: { // Select a cargo filter criteria if (this->cargo_filter_criteria_loco != index) { - this->cargo_filter_criteria_loco = index; + this->cargo_filter_criteria_loco = static_cast(index); _last_filter_criteria_loco = this->cargo_filter_loco[this->cargo_filter_criteria_loco]; /* deactivate filter if criteria is 'Show All', activate it otherwise */ this->eng_list_loco.SetFilterState(this->cargo_filter_loco[this->cargo_filter_criteria_loco] != CF_ANY); @@ -3147,7 +3155,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { case WID_BV_SORT_DROPDOWN_WAGON: { if (this->sort_criteria_wagon != index) { - this->sort_criteria_wagon = index; + this->sort_criteria_wagon = static_cast(index); _last_sort_criteria_wagon = this->sort_criteria_wagon; this->eng_list_wagon.ForceRebuild(); } @@ -3156,7 +3164,7 @@ struct BuildVehicleWindowTrainAdvanced : Window { case WID_BV_CARGO_FILTER_DROPDOWN_WAGON: { // Select a cargo filter criteria if (this->cargo_filter_criteria_wagon != index) { - this->cargo_filter_criteria_wagon = index; + this->cargo_filter_criteria_wagon = static_cast(index); _last_filter_criteria_wagon = this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]; /* deactivate filter if criteria is 'Show All', activate it otherwise */ this->eng_list_wagon.SetFilterState(this->cargo_filter_wagon[this->cargo_filter_criteria_wagon] != CF_ANY); @@ -3169,22 +3177,22 @@ struct BuildVehicleWindowTrainAdvanced : Window { this->SetDirty(); } - virtual void OnResize() + void OnResize() override { this->vscroll_loco->SetCapacityFromWidget(this, WID_BV_LIST_LOCO); this->vscroll_wagon->SetCapacityFromWidget(this, WID_BV_LIST_WAGON); } - void AddVirtualEngine(Train *toadd) + void AddVirtualEngine(Train *to_add) const { if (this->virtual_train_out == nullptr) return; if (*(this->virtual_train_out) == nullptr) { - *(this->virtual_train_out) = toadd; + *(this->virtual_train_out) = to_add; } else { - VehicleID target = (*(this->virtual_train_out))->GetLastUnit()->index; + const VehicleID target = (*(this->virtual_train_out))->GetLastUnit()->index; - DoCommandP(0, (1 << 21) | toadd->index, target, CMD_MOVE_RAIL_VEHICLE); + DoCommandP(0, (1 << 21) | to_add->index, target, CMD_MOVE_RAIL_VEHICLE); } InvalidateWindowClassesData(WC_CREATE_TEMPLATE); InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN); From b210a825b1aee7c9aebdaa30cf68a60a9f74c041 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Mon, 21 Jun 2021 01:10:49 +0200 Subject: [PATCH 07/17] Add German translations --- src/lang/german.txt | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/lang/german.txt b/src/lang/german.txt index f1724dd482..61f5fb0ff0 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -613,6 +613,11 @@ STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Zeige ke STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Diagrammschalter für Frachttyp ein/aus STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} +STR_GRAPH_CARGO_DAYS_MODE :{TINY_FONT}{BLACK}Tage unterwegs +STR_GRAPH_CARGO_SPEED_MODE :{TINY_FONT}{BLACK}Durchschnittsgeschwindigkeit +STR_GRAPH_CARGO_TOOLTIP_DAYS_MODE :{BLACK}Lieferzeit auf X-Achse des Diagramms anzeigen +STR_GRAPH_CARGO_TOOLTIP_SPEED_MODE :{BLACK}Durchschnittsgeschwindigkeit auf X-Achse des Diagramms anzeigen + STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Zeige detailierte Leistungsaufschlüsselung # Graph key window @@ -884,6 +889,7 @@ STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} hat sich verirrt STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}Der Ertrag von {VEHICLE} lag im letzten Jahr bei{}{CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} kann sein Ziel nicht erreichen, da es außer Reichweite liegt +STR_NEWS_TRAIN_OVERSHOT_STATION :{WHITE}{VEHICLE} konnte wegen zu hoher Geschwindigkeit nicht bei {STRING1} anhalten STR_NEWS_ORDER_REFIT_FAILED :{WHITE}Umrüstung fehlgeschlagen bei {VEHICLE} STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Automatisches Ersetzen für {VEHICLE} fehlgeschlagen{}{STRING} @@ -4426,6 +4432,9 @@ STR_BUY_VEHICLE_SHIP_CAPTION :Neue Schiffe STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Neue Flugzeuge ############ range for vehicle availability ends +STR_BUY_VEHICLE_TRAIN_LOCOMOTIVES :Lokomotiven und Triebköpfe +STR_BUY_VEHICLE_TRAIN_WAGONS :Waggons + STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Kosten: {GOLD}{CURRENCY_LONG}{BLACK} Gewicht: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Kosten: {GOLD}{CURRENCY_LONG}{BLACK} (Umrüstkosten: {GOLD}{CURRENCY_LONG}{BLACK}) Gewicht: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Geschw.: {GOLD}{VELOCITY}{BLACK} Leistung: {GOLD}{POWER} @@ -4468,30 +4477,40 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Fahrzeug STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Schiff kaufen STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Flugzeug kaufen -STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :Fahrzeug kaufen und umrüsten +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Fahrzeug kaufen und umrüsten STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Fahrzeug kaufen und umrüsten STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Schiff kaufen und umrüsten -STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :Flugzeug kaufen und umrüsten +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Flugzeug kaufen und umrüsten +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_LOCOMOTIVE_BUTTON :{BLACK}Lokomotive kaufen und umrüsten +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_WAGON_BUTTON :{BLACK}Waggon kaufen und umrüsten STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Ausgewähltes Fahrzeug kaufen. Shift+Klick zeigt einen Kostenvoranschlag STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Ausgewähltes Fahrzeug kaufen. Umschalt+Klick zeigt einen Kostenvoranschlag STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Ausgewähltes Schiff kaufen. Umschalt+Klick zeigt einen Kostenvoranschlag STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Augewähltes Flugzeug kaufen. Shift+Klick zeigt einen Kostenvoranschlag +STR_BUY_VEHICLE_TRAIN_BUY_LOCOMOTIVE_TOOLTIP :{BLACK}Augewählte Lokomotive oder Triebkopf kaufen. Shift+Klick zeigt einen Kostenvoranschlag +STR_BUY_VEHICLE_TRAIN_BUY_WAGON_TOOLTIP :{BLACK}Augewählten Waggon kaufen. Shift+Klick zeigt einen Kostenvoranschlag STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Ausgewähltes Fahrzeug kaufen und umrüsten. Umschalt+Klick zeigt einen Kostenvoranschlag STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Ausgewähltes Straßenfahrzeug kaufen und umrüsten. Umschalt+Klick zeigt einen Kostenvoranschlag STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Ausgewähltes Schiff kaufen und umrüsten. Umschalt+Klick zeigt einen Kostenvoranschlag STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Ausgewähltes Flugzeug kaufen und umrüsten. Umschalt+Klick zeigt einen Kostenvoranschlag +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_LOCOMOTIVE_TOOLTIP :{BLACK}Augewählte Lokomotive oder Triebkopf kaufen und umrüsten. Umschalt+Klick zeigt einen Kostenvoranschlag +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_WAGON_TOOLTIP :{BLACK}Augewählten Waggon kaufen und umrüsten. Umschalt+Klick zeigt einen Kostenvoranschlag STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Umbenennen STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Umbenennen STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Umbenennen STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Umbenennen +STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_BUTTON :{BLACK}Lokomotive umbenennen +STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_BUTTON :{BLACK}Waggon umbenennen STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Umbenennen der Waggontypen STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Fahrzeug umbenennen STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Schiff umbenennen STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Flugzeug umbenennen +STR_BUY_VEHICLE_TRAIN_RENAME_LOCOMOTIVE_TOOLTIP :{BLACK}Lokomotive oder Triebkopf umbenennen +STR_BUY_VEHICLE_TRAIN_RENAME_WAGON_TOOLTIP :{BLACK}Waggon umbenennen STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON :{BLACK}Ausblenden STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_TOGGLE_BUTTON :{BLACK}Ausblenden @@ -4512,6 +4531,8 @@ STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Zugtyp u STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Fahrzeug umbenennen STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Schiff umbenennen STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Flugzeug umbenennen +STR_QUERY_RENAME_TRAIN_TYPE_LOCOMOTIVE_CAPTION :{WHITE}Lokomotive umbenennen +STR_QUERY_RENAME_TRAIN_TYPE_WAGON_CAPTION :{WHITE}Waggon umbenennen # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} From 2370df82aa09b9114515e194220b797f5c770b31 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Mon, 21 Jun 2021 07:56:58 +0200 Subject: [PATCH 08/17] Fix string parameter --- src/lang/german.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/german.txt b/src/lang/german.txt index 61f5fb0ff0..fbc4aa3bc6 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -889,7 +889,7 @@ STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} hat sich verirrt STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}Der Ertrag von {VEHICLE} lag im letzten Jahr bei{}{CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} kann sein Ziel nicht erreichen, da es außer Reichweite liegt -STR_NEWS_TRAIN_OVERSHOT_STATION :{WHITE}{VEHICLE} konnte wegen zu hoher Geschwindigkeit nicht bei {STRING1} anhalten +STR_NEWS_TRAIN_OVERSHOT_STATION :{WHITE}{VEHICLE} konnte wegen zu hoher Geschwindigkeit nicht bei {STRING} anhalten STR_NEWS_ORDER_REFIT_FAILED :{WHITE}Umrüstung fehlgeschlagen bei {VEHICLE} STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Automatisches Ersetzen für {VEHICLE} fehlgeschlagen{}{STRING} From 225e1ca63461e886407753eeff7e04b21ead4f83 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Mon, 21 Jun 2021 08:24:16 +0200 Subject: [PATCH 09/17] Rearrange file to increase diff readability --- src/build_vehicle_gui.cpp | 815 +++++++++++++++++++------------------- 1 file changed, 407 insertions(+), 408 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 398c117553..a8573f3638 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -49,9 +49,7 @@ uint GetEngineListHeight(VehicleType type) return std::max(FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM, GetVehicleImageCellSize(type, EIT_PURCHASE).height); } -/** - * Normal layout for roadvehicles, ships and airplanes. -*/ +/* Normal layout for roadvehicles, ships and airplanes. */ static const NWidgetPart _nested_build_vehicle_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), @@ -547,323 +545,6 @@ static bool AircraftRangeSorter(const EngineID &a, const EngineID &b) return _engine_sort_direction ? r > 0 : r < 0; } -/* Locomotive sorting functions. */ -/** - * Determines order of locomotives by engineID - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineNumberSorterLoco(const EngineID &a, const EngineID &b) -{ - int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; - - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by introduction date - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineIntroDateSorterLoco(const EngineID &a, const EngineID &b) -{ - const int va = Engine::Get(a)->intro_date; - const int vb = Engine::Get(b)->intro_date; - const int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by name - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineNameSorterLoco(const EngineID &a, const EngineID &b) -{ - static char last_name[2][64] = { "", "" }; - - if (a != _last_engine[0]) { - _last_engine[0] = a; - SetDParam(0, a); - GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); - } - - if (b != _last_engine[1]) { - _last_engine[1] = b; - SetDParam(0, b); - GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); - } - - int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by purchase cost - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineCostSorterLoco(const EngineID &a, const EngineID &b) -{ - Money va = Engine::Get(a)->GetCost(); - Money vb = Engine::Get(b)->GetCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by speed - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineSpeedSorterLoco(const EngineID &a, const EngineID &b) -{ - int va = Engine::Get(a)->GetDisplayMaxSpeed(); - int vb = Engine::Get(b)->GetDisplayMaxSpeed(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by power - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EnginePowerSorterLoco(const EngineID &a, const EngineID &b) -{ - int va = Engine::Get(a)->GetPower(); - int vb = Engine::Get(b)->GetPower(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by tractive effort - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineTractiveEffortSorterLoco(const EngineID &a, const EngineID &b) -{ - int va = Engine::Get(a)->GetDisplayMaxTractiveEffort(); - int vb = Engine::Get(b)->GetDisplayMaxTractiveEffort(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by running costs - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineRunningCostSorterLoco(const EngineID &a, const EngineID &b) -{ - Money va = Engine::Get(a)->GetRunningCost(); - Money vb = Engine::Get(b)->GetRunningCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by running costs - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EnginePowerVsRunningCostSorterLoco(const EngineID &a, const EngineID &b) -{ - const Engine *e_a = Engine::Get(a); - const Engine *e_b = Engine::Get(b); - uint p_a = e_a->GetPower(); - uint p_b = e_b->GetPower(); - Money r_a = e_a->GetRunningCost(); - Money r_b = e_b->GetRunningCost(); - /* Check if running cost is zero in one or both engines. - * If only one of them is zero then that one has higher value, - * else if both have zero cost then compare powers. */ - if (r_a == 0) { - if (r_b == 0) { - /* If it is ambiguous which to return go with their ID */ - if (p_a == p_b) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco != (p_a < p_b); - } - return !_internal_sort_order_loco; - } - if (r_b == 0) return _internal_sort_order_loco; - /* Using double for more precision when comparing close values. - * This shouldn't have any major effects in performance nor in keeping - * the game in sync between players since it's used in GUI only in client side */ - double v_a = (double)p_a / (double)r_a; - double v_b = (double)p_b / (double)r_b; - /* Use EngineID to sort if both have same power/running cost, - * since we want consistent sorting. - * Also if both have no power then sort with reverse of running cost to simulate - * previous sorting behaviour for wagons. */ - if (v_a == 0 && v_b == 0) return !EngineRunningCostSorterLoco(a, b); - if (v_a == v_b) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco != (v_a < v_b); -} - -/* Wagon sorting functions. */ - -/** - * Determines order of wagons by engineID - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineNumberSorterWagon(const EngineID &a, const EngineID &b) -{ - int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; - - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by introduction date - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineIntroDateSorterWagon(const EngineID &a, const EngineID &b) -{ - const int va = Engine::Get(a)->intro_date; - const int vb = Engine::Get(b)->intro_date; - const int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by name - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineNameSorterWagon(const EngineID &a, const EngineID &b) -{ - static char last_name[2][64] = { "", "" }; - - if (a != _last_engine[0]) { - _last_engine[0] = a; - SetDParam(0, a); - GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); - } - - if (b != _last_engine[1]) { - _last_engine[1] = b; - SetDParam(0, b); - GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); - } - - int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by purchase cost - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineCostSorterWagon(const EngineID &a, const EngineID &b) -{ - Money va = Engine::Get(a)->GetCost(); - Money vb = Engine::Get(b)->GetCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by speed - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineSpeedSorterWagon(const EngineID &a, const EngineID &b) -{ - int va = Engine::Get(a)->GetDisplayMaxSpeed(); - int vb = Engine::Get(b)->GetDisplayMaxSpeed(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by running costs - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineRunningCostSorterWagon(const EngineID &a, const EngineID &b) -{ - Money va = Engine::Get(a)->GetRunningCost(); - Money vb = Engine::Get(b)->GetRunningCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of train wagons by capacity - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool TrainEngineCapacitySorterWagon(const EngineID &a, const EngineID &b) -{ - const RailVehicleInfo *rvi_a = RailVehInfo(a); - const RailVehicleInfo *rvi_b = RailVehInfo(b); - - int va = GetTotalCapacityOfArticulatedParts(a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); - int vb = GetTotalCapacityOfArticulatedParts(b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - /** Sort functions for the vehicle sort criteria, for each vehicle type. */ EngList_SortTypeFunction * const _engine_sort_functions[][12] = {{ /* Trains */ @@ -976,60 +657,6 @@ const StringID _engine_sort_listing[][13] = {{ INVALID_STRING_ID }}; -static EngList_SortTypeFunction * const _sorter_loco[12] = { - /* Locomotives */ - &EngineNumberSorterLoco, - &EngineCostSorterLoco, - &EngineSpeedSorterLoco, - &EnginePowerSorterLoco, - &EngineTractiveEffortSorterLoco, - &EngineIntroDateSorterLoco, - &EngineNameSorterLoco, - &EngineRunningCostSorterLoco, - &EnginePowerVsRunningCostSorterLoco, - &EngineReliabilitySorter, - &TrainEngineCapacitySorter -}; - -static EngList_SortTypeFunction * const _sorter_wagon[7] = { - /* Wagons */ - &EngineNumberSorterWagon, - &EngineCostSorterWagon, - &EngineSpeedSorterWagon, - &EngineIntroDateSorterWagon, - &EngineNameSorterWagon, - &EngineRunningCostSorterWagon, - &TrainEngineCapacitySorterWagon -}; - -static const StringID _sort_listing_loco[12] = { - /* Locomotives */ - STR_SORT_BY_ENGINE_ID, - STR_SORT_BY_COST, - STR_SORT_BY_MAX_SPEED, - STR_SORT_BY_POWER, - STR_SORT_BY_TRACTIVE_EFFORT, - STR_SORT_BY_INTRO_DATE, - STR_SORT_BY_NAME, - STR_SORT_BY_RUNNING_COST, - STR_SORT_BY_POWER_VS_RUNNING_COST, - STR_SORT_BY_RELIABILITY, - STR_SORT_BY_CARGO_CAPACITY, - INVALID_STRING_ID -}; - -static const StringID _sort_listing_wagon[8] = { - /* Wagons */ - STR_SORT_BY_ENGINE_ID, - STR_SORT_BY_COST, - STR_SORT_BY_MAX_SPEED, - STR_SORT_BY_INTRO_DATE, - STR_SORT_BY_NAME, - STR_SORT_BY_RUNNING_COST, - STR_SORT_BY_CARGO_CAPACITY, - INVALID_STRING_ID -}; - /** Filters vehicles by cargo and engine (in case of rail vehicle). */ static bool CDECL CargoAndEngineFilter(const EngineID *eid, const CargoID cid) { @@ -1536,34 +1163,6 @@ void DisplayVehicleSortDropDown(Window *w, const VehicleType vehicle_type, const ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask); } -/** - * Display the dropdown for the locomotive sort criteria. - * @param w Parent window (holds the dropdown button). - * @param selected Currently selected sort criterion. - */ -void DisplayLocomotiveSortDropDown(Window *w, int selected) -{ - uint32 hidden_mask = 0; - /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ - SetBit(hidden_mask, 4); // tractive effort - ShowDropDownMenu(w, _sort_listing_loco, selected, WID_BV_SORT_DROPDOWN_LOCO, 0, hidden_mask); -} - -/** - * Display the dropdown for the wagon sort criteria. - * @param w Parent window (holds the dropdown button). - * @param selected Currently selected sort criterion. - */ -void DisplayWagonSortDropDown(Window *w, int selected) -{ - uint32 hidden_mask = 0; - /* Disable sorting by maximum speed when wagon speed is disabled. */ - if (!_settings_game.vehicle.wagon_speed_limits) { - SetBit(hidden_mask, 2); // maximum speed - } - ShowDropDownMenu(w, _sort_listing_wagon, selected, WID_BV_SORT_DROPDOWN_WAGON, 0, hidden_mask); -} - /** GUI for building vehicles. */ struct BuildVehicleWindow : Window { VehicleType vehicle_type; ///< Type of vehicles shown in the window. @@ -2230,6 +1829,405 @@ struct BuildVehicleWindow : Window { } }; +/* Locomotive sorting functions. */ +/** + * Determines order of locomotives by engineID + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineNumberSorterLoco(const EngineID &a, const EngineID &b) +{ + int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; + + return _internal_sort_order_loco ? r > 0 : r < 0; +} + +/** + * Determines order of locomotives by introduction date + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineIntroDateSorterLoco(const EngineID &a, const EngineID &b) +{ + const int va = Engine::Get(a)->intro_date; + const int vb = Engine::Get(b)->intro_date; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? r > 0 : r < 0; +} + +/** + * Determines order of locomotives by name + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineNameSorterLoco(const EngineID &a, const EngineID &b) +{ + static char last_name[2][64] = { "", "" }; + + if (a != _last_engine[0]) { + _last_engine[0] = a; + SetDParam(0, a); + GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); + } + + if (b != _last_engine[1]) { + _last_engine[1] = b; + SetDParam(0, b); + GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? r > 0 : r < 0; +} + +/** + * Determines order of locomotives by purchase cost + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineCostSorterLoco(const EngineID &a, const EngineID &b) +{ + Money va = Engine::Get(a)->GetCost(); + Money vb = Engine::Get(b)->GetCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? r > 0 : r < 0; +} + +/** + * Determines order of locomotives by speed + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineSpeedSorterLoco(const EngineID &a, const EngineID &b) +{ + int va = Engine::Get(a)->GetDisplayMaxSpeed(); + int vb = Engine::Get(b)->GetDisplayMaxSpeed(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? r > 0 : r < 0; +} + +/** + * Determines order of locomotives by power + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EnginePowerSorterLoco(const EngineID &a, const EngineID &b) +{ + int va = Engine::Get(a)->GetPower(); + int vb = Engine::Get(b)->GetPower(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? r > 0 : r < 0; +} + +/** + * Determines order of locomotives by tractive effort + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineTractiveEffortSorterLoco(const EngineID &a, const EngineID &b) +{ + int va = Engine::Get(a)->GetDisplayMaxTractiveEffort(); + int vb = Engine::Get(b)->GetDisplayMaxTractiveEffort(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? r > 0 : r < 0; +} + +/** + * Determines order of locomotives by running costs + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineRunningCostSorterLoco(const EngineID &a, const EngineID &b) +{ + Money va = Engine::Get(a)->GetRunningCost(); + Money vb = Engine::Get(b)->GetRunningCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco ? r > 0 : r < 0; +} + +/** + * Determines order of locomotives by running costs + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EnginePowerVsRunningCostSorterLoco(const EngineID &a, const EngineID &b) +{ + const Engine *e_a = Engine::Get(a); + const Engine *e_b = Engine::Get(b); + uint p_a = e_a->GetPower(); + uint p_b = e_b->GetPower(); + Money r_a = e_a->GetRunningCost(); + Money r_b = e_b->GetRunningCost(); + /* Check if running cost is zero in one or both engines. + * If only one of them is zero then that one has higher value, + * else if both have zero cost then compare powers. */ + if (r_a == 0) { + if (r_b == 0) { + /* If it is ambiguous which to return go with their ID */ + if (p_a == p_b) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco != (p_a < p_b); + } + return !_internal_sort_order_loco; + } + if (r_b == 0) return _internal_sort_order_loco; + /* Using double for more precision when comparing close values. + * This shouldn't have any major effects in performance nor in keeping + * the game in sync between players since it's used in GUI only in client side */ + double v_a = (double)p_a / (double)r_a; + double v_b = (double)p_b / (double)r_b; + /* Use EngineID to sort if both have same power/running cost, + * since we want consistent sorting. + * Also if both have no power then sort with reverse of running cost to simulate + * previous sorting behaviour for wagons. */ + if (v_a == 0 && v_b == 0) return !EngineRunningCostSorterLoco(a, b); + if (v_a == v_b) return EngineNumberSorterLoco(a, b); + return _internal_sort_order_loco != (v_a < v_b); +} + +/* Wagon sorting functions. */ + +/** + * Determines order of wagons by engineID + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineNumberSorterWagon(const EngineID &a, const EngineID &b) +{ + int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; + + return _internal_sort_order_wagon ? r > 0 : r < 0; +} + +/** + * Determines order of wagons by introduction date + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineIntroDateSorterWagon(const EngineID &a, const EngineID &b) +{ + const int va = Engine::Get(a)->intro_date; + const int vb = Engine::Get(b)->intro_date; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? r > 0 : r < 0; +} + +/** + * Determines order of wagons by name + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineNameSorterWagon(const EngineID &a, const EngineID &b) +{ + static char last_name[2][64] = { "", "" }; + + if (a != _last_engine[0]) { + _last_engine[0] = a; + SetDParam(0, a); + GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); + } + + if (b != _last_engine[1]) { + _last_engine[1] = b; + SetDParam(0, b); + GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? r > 0 : r < 0; +} + +/** + * Determines order of wagons by purchase cost + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineCostSorterWagon(const EngineID &a, const EngineID &b) +{ + Money va = Engine::Get(a)->GetCost(); + Money vb = Engine::Get(b)->GetCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? r > 0 : r < 0; +} + +/** + * Determines order of wagons by speed + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineSpeedSorterWagon(const EngineID &a, const EngineID &b) +{ + int va = Engine::Get(a)->GetDisplayMaxSpeed(); + int vb = Engine::Get(b)->GetDisplayMaxSpeed(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? r > 0 : r < 0; +} + +/** + * Determines order of wagons by running costs + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool EngineRunningCostSorterWagon(const EngineID &a, const EngineID &b) +{ + Money va = Engine::Get(a)->GetRunningCost(); + Money vb = Engine::Get(b)->GetRunningCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? r > 0 : r < 0; +} + +/** + * Determines order of train wagons by capacity + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static bool TrainEngineCapacitySorterWagon(const EngineID &a, const EngineID &b) +{ + const RailVehicleInfo *rvi_a = RailVehInfo(a); + const RailVehicleInfo *rvi_b = RailVehInfo(b); + + int va = GetTotalCapacityOfArticulatedParts(a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int vb = GetTotalCapacityOfArticulatedParts(b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorterWagon(a, b); + return _internal_sort_order_wagon ? r > 0 : r < 0; +} + +static EngList_SortTypeFunction * const _sorter_loco[12] = { + /* Locomotives */ + &EngineNumberSorterLoco, + &EngineCostSorterLoco, + &EngineSpeedSorterLoco, + &EnginePowerSorterLoco, + &EngineTractiveEffortSorterLoco, + &EngineIntroDateSorterLoco, + &EngineNameSorterLoco, + &EngineRunningCostSorterLoco, + &EnginePowerVsRunningCostSorterLoco, + &EngineReliabilitySorter, + &TrainEngineCapacitySorter +}; + +static EngList_SortTypeFunction * const _sorter_wagon[7] = { + /* Wagons */ + &EngineNumberSorterWagon, + &EngineCostSorterWagon, + &EngineSpeedSorterWagon, + &EngineIntroDateSorterWagon, + &EngineNameSorterWagon, + &EngineRunningCostSorterWagon, + &TrainEngineCapacitySorterWagon +}; + +static const StringID _sort_listing_loco[12] = { + /* Locomotives */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_POWER, + STR_SORT_BY_TRACTIVE_EFFORT, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_POWER_VS_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}; + +static const StringID _sort_listing_wagon[8] = { + /* Wagons */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}; + +/** + * Display the dropdown for the locomotive sort criteria. + * @param w Parent window (holds the dropdown button). + * @param selected Currently selected sort criterion. + */ +void DisplayLocomotiveSortDropDown(Window *w, int selected) +{ + uint32 hidden_mask = 0; + /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ + SetBit(hidden_mask, 4); // tractive effort + ShowDropDownMenu(w, _sort_listing_loco, selected, WID_BV_SORT_DROPDOWN_LOCO, 0, hidden_mask); +} + +/** + * Display the dropdown for the wagon sort criteria. + * @param w Parent window (holds the dropdown button). + * @param selected Currently selected sort criterion. + */ +void DisplayWagonSortDropDown(Window *w, int selected) +{ + uint32 hidden_mask = 0; + /* Disable sorting by maximum speed when wagon speed is disabled. */ + if (!_settings_game.vehicle.wagon_speed_limits) { + SetBit(hidden_mask, 2); // maximum speed + } + ShowDropDownMenu(w, _sort_listing_wagon, selected, WID_BV_SORT_DROPDOWN_WAGON, 0, hidden_mask); +} + /** Advanced window for trains. It is divided into two parts, one for locomotives and one for wagons. */ struct BuildVehicleWindowTrainAdvanced final : Window { @@ -3236,6 +3234,13 @@ static WindowDesc _build_vehicle_desc( _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) ); +static WindowDesc _build_template_vehicle_desc( + WDP_AUTO, "build_vehicle", 240, 268, + WC_BUILD_VIRTUAL_TRAIN, WC_CREATE_TEMPLATE, + WDF_CONSTRUCTION, + _nested_build_vehicle_widgets_train_advanced, lengthof(_nested_build_vehicle_widgets_train_advanced) +); + static WindowDesc _build_vehicle_desc_train_advanced( WDP_AUTO, "build_vehicle", 480, 268, WC_BUILD_VEHICLE, WC_NONE, @@ -3243,12 +3248,6 @@ static WindowDesc _build_vehicle_desc_train_advanced( _nested_build_vehicle_widgets_train_advanced, lengthof(_nested_build_vehicle_widgets_train_advanced) ); -static WindowDesc _build_template_vehicle_desc( - WDP_AUTO, "build_vehicle", 240, 268, - WC_BUILD_VIRTUAL_TRAIN, WC_CREATE_TEMPLATE, - WDF_CONSTRUCTION, - _nested_build_vehicle_widgets_train_advanced, lengthof(_nested_build_vehicle_widgets_train_advanced) -); void ShowBuildVehicleWindow(const TileIndex tile, const VehicleType type) { From b4856d3164fc82a276f2a8a68cbe17f64c77cac0 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 28 Jun 2021 23:02:16 +0100 Subject: [PATCH 10/17] Trim trailing whitespace --- src/build_vehicle_gui.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index a8573f3638..d11ba07c5e 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -2318,7 +2318,7 @@ struct BuildVehicleWindowTrainAdvanced final : Window { BuildVehicleWindowTrainAdvanced(WindowDesc *desc, TileIndex tile, Train **virtual_train_out) : Window(desc) { this->vehicle_type = VEH_TRAIN; - this->window_number = tile == INVALID_TILE ? static_cast(VEH_TRAIN) : tile; + this->window_number = tile == INVALID_TILE ? static_cast(VEH_TRAIN) : tile; this->virtual_train_out = virtual_train_out; this->virtual_train_mode = (virtual_train_out != nullptr); @@ -2432,10 +2432,10 @@ struct BuildVehicleWindowTrainAdvanced final : Window { this->cargo_filter_texts_loco[filter_items_loco] = STR_PURCHASE_INFO_ALL_TYPES; filter_items_loco++; - /* Add item for vehicles not carrying anything, e.g. train engines. */ + /* Add item for vehicles not carrying anything, e.g. train engines. */ this->cargo_filter_loco[filter_items_loco] = CF_NONE; this->cargo_filter_texts_loco[filter_items_loco] = STR_PURCHASE_INFO_NONE; - filter_items_loco++; + filter_items_loco++; /* Collect available cargo types for filtering. */ const CargoSpec *cs_loco; @@ -2474,14 +2474,14 @@ struct BuildVehicleWindowTrainAdvanced final : Window { /* Add item for vehicles not carrying anything, e.g. train engines. * This could also be useful for eye candy vehicles of other types, but is likely too confusing for joe, */ - + this->cargo_filter_wagon[filter_items_wagon] = CF_NONE; this->cargo_filter_texts_wagon[filter_items_wagon] = STR_PURCHASE_INFO_NONE; filter_items_wagon++; - + /* Collect available cargo types for filtering. */ - + const CargoSpec *cs_wagon; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs_wagon) { @@ -2643,7 +2643,7 @@ struct BuildVehicleWindowTrainAdvanced final : Window { if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; /* Filter now! So num_engines and num_wagons is valid */ - if (!FilterSingleEngineLoco(eid)) continue; + if (!FilterSingleEngineLoco(eid)) continue; if (rvi->railveh_type != RAILVEH_WAGON) { num_engines_loco++; @@ -2900,7 +2900,7 @@ struct BuildVehicleWindowTrainAdvanced final : Window { { if (!gui_scope) return; - /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ + /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ this->eng_list_loco.ForceRebuild(); this->eng_list_wagon.ForceRebuild(); } From 1a7ebfd06ce7aa5939cac4d7d33b78077416aa99 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 28 Jun 2021 23:13:50 +0100 Subject: [PATCH 11/17] Fix duplication of sorter functions --- src/build_vehicle_gui.cpp | 361 +++----------------------------------- 1 file changed, 21 insertions(+), 340 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index d11ba07c5e..cb0c60f526 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -187,12 +187,10 @@ bool _engine_sort_show_hidden_locos = false; ///< Las bool _engine_sort_show_hidden_wagons = false; ///< Last set 'show hidden wagons' setting. static CargoID _engine_sort_last_cargo_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ANY}; ///< Last set filter criteria, for each vehicle type. -static bool _internal_sort_order_loco; ///< false = descending, true = ascending static byte _last_sort_criteria_loco = 0; static bool _last_sort_order_loco = false; static CargoID _last_filter_criteria_loco = CF_ANY; -static bool _internal_sort_order_wagon; ///< false = descending, true = ascending static byte _last_sort_criteria_wagon = 0; static bool _last_sort_order_wagon = false; static CargoID _last_filter_criteria_wagon = CF_ANY; @@ -1829,347 +1827,30 @@ struct BuildVehicleWindow : Window { } }; -/* Locomotive sorting functions. */ -/** - * Determines order of locomotives by engineID - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineNumberSorterLoco(const EngineID &a, const EngineID &b) -{ - int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; - - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by introduction date - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineIntroDateSorterLoco(const EngineID &a, const EngineID &b) -{ - const int va = Engine::Get(a)->intro_date; - const int vb = Engine::Get(b)->intro_date; - const int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by name - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineNameSorterLoco(const EngineID &a, const EngineID &b) -{ - static char last_name[2][64] = { "", "" }; - - if (a != _last_engine[0]) { - _last_engine[0] = a; - SetDParam(0, a); - GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); - } - - if (b != _last_engine[1]) { - _last_engine[1] = b; - SetDParam(0, b); - GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); - } - - int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by purchase cost - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineCostSorterLoco(const EngineID &a, const EngineID &b) -{ - Money va = Engine::Get(a)->GetCost(); - Money vb = Engine::Get(b)->GetCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by speed - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineSpeedSorterLoco(const EngineID &a, const EngineID &b) -{ - int va = Engine::Get(a)->GetDisplayMaxSpeed(); - int vb = Engine::Get(b)->GetDisplayMaxSpeed(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by power - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EnginePowerSorterLoco(const EngineID &a, const EngineID &b) -{ - int va = Engine::Get(a)->GetPower(); - int vb = Engine::Get(b)->GetPower(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by tractive effort - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineTractiveEffortSorterLoco(const EngineID &a, const EngineID &b) -{ - int va = Engine::Get(a)->GetDisplayMaxTractiveEffort(); - int vb = Engine::Get(b)->GetDisplayMaxTractiveEffort(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by running costs - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineRunningCostSorterLoco(const EngineID &a, const EngineID &b) -{ - Money va = Engine::Get(a)->GetRunningCost(); - Money vb = Engine::Get(b)->GetRunningCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco ? r > 0 : r < 0; -} - -/** - * Determines order of locomotives by running costs - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EnginePowerVsRunningCostSorterLoco(const EngineID &a, const EngineID &b) -{ - const Engine *e_a = Engine::Get(a); - const Engine *e_b = Engine::Get(b); - uint p_a = e_a->GetPower(); - uint p_b = e_b->GetPower(); - Money r_a = e_a->GetRunningCost(); - Money r_b = e_b->GetRunningCost(); - /* Check if running cost is zero in one or both engines. - * If only one of them is zero then that one has higher value, - * else if both have zero cost then compare powers. */ - if (r_a == 0) { - if (r_b == 0) { - /* If it is ambiguous which to return go with their ID */ - if (p_a == p_b) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco != (p_a < p_b); - } - return !_internal_sort_order_loco; - } - if (r_b == 0) return _internal_sort_order_loco; - /* Using double for more precision when comparing close values. - * This shouldn't have any major effects in performance nor in keeping - * the game in sync between players since it's used in GUI only in client side */ - double v_a = (double)p_a / (double)r_a; - double v_b = (double)p_b / (double)r_b; - /* Use EngineID to sort if both have same power/running cost, - * since we want consistent sorting. - * Also if both have no power then sort with reverse of running cost to simulate - * previous sorting behaviour for wagons. */ - if (v_a == 0 && v_b == 0) return !EngineRunningCostSorterLoco(a, b); - if (v_a == v_b) return EngineNumberSorterLoco(a, b); - return _internal_sort_order_loco != (v_a < v_b); -} - -/* Wagon sorting functions. */ - -/** - * Determines order of wagons by engineID - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineNumberSorterWagon(const EngineID &a, const EngineID &b) -{ - int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; - - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by introduction date - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineIntroDateSorterWagon(const EngineID &a, const EngineID &b) -{ - const int va = Engine::Get(a)->intro_date; - const int vb = Engine::Get(b)->intro_date; - const int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by name - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineNameSorterWagon(const EngineID &a, const EngineID &b) -{ - static char last_name[2][64] = { "", "" }; - - if (a != _last_engine[0]) { - _last_engine[0] = a; - SetDParam(0, a); - GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); - } - - if (b != _last_engine[1]) { - _last_engine[1] = b; - SetDParam(0, b); - GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); - } - - int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by purchase cost - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineCostSorterWagon(const EngineID &a, const EngineID &b) -{ - Money va = Engine::Get(a)->GetCost(); - Money vb = Engine::Get(b)->GetCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by speed - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineSpeedSorterWagon(const EngineID &a, const EngineID &b) -{ - int va = Engine::Get(a)->GetDisplayMaxSpeed(); - int vb = Engine::Get(b)->GetDisplayMaxSpeed(); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of wagons by running costs - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool EngineRunningCostSorterWagon(const EngineID &a, const EngineID &b) -{ - Money va = Engine::Get(a)->GetRunningCost(); - Money vb = Engine::Get(b)->GetRunningCost(); - int r = ClampToI32(va - vb); - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -/** - * Determines order of train wagons by capacity - * @param a first engine to compare - * @param b second engine to compare - * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal - */ -static bool TrainEngineCapacitySorterWagon(const EngineID &a, const EngineID &b) -{ - const RailVehicleInfo *rvi_a = RailVehInfo(a); - const RailVehicleInfo *rvi_b = RailVehInfo(b); - - int va = GetTotalCapacityOfArticulatedParts(a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); - int vb = GetTotalCapacityOfArticulatedParts(b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); - int r = va - vb; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorterWagon(a, b); - return _internal_sort_order_wagon ? r > 0 : r < 0; -} - -static EngList_SortTypeFunction * const _sorter_loco[12] = { +static EngList_SortTypeFunction * const _sorter_loco[11] = { /* Locomotives */ - &EngineNumberSorterLoco, - &EngineCostSorterLoco, - &EngineSpeedSorterLoco, - &EnginePowerSorterLoco, - &EngineTractiveEffortSorterLoco, - &EngineIntroDateSorterLoco, - &EngineNameSorterLoco, - &EngineRunningCostSorterLoco, - &EnginePowerVsRunningCostSorterLoco, + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EnginePowerSorter, + &EngineTractiveEffortSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EnginePowerVsRunningCostSorter, &EngineReliabilitySorter, &TrainEngineCapacitySorter }; static EngList_SortTypeFunction * const _sorter_wagon[7] = { /* Wagons */ - &EngineNumberSorterWagon, - &EngineCostSorterWagon, - &EngineSpeedSorterWagon, - &EngineIntroDateSorterWagon, - &EngineNameSorterWagon, - &EngineRunningCostSorterWagon, - &TrainEngineCapacitySorterWagon + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &TrainEngineCapacitySorter }; static const StringID _sort_listing_loco[12] = { @@ -2694,12 +2375,12 @@ struct BuildVehicleWindowTrainAdvanced final : Window { _last_engine[0] = _last_engine[1] = INVALID_ENGINE; /* Sort locomotives */ - _internal_sort_order_loco = this->descending_sort_order_loco; - EngList_SortPartial(&this->eng_list_loco, _sorter_loco[this->sort_criteria_loco], 0, num_engines_loco); + _engine_sort_direction = this->descending_sort_order_loco; + EngList_Sort(&this->eng_list_loco, _sorter_loco[this->sort_criteria_loco]); /* Sort wagons */ - _internal_sort_order_wagon = this->descending_sort_order_wagon; - EngList_SortPartial(&this->eng_list_wagon, _sorter_wagon[this->sort_criteria_wagon], 0, num_wagons_wagon); + _engine_sort_direction = this->descending_sort_order_wagon; + EngList_Sort(&this->eng_list_wagon, _sorter_wagon[this->sort_criteria_wagon]); } From 42d1987713314432209c527c90f0bf0fa40615b5 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 28 Jun 2021 23:35:00 +0100 Subject: [PATCH 12/17] Fix crash when building template vehicles --- src/build_vehicle_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index cb0c60f526..395d107121 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -2886,7 +2886,7 @@ void CcAddVirtualEngine(const CommandCost &result, TileIndex tile, uint32 p1, ui if (window != nullptr) { Train *train = Train::From(Vehicle::Get(_new_vehicle_id)); - dynamic_cast(window)->AddVirtualEngine(train); + dynamic_cast(window)->AddVirtualEngine(train); } else { DoCommandP(0, _new_vehicle_id | (1 << 21), 0, CMD_SELL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_SELL_TRAIN)); } From ab5cee70ece358392ec4c23ca05417ea7b967838 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 28 Jun 2021 23:38:12 +0100 Subject: [PATCH 13/17] Fix whitespace/code style issues --- src/build_vehicle_gui.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 395d107121..62bc4bbdf8 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -2431,8 +2431,7 @@ struct BuildVehicleWindowTrainAdvanced final : Window { if (_ctrl_pressed) { this->OnClick(pt, WID_BV_SHOW_HIDE_LOCO, 1); - } - else if (click_count > 1 && !this->listview_mode) { + } else if (click_count > 1 && !this->listview_mode) { this->OnClick(pt, WID_BV_BUILD_LOCO, 1); } break; @@ -2514,8 +2513,7 @@ struct BuildVehicleWindowTrainAdvanced final : Window { if (_ctrl_pressed) { this->OnClick(pt, WID_BV_SHOW_HIDE_WAGON, 1); - } - else if (click_count > 1 && !this->listview_mode) { + } else if (click_count > 1 && !this->listview_mode) { this->OnClick(pt, WID_BV_BUILD_WAGON, 1); } break; @@ -2608,8 +2606,7 @@ struct BuildVehicleWindowTrainAdvanced final : Window { const Engine *engine = (this->sel_engine_loco == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_loco); if (engine != nullptr && engine->IsHidden(_local_company)) { SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type); - } - else { + } else { SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); } break; @@ -2644,8 +2641,7 @@ struct BuildVehicleWindowTrainAdvanced final : Window { const Engine *engine = (this->sel_engine_wagon == INVALID_ENGINE) ? nullptr : Engine::GetIfValid(this->sel_engine_wagon); if (engine != nullptr && engine->IsHidden(_local_company)) { SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type); - } - else { + } else { SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); } break; @@ -2799,12 +2795,9 @@ struct BuildVehicleWindowTrainAdvanced final : Window { { if (str == nullptr) return; - if(this->rename_engine_loco != INVALID_ENGINE) - { + if (this->rename_engine_loco != INVALID_ENGINE) { DoCommandP(0, this->rename_engine_loco, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), nullptr, str); - } - else - { + } else { DoCommandP(0, this->rename_engine_wagon, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), nullptr, str); } } From d1114b6b79d34d052dcb5be1c03ea4cc696c0ba4 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 28 Jun 2021 23:43:37 +0100 Subject: [PATCH 14/17] Fix build wagon button building locomotives instead --- src/build_vehicle_gui.cpp | 52 +++++++++++++++------------------------ 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 62bc4bbdf8..89d1ea82a8 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -2400,6 +2400,24 @@ struct BuildVehicleWindowTrainAdvanced final : Window { this->eng_list_wagon.RebuildDone(); } + void BuildEngine(const EngineID selected, CargoID cargo) + { + if (selected != INVALID_ENGINE) { + CommandCallback *callback; + uint32 cmd; + if (this->virtual_train_mode) { + callback = CcAddVirtualEngine; + cmd = CMD_BUILD_VIRTUAL_RAIL_VEHICLE; + } else { + callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(selected)->railveh_type == RAILVEH_WAGON) + ? CcBuildWagon : CcBuildPrimaryVehicle; + cmd = GetCmdBuildVeh(this->vehicle_type); + } + if (cargo == CF_ANY || cargo == CF_ENGINES) cargo = CF_NONE; + DoCommandP(this->window_number, selected | (cargo << 24), 0, cmd, callback); + } + } + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { @@ -2456,22 +2474,7 @@ struct BuildVehicleWindowTrainAdvanced final : Window { } case WID_BV_BUILD_LOCO: { - const EngineID selected_loco = this->sel_engine_loco; - if (selected_loco != INVALID_ENGINE) { - CommandCallback *callback; - uint32 cmd; - if (this->virtual_train_mode) { - callback = CcAddVirtualEngine; - cmd = CMD_BUILD_VIRTUAL_RAIL_VEHICLE; - } else { - callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(selected_loco)->railveh_type == RAILVEH_WAGON) - ? CcBuildWagon : CcBuildPrimaryVehicle; - cmd = GetCmdBuildVeh(this->vehicle_type); - } - CargoID cargo = this->cargo_filter_loco[this->cargo_filter_criteria_loco]; - if (cargo == CF_ANY || cargo == CF_ENGINES) cargo = CF_NONE; - DoCommandP(this->window_number, selected_loco | (cargo << 24), 0, cmd, callback); - } + this->BuildEngine(this->sel_engine_loco, this->cargo_filter_loco[this->cargo_filter_criteria_loco]); break; } @@ -2538,22 +2541,7 @@ struct BuildVehicleWindowTrainAdvanced final : Window { } case WID_BV_BUILD_WAGON: { - const EngineID selected_wagon = this->sel_engine_loco; - if (selected_wagon != INVALID_ENGINE) { - CommandCallback *callback; - uint32 cmd; - if (this->virtual_train_mode) { - callback = CcAddVirtualEngine; - cmd = CMD_BUILD_VIRTUAL_RAIL_VEHICLE; - } else { - callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(selected_wagon)->railveh_type == RAILVEH_WAGON) - ? CcBuildWagon : CcBuildPrimaryVehicle; - cmd = GetCmdBuildVeh(this->vehicle_type); - } - CargoID cargo = this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]; - if (cargo == CF_ANY || cargo == CF_ENGINES) cargo = CF_NONE; - DoCommandP(this->window_number, selected_wagon | (cargo << 24), 0, cmd, callback); - } + this->BuildEngine(this->sel_engine_wagon, this->cargo_filter_wagon[this->cargo_filter_criteria_wagon]); break; } From 70f750912669f1dc535e14991094e463d3ec3660 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 28 Jun 2021 23:55:11 +0100 Subject: [PATCH 15/17] Create common base class for build vehicle windows --- src/build_vehicle_gui.cpp | 96 +++++++++++++++------------------------ 1 file changed, 36 insertions(+), 60 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 89d1ea82a8..cad441291b 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1161,9 +1161,39 @@ void DisplayVehicleSortDropDown(Window *w, const VehicleType vehicle_type, const ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask); } -/** GUI for building vehicles. */ -struct BuildVehicleWindow : Window { +struct BuildVehicleWindowCommon : Window { VehicleType vehicle_type; ///< Type of vehicles shown in the window. + bool virtual_train_mode; ///< Are we building a virtual train? + Train **virtual_train_out; ///< Virtual train ptr + bool listview_mode; ///< If set, only display the available vehicles and do not show a 'build' button. + + BuildVehicleWindowCommon(WindowDesc *desc, TileIndex tile, VehicleType type, Train **virtual_train_out) : Window(desc) + { + this->vehicle_type = type; + this->window_number = tile == INVALID_TILE ? (int)type : tile; + this->virtual_train_out = virtual_train_out; + this->virtual_train_mode = (virtual_train_out != nullptr); + if (this->virtual_train_mode) this->window_number = 0; + this->listview_mode = (tile == INVALID_TILE) && !virtual_train_mode; + } + + void AddVirtualEngine(Train *toadd) + { + if (this->virtual_train_out == nullptr) return; + + if (*(this->virtual_train_out) == nullptr) { + *(this->virtual_train_out) = toadd; + InvalidateWindowClassesData(WC_CREATE_TEMPLATE); + } else { + VehicleID target = (*(this->virtual_train_out))->GetLastUnit()->index; + + DoCommandP(0, (1 << 23) | (1 << 21) | toadd->index, target, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE), CcMoveNewVirtualEngine); + } + } +}; + +/** GUI for building vehicles. */ +struct BuildVehicleWindow : BuildVehicleWindowCommon { union { RailType railtype; ///< Rail type to show, or #INVALID_RAILTYPE. RoadType roadtype; ///< Road type to show, or #INVALID_ROADTYPE. @@ -1171,7 +1201,6 @@ struct BuildVehicleWindow : Window { bool descending_sort_order; ///< Sort direction, @see _engine_sort_direction byte sort_criteria; ///< Current sort criterium. bool show_hidden_engines; ///< State of the 'show hidden engines' button. - bool listview_mode; ///< If set, only display the available vehicles and do not show a 'build' button. EngineID sel_engine; ///< Currently selected engine, or #INVALID_ENGINE EngineID rename_engine; ///< Engine being renamed. GUIEngineList eng_list; @@ -1180,8 +1209,6 @@ struct BuildVehicleWindow : Window { byte cargo_filter_criteria; ///< Selected cargo filter int details_height; ///< Minimal needed height of the details panels, in text lines (found so far). Scrollbar *vscroll; - bool virtual_train_mode; ///< Are we building a virtual train? - Train **virtual_train_out; ///< Virtual train ptr TestedEngineDetails te; ///< Tested cost and capacity after refit. void SetBuyVehicleText() @@ -1205,15 +1232,8 @@ struct BuildVehicleWindow : Window { } } - BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type, Train **virtual_train_out) : Window(desc) + BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type, Train **virtual_train_out) : BuildVehicleWindowCommon(desc, tile, type, virtual_train_out) { - this->vehicle_type = type; - this->window_number = tile == INVALID_TILE ? (int)type : tile; - this->virtual_train_out = virtual_train_out; - this->virtual_train_mode = (virtual_train_out != nullptr); - if (this->virtual_train_mode) this->window_number = 0; - this->listview_mode = (tile == INVALID_TILE) && !virtual_train_mode; - this->sel_engine = INVALID_ENGINE; this->sort_criteria = _engine_sort_last_criteria[type]; @@ -1811,20 +1831,6 @@ struct BuildVehicleWindow : Window { { this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST); } - - void AddVirtualEngine(Train *toadd) - { - if (this->virtual_train_out == nullptr) return; - - if (*(this->virtual_train_out) == nullptr) { - *(this->virtual_train_out) = toadd; - InvalidateWindowClassesData(WC_CREATE_TEMPLATE); - } else { - VehicleID target = (*(this->virtual_train_out))->GetLastUnit()->index; - - DoCommandP(0, (1 << 23) | (1 << 21) | toadd->index, target, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE), CcMoveNewVirtualEngine); - } - } }; static EngList_SortTypeFunction * const _sorter_loco[11] = { @@ -1910,14 +1916,11 @@ void DisplayWagonSortDropDown(Window *w, int selected) } /** Advanced window for trains. It is divided into two parts, one for locomotives and one for wagons. */ -struct BuildVehicleWindowTrainAdvanced final : Window { +struct BuildVehicleWindowTrainAdvanced final : BuildVehicleWindowCommon { /* Locomotives and wagons */ - VehicleType vehicle_type; ///< Type of vehicles shown in the window. RailType railtype; ///< Filter to apply. - bool listview_mode; ///< If set, only display the available vehicles and do not show a 'build' button. - /* Locomotives */ @@ -1948,10 +1951,6 @@ struct BuildVehicleWindowTrainAdvanced final : Window { CargoID cargo_filter_wagon[NUM_CARGO + 2] {}; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE StringID cargo_filter_texts_wagon[NUM_CARGO + 3] {}; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID - - bool virtual_train_mode; ///< Are we building a virtual train? - Train **virtual_train_out; ///< Virtual train ptr - TestedEngineDetails te; ///< Tested cost and capacity after refit. void SetBuyLocomotiveText() @@ -1996,15 +1995,8 @@ struct BuildVehicleWindowTrainAdvanced final : Window { } } - BuildVehicleWindowTrainAdvanced(WindowDesc *desc, TileIndex tile, Train **virtual_train_out) : Window(desc) + BuildVehicleWindowTrainAdvanced(WindowDesc *desc, TileIndex tile, Train **virtual_train_out) : BuildVehicleWindowCommon(desc, tile, VEH_TRAIN, virtual_train_out) { - this->vehicle_type = VEH_TRAIN; - this->window_number = tile == INVALID_TILE ? static_cast(VEH_TRAIN) : tile; - - this->virtual_train_out = virtual_train_out; - this->virtual_train_mode = (virtual_train_out != nullptr); - if (this->virtual_train_mode) this->window_number = 0; - this->sel_engine_loco = INVALID_ENGINE; this->sort_criteria_loco = _last_sort_criteria_loco; this->descending_sort_order_loco = _last_sort_order_loco; @@ -2016,7 +2008,6 @@ struct BuildVehicleWindowTrainAdvanced final : Window { this->show_hidden_locos = _engine_sort_show_hidden_locos; this->railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile); - this->listview_mode = (tile == INVALID_TILE) && !virtual_train_mode; this->UpdateFilterByTile(); @@ -2842,21 +2833,6 @@ struct BuildVehicleWindowTrainAdvanced final : Window { this->vscroll_loco->SetCapacityFromWidget(this, WID_BV_LIST_LOCO); this->vscroll_wagon->SetCapacityFromWidget(this, WID_BV_LIST_WAGON); } - - void AddVirtualEngine(Train *to_add) const - { - if (this->virtual_train_out == nullptr) return; - - if (*(this->virtual_train_out) == nullptr) { - *(this->virtual_train_out) = to_add; - } else { - const VehicleID target = (*(this->virtual_train_out))->GetLastUnit()->index; - - DoCommandP(0, (1 << 21) | to_add->index, target, CMD_MOVE_RAIL_VEHICLE); - } - InvalidateWindowClassesData(WC_CREATE_TEMPLATE); - InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN); - } }; void CcAddVirtualEngine(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd) @@ -2867,7 +2843,7 @@ void CcAddVirtualEngine(const CommandCost &result, TileIndex tile, uint32 p1, ui if (window != nullptr) { Train *train = Train::From(Vehicle::Get(_new_vehicle_id)); - dynamic_cast(window)->AddVirtualEngine(train); + dynamic_cast(window)->AddVirtualEngine(train); } else { DoCommandP(0, _new_vehicle_id | (1 << 21), 0, CMD_SELL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_SELL_TRAIN)); } From 5e418128daa826487b1c0ee0b7d90db0ff4326d4 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 29 Jun 2021 00:11:07 +0100 Subject: [PATCH 16/17] Add setting for whether to use dual pane train purchase window --- src/build_vehicle_gui.cpp | 17 ++++++++++++++--- src/lang/english.txt | 3 +++ src/settings_gui.cpp | 1 + src/settings_type.h | 1 + src/table/settings.ini | 7 +++++++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index cad441291b..1e3425a527 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -2876,7 +2876,7 @@ static WindowDesc _build_template_vehicle_desc( WDP_AUTO, "build_vehicle", 240, 268, WC_BUILD_VIRTUAL_TRAIN, WC_CREATE_TEMPLATE, WDF_CONSTRUCTION, - _nested_build_vehicle_widgets_train_advanced, lengthof(_nested_build_vehicle_widgets_train_advanced) + _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) ); static WindowDesc _build_vehicle_desc_train_advanced( @@ -2886,6 +2886,13 @@ static WindowDesc _build_vehicle_desc_train_advanced( _nested_build_vehicle_widgets_train_advanced, lengthof(_nested_build_vehicle_widgets_train_advanced) ); +static WindowDesc _build_template_vehicle_desc_advanced( + WDP_AUTO, "build_vehicle", 480, 268, + WC_BUILD_VIRTUAL_TRAIN, WC_CREATE_TEMPLATE, + WDF_CONSTRUCTION, + _nested_build_vehicle_widgets_train_advanced, lengthof(_nested_build_vehicle_widgets_train_advanced) +); + void ShowBuildVehicleWindow(const TileIndex tile, const VehicleType type) { @@ -2899,7 +2906,7 @@ void ShowBuildVehicleWindow(const TileIndex tile, const VehicleType type) DeleteWindowById(WC_BUILD_VEHICLE, num); - if(type == VEH_TRAIN) { + if (type == VEH_TRAIN && _settings_client.gui.dual_pane_train_purchase_window) { new BuildVehicleWindowTrainAdvanced(&_build_vehicle_desc_train_advanced, tile, nullptr); } else { new BuildVehicleWindow(&_build_vehicle_desc, tile, type, nullptr); @@ -2912,5 +2919,9 @@ void ShowTemplateTrainBuildVehicleWindow(Train **virtual_train) DeleteWindowById(WC_BUILD_VIRTUAL_TRAIN, 0); - new BuildVehicleWindowTrainAdvanced(&_build_template_vehicle_desc, INVALID_TILE, virtual_train); + if (_settings_client.gui.dual_pane_train_purchase_window) { + new BuildVehicleWindowTrainAdvanced(&_build_template_vehicle_desc_advanced, INVALID_TILE, virtual_train); + } else { + new BuildVehicleWindow(&_build_template_vehicle_desc, INVALID_TILE, VEH_TRAIN, virtual_train); + } } diff --git a/src/lang/english.txt b/src/lang/english.txt index 24ffc38470..9d4b27f489 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1476,6 +1476,9 @@ STR_CONFIG_SETTING_DEMOLISH_CONFIRM_MODE_OFF :Off STR_CONFIG_SETTING_DEMOLISH_CONFIRM_MODE_INDUSTRY :Industries STR_CONFIG_SETTING_DEMOLISH_CONFIRM_MODE_ALL :Industries and rail stations +STR_CONFIG_SETTING_DUAL_PANE_TRAIN_PURCHASE_WINDOW :Separate locomotives and wagons in train purchase window: {STRING2} +STR_CONFIG_SETTING_DUAL_PANE_TRAIN_PURCHASE_WINDOW_HELPTEXT :When enabled, the train purchase window shows locomotives and wagons in separate side-by-side lists. + STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES :Enable signals on bridges/tunnels advanced modes: {STRING2} STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES_HELPTEXT :Enables use of advanced modes of signal simulation on bridges and tunnels. When disabled, bridges/tunnels which are not already in an advanced mode cannot be changed to an advanced mode, however other players may choose to enable this setting and use an advanced mode. diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 48416d33a3..3d05450606 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1842,6 +1842,7 @@ static SettingsContainer &GetSettingsTree() interface->Add(new SettingEntry("gui.open_vehicle_gui_clone_share")); interface->Add(new SettingEntry("gui.vehicle_names")); interface->Add(new SettingEntry("gui.station_rating_tooltip_mode")); + interface->Add(new SettingEntry("gui.dual_pane_train_purchase_window")); } SettingsPage *advisors = main->Add(new SettingsPage(STR_CONFIG_SETTING_ADVISORS)); diff --git a/src/settings_type.h b/src/settings_type.h index e2f245a7d1..f1d5c56c57 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -223,6 +223,7 @@ struct GUISettings : public TimeSettings { bool shade_trees_on_slopes; ///< Shade trees on slopes uint8 station_rating_tooltip_mode; ///< Station rating tooltip mode uint8 demolish_confirm_mode; ///< Demolition confirmation mode + bool dual_pane_train_purchase_window; ///< Dual pane train purchase window uint16 console_backlog_timeout; ///< the minimum amount of time items should be in the console backlog before they will be removed in ~3 seconds granularity. uint16 console_backlog_length; ///< the minimum amount of items in the console backlog before items will be removed. diff --git a/src/table/settings.ini b/src/table/settings.ini index f1c3aec765..200e0fa12e 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -5539,6 +5539,13 @@ strhelp = STR_CONFIG_SETTING_DEMOLISH_CONFIRM_MODE_HELPTEXT strval = STR_CONFIG_SETTING_DEMOLISH_CONFIRM_MODE_OFF cat = SC_BASIC +[SDTC_BOOL] +var = gui.dual_pane_train_purchase_window +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = true +str = STR_CONFIG_SETTING_DUAL_PANE_TRAIN_PURCHASE_WINDOW +strhelp = STR_CONFIG_SETTING_DUAL_PANE_TRAIN_PURCHASE_WINDOW_HELPTEXT + ; For the dedicated build we'll enable dates in logs by default. [SDTC_BOOL] ifdef = DEDICATED From dd5866c2c27d93fc657795e06290667e7533f53e Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 29 Jun 2021 00:29:19 +0100 Subject: [PATCH 17/17] Fix loco and wagon button rows having different heights --- src/build_vehicle_gui.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 1e3425a527..36a2191bcf 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -2677,6 +2677,11 @@ struct BuildVehicleWindowTrainAdvanced final : BuildVehicleWindowCommon { size->height += padding.height; break; } + + case WID_BV_RENAME_LOCO: { + *size = maxdim(*size, NWidgetLeaf::resizebox_dimension); + break; + } } }