From d7f561a4008c7a7d5840ebf1791c5b1885f965df Mon Sep 17 00:00:00 2001 From: peter1138 Date: Wed, 27 Feb 2019 07:00:33 +0000 Subject: [PATCH 01/20] Change: Add variant property to engines. --- src/engine.cpp | 3 +++ src/engine_base.h | 12 ++++++++++++ src/engine_type.h | 1 + src/newgrf.cpp | 21 +++++++++++++++++++++ src/table/engines.h | 12 ++++++------ 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/engine.cpp b/src/engine.cpp index d1e9cc472f..3e8aeeab49 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -73,6 +73,7 @@ Engine::Engine(VehicleType type, EngineID base) this->grf_prop.local_id = base; this->list_position = base; this->preview_company = INVALID_COMPANY; + this->display_last_variant = INVALID_ENGINE; /* Check if this base engine is within the original engine data range */ if (base >= _engine_counts[type]) { @@ -93,6 +94,8 @@ Engine::Engine(VehicleType type, EngineID base) } /* Set cargo aging period to the default value. */ this->info.cargo_age_period = CARGO_AGING_TICKS; + /* Not a variant */ + this->info.variant_id = INVALID_ENGINE; return; } diff --git a/src/engine_base.h b/src/engine_base.h index 7822111e77..14af402021 100644 --- a/src/engine_base.h +++ b/src/engine_base.h @@ -21,6 +21,15 @@ struct WagonOverride { const SpriteGroup *group; }; +/** Flags used client-side in the purchase/autorenew engine list. */ +enum class EngineDisplayFlags : byte { + None = 0, ///< No flag set. + HasVariants = (1U << 0), ///< Set if engine has variants. + IsFolded = (1U << 1), ///< Set if display of variants should be folded (hidden). + Shaded = (1U << 2), ///< Set if engine should be masked. +}; +DECLARE_ENUM_AS_BIT_SET(EngineDisplayFlags) + typedef Pool EnginePool; extern EnginePool _engine_pool; @@ -45,6 +54,9 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> { uint8 original_image_index; ///< Original vehicle image index, thus the image index of the overridden vehicle VehicleType type; ///< %Vehicle type, ie #VEH_ROAD, #VEH_TRAIN, etc. + EngineDisplayFlags display_flags; ///< NOSAVE client-side-only display flags for build engine list. + EngineID display_last_variant; ///< NOSAVE client-side-only last variant selected. + EngineInfo info; union { diff --git a/src/engine_type.h b/src/engine_type.h index 3eccc663e1..9cee244f12 100644 --- a/src/engine_type.h +++ b/src/engine_type.h @@ -145,6 +145,7 @@ struct EngineInfo { int8 retire_early; ///< Number of years early to retire vehicle StringID string_id; ///< Default name of engine uint16 cargo_age_period; ///< Number of ticks before carried cargo is aged. + EngineID variant_id; ///< Engine variant ID. If set, will be treated specially in purchase lists. }; /** diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 6045a8438a..16eb7696bb 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -1334,6 +1334,10 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop rvi->curve_speed_mod = buf->ReadWord(); break; + case 0x2F: // Engine variant + ei->variant_id = GetNewEngineID(_cur.grffile, VEH_TRAIN, buf->ReadWord()); + break; + default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; @@ -1528,6 +1532,10 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop break; } + case 0x26: // Engine variant + ei->variant_id = GetNewEngineID(_cur.grffile, VEH_ROAD, buf->ReadWord()); + break; + default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; @@ -1700,6 +1708,10 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop break; } + case 0x20: // Engine variant + ei->variant_id = GetNewEngineID(_cur.grffile, VEH_SHIP, buf->ReadWord()); + break; + default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; @@ -1854,6 +1866,10 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int avi->max_range = buf->ReadWord(); break; + case 0x20: // Engine variant + ei->variant_id = GetNewEngineID(_cur.grffile, VEH_AIRCRAFT, buf->ReadWord()); + break; + default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; @@ -8983,6 +8999,11 @@ static void FinaliseEngineArray() if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; + /* Set appropriate flags on variant engine */ + if (e->info.variant_id != INVALID_ENGINE) { + Engine::Get(e->info.variant_id)->display_flags |= EngineDisplayFlags::HasVariants; + } + /* Skip wagons, there livery is defined via the engine */ if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) { LiveryScheme ls = GetEngineLiveryScheme(e->index, INVALID_ENGINE, nullptr); diff --git a/src/table/engines.h b/src/table/engines.h index 2a207dd760..6d45bfb02f 100644 --- a/src/table/engines.h +++ b/src/table/engines.h @@ -24,7 +24,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MT(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } +#define MT(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } /** * Writes the properties of a multiple-unit train into the EngineInfo struct. @@ -37,7 +37,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MM(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_IS_MU, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } +#define MM(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_IS_MU, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } /** * Writes the properties of a train carriage into the EngineInfo struct. @@ -50,7 +50,7 @@ * @see MT * @note the 5 between b and f is the load amount */ -#define MW(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } +#define MW(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } /** * Writes the properties of a road vehicle into the EngineInfo struct. @@ -63,7 +63,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MR(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } +#define MR(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } /** * Writes the properties of a ship into the EngineInfo struct. @@ -75,7 +75,7 @@ * @param f Bitmask of the climates * @note the 10 between b and f is the load amount */ -#define MS(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 10, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } +#define MS(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 10, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } /** * Writes the properties of an aeroplane into the EngineInfo struct. @@ -86,7 +86,7 @@ * @param e Bitmask of the climates * @note the 20 between b and e is the load amount */ -#define MA(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 20, e, CT_INVALID, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } +#define MA(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 20, e, CT_INVALID, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } /* Climates * T = Temperate From c11db7d5934085070e94da6486c702f9de4bb882 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 6 Dec 2022 17:28:28 +0000 Subject: [PATCH 02/20] Change: Clear last variant when engine becomes unavailable. --- src/engine.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/engine.cpp b/src/engine.cpp index 3e8aeeab49..a55fac9b7e 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -562,6 +562,18 @@ static bool IsWagon(EngineID index) return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON; } +/** + * Ensure engine is not set as the last used variant for any other engine. + * @param engine_id Engine being removed. + * @param type Type of engine. + */ +static void ClearLastVariant(EngineID engine_id, VehicleType type) +{ + for (Engine *e : Engine::IterateType(type)) { + if (e->display_last_variant == engine_id) e->display_last_variant = INVALID_ENGINE; + } +} + /** * Update #Engine::reliability and (if needed) update the engine GUIs. * @param e %Engine to update. @@ -577,6 +589,7 @@ static void CalcEngineReliability(Engine *e) if (retire_early != 0 && age >= retire_early_max_age) { /* Early retirement is enabled and we're past the date... */ e->company_avail = 0; + ClearLastVariant(e->index, e->type); AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); } } @@ -597,6 +610,7 @@ static void CalcEngineReliability(Engine *e) e->company_avail = 0; e->reliability = e->reliability_final; /* Kick this engine out of the lists */ + ClearLastVariant(e->index, e->type); AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); } SetWindowClassesDirty(WC_BUILD_VEHICLE); // Update to show the new reliability @@ -750,6 +764,7 @@ static void DisableEngineForCompany(EngineID eid, CompanyID company) } if (company == _local_company) { + ClearLastVariant(e->index, e->type); AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); } } From 94167dfd34716dda14ee4b2fa12b1d62a14c6d85 Mon Sep 17 00:00:00 2001 From: peter1138 Date: Wed, 27 Feb 2019 07:04:17 +0000 Subject: [PATCH 03/20] Change: Add variant hierarchy to build vehicle window list. --- src/autoreplace_gui.cpp | 64 ++++++++++--- src/build_vehicle_gui.cpp | 197 +++++++++++++++++++++++--------------- src/engine_gui.h | 17 +++- 3 files changed, 188 insertions(+), 90 deletions(-) diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index 35ea32f033..fc6b0d53a2 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -33,11 +33,11 @@ #include "safeguards.h" -void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group); +void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group); -static bool EngineNumberSorter(const EngineID &a, const EngineID &b) +static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - return Engine::Get(a)->list_position < Engine::Get(b)->list_position; + return Engine::Get(a.engine_id)->list_position < Engine::Get(b.engine_id)->list_position; } /** @@ -113,6 +113,22 @@ class ReplaceVehicleWindow : public Window { return true; } + void AddChildren(const GUIEngineList &source, GUIEngineList &target, EngineID parent, int indent, int side) + { + for (const auto &item : source) { + if (item.variant_id != parent || item.engine_id == parent) continue; + + const Engine *e = Engine::Get(item.engine_id); + EngineDisplayFlags flags = item.flags; + if (e->display_last_variant != INVALID_ENGINE) flags &= ~EngineDisplayFlags::Shaded; + target.emplace_back(e->display_last_variant == INVALID_ENGINE ? item.engine_id : e->display_last_variant, item.engine_id, flags, indent); + + /* Add variants if not folded */ + if ((item.flags & (EngineDisplayFlags::HasVariants | EngineDisplayFlags::IsFolded)) == EngineDisplayFlags::HasVariants) { + AddChildren(source, target, item.engine_id, indent + 1, side); + } + } + } /** * Generate an engines list @@ -120,12 +136,12 @@ class ReplaceVehicleWindow : public Window { */ void GenerateReplaceVehList(bool draw_left) { + std::vector variants; EngineID selected_engine = INVALID_ENGINE; VehicleType type = (VehicleType)this->window_number; byte side = draw_left ? 0 : 1; - GUIEngineList *list = &this->engines[side]; - list->clear(); + GUIEngineList list; for (const Engine *e : Engine::IterateType(type)) { if (!draw_left && !this->show_hidden_engines && e->IsHidden(_local_company)) continue; @@ -155,15 +171,37 @@ class ReplaceVehicleWindow : public Window { if (!CheckAutoreplaceValidity(this->sel_engine[0], eid, _local_company)) continue; } - list->push_back(eid); + EngineDisplayFlags flags = (side == 0) ? EngineDisplayFlags::None : e->display_flags; + if (side == 1 && eid == this->sel_engine[0]) flags |= EngineDisplayFlags::Shaded; + list.emplace_back(eid, e->info.variant_id, flags, 0); + + if (side == 1 && e->info.variant_id != INVALID_ENGINE) variants.push_back(e->info.variant_id); if (eid == this->sel_engine[side]) selected_engine = eid; // The selected engine is still in the list } + + if (side == 1) { + /* ensure primary engine of variant group is in list */ + for (const auto &variant : variants) { + if (std::find(list.begin(), list.end(), variant) == list.end()) { + const Engine *e = Engine::Get(variant); + list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlags::Shaded, 0); + } + } + } + this->sel_engine[side] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore) if (draw_left) { - EngList_Sort(list, &EngineNumberSorter); + EngList_Sort(&list, &EngineNumberSorter); } else { _engine_sort_direction = this->descending_sort_order; - EngList_Sort(list, _engine_sort_functions[this->window_number][this->sort_criteria]); + EngList_Sort(&list, _engine_sort_functions[this->window_number][this->sort_criteria]); + } + + this->engines[side].clear(); + if (side == 1) { + AddChildren(list, this->engines[side], INVALID_ENGINE, 0, side); + } else { + this->engines[side].swap(list); } } @@ -177,7 +215,7 @@ class ReplaceVehicleWindow : public Window { this->GenerateReplaceVehList(true); this->vscroll[0]->SetCount((uint)this->engines[0].size()); if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && this->engines[0].size() != 0) { - this->sel_engine[0] = this->engines[0][0]; + this->sel_engine[0] = this->engines[0][0].engine_id; } } @@ -198,8 +236,8 @@ class ReplaceVehicleWindow : public Window { this->vscroll[1]->SetCount((uint)this->engines[1].size()); if (this->reset_sel_engine && this->sel_engine[1] != INVALID_ENGINE) { int position = 0; - for (EngineID &eid : this->engines[1]) { - if (eid == this->sel_engine[1]) break; + for (const auto &item : this->engines[1]) { + if (item.engine_id == this->sel_engine[1]) break; ++position; } this->vscroll[1]->ScrollTowards(position); @@ -433,7 +471,7 @@ public: EngineID end = static_cast(std::min(this->vscroll[side]->GetCapacity() + start, this->engines[side].size())); /* Do the actual drawing */ - DrawEngineList((VehicleType)this->window_number, r, &this->engines[side], start, end, this->sel_engine[side], side == 0, this->sel_group); + DrawEngineList((VehicleType)this->window_number, r, this->engines[side], start, end, this->sel_engine[side], side == 0, this->sel_group); break; } } @@ -579,7 +617,7 @@ public: uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget); size_t engine_count = this->engines[click_side].size(); - EngineID e = engine_count > i ? this->engines[click_side][i] : INVALID_ENGINE; + EngineID e = engine_count > i ? this->engines[click_side][i].engine_id : INVALID_ENGINE; /* If Ctrl is pressed on the left side and we don't have any engines of the selected type, stop autoreplacing. * This is most common when we have finished autoreplacing the engine and want to remove it from the list. */ diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 31114b8965..26deec82e5 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -106,9 +106,9 @@ static CargoID _engine_sort_last_cargo_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EngineNumberSorter(const EngineID &a, const EngineID &b) +static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; + int r = Engine::Get(a.engine_id)->list_position - Engine::Get(b.engine_id)->list_position; return _engine_sort_direction ? r > 0 : r < 0; } @@ -119,10 +119,10 @@ static bool EngineNumberSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EngineIntroDateSorter(const EngineID &a, const EngineID &b) +static bool EngineIntroDateSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - const int va = Engine::Get(a)->intro_date; - const int vb = Engine::Get(b)->intro_date; + const int va = Engine::Get(a.engine_id)->intro_date; + const int vb = Engine::Get(b.engine_id)->intro_date; const int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ @@ -139,19 +139,19 @@ static EngineID _last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EngineNameSorter(const EngineID &a, const EngineID &b) +static bool EngineNameSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { static char last_name[2][64] = { "", "" }; - if (a != _last_engine[0]) { - _last_engine[0] = a; - SetDParam(0, a); + if (a.engine_id != _last_engine[0]) { + _last_engine[0] = a.engine_id; + SetDParam(0, a.engine_id); GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); } - if (b != _last_engine[1]) { - _last_engine[1] = b; - SetDParam(0, b); + if (b.engine_id != _last_engine[1]) { + _last_engine[1] = b.engine_id; + SetDParam(0, b.engine_id); GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); } @@ -168,10 +168,10 @@ static bool EngineNameSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EngineReliabilitySorter(const EngineID &a, const EngineID &b) +static bool EngineReliabilitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - const int va = Engine::Get(a)->reliability; - const int vb = Engine::Get(b)->reliability; + const int va = Engine::Get(a.engine_id)->reliability; + const int vb = Engine::Get(b.engine_id)->reliability; const int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ @@ -185,10 +185,10 @@ static bool EngineReliabilitySorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EngineCostSorter(const EngineID &a, const EngineID &b) +static bool EngineCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - Money va = Engine::Get(a)->GetCost(); - Money vb = Engine::Get(b)->GetCost(); + Money va = Engine::Get(a.engine_id)->GetCost(); + Money vb = Engine::Get(b.engine_id)->GetCost(); int r = ClampToI32(va - vb); /* Use EngineID to sort instead since we want consistent sorting */ @@ -202,10 +202,10 @@ static bool EngineCostSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EngineSpeedSorter(const EngineID &a, const EngineID &b) +static bool EngineSpeedSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - int va = Engine::Get(a)->GetDisplayMaxSpeed(); - int vb = Engine::Get(b)->GetDisplayMaxSpeed(); + int va = Engine::Get(a.engine_id)->GetDisplayMaxSpeed(); + int vb = Engine::Get(b.engine_id)->GetDisplayMaxSpeed(); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ @@ -219,10 +219,10 @@ static bool EngineSpeedSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EnginePowerSorter(const EngineID &a, const EngineID &b) +static bool EnginePowerSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - int va = Engine::Get(a)->GetPower(); - int vb = Engine::Get(b)->GetPower(); + int va = Engine::Get(a.engine_id)->GetPower(); + int vb = Engine::Get(b.engine_id)->GetPower(); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ @@ -236,10 +236,10 @@ static bool EnginePowerSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EngineTractiveEffortSorter(const EngineID &a, const EngineID &b) +static bool EngineTractiveEffortSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - int va = Engine::Get(a)->GetDisplayMaxTractiveEffort(); - int vb = Engine::Get(b)->GetDisplayMaxTractiveEffort(); + int va = Engine::Get(a.engine_id)->GetDisplayMaxTractiveEffort(); + int vb = Engine::Get(b.engine_id)->GetDisplayMaxTractiveEffort(); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ @@ -253,10 +253,10 @@ static bool EngineTractiveEffortSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EngineRunningCostSorter(const EngineID &a, const EngineID &b) +static bool EngineRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - Money va = Engine::Get(a)->GetRunningCost(); - Money vb = Engine::Get(b)->GetRunningCost(); + Money va = Engine::Get(a.engine_id)->GetRunningCost(); + Money vb = Engine::Get(b.engine_id)->GetRunningCost(); int r = ClampToI32(va - vb); /* Use EngineID to sort instead since we want consistent sorting */ @@ -270,10 +270,10 @@ static bool EngineRunningCostSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool EnginePowerVsRunningCostSorter(const EngineID &a, const EngineID &b) +static bool EnginePowerVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - const Engine *e_a = Engine::Get(a); - const Engine *e_b = Engine::Get(b); + const Engine *e_a = Engine::Get(a.engine_id); + const Engine *e_b = Engine::Get(b.engine_id); uint p_a = e_a->GetPower(); uint p_b = e_b->GetPower(); Money r_a = e_a->GetRunningCost(); @@ -312,13 +312,13 @@ static bool EnginePowerVsRunningCostSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool TrainEngineCapacitySorter(const EngineID &a, const EngineID &b) +static bool TrainEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - const RailVehicleInfo *rvi_a = RailVehInfo(a); - const RailVehicleInfo *rvi_b = RailVehInfo(b); + const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id); + const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id); - 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 va = GetTotalCapacityOfArticulatedParts(a.engine_id) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int vb = GetTotalCapacityOfArticulatedParts(b.engine_id) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ @@ -332,10 +332,10 @@ static bool TrainEngineCapacitySorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool TrainEnginesThenWagonsSorter(const EngineID &a, const EngineID &b) +static bool TrainEnginesThenWagonsSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - int val_a = (RailVehInfo(a)->railveh_type == RAILVEH_WAGON ? 1 : 0); - int val_b = (RailVehInfo(b)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int val_a = (RailVehInfo(a.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int val_b = (RailVehInfo(b.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0); int r = val_a - val_b; /* Use EngineID to sort instead since we want consistent sorting */ @@ -351,10 +351,10 @@ static bool TrainEnginesThenWagonsSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool RoadVehEngineCapacitySorter(const EngineID &a, const EngineID &b) +static bool RoadVehEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - int va = GetTotalCapacityOfArticulatedParts(a); - int vb = GetTotalCapacityOfArticulatedParts(b); + int va = GetTotalCapacityOfArticulatedParts(a.engine_id); + int vb = GetTotalCapacityOfArticulatedParts(b.engine_id); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ @@ -370,10 +370,10 @@ static bool RoadVehEngineCapacitySorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool ShipEngineCapacitySorter(const EngineID &a, const EngineID &b) +static bool ShipEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - const Engine *e_a = Engine::Get(a); - const Engine *e_b = Engine::Get(b); + const Engine *e_a = Engine::Get(a.engine_id); + const Engine *e_b = Engine::Get(b.engine_id); int va = e_a->GetDisplayDefaultCapacity(); int vb = e_b->GetDisplayDefaultCapacity(); @@ -392,10 +392,10 @@ static bool ShipEngineCapacitySorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool AircraftEngineCargoSorter(const EngineID &a, const EngineID &b) +static bool AircraftEngineCargoSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - const Engine *e_a = Engine::Get(a); - const Engine *e_b = Engine::Get(b); + const Engine *e_a = Engine::Get(a.engine_id); + const Engine *e_b = Engine::Get(b.engine_id); uint16 mail_a, mail_b; int va = e_a->GetDisplayDefaultCapacity(&mail_a); @@ -420,10 +420,10 @@ static bool AircraftEngineCargoSorter(const EngineID &a, const EngineID &b) * @param b second engine to compare * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static bool AircraftRangeSorter(const EngineID &a, const EngineID &b) +static bool AircraftRangeSorter(const GUIEngineListItem &a, const GUIEngineListItem &b) { - uint16 r_a = Engine::Get(a)->GetRange(); - uint16 r_b = Engine::Get(b)->GetRange(); + uint16 r_a = Engine::Get(a.engine_id)->GetRange(); + uint16 r_b = Engine::Get(b.engine_id)->GetRange(); int r = r_a - r_b; @@ -537,14 +537,14 @@ const StringID _engine_sort_listing[][12] = {{ }}; /** Filters vehicles by cargo and engine (in case of rail vehicle). */ -static bool CDECL CargoAndEngineFilter(const EngineID *eid, const CargoID cid) +static bool CDECL CargoAndEngineFilter(const GUIEngineListItem *item, const CargoID cid) { if (cid == CF_ANY) { return true; } else if (cid == CF_ENGINES) { - return Engine::Get(*eid)->GetPower() != 0; + return Engine::Get(item->engine_id)->GetPower() != 0; } else { - CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true) & _standard_cargo_mask; + CargoTypes refit_mask = GetUnionOfArticulatedRefitMasks(item->engine_id, true) & _standard_cargo_mask; return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid)); } } @@ -962,12 +962,12 @@ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, * @param show_count Whether to show the amount of engines or not * @param selected_group the group to list the engines of */ -void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group) +void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group) { static const int sprite_y_offsets[] = { -1, -1, -2, -2 }; /* Obligatory sanity checks! */ - assert(max <= eng_list->size()); + assert(max <= eng_list.size()); bool rtl = _current_text_dir == TD_RTL; int step_size = GetEngineListHeight(type); @@ -998,7 +998,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList *eng_li int y = ir.top; for (; min < max; min++, y += step_size) { - const EngineID engine = (*eng_list)[min]; + const EngineID engine = eng_list[min].engine_id; /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); @@ -1078,6 +1078,23 @@ struct BuildVehicleWindow : Window { } } + void AddChildren(const GUIEngineList &source, EngineID parent, int indent) + { + for (const auto &item : source) { + if (item.variant_id != parent || item.engine_id == parent) continue; + + const Engine *e = Engine::Get(item.engine_id); + EngineDisplayFlags flags = item.flags; + if (e->display_last_variant != INVALID_ENGINE) flags &= ~EngineDisplayFlags::Shaded; + this->eng_list.emplace_back(e->display_last_variant == INVALID_ENGINE ? item.engine_id : e->display_last_variant, item.engine_id, flags, indent); + + /* Add variants if not folded */ + if ((item.flags & (EngineDisplayFlags::HasVariants | EngineDisplayFlags::IsFolded)) == EngineDisplayFlags::HasVariants) { + AddChildren(source, item.engine_id, indent + 1); + } + } + } + BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc) { this->vehicle_type = type; @@ -1125,7 +1142,7 @@ struct BuildVehicleWindow : Window { 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.size() > 0) { - this->SelectEngine(this->eng_list[0]); + this->SelectEngine(this->eng_list[0].engine_id); } else { this->SelectEngine(INVALID_ENGINE); } @@ -1257,7 +1274,7 @@ struct BuildVehicleWindow : Window { if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine this->SelectEngine(INVALID_ENGINE); } else if (std::find(this->eng_list.begin(), this->eng_list.end(), this->sel_engine) == this->eng_list.end()) { // previously selected engine didn't pass the filter, select the first engine of the list - this->SelectEngine(this->eng_list[0]); + this->SelectEngine(this->eng_list[0].engine_id); } } @@ -1265,17 +1282,19 @@ struct BuildVehicleWindow : Window { bool FilterSingleEngine(EngineID eid) { CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria]; - return CargoAndEngineFilter(&eid, filter_type); + GUIEngineListItem item = {eid, eid, EngineDisplayFlags::None, 0}; + return CargoAndEngineFilter(&item, filter_type); } /* Figure out what train EngineIDs to put in the list */ - void GenerateBuildTrainList() + void GenerateBuildTrainList(GUIEngineList &list) { + std::vector variants; EngineID sel_id = INVALID_ENGINE; int num_engines = 0; int num_wagons = 0; - this->eng_list.clear(); + list.clear(); /* Make list of all available train engines and wagons. * Also check to see if the previously selected engine is still available, @@ -1292,7 +1311,7 @@ struct BuildVehicleWindow : Window { /* Filter now! So num_engines and num_wagons is valid */ if (!FilterSingleEngine(eid)) continue; - this->eng_list.push_back(eid); + list.emplace_back(eid, e->info.variant_id, e->display_flags, 0); if (rvi->railveh_type != RAILVEH_WAGON) { num_engines++; @@ -1300,9 +1319,18 @@ struct BuildVehicleWindow : Window { num_wagons++; } + if (e->info.variant_id != eid && e->info.variant_id != INVALID_ENGINE) variants.push_back(e->info.variant_id); if (eid == this->sel_engine) sel_id = eid; } + /* ensure primary engine of variant group is in list */ + for (const auto &variant : variants) { + if (std::find(list.begin(), list.end(), variant) == list.end()) { + const Engine *e = Engine::Get(variant); + list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlags::Shaded, 0); + } + } + this->SelectEngine(sel_id); /* invalidate cached values for name sorter - engine names could change */ @@ -1310,14 +1338,14 @@ struct BuildVehicleWindow : Window { /* make engines first, and then wagons, sorted by selected sort_criteria */ _engine_sort_direction = false; - EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter); + EngList_Sort(&list, TrainEnginesThenWagonsSorter); /* and then sort engines */ _engine_sort_direction = this->descending_sort_order; - EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines); + EngList_SortPartial(&list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines); /* and finally sort wagons */ - EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], num_engines, num_wagons); + EngList_SortPartial(&list, _engine_sort_functions[0][this->sort_criteria], num_engines, num_wagons); } /* Figure out what road vehicle EngineIDs to put in the list */ @@ -1333,7 +1361,7 @@ struct BuildVehicleWindow : Window { if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue; if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue; - this->eng_list.push_back(eid); + this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0); if (eid == this->sel_engine) sel_id = eid; } @@ -1350,7 +1378,7 @@ struct BuildVehicleWindow : Window { if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; EngineID eid = e->index; if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue; - this->eng_list.push_back(eid); + this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0); if (eid == this->sel_engine) sel_id = eid; } @@ -1377,7 +1405,7 @@ struct BuildVehicleWindow : Window { /* First VEH_END window_numbers are fake to allow a window open for all different types at once */ if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue; - this->eng_list.push_back(eid); + this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0); if (eid == this->sel_engine) sel_id = eid; } @@ -1392,13 +1420,18 @@ struct BuildVehicleWindow : Window { /* Update filter type in case the road/railtype of the depot got converted */ this->UpdateFilterByTile(); + this->eng_list.clear(); + + GUIEngineList list; + switch (this->vehicle_type) { default: NOT_REACHED(); case VEH_TRAIN: - this->GenerateBuildTrainList(); + this->GenerateBuildTrainList(list); + AddChildren(list, INVALID_ENGINE, 0); this->eng_list.shrink_to_fit(); this->eng_list.RebuildDone(); - return; // trains should not reach the last sorting + return; case VEH_ROAD: this->GenerateBuildRoadVehList(); break; @@ -1412,9 +1445,23 @@ struct BuildVehicleWindow : Window { this->FilterEngineList(); + /* ensure primary engine of variant group is in list after filtering */ + std::vector variants; + for (const auto &item : this->eng_list) { + if (item.engine_id != item.variant_id && item.variant_id != INVALID_ENGINE) variants.push_back(item.variant_id); + } + for (const auto &variant : variants) { + if (std::find(this->eng_list.begin(), this->eng_list.end(), variant) == this->eng_list.end()) { + const Engine *e = Engine::Get(variant); + list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlags::Shaded, 0); + } + } + _engine_sort_direction = this->descending_sort_order; EngList_Sort(&this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]); + this->eng_list.swap(list); + AddChildren(list, INVALID_ENGINE, 0); this->eng_list.shrink_to_fit(); this->eng_list.RebuildDone(); } @@ -1440,7 +1487,7 @@ struct BuildVehicleWindow : Window { case WID_BV_LIST: { uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST); size_t num_items = this->eng_list.size(); - this->SelectEngine((i < num_items) ? this->eng_list[i] : INVALID_ENGINE); + this->SelectEngine((i < num_items) ? this->eng_list[i].engine_id : INVALID_ENGINE); this->SetDirty(); if (_ctrl_pressed) { this->OnClick(pt, WID_BV_SHOW_HIDE, 1); @@ -1589,7 +1636,7 @@ struct BuildVehicleWindow : Window { DrawEngineList( this->vehicle_type, r, - &this->eng_list, + this->eng_list, this->vscroll->GetPosition(), static_cast(std::min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.size())), this->sel_engine, diff --git a/src/engine_gui.h b/src/engine_gui.h index f987f57d35..7a766bfc8a 100644 --- a/src/engine_gui.h +++ b/src/engine_gui.h @@ -14,10 +14,23 @@ #include "sortlist_type.h" #include "gfx_type.h" #include "vehicle_type.h" +#include "engine_base.h" -typedef GUIList GUIEngineList; +struct GUIEngineListItem { + EngineID engine_id; ///< Engine to display in build purchase list + EngineID variant_id; ///< Variant group of the engine. + EngineDisplayFlags flags; ///< Flags for toggling/drawing (un)folded status and controlling indentation. + int8 indent; ///< Display indentation level. -typedef bool EngList_SortTypeFunction(const EngineID&, const EngineID&); ///< argument type for #EngList_Sort. + GUIEngineListItem(EngineID engine_id, EngineID variant_id, EngineDisplayFlags flags, int indent) : engine_id(engine_id), variant_id(variant_id), flags(flags), indent(indent) {} + + /* Used when searching list only by engine_id. */ + bool operator == (const EngineID &other) const { return this->engine_id == other; } +}; + +typedef GUIList GUIEngineList; + +typedef bool EngList_SortTypeFunction(const GUIEngineListItem&, const GUIEngineListItem&); ///< argument type for #EngList_Sort. void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare); void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, uint begin, uint num_items); From 85814b29d4c2c7165841b588d1972fcfa84eabd6 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 5 Dec 2022 19:54:41 +0000 Subject: [PATCH 04/20] Feature: Vehicle add-ons can now group engines in purchase list. Grouped engines are collapsed by default but can be expanded. This allows similar engines to be grouped together to avoid cluttering the list. Suggested uses for this are e.g.: * Liveries; same stats but different paint job. * Re-gearing; engine design is mostly the same but different stats. ... but avoiding complex hidden cargo subtype refit systems. Grouped engines are otherwise separate, so can be independently autoreplaced, even between variants. --- src/autoreplace_gui.cpp | 21 ++++++++++- src/build_vehicle_gui.cpp | 75 +++++++++++++++++++++++++++++++++------ src/newgrf.cpp | 2 +- 3 files changed, 85 insertions(+), 13 deletions(-) diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index fc6b0d53a2..2c8186f294 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -125,6 +125,10 @@ class ReplaceVehicleWindow : public Window { /* Add variants if not folded */ if ((item.flags & (EngineDisplayFlags::HasVariants | EngineDisplayFlags::IsFolded)) == EngineDisplayFlags::HasVariants) { + /* Add this engine again as a child */ + if ((item.flags & EngineDisplayFlags::Shaded) == EngineDisplayFlags::None) { + target.emplace_back(item.engine_id, item.engine_id, EngineDisplayFlags::None, indent + 1); + } AddChildren(source, target, item.engine_id, indent + 1, side); } } @@ -617,7 +621,22 @@ public: uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget); size_t engine_count = this->engines[click_side].size(); - EngineID e = engine_count > i ? this->engines[click_side][i].engine_id : INVALID_ENGINE; + EngineID e = INVALID_ENGINE; + if (i < engine_count) { + const auto &item = this->engines[click_side][i]; + const Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL); + if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) { + /* toggle folded flag on engine */ + assert(item.variant_id != INVALID_ENGINE); + Engine *engine = Engine::Get(item.variant_id); + engine->display_flags ^= EngineDisplayFlags::IsFolded; + + InvalidateWindowData(WC_REPLACE_VEHICLE, (VehicleType)this->window_number, 0); // Update the autoreplace window + InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well + return; + } + if ((item.flags & EngineDisplayFlags::Shaded) == EngineDisplayFlags::None) e = item.engine_id; + } /* If Ctrl is pressed on the left side and we don't have any engines of the selected type, stop autoreplacing. * This is most common when we have finished autoreplacing the engine and want to remove it from the list. */ diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 26deec82e5..e9b7e90c34 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -974,9 +974,10 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left; int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right; int sprite_width = sprite_left + sprite_right; + int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width); + int linecolour = _colour_gradient[COLOUR_ORANGE][4]; Rect ir = r.WithHeight(step_size).Shrink(WidgetDimensions::scaled.matrix); - int sprite_x = ir.WithWidth(sprite_width, rtl).left + sprite_left; int sprite_y_offset = ScaleSpriteTrad(sprite_y_offsets[type]) + ir.Height() / 2; Dimension replace_icon = {0, 0}; @@ -987,7 +988,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width; } - Rect tr = ir.Indent(sprite_width + WidgetDimensions::scaled.hsep_wide, rtl); // Name position + Rect tr = ir.Indent(circle_width + WidgetDimensions::scaled.hsep_normal + sprite_width + WidgetDimensions::scaled.hsep_wide, rtl); // Name position Rect cr = tr.Indent(replace_icon.width + WidgetDimensions::scaled.hsep_wide, !rtl).WithWidth(count_width, !rtl); // Count position Rect rr = tr.WithWidth(replace_icon.width, !rtl); // Replace icon position if (show_count) tr = tr.Indent(count_width + WidgetDimensions::scaled.hsep_normal + replace_icon.width + WidgetDimensions::scaled.hsep_wide, !rtl); @@ -998,22 +999,40 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li int y = ir.top; for (; min < max; min++, y += step_size) { - const EngineID engine = eng_list[min].engine_id; + const auto &item = eng_list[min]; + uint indent = item.indent * WidgetDimensions::scaled.hsep_indent; + bool has_variants = (item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None; + bool is_folded = (item.flags & EngineDisplayFlags::IsFolded) != EngineDisplayFlags::None; + bool shaded = (item.flags & EngineDisplayFlags::Shaded) != EngineDisplayFlags::None; /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ - const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); + const uint num_engines = GetGroupNumEngines(_local_company, selected_group, item.engine_id); - const Engine *e = Engine::Get(engine); + const Engine *e = Engine::Get(item.engine_id); bool hidden = HasBit(e->company_hidden, _local_company); StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME; - TextColour tc = (engine == selected_id) ? TC_WHITE : (TC_NO_SHADE | (hidden ? TC_GREY : TC_BLACK)); + TextColour tc = (item.engine_id == selected_id) ? TC_WHITE : (TC_NO_SHADE | ((hidden | shaded) ? TC_GREY : TC_BLACK)); - SetDParam(0, engine); - DrawString(tr.left, tr.right, y + normal_text_y_offset, str, tc); - DrawVehicleEngine(r.left, r.right, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); + SetDParam(0, item.engine_id); + Rect itr = tr.Indent(indent, rtl); + DrawString(itr.left, itr.right, y + normal_text_y_offset, str, tc); + int sprite_x = ir.Indent(indent + circle_width + WidgetDimensions::scaled.hsep_normal, rtl).WithWidth(sprite_width, rtl).left + sprite_left; + DrawVehicleEngine(r.left, r.right, sprite_x, y + sprite_y_offset, item.engine_id, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(item.engine_id, _local_company), EIT_PURCHASE); if (show_count) { SetDParam(0, num_engines); DrawString(cr.left, cr.right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); - if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, rr.left, y + replace_icon_y_offset); + if (EngineHasReplacementForCompany(Company::Get(_local_company), item.engine_id, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, rr.left, y + replace_icon_y_offset); + } + if (has_variants) { + Rect fr = ir.Indent(indent, rtl).WithWidth(circle_width, rtl); + DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, {fr.left, y, fr.right, y + ir.Height() - 1}, false, SA_CENTER); + } + if (indent > 0) { + /* Draw tree lines */ + Rect fr = ir.Indent(indent - WidgetDimensions::scaled.hsep_indent, rtl).WithWidth(circle_width, rtl); + int ycenter = y + normal_text_y_offset + FONT_HEIGHT_NORMAL / 2; + bool continues = (min + 1U) < eng_list.size() && eng_list[min + 1].indent == item.indent; + GfxDrawLine(fr.left + circle_width / 2, y - WidgetDimensions::scaled.matrix.top, fr.left + circle_width / 2, continues ? y - WidgetDimensions::scaled.matrix.top + step_size - 1 : ycenter, linecolour, WidgetDimensions::scaled.fullbevel.top); + GfxDrawLine(fr.left + circle_width / 2, ycenter, fr.right, ycenter, linecolour, WidgetDimensions::scaled.fullbevel.top); } } } @@ -1090,6 +1109,10 @@ struct BuildVehicleWindow : Window { /* Add variants if not folded */ if ((item.flags & (EngineDisplayFlags::HasVariants | EngineDisplayFlags::IsFolded)) == EngineDisplayFlags::HasVariants) { + /* Add this engine again as a child */ + if ((item.flags & EngineDisplayFlags::Shaded) == EngineDisplayFlags::None) { + this->eng_list.emplace_back(item.engine_id, item.engine_id, EngineDisplayFlags::None, indent + 1); + } AddChildren(source, item.engine_id, indent + 1); } } @@ -1487,7 +1510,23 @@ struct BuildVehicleWindow : Window { case WID_BV_LIST: { uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST); size_t num_items = this->eng_list.size(); - this->SelectEngine((i < num_items) ? this->eng_list[i].engine_id : INVALID_ENGINE); + EngineID e = INVALID_ENGINE; + if (i < num_items) { + const auto &item = this->eng_list[i]; + const Rect r = this->GetWidget(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL); + if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) { + /* toggle folded flag on engine */ + assert(item.variant_id != INVALID_ENGINE); + Engine *engine = Engine::Get(item.variant_id); + engine->display_flags ^= EngineDisplayFlags::IsFolded; + + InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window + InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well + return; + } + if ((item.flags & EngineDisplayFlags::Shaded) == EngineDisplayFlags::None) e = item.engine_id; + } + this->SelectEngine(e); this->SetDirty(); if (_ctrl_pressed) { this->OnClick(pt, WID_BV_SHOW_HIDE, 1); @@ -1523,6 +1562,20 @@ struct BuildVehicleWindow : Window { } else { Command::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildPrimaryVehicle, this->window_number, sel_eng, true, cargo, INVALID_CLIENT_ID); } + + /* Update last used variant and refresh if necessary. */ + bool refresh = false; + int recursion = 10; /* In case of infinite loop */ + for (Engine *e = Engine::Get(sel_eng); recursion > 0; e = Engine::Get(e->info.variant_id), --recursion) { + refresh |= (e->display_last_variant != sel_eng); + e->display_last_variant = sel_eng; + if (e->info.variant_id == INVALID_ENGINE) break; + } + if (refresh) { + InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window + InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well + return; + } } break; } diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 16eb7696bb..71f7abbd25 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -9001,7 +9001,7 @@ static void FinaliseEngineArray() /* Set appropriate flags on variant engine */ if (e->info.variant_id != INVALID_ENGINE) { - Engine::Get(e->info.variant_id)->display_flags |= EngineDisplayFlags::HasVariants; + Engine::Get(e->info.variant_id)->display_flags |= EngineDisplayFlags::HasVariants | EngineDisplayFlags::IsFolded; } /* Skip wagons, there livery is defined via the engine */ From 898dadadb2a34b589f4d43f65a146c81b674e502 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 9 Dec 2022 00:33:32 +0000 Subject: [PATCH 05/20] Change: Mark build/autoreplace windows dirty less often in monthy loop. These window classes were marked dirty for every engine that had reliability calculated every month. --- src/engine.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/engine.cpp b/src/engine.cpp index a55fac9b7e..6c75ee3e74 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -613,8 +613,7 @@ static void CalcEngineReliability(Engine *e) ClearLastVariant(e->index, e->type); AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); } - SetWindowClassesDirty(WC_BUILD_VEHICLE); // Update to show the new reliability - SetWindowClassesDirty(WC_REPLACE_VEHICLE); + } /** Compute the value for #_year_engine_aging_stops. */ @@ -716,6 +715,9 @@ void StartupEngines() /* Invalidate any open purchase lists */ InvalidateWindowClassesData(WC_BUILD_VEHICLE); + + SetWindowClassesDirty(WC_BUILD_VEHICLE); + SetWindowClassesDirty(WC_REPLACE_VEHICLE); } /** @@ -1031,11 +1033,13 @@ static void NewVehicleAvailable(Engine *e) void EnginesMonthlyLoop() { if (_cur_year < _year_engine_aging_stops) { + bool refresh = false; for (Engine *e : Engine::Iterate()) { /* Age the vehicle */ if ((e->flags & ENGINE_AVAILABLE) && e->age != MAX_DAY) { e->age++; CalcEngineReliability(e); + refresh = true; } /* Do not introduce invalid engines */ @@ -1062,6 +1066,11 @@ void EnginesMonthlyLoop() } InvalidateWindowClassesData(WC_BUILD_VEHICLE); // rebuild the purchase list (esp. when sorted by reliability) + + if (refresh) { + SetWindowClassesDirty(WC_BUILD_VEHICLE); + SetWindowClassesDirty(WC_REPLACE_VEHICLE); + } } } From 3485709f537215754246ad6181b597ee521eeade Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 9 Dec 2022 01:40:55 +0000 Subject: [PATCH 06/20] Add: Additional vehicle flags to control variants. --- src/engine.cpp | 49 +++++++++++++++++++++++++++++------ src/engine_func.h | 1 + src/engine_type.h | 10 +++++++ src/newgrf.cpp | 16 ++++++++++++ src/saveload/oldloader_sl.cpp | 1 + src/table/engines.h | 12 ++++----- 6 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/engine.cpp b/src/engine.cpp index 6c75ee3e74..abcf4f9d7a 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -578,9 +578,16 @@ static void ClearLastVariant(EngineID engine_id, VehicleType type) * Update #Engine::reliability and (if needed) update the engine GUIs. * @param e %Engine to update. */ -static void CalcEngineReliability(Engine *e) +void CalcEngineReliability(Engine *e, bool new_month) { - uint age = e->age; + /* Get source engine for reliability age. This is normally our engine unless variant reliability syncing is requested. */ + Engine *re = e; + while (re->info.variant_id != INVALID_ENGINE && re->info.variant_id != re->index && (re->info.extra_flags & ExtraEngineFlags::SyncReliability) != ExtraEngineFlags::None) { + re = Engine::Get(re->info.variant_id); + } + + uint age = re->age; + if (new_month && re->index > e->index && age != MAX_DAY) age++; /* parent variant's age has not yet updated. */ /* Check for early retirement */ if (e->company_avail != 0 && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) { @@ -671,7 +678,16 @@ void StartupOneEngine(Engine *e, Date aging_date) e->flags |= ENGINE_AVAILABLE; } - RestoreRandomSeeds(saved_seeds); + /* Get parent variant index for syncing reliability via random seed. */ + const Engine *re = e; + while (re->info.variant_id != INVALID_ENGINE && re->info.variant_id != re->index && (re->info.extra_flags & ExtraEngineFlags::SyncReliability) != ExtraEngineFlags::None) { + re = Engine::Get(re->info.variant_id); + } + + SetRandomSeed(_settings_game.game_creation.generation_seed ^ + re->index ^ + e->type ^ + e->GetGRFID()); r = Random(); e->reliability_start = GB(r, 16, 14) + 0x7AE0; @@ -683,9 +699,9 @@ void StartupOneEngine(Engine *e, Date aging_date) e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96; e->duration_phase_3 = GB(r, 9, 7) + 120; - e->reliability_spd_dec = ei->decay_speed << 2; + RestoreRandomSeeds(saved_seeds); - CalcEngineReliability(e); + e->reliability_spd_dec = ei->decay_speed << 2; /* prevent certain engines from ever appearing. */ if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) { @@ -706,6 +722,9 @@ void StartupEngines() for (Engine *e : Engine::Iterate()) { StartupOneEngine(e, aging_date); } + for (Engine *e : Engine::Iterate()) { + CalcEngineReliability(e, false); + } /* Update the bitmasks for the vehicle lists */ for (Company *c : Company::Iterate()) { @@ -775,8 +794,9 @@ static void DisableEngineForCompany(EngineID eid, CompanyID company) * Company \a company accepts engine \a eid for preview. * @param eid Engine being accepted (is under preview). * @param company Current company previewing the engine. + * @param recursion_depth Recursion depth to avoid infinite loop. */ -static void AcceptEnginePreview(EngineID eid, CompanyID company) +static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_depth = 0) { Engine *e = Engine::Get(eid); @@ -791,6 +811,16 @@ static void AcceptEnginePreview(EngineID eid, CompanyID company) * we have to use the GUI-scope scheduling of InvalidateWindowData. */ InvalidateWindowData(WC_ENGINE_PREVIEW, eid); + + /* Don't search for variants to include if we are 10 levels deep already. */ + if (recursion_depth >= 10) return; + + /* Find variants to be included in preview. */ + for (Engine *ve : Engine::IterateType(e->type)) { + if (ve->index != eid && ve->info.variant_id == eid && (ve->info.extra_flags & ExtraEngineFlags::JoinPreview) != ExtraEngineFlags::None) { + AcceptEnginePreview(ve->index, company, recursion_depth + 1); + } + } } /** @@ -1014,7 +1044,7 @@ static void NewVehicleAvailable(Engine *e) if (!IsVehicleTypeDisabled(e->type, true)) AI::BroadcastNewEvent(new ScriptEventEngineAvailable(index)); /* Only provide the "New Vehicle available" news paper entry, if engine can be built. */ - if (!IsVehicleTypeDisabled(e->type, false)) { + if (!IsVehicleTypeDisabled(e->type, false) && (e->info.extra_flags & ExtraEngineFlags::NoNews) == ExtraEngineFlags::None) { SetDParam(0, GetEngineCategoryName(index)); SetDParam(1, index); AddNewsItem(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NT_NEW_VEHICLES, NF_VEHICLE, NR_ENGINE, index); @@ -1038,7 +1068,7 @@ void EnginesMonthlyLoop() /* Age the vehicle */ if ((e->flags & ENGINE_AVAILABLE) && e->age != MAX_DAY) { e->age++; - CalcEngineReliability(e); + CalcEngineReliability(e, true); refresh = true; } @@ -1058,6 +1088,9 @@ void EnginesMonthlyLoop() /* Do not introduce new rail wagons */ if (IsWagon(e->index)) continue; + /* Engine has no preview */ + if ((e->info.extra_flags & ExtraEngineFlags::NoPreview) != ExtraEngineFlags::None) continue; + /* Show preview dialog to one of the companies. */ e->flags |= ENGINE_EXCLUSIVE_PREVIEW; e->preview_company = INVALID_COMPANY; diff --git a/src/engine_func.h b/src/engine_func.h index 97bfd0894b..f7d7dad9f8 100644 --- a/src/engine_func.h +++ b/src/engine_func.h @@ -26,6 +26,7 @@ bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company); bool IsEngineRefittable(EngineID engine); void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits, CargoID cargo_type, uint cargo_capacity); void SetYearEngineAgingStops(); +void CalcEngineReliability(Engine *e, bool new_month); void StartupOneEngine(Engine *e, Date aging_date); uint GetTotalCapacityOfArticulatedParts(EngineID engine); diff --git a/src/engine_type.h b/src/engine_type.h index 9cee244f12..eeccf3e2b8 100644 --- a/src/engine_type.h +++ b/src/engine_type.h @@ -126,6 +126,15 @@ struct RoadVehicleInfo { RoadType roadtype; ///< Road type }; +enum class ExtraEngineFlags : uint32 { + None = 0, + NoNews = (1U << 0), ///< No 'new vehicle' news will be generated. + NoPreview = (1U << 1), ///< No exclusive preview will be offered. + JoinPreview = (1U << 2), ///< Engine will join exclusive preview with variant parent. + SyncReliability = (1U << 3), ///< Engine reliability will be synced with variant parent. +}; +DECLARE_ENUM_AS_BIT_SET(ExtraEngineFlags); + /** * Information about a vehicle * @see table/engines.h @@ -146,6 +155,7 @@ struct EngineInfo { StringID string_id; ///< Default name of engine uint16 cargo_age_period; ///< Number of ticks before carried cargo is aged. EngineID variant_id; ///< Engine variant ID. If set, will be treated specially in purchase lists. + ExtraEngineFlags extra_flags; }; /** diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 71f7abbd25..2d9dc1078f 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -1338,6 +1338,10 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop ei->variant_id = GetNewEngineID(_cur.grffile, VEH_TRAIN, buf->ReadWord()); break; + case 0x30: // Extra miscellaneous flags + ei->extra_flags = static_cast(buf->ReadDWord()); + break; + default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; @@ -1536,6 +1540,10 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop ei->variant_id = GetNewEngineID(_cur.grffile, VEH_ROAD, buf->ReadWord()); break; + case 0x27: // Extra miscellaneous flags + ei->extra_flags = static_cast(buf->ReadDWord()); + break; + default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; @@ -1712,6 +1720,10 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop ei->variant_id = GetNewEngineID(_cur.grffile, VEH_SHIP, buf->ReadWord()); break; + case 0x21: // Extra miscellaneous flags + ei->extra_flags = static_cast(buf->ReadDWord()); + break; + default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; @@ -1870,6 +1882,10 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int ei->variant_id = GetNewEngineID(_cur.grffile, VEH_AIRCRAFT, buf->ReadWord()); break; + case 0x21: // Extra miscellaneous flags + ei->extra_flags = static_cast(buf->ReadDWord()); + break; + default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index a419e4b344..74a2996601 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -402,6 +402,7 @@ static bool FixTTOEngines() /* Default engine is used */ _date += DAYS_TILL_ORIGINAL_BASE_YEAR; StartupOneEngine(e, aging_date); + CalcEngineReliability(e, false); e->intro_date -= DAYS_TILL_ORIGINAL_BASE_YEAR; _date -= DAYS_TILL_ORIGINAL_BASE_YEAR; diff --git a/src/table/engines.h b/src/table/engines.h index 6d45bfb02f..e3b1481d7f 100644 --- a/src/table/engines.h +++ b/src/table/engines.h @@ -24,7 +24,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MT(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } +#define MT(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None } /** * Writes the properties of a multiple-unit train into the EngineInfo struct. @@ -37,7 +37,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MM(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_IS_MU, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } +#define MM(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_IS_MU, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None } /** * Writes the properties of a train carriage into the EngineInfo struct. @@ -50,7 +50,7 @@ * @see MT * @note the 5 between b and f is the load amount */ -#define MW(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } +#define MW(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None } /** * Writes the properties of a road vehicle into the EngineInfo struct. @@ -63,7 +63,7 @@ * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ -#define MR(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } +#define MR(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None } /** * Writes the properties of a ship into the EngineInfo struct. @@ -75,7 +75,7 @@ * @param f Bitmask of the climates * @note the 10 between b and f is the load amount */ -#define MS(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 10, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } +#define MS(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 10, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None } /** * Writes the properties of an aeroplane into the EngineInfo struct. @@ -86,7 +86,7 @@ * @param e Bitmask of the climates * @note the 20 between b and e is the load amount */ -#define MA(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 20, e, CT_INVALID, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE } +#define MA(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 20, e, CT_INVALID, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS, INVALID_ENGINE, ExtraEngineFlags::None } /* Climates * T = Temperate From 74180efe7fb170929ca868e6668bce129ae0d888 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 11 Dec 2022 13:22:17 +0000 Subject: [PATCH 07/20] Change: Attempt to improve randomisation of reliability --- src/engine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine.cpp b/src/engine.cpp index abcf4f9d7a..8bd14849ad 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -685,7 +685,8 @@ void StartupOneEngine(Engine *e, Date aging_date) } SetRandomSeed(_settings_game.game_creation.generation_seed ^ - re->index ^ + (re->index << 16) ^ (re->info.base_intro << 12) ^ (re->info.decay_speed << 8) ^ + (re->info.lifelength << 4) ^ re->info.retire_early ^ e->type ^ e->GetGRFID()); From cbf48c4dd9aa4268df835e6ac1207db8094a935d Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 12 Dec 2022 11:17:55 +0000 Subject: [PATCH 08/20] Change: Add extra random seed to StartupEngines(). This means that calling reset_engines will rerandomise introduction dates and reliability. Probably not necessary. --- src/engine.cpp | 10 ++++++---- src/engine_func.h | 2 +- src/saveload/oldloader_sl.cpp | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/engine.cpp b/src/engine.cpp index 8bd14849ad..3423c7f40f 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -648,8 +648,9 @@ void SetYearEngineAgingStops() * Start/initialise one engine. * @param e The engine to initialise. * @param aging_date The date used for age calculations. + * @param seed Random seed. */ -void StartupOneEngine(Engine *e, Date aging_date) +void StartupOneEngine(Engine *e, Date aging_date, uint32 seed) { const EngineInfo *ei = &e->info; @@ -662,7 +663,7 @@ void StartupOneEngine(Engine *e, Date aging_date) * Make sure they use the same randomisation of the date. */ SavedRandomSeeds saved_seeds; SaveRandomSeeds(&saved_seeds); - SetRandomSeed(_settings_game.game_creation.generation_seed ^ + SetRandomSeed(_settings_game.game_creation.generation_seed ^ seed ^ ei->base_intro ^ e->type ^ e->GetGRFID()); @@ -684,7 +685,7 @@ void StartupOneEngine(Engine *e, Date aging_date) re = Engine::Get(re->info.variant_id); } - SetRandomSeed(_settings_game.game_creation.generation_seed ^ + SetRandomSeed(_settings_game.game_creation.generation_seed ^ seed ^ (re->index << 16) ^ (re->info.base_intro << 12) ^ (re->info.decay_speed << 8) ^ (re->info.lifelength << 4) ^ re->info.retire_early ^ e->type ^ @@ -719,9 +720,10 @@ void StartupEngines() { /* Aging of vehicles stops, so account for that when starting late */ const Date aging_date = std::min(_date, ConvertYMDToDate(_year_engine_aging_stops, 0, 1)); + uint32 seed = Random(); for (Engine *e : Engine::Iterate()) { - StartupOneEngine(e, aging_date); + StartupOneEngine(e, aging_date, seed); } for (Engine *e : Engine::Iterate()) { CalcEngineReliability(e, false); diff --git a/src/engine_func.h b/src/engine_func.h index f7d7dad9f8..0d69743bfe 100644 --- a/src/engine_func.h +++ b/src/engine_func.h @@ -27,7 +27,7 @@ bool IsEngineRefittable(EngineID engine); void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits, CargoID cargo_type, uint cargo_capacity); void SetYearEngineAgingStops(); void CalcEngineReliability(Engine *e, bool new_month); -void StartupOneEngine(Engine *e, Date aging_date); +void StartupOneEngine(Engine *e, Date aging_date, uint32 seed); uint GetTotalCapacityOfArticulatedParts(EngineID engine); diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 74a2996601..fc09c7e787 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -401,7 +401,7 @@ static bool FixTTOEngines() if (oi == 255) { /* Default engine is used */ _date += DAYS_TILL_ORIGINAL_BASE_YEAR; - StartupOneEngine(e, aging_date); + StartupOneEngine(e, aging_date, 0); CalcEngineReliability(e, false); e->intro_date -= DAYS_TILL_ORIGINAL_BASE_YEAR; _date -= DAYS_TILL_ORIGINAL_BASE_YEAR; From efa20dd96939f811a4a9c5d8aadd251e72a29f94 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 18 Dec 2022 12:27:26 +0000 Subject: [PATCH 09/20] Change: Support engine property 0xC6 in purchase list. --- src/newgrf_engine.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index a8dace53f8..af72c65ed1 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -975,6 +975,8 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, case 0x92: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF); // Date of last service case 0x93: return GB(Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF), 8, 8); case 0xC4: return Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; // Build year + case 0xC6: return Engine::Get(this->self_type)->grf_prop.local_id; + case 0xC7: return GB(Engine::Get(this->self_type)->grf_prop.local_id, 8, 8); case 0xDA: return INVALID_VEHICLE; // Next vehicle case 0xF2: return 0; // Cargo subtype } From 8063fcb6e03f4a2d20d0b28f6b93ca9a57fd923f Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Sun, 25 Dec 2022 13:20:31 -0500 Subject: [PATCH 10/20] Feature: Ctrl-click to bulk edit timetable speeds/waiting times (#10265) --- src/command_type.h | 1 + src/lang/english.txt | 10 +++++----- src/timetable_cmd.cpp | 33 +++++++++++++++++++++++++++++++++ src/timetable_cmd.h | 10 ++++++---- src/timetable_gui.cpp | 23 ++++++++++++++++++++--- 5 files changed, 65 insertions(+), 12 deletions(-) diff --git a/src/command_type.h b/src/command_type.h index 0ce1a9a58d..d2b573b333 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -331,6 +331,7 @@ enum Commands : uint16 { CMD_MOVE_ORDER, ///< move an order CMD_CHANGE_TIMETABLE, ///< change the timetable for a vehicle + CMD_BULK_CHANGE_TIMETABLE, ///< change the timetable for all orders of a vehicle CMD_SET_VEHICLE_ON_TIME, ///< set the vehicle on time feature (timetable) CMD_AUTOFILL_TIMETABLE, ///< autofill the timetable CMD_SET_TIMETABLE_START, ///< set the date that a timetable should start diff --git a/src/lang/english.txt b/src/lang/english.txt index 9b14575ac1..dedf5b8519 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4511,22 +4511,22 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Start da STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Select a date as starting point of this timetable. Ctrl+Click distributes all vehicles sharing this order evenly from the given date based on their relative order, if the order is completely timetabled STR_TIMETABLE_CHANGE_TIME :{BLACK}Change Time -STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Change the amount of time that the highlighted order should take +STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Change the amount of time that the highlighted order should take. Ctrl+Click sets the time for all orders STR_TIMETABLE_CLEAR_TIME :{BLACK}Clear Time -STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clear the amount of time for the highlighted order +STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clear the amount of time for the highlighted order. Ctrl+Click clears the time for all orders STR_TIMETABLE_CHANGE_SPEED :{BLACK}Change Speed Limit -STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Change the maximum travel speed of the highlighted order +STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Change the maximum travel speed of the highlighted order. Ctrl+Click sets the speed for all orders STR_TIMETABLE_CLEAR_SPEED :{BLACK}Clear Speed Limit -STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clear the maximum travel speed of the highlighted order +STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clear the maximum travel speed of the highlighted order. Ctrl+Click clears the speed for all orders STR_TIMETABLE_RESET_LATENESS :{BLACK}Reset Late Counter STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reset the lateness counter, so the vehicle will be on time STR_TIMETABLE_AUTOFILL :{BLACK}Autofill -STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey (Ctrl+Click to try to keep waiting times) +STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey. Ctrl+Click to try to keep waiting times STR_TIMETABLE_EXPECTED :{BLACK}Expected STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 6f7dcca55b..f800b25ae6 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -173,6 +173,39 @@ CommandCost CmdChangeTimetable(DoCommandFlag flags, VehicleID veh, VehicleOrderI return CommandCost(); } +/** + * Change timetable data of all orders of a vehicle. + * @param flags Operation to perform. + * @param veh Vehicle with the orders to change. + * @param mtf Timetable data to change (@see ModifyTimetableFlags) + * @param data The data to modify as specified by \c mtf. + * 0 to clear times, UINT16_MAX to clear speed limit. + * @return the cost of this operation or an error + */ +CommandCost CmdBulkChangeTimetable(DoCommandFlag flags, VehicleID veh, ModifyTimetableFlags mtf, uint16 data) +{ + Vehicle *v = Vehicle::GetIfValid(veh); + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; + + CommandCost ret = CheckOwnership(v->owner); + if (ret.Failed()) return ret; + + if (mtf >= MTF_END) return CMD_ERROR; + + if (v->GetNumOrders() == 0) return CMD_ERROR; + + if (flags & DC_EXEC) { + for (VehicleOrderID order_number = 0; order_number < v->GetNumOrders(); order_number++) { + Order *order = v->GetOrder(order_number); + if (order == nullptr || order->IsType(OT_IMPLICIT)) continue; + + Command::Do(DC_EXEC, v->index, order_number, mtf, data); + } + } + + return CommandCost(); +} + /** * Clear the lateness counter to make the vehicle on time. * @param flags Operation to perform. diff --git a/src/timetable_cmd.h b/src/timetable_cmd.h index ddf1277372..7be7982320 100644 --- a/src/timetable_cmd.h +++ b/src/timetable_cmd.h @@ -13,13 +13,15 @@ #include "command_type.h" CommandCost CmdChangeTimetable(DoCommandFlag flags, VehicleID veh, VehicleOrderID order_number, ModifyTimetableFlags mtf, uint16 data); +CommandCost CmdBulkChangeTimetable(DoCommandFlag flags, VehicleID veh, ModifyTimetableFlags mtf, uint16 data); CommandCost CmdSetVehicleOnTime(DoCommandFlag flags, VehicleID veh); CommandCost CmdAutofillTimetable(DoCommandFlag flags, VehicleID veh, bool autofill, bool preserve_wait_time); CommandCost CmdSetTimetableStart(DoCommandFlag flags, VehicleID veh_id, bool timetable_all, Date start_date); -DEF_CMD_TRAIT(CMD_CHANGE_TIMETABLE, CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT) -DEF_CMD_TRAIT(CMD_SET_VEHICLE_ON_TIME, CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT) -DEF_CMD_TRAIT(CMD_AUTOFILL_TIMETABLE, CmdAutofillTimetable, 0, CMDT_ROUTE_MANAGEMENT) -DEF_CMD_TRAIT(CMD_SET_TIMETABLE_START, CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT) +DEF_CMD_TRAIT(CMD_CHANGE_TIMETABLE, CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT) +DEF_CMD_TRAIT(CMD_BULK_CHANGE_TIMETABLE, CmdBulkChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT) +DEF_CMD_TRAIT(CMD_SET_VEHICLE_ON_TIME, CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT) +DEF_CMD_TRAIT(CMD_AUTOFILL_TIMETABLE, CmdAutofillTimetable, 0, CMDT_ROUTE_MANAGEMENT) +DEF_CMD_TRAIT(CMD_SET_TIMETABLE_START, CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT) #endif /* TIMETABLE_CMD_H */ diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index 7a48756f57..f6b1e3da93 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -156,6 +156,8 @@ struct TimetableWindow : Window { uint deparr_abbr_width; ///< The width of the departure/arrival abbreviation Scrollbar *vscroll; bool query_is_speed_query; ///< The currently open query window is a speed query and not a time query. + bool set_start_date_all; ///< Set start date using minutes text entry for all timetable entries (ctrl-click) action + bool change_timetable_all; ///< Set wait time or speed for all timetable entries (ctrl-click) action TimetableWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), @@ -551,6 +553,7 @@ struct TimetableWindow : Window { } this->query_is_speed_query = false; + this->change_timetable_all = _ctrl_pressed && (order != nullptr); ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); break; } @@ -571,19 +574,28 @@ struct TimetableWindow : Window { } this->query_is_speed_query = true; + this->change_timetable_all = _ctrl_pressed && (order != nullptr); ShowQueryString(current, STR_TIMETABLE_CHANGE_SPEED, 31, this, CS_NUMERAL, QSF_NONE); break; } case WID_VT_CLEAR_TIME: { // Clear waiting time. auto [order_id, mtf] = PackTimetableArgs(v, this->sel_index, false); - Command::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, order_id, mtf, 0); + if (_ctrl_pressed) { + Command::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, mtf, 0); + } else { + Command::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, order_id, mtf, 0); + } break; } case WID_VT_CLEAR_SPEED: { // Clear max speed button. auto [order_id, mtf] = PackTimetableArgs(v, this->sel_index, true); - Command::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, order_id, mtf, UINT16_MAX); + if (_ctrl_pressed) { + Command::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, mtf, UINT16_MAX); + } else { + Command::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, order_id, mtf, UINT16_MAX); + } break; } @@ -622,7 +634,12 @@ struct TimetableWindow : Window { } auto [order_id, mtf] = PackTimetableArgs(v, this->sel_index, this->query_is_speed_query); - Command::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, order_id, mtf, std::min(val, UINT16_MAX)); + + if (this->change_timetable_all) { + Command::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, mtf, std::min(val, UINT16_MAX)); + } else { + Command::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, v->index, order_id, mtf, std::min(val, UINT16_MAX)); + } } void OnResize() override From 4ffe7e04778bf79af1cc73de92636cfcf7ba127e Mon Sep 17 00:00:00 2001 From: Tyler Trahan Date: Sun, 25 Dec 2022 13:26:26 -0500 Subject: [PATCH 11/20] Fix #10198: Rearrange Intro GUI to make button rows narrower (#10203) --- src/intro_gui.cpp | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/intro_gui.cpp b/src/intro_gui.cpp index 001736a8f5..7e86c1e53c 100644 --- a/src/intro_gui.cpp +++ b/src/intro_gui.cpp @@ -380,7 +380,7 @@ static const NWidgetPart _nested_select_game_widgets[] = { NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_SPACER), SetMinimalSize(0, 8), - /* 'generate game' and 'load game' buttons */ + /* 'New Game' and 'Load Game' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_GENERATE_GAME), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetPadding(0, 0, 0, 10), SetFill(1, 0), @@ -390,7 +390,7 @@ static const NWidgetPart _nested_select_game_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 6), - /* 'play scenario' and 'play heightmap' buttons */ + /* 'Play Scenario' and 'Play Heightmap' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_PLAY_SCENARIO), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetPadding(0, 0, 0, 10), SetFill(1, 0), @@ -400,7 +400,7 @@ static const NWidgetPart _nested_select_game_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 6), - /* 'edit scenario' and 'play multiplayer' buttons */ + /* 'Scenario Editor' and 'Multiplayer' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_EDIT_SCENARIO), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_SCENARIO_EDITOR, STR_INTRO_TOOLTIP_SCENARIO_EDITOR), SetPadding(0, 0, 0, 10), SetFill(1, 0), @@ -410,7 +410,7 @@ static const NWidgetPart _nested_select_game_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 7), - /* climate selection buttons */ + /* Climate selection buttons */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(10, 0), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_SGI_TEMPERATE_LANDSCAPE), SetMinimalSize(77, 55), @@ -439,7 +439,7 @@ static const NWidgetPart _nested_select_game_widgets[] = { EndContainer(), EndContainer(), - /* 'game options' and 'advanced settings' buttons */ + /* 'Game Options' and 'Settings' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_OPTIONS), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_GAME_OPTIONS, STR_INTRO_TOOLTIP_GAME_OPTIONS), SetPadding(0, 0, 0, 10), SetFill(1, 0), @@ -449,29 +449,35 @@ static const NWidgetPart _nested_select_game_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 6), - /* 'AO settings', 'Game Script settings', and 'newgrf settings' buttons */ + /* 'AI Settings' and 'Game Script Settings' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_AI_SETTINGS), SetMinimalSize(105, 12), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_AI_SETTINGS), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_AI_SETTINGS, STR_INTRO_TOOLTIP_AI_SETTINGS), SetPadding(0, 0, 0, 10), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_GS_SETTINGS), SetMinimalSize(106, 12), - SetDataTip(STR_INTRO_GAMESCRIPT_SETTINGS, STR_INTRO_TOOLTIP_GAMESCRIPT_SETTINGS), SetPadding(0, 0, 0, 0), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_GRF_SETTINGS), SetMinimalSize(105, 12), - SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_INTRO_TOOLTIP_NEWGRF_SETTINGS), SetPadding(0, 10, 0, 0), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_GS_SETTINGS), SetMinimalSize(158, 12), + SetDataTip(STR_INTRO_GAMESCRIPT_SETTINGS, STR_INTRO_TOOLTIP_GAMESCRIPT_SETTINGS), SetPadding(0, 10, 0, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 6), - /* 'online content' and 'highscore' buttons */ + /* 'Check Online Content' and 'NewGRF Settings' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_CONTENT_DOWNLOAD), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), SetPadding(0, 0, 0, 10), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_HIGHSCORE), SetMinimalSize(158, 12), - SetDataTip(STR_INTRO_HIGHSCORE, STR_INTRO_TOOLTIP_HIGHSCORE), SetPadding(0, 10, 0, 0), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_GRF_SETTINGS), SetMinimalSize(158, 12), + SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_INTRO_TOOLTIP_NEWGRF_SETTINGS), SetPadding(0, 10, 0, 0), SetFill(1, 0), + EndContainer(), + + NWidget(NWID_SPACER), SetMinimalSize(0, 6), + + /* 'Highscore Table' button */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_HIGHSCORE), SetMinimalSize(316, 12), + SetDataTip(STR_INTRO_HIGHSCORE, STR_INTRO_TOOLTIP_HIGHSCORE), SetPadding(0, 10, 0, 10), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 6), - /* 'exit program' button */ + /* 'Exit' button */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_EXIT), SetMinimalSize(128, 12), From 35d55bd5348111568f06c17af244668e219ed3ce Mon Sep 17 00:00:00 2001 From: Didac Perez Parera Date: Sun, 25 Dec 2022 10:42:50 -0800 Subject: [PATCH 12/20] Feature: Expand all towns in the scenario editor (#10215) --- src/lang/english.txt | 2 ++ src/town_gui.cpp | 12 ++++++++++-- src/widgets/town_widget.h | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index dedf5b8519..2573e41efb 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2851,6 +2851,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Random T STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Found town in random location STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Many random towns STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Cover the map with randomly placed towns +STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}Expand all towns +STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Make all towns grow slightly STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Town name: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Enter town name diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 4cdd1828c1..a368d19c8d 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -1061,7 +1061,9 @@ static const NWidgetPart _nested_found_town_widgets[] = { NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetMinimalSize(156, 12), SetFill(1, 0), - SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetPadding(0, 2, 0, 2), + SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetPadding(0, 2, 1, 2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_EXPAND_ALL_TOWNS), SetMinimalSize(156, 12), SetFill(1, 0), + SetDataTip(STR_FOUND_TOWN_EXPAND_ALL_TOWNS, STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP), SetPadding(0, 2, 0, 2), /* Town name selection. */ NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(156, 14), SetPadding(0, 2, 0, 2), SetDataTip(STR_FOUND_TOWN_NAME_TITLE, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_TF_TOWN_NAME_EDITBOX), SetMinimalSize(156, 12), SetPadding(0, 2, 3, 2), @@ -1155,7 +1157,7 @@ public: void UpdateButtons(bool check_availability) { if (check_availability && _game_mode != GM_EDITOR) { - this->SetWidgetsDisabledState(true, WID_TF_RANDOM_TOWN, WID_TF_MANY_RANDOM_TOWNS, WID_TF_SIZE_LARGE, WIDGET_LIST_END); + this->SetWidgetsDisabledState(true, WID_TF_RANDOM_TOWN, WID_TF_MANY_RANDOM_TOWNS, WID_TF_EXPAND_ALL_TOWNS, WID_TF_SIZE_LARGE, WIDGET_LIST_END); this->SetWidgetsDisabledState(_settings_game.economy.found_town != TF_CUSTOM_LAYOUT, WID_TF_LAYOUT_ORIGINAL, WID_TF_LAYOUT_BETTER, WID_TF_LAYOUT_GRID2, WID_TF_LAYOUT_GRID3, WID_TF_LAYOUT_RANDOM, WIDGET_LIST_END); if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT) town_layout = _settings_game.economy.town_layout; @@ -1222,6 +1224,12 @@ public: break; } + case WID_TF_EXPAND_ALL_TOWNS: + for (Town *t : Town::Iterate()) { + Command::Do(DC_EXEC, t->index, 0); + } + break; + case WID_TF_SIZE_SMALL: case WID_TF_SIZE_MEDIUM: case WID_TF_SIZE_LARGE: case WID_TF_SIZE_RANDOM: this->town_size = (TownSize)(widget - WID_TF_SIZE_SMALL); this->UpdateButtons(false); diff --git a/src/widgets/town_widget.h b/src/widgets/town_widget.h index 1a3291a3db..f16a8a585e 100644 --- a/src/widgets/town_widget.h +++ b/src/widgets/town_widget.h @@ -49,6 +49,7 @@ enum TownFoundingWidgets { WID_TF_NEW_TOWN, ///< Create a new town. WID_TF_RANDOM_TOWN, ///< Randomly place a town. WID_TF_MANY_RANDOM_TOWNS, ///< Randomly place many towns. + WID_TF_EXPAND_ALL_TOWNS, ///< Make all towns grow slightly. WID_TF_TOWN_NAME_EDITBOX, ///< Editor for the town name. WID_TF_TOWN_NAME_RANDOM, ///< Generate a random town name. WID_TF_SIZE_SMALL, ///< Selection for a small town. From c53f29df530ab1e33c58181ba8bc9dfcd6c989a0 Mon Sep 17 00:00:00 2001 From: Daniel Robinson <62957152+carlossss111@users.noreply.github.com> Date: Sun, 25 Dec 2022 22:12:06 +0000 Subject: [PATCH 13/20] Fix #10181: Show error message on failed industry prospecting (#10202) --- src/industry_cmd.cpp | 16 ++++++++++++---- src/lang/english.txt | 3 +++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index b81ba18604..e1c2db2289 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -2040,12 +2040,13 @@ CommandCost CmdBuildIndustry(DoCommandFlag flags, TileIndex tile, IndustryType i Industry *ind = nullptr; if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) { if (flags & DC_EXEC) { - /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */ - Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); /* Prospecting has a chance to fail, however we cannot guarantee that something can * be built on the map, so the chance gets lower when the map is fuller, but there * is nothing we can really do about that. */ - if (deity_prospect || Random() <= indspec->prospecting_chance) { + bool prospect_success = deity_prospect || Random() <= indspec->prospecting_chance; + if (prospect_success) { + /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */ + Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); for (int i = 0; i < 5000; i++) { /* We should not have more than one Random() in a function call * because parameter evaluation order is not guaranteed in the c++ standard @@ -2061,8 +2062,15 @@ CommandCost CmdBuildIndustry(DoCommandFlag flags, TileIndex tile, IndustryType i } if (ret.Succeeded()) break; } + cur_company.Restore(); + } + if (ret.Failed()) { + if (prospect_success) { + ShowErrorMessage(STR_ERROR_CAN_T_PROSPECT_INDUSTRY, STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING, WL_INFO); + } else { + ShowErrorMessage(STR_ERROR_CAN_T_PROSPECT_INDUSTRY, STR_ERROR_PROSPECTING_WAS_UNLUCKY, WL_INFO); + } } - cur_company.Restore(); } } else { size_t layout = first_layout; diff --git a/src/lang/english.txt b/src/lang/english.txt index 2573e41efb..fe06a7c03a 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4784,6 +4784,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... too STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Can't generate industries... STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Can't build {STRING} here... STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Can't construct this industry type here... +STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}Can't prospect industry... STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... too close to another industry STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... must found town first STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... only one allowed per town @@ -4798,6 +4799,8 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... fore STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... can only be built above the snow-line STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... can only be built below the snow-line +STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}The funding failed to prospect due to bad luck; try again +STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}There were no suitable places to prospect for this industry STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}There were no suitable places for '{STRING}' industries STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Change the map generation parameters to get a better map From 4f26f6b8aa0d977437952c658fa30cfe09f3d1e5 Mon Sep 17 00:00:00 2001 From: PeterN Date: Sun, 25 Dec 2022 22:32:22 +0000 Subject: [PATCH 14/20] Cleanup: Simplify GRFLabel linked-list with std::vector. (#10284) --- src/newgrf.cpp | 38 +++++++++----------------------------- src/newgrf.h | 5 +++-- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 2d9dc1078f..5f1991ae6e 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -429,13 +429,7 @@ static GRFFile *GetFileByFilename(const char *filename) /** Reset all NewGRFData that was used only while processing data */ static void ClearTemporaryNewGRFData(GRFFile *gf) { - /* Clear the GOTO labels used for GRF processing */ - for (GRFLabel *l = gf->label; l != nullptr;) { - GRFLabel *l2 = l->next; - free(l); - l = l2; - } - gf->label = nullptr; + gf->labels.clear(); } /** @@ -6745,15 +6739,15 @@ static void SkipIf(ByteReader *buf) * file. The jump will always be the first matching label that follows * the current nfo_line. If no matching label is found, the first matching * label in the file is used. */ - GRFLabel *choice = nullptr; - for (GRFLabel *label = _cur.grffile->label; label != nullptr; label = label->next) { - if (label->label != numsprites) continue; + const GRFLabel *choice = nullptr; + for (const auto &label : _cur.grffile->labels) { + if (label.label != numsprites) continue; /* Remember a goto before the current line */ - if (choice == nullptr) choice = label; + if (choice == nullptr) choice = &label; /* If we find a label here, this is definitely good */ - if (label->nfo_line > _cur.nfo_line) { - choice = label; + if (label.nfo_line > _cur.nfo_line) { + choice = &label; break; } } @@ -7601,23 +7595,9 @@ static void DefineGotoLabel(ByteReader *buf) byte nfo_label = buf->ReadByte(); - GRFLabel *label = MallocT(1); - label->label = nfo_label; - label->nfo_line = _cur.nfo_line; - label->pos = _cur.file->GetPos(); - label->next = nullptr; - - /* Set up a linked list of goto targets which we will search in an Action 0x7/0x9 */ - if (_cur.grffile->label == nullptr) { - _cur.grffile->label = label; - } else { - /* Attach the label to the end of the list */ - GRFLabel *l; - for (l = _cur.grffile->label; l->next != nullptr; l = l->next) {} - l->next = label; - } + _cur.grffile->labels.emplace_back(nfo_label, _cur.nfo_line, _cur.file->GetPos()); - grfmsg(2, "DefineGotoLabel: GOTO target with label 0x%02X", label->label); + grfmsg(2, "DefineGotoLabel: GOTO target with label 0x%02X", nfo_label); } /** diff --git a/src/newgrf.h b/src/newgrf.h index eb6c22d477..9e6a4f1c25 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -98,7 +98,8 @@ struct GRFLabel { byte label; uint32 nfo_line; size_t pos; - struct GRFLabel *next; + + GRFLabel(byte label, uint32 nfo_line, size_t pos) : label(label), nfo_line(nfo_line), pos(pos) {} }; /** Dynamic data of a loaded NewGRF */ @@ -121,7 +122,7 @@ struct GRFFile : ZeroedMemoryAllocator { uint32 param[0x80]; uint param_end; ///< one more than the highest set parameter - GRFLabel *label; ///< Pointer to the first label. This is a linked list, not an array. + std::vector labels; ///< List of labels std::vector cargo_list; ///< Cargo translation table (local ID -> label) uint8 cargo_map[NUM_CARGO]; ///< Inverse cargo translation table (CargoID -> local ID) From 3d3ed87d99a6f7de2ae0dfbf9a192f2ecd2a123f Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Mon, 26 Dec 2022 00:03:39 +0100 Subject: [PATCH 15/20] Fix: Bad alignment of button icons when using the original baseset. (#10200) --- media/baseset/orig_extra.grf | Bin 328676 -> 329463 bytes media/baseset/orig_extra/fix_gui_icons.nfo | 12 ++++++++++++ media/baseset/orig_extra/fix_gui_icons.png | Bin 0 -> 1493 bytes media/baseset/orig_extra/orig_extra.nfo | 1 + 4 files changed, 13 insertions(+) create mode 100644 media/baseset/orig_extra/fix_gui_icons.nfo create mode 100644 media/baseset/orig_extra/fix_gui_icons.png diff --git a/media/baseset/orig_extra.grf b/media/baseset/orig_extra.grf index 728a8b2555bb3de7506193ed1124209dafa33ad7..881c4631cec0aeb0ccd4b64bef6b8fcb520be2d4 100644 GIT binary patch delta 791 zcmYk4PiPZC6vp?>Or~jC1>J4Cv%1YA$W;@ z5?Vn)(1R!S=tZbfp&o>s+9a)*<0^uqh`g&_Jl3rj{Z5bfeTN_Kd*2tF-wzzdtj%Ay zS(8DNktU-}#@?{RCwg?RwK;gETpKN1D_@NQ&HV-KPAT@l+POYxBJKgmynW1Pmz=~}g2Dk1u&{?rz z!#MPAqlpuV)z!7NHKe57F%z`W95PPJhORko`Zz#$V`Bp;egFQ632~M|D%CM_tlR0V zM-JK)c+xnDZU>+fjo0FQk^}E8W2(0td#wF#DTUF}w|lj>3;(l@)L&drkZd-qkdctI z7DzTkyI)H!1F5swXaoq_NhO2)R6fX?VF-;4abzGr?dSceyp(~$(`FynzMr3-!Vw-w z>8mVGgTixUIxyoT(0GAp6^(P<2&MvwHjx^0cn5cz`W~v4!WvUjNpqewG@iwSIJ}iO zW?q^MNW-a=4fG*v?wKK?CH7$m%6y1k<4rt?^Y|5)VkT-n<013Y?7-C+dd2u=EEpsk8ai12ut008R%319#K diff --git a/media/baseset/orig_extra/fix_gui_icons.nfo b/media/baseset/orig_extra/fix_gui_icons.nfo new file mode 100644 index 0000000000..2fdb8880bd --- /dev/null +++ b/media/baseset/orig_extra/fix_gui_icons.nfo @@ -0,0 +1,12 @@ +// This file is part of OpenTTD. +// OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. +// OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . +// + -1 * 0 0C "Fix alignment of button icons." + +// Fix alignment of button icons. + -1 * 11 0A 03 01 DC 02 01 E2 02 01 E6 02 + -1 sprites/fix_gui_icons.png 8bpp 8 13 20 20 0 0 normal nocrop + -1 sprites/fix_gui_icons.png 8bpp 40 13 20 20 0 0 normal nocrop + -1 sprites/fix_gui_icons.png 8bpp 72 13 20 20 0 0 normal nocrop diff --git a/media/baseset/orig_extra/fix_gui_icons.png b/media/baseset/orig_extra/fix_gui_icons.png new file mode 100644 index 0000000000000000000000000000000000000000..0630179616f43a479145cfe056ec48d1d03257fe GIT binary patch literal 1493 zcmWkse{hR;9R45((t0;(m+rz|6k*xK^_`|$j+dqFTcUeaN=(?RQZj-dvshDo@v4}N z+%B_NqYLY8u?6uvC9B$UkxkH9oa`2p8Je5ajF!@Gn`L*;kGtodKb}9HopgC=*3g%S z0zg(7rL4&KvJA)b2V}I}c-;&z0BDuE7$A*d7>?sInT#Y!nx=I+oylb4IL_g4csw4z z-yaT#W3gB=nM4Q?3QDQcY8ay-Q?WT+Zm-WDjI_mNQXZ)g&?+IL6`ReZ!=dx}xJbl9 zNqHKDP)|!OddkUZ{cdwK;OLC|NZ@IBm=VLRIN_G70%}7_gkH)+IHliX#ceJ(@rq*W;bM#^KAd>4cH&7!CaPx>(w1=P(V)Qa03!jXc`}Aa8U<=jsCS52k5o*Eq)J?&kNlk&duT)L~3`*i^tli+MVU&@7kORHR$S_^sA_iBd+WNm57CCY{d8aZO%tYc!gW z2#uuFt|7g8RnV+S*!0M4MF9^2kpc2KAlyLtfr*ODak)LI@jPUMD3CxH$%tr!gfSCF zj<&f?-d0y69(jno1Q8_&lz~oz>=xvAqgWVqrYNCNE43Mw9-A)cu_nU4?lylq*@hGV zS^yTn4G;uK0H6$LKn6foKuv&J0mT6!h*^$TG^ja9>qHFOq-1RAbo$bQ*#`h%h>=>j0btmO|Je_|aEUVEU{l$g z;=%U>dAWH7v3b6Bfd2Y2EdtK=igp>X20Y@)eq>=_rf8@V>aTt_k&z^Z|LEh^XCbs#Uv%Gu}0~_)rXE0r%IVg{HJ%DBX?HT7Jl|>OWj8g zvP;)0J|4{)=NIlODQv8&sxJu5ppGbu_i2y5Sew(hf4J2-+Sc#j!rVE>^xo@7rj8wX zC08Xma4)B5Uvly0blcV`_>$N2W(>?JKB0xL4!@=ySwJn?e>JGB+)!K=db@`o+ME`q zns^w>^rsnE}Uq19hd*J`&f4SI8EKD)2CWCEgRGl zU8E{KbZ>p5x2U}^@9LGuJ1U87dhIKX(rG8pSB?6sXo77pCjWW;nb{A{DSARZWs0LE z-w)$G+VTU7+wwZj1y46)71h=CbKhy1F0Z>a_ja$uF!O^%ch;o_YhFXv@9sOv?`-Pk zp8FpPXV(ANIbrvdWtSdhVdZ6&<4u;{wQ0ik Date: Sun, 25 Dec 2022 23:05:14 +0000 Subject: [PATCH 16/20] Fix #10224: Don't fiddle with fast-forward when saving. (#10230) The original comment about saving with fast-forward on was written 18 years ago, and predates lots of changes to how saveload work. --- src/saveload/saveload.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 6df65c36df..04e8113820 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -210,7 +210,6 @@ struct SaveLoadParams { StringID error_str; ///< the translatable error message to show char *extra_msg; ///< the error message - uint16 game_speed; ///< The game speed when saving started. bool saveinprogress; ///< Whether there is currently a save in progress. }; @@ -2913,15 +2912,9 @@ static inline void ClearSaveLoadState() _sl.lf = nullptr; } -/** - * Update the gui accordingly when starting saving - * and set locks on saveload. Also turn off fast-forward cause with that - * saving takes Aaaaages - */ +/** Update the gui accordingly when starting saving and set locks on saveload. */ static void SaveFileStart() { - _sl.game_speed = _game_speed; - _game_speed = 100; SetMouseCursorBusy(true); InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START); @@ -2931,7 +2924,6 @@ static void SaveFileStart() /** Update the gui accordingly when saving is done and release locks on saveload. */ static void SaveFileDone() { - if (_game_mode != GM_MENU) _game_speed = _sl.game_speed; SetMouseCursorBusy(false); InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH); From 9e56e1614787bfed5a34bf177f22d6b14467856e Mon Sep 17 00:00:00 2001 From: PeterN Date: Mon, 26 Dec 2022 18:26:01 +0000 Subject: [PATCH 17/20] Fix: Local authority window rating list height ignored icon sizes. (#10285) Only font height was taken into account, so the list was broken if icon sizes were taller than font height. --- src/town_gui.cpp | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/town_gui.cpp b/src/town_gui.cpp index a368d19c8d..e44531a5cb 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -73,6 +73,9 @@ private: TownActions enabled_actions; ///< Actions that are enabled in settings. TownActions available_actions; ///< Actions that are available to execute for the current company. + Dimension icon_size; ///< Dimensions of company icon + Dimension exclusive_size; ///< Dimensions of exlusive icon + /** * Get the position of the Nth set bit. * @@ -117,6 +120,12 @@ public: this->InitNested(window_number); } + void OnInit() override + { + this->icon_size = GetSpriteSize(SPR_COMPANY_ICON); + this->exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT); + } + void OnPaint() override { this->available_actions = GetMaskOfTownActions(_local_company, this->town); @@ -139,26 +148,22 @@ public: { Rect r = this->GetWidget(WID_TA_RATING_INFO)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect); - DrawString(r, STR_LOCAL_AUTHORITY_COMPANY_RATINGS); - r.top += FONT_HEIGHT_NORMAL; - - Dimension icon_size = GetSpriteSize(SPR_COMPANY_ICON); - int icon_width = icon_size.width; - int icon_y_offset = (FONT_HEIGHT_NORMAL - icon_size.height) / 2; + int text_y_offset = (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2; + int icon_y_offset = (this->resize.step_height - this->icon_size.height) / 2; + int exclusive_y_offset = (this->resize.step_height - this->exclusive_size.height) / 2; - Dimension exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT); - int exclusive_width = exclusive_size.width; - int exclusive_y_offset = (FONT_HEIGHT_NORMAL - exclusive_size.height) / 2; + DrawString(r.left, r.right, r.top + text_y_offset, STR_LOCAL_AUTHORITY_COMPANY_RATINGS); + r.top += this->resize.step_height; bool rtl = _current_text_dir == TD_RTL; - Rect text = r.Indent(icon_width + WidgetDimensions::scaled.hsep_normal + exclusive_width + WidgetDimensions::scaled.hsep_normal, rtl); - uint icon_left = r.WithWidth(icon_width, rtl).left; - uint exclusive_left = r.Indent(icon_width + WidgetDimensions::scaled.hsep_normal, rtl).WithWidth(exclusive_width, rtl).left; + Rect icon = r.WithWidth(this->icon_size.width, rtl); + Rect exclusive = r.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal, rtl).WithWidth(this->exclusive_size.width, rtl); + Rect text = r.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal + this->exclusive_size.width + WidgetDimensions::scaled.hsep_normal, rtl); /* Draw list of companies */ for (const Company *c : Company::Iterate()) { if ((HasBit(this->town->have_ratings, c->index) || this->town->exclusivity == c->index)) { - DrawCompanyIcon(c->index, icon_left, text.top + icon_y_offset); + DrawCompanyIcon(c->index, icon.left, text.top + icon_y_offset); SetDParam(0, c->index); SetDParam(1, c->index); @@ -175,11 +180,11 @@ public: SetDParam(2, str); if (this->town->exclusivity == c->index) { - DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive_left, r.top + exclusive_y_offset); + DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive.left, text.top + exclusive_y_offset); } - DrawString(text, STR_LOCAL_AUTHORITY_COMPANY_RATING); - text.top += FONT_HEIGHT_NORMAL; + DrawString(text.left, text.right, text.top + text_y_offset, STR_LOCAL_AUTHORITY_COMPANY_RATING); + text.top += this->resize.step_height; } } @@ -261,8 +266,8 @@ public: break; case WID_TA_RATING_INFO: - resize->height = FONT_HEIGHT_NORMAL; - size->height = 9 * FONT_HEIGHT_NORMAL + padding.height; + resize->height = std::max({this->icon_size.height + WidgetDimensions::scaled.vsep_normal, this->exclusive_size.height + WidgetDimensions::scaled.vsep_normal, (uint)FONT_HEIGHT_NORMAL}); + size->height = 9 * resize->height + padding.height; break; } } From 7a1863129152ef0367b1dbc72aad198cecde39d5 Mon Sep 17 00:00:00 2001 From: translators Date: Mon, 26 Dec 2022 18:42:39 +0000 Subject: [PATCH 18/20] Update: Translations from eints italian: 10 changes by bagnacauda romanian: 91 changes by bnegrut russian: 6 changes by Ln-Wolf finnish: 9 changes by hpiirai portuguese: 8 changes by azulcosta --- src/lang/finnish.txt | 16 ++--- src/lang/italian.txt | 15 +++-- src/lang/portuguese.txt | 14 +++-- src/lang/romanian.txt | 128 ++++++++++++++++++++++++++++------------ src/lang/russian.txt | 10 ++-- 5 files changed, 124 insertions(+), 59 deletions(-) diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index ac7410a938..be42fc2bd6 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -1328,7 +1328,7 @@ STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :Uudet käskyt o STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normaalisti kulkuneuvo pysähtyy jokaisella läpikulkemallaan asemalla. Mikäli tämä asetus on käytössä kulkuneuvot eivät pysähdy ajaessaan asemien läpi. Huomioi, että tämä asetus määrittää oletusarvoisen toiminnon uusille kulkuneuvoille. Asetusta voidaan muuttaa erikseen kunkin kulkuneuvon kohdalla STR_CONFIG_SETTING_STOP_LOCATION :Uudet junien käskyt pysäyttävät junan aseman {STRING} -STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Paikka, johon juna pysähtyy oletuksena asemalla. ”Alkuun” tarkoittaa, että junan viimeinen vaunu pysähtyy laiturin alkuun; ”keskelle” tarkoittaa junan pysähtymistä keskelle laituria; ja ”loppuun” tarkoittaa, että veturi pysähtyy laiturin päähän. Huomaa, että tämä asetus määrittää vain oletusarvon uusille määräyksille. Yksittäisten määräysten kohdalla käyttäytymistä voi muuttaa tästä asetuksesta huolimatta +STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Paikka, johon juna pysähtyy oletuksena asemalla. ”Alkuun” tarkoittaa, että junan viimeinen vaunu pysähtyy laiturin alkuun; ”keskelle” tarkoittaa junan pysähtymistä keskelle laituria; ja ”loppuun” tarkoittaa, että veturi pysähtyy laiturin päähän. Huomaa, että tämä asetus määrittää vain oletusarvon uusille käskyille. Yksittäisten käskyjen kohdalla käyttäytymistä voi muuttaa tästä asetuksesta huolimatta ###length 3 STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :alkuun STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :keskelle @@ -1390,7 +1390,7 @@ STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Varoita, jos ku STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Lähetä viesti, jos kulkuneuvo ei löydä reittiä määränpäähänsä STR_CONFIG_SETTING_ORDER_REVIEW :Tarkista kulkuneuvojen pysähdykset: {STRING} -STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Mikäli käytössä, kulkuneuvojen määräykset tarkistetaan väliajoin ja havaituista ongelmista ilmoitetaan uutisviestillä +STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Mikäli käytössä, kulkuneuvojen käskyjä tarkastetaan väliajoin, ja havaituista ongelmista ilmoitetaan uutisviestillä ###length 3 STR_CONFIG_SETTING_ORDER_REVIEW_OFF :Ei STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Kyllä, mutta ei pysäytetyille @@ -2851,6 +2851,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Satunnai STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Perusta kunta satunnaiseen paikkaan STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Monta satunnaista kuntaa STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Täytä kartta satunnaisesti sijoitetuilla kunnilla +STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}Laajenna kaikkia kuntia +STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Kasvata kaikkia kuntia hieman STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Kunnan nimi: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Syötä kunnan nimi @@ -4511,22 +4513,22 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Aloitusp STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Valitse päivämäärä aikataulun aloitusajankohdaksi. Ctrl+napsautus levittää kaikki tämän käskyjoukon jakavat kulkuneuvot tasaisesti niiden keskinäisen järjestyksen mukaan, mikäli käskyjoukko on kokonaan aikataulutettu STR_TIMETABLE_CHANGE_TIME :{BLACK}Muuta aikaa -STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Aseta kuinka kauan käskyn tulisi kestää +STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Muuta aikaa, jonka valitun käskyn tulisi kestää. Ctrl+napsautus asettaa keston kaikille käskyille STR_TIMETABLE_CLEAR_TIME :{BLACK}Nollaa aika -STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Nollaa tämän rivin aika +STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Nollaa valitun käskyn keston. Ctrl+napsautus nollaa kaikkien käskyjen kestot STR_TIMETABLE_CHANGE_SPEED :{BLACK}Muuta nopeusrajoitusta -STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Muuta valitun määräyksen suurinta sallittua nopeutta +STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Muuta suurinta sallittua nopeutta valitulle käskylle. Ctrl+napsautus asettaa nopeusrajoituksen kaikille käskyille STR_TIMETABLE_CLEAR_SPEED :{BLACK}Tyhjennä nopeusrajoitus -STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Tyhjennä valitun määräyksen suurin sallittu nopeus +STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Poista suurin sallittu nopeus valitulta käskyltä. Ctrl+napsautus poistaa kaikkien käskyjen nopeusrajoitukset STR_TIMETABLE_RESET_LATENESS :{BLACK}Nollaa myöhästymislaskuri STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Nollaa myöhästymislaskuri, jotta vaunu olisi taas aikataulussa STR_TIMETABLE_AUTOFILL :{BLACK}Automaattinen -STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Täytä aikataulu automaattisesti seuraavan matkan arvoilla (Ctrl+napsautus: yritä säilyttää odotusajat) +STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Täytä aikataulu automaattisesti seuraavan matkan arvoilla. Ctrl+napsautus: yritä säilyttää odotusajat STR_TIMETABLE_EXPECTED :{BLACK}Odotettu STR_TIMETABLE_SCHEDULED :{BLACK}Aikataulu diff --git a/src/lang/italian.txt b/src/lang/italian.txt index 5e05ad4567..4c638461f7 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -2892,6 +2892,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Città c STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Fonda una città in una posizione casuale STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Alcune città casuali STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Copre la mappa con città posizionate casualmente +STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}Espandi tutte le città +STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Fa crescere leggermente tutte le città STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Nome città: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Inserire il nome della città @@ -3368,7 +3370,10 @@ STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Rapprese STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Sposta lo sprite, cambiando gli spiazzamenti X e Y. CTRL+clic sposta lo sprite di otto unità alla volta ###length 2 +STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}Spiazzamento del centro +STR_SPRITE_ALIGNER_CENTRE_SPRITE :{BLACK}Sprite centrato +STR_SPRITE_ALIGNER_CROSSHAIR :{BLACK}Mirino STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Reimposta posizione relativa STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Reimposta gli spiazzamenti relativi attuali @@ -4549,22 +4554,22 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Data ini STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Seleziona una data come punto di partenza della tabella oraria. Ctrl+click distribuisce tutti i veicoli che condividono questo ordine in modo uniforme dalla data indicata in base al loro ordine relativo, se l'ordine è completamente programmato. STR_TIMETABLE_CHANGE_TIME :{BLACK}Cambia tempo -STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Cambia la quantità di tempo che dovrebbe essere impiegata per l'ordine selezionato +STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Cambia la quantità di tempo che dovrebbe essere impiegata per l'ordine selezionato. CTRL+clic imposta il tempo di tutti gli ordini STR_TIMETABLE_CLEAR_TIME :{BLACK}Elimina tempo -STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Elimina l'impostazione della quantità di tempo per l'ordine selezionato +STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Elimina l'impostazione della quantità di tempo per l'ordine selezionato. CTRL+clic la rimuove da tutti gli ordini STR_TIMETABLE_CHANGE_SPEED :{BLACK}Cambia limite di velocità -STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Cambia l'impostazione del limite di velocità per l'ordine selezionato +STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Cambia l'impostazione del limite di velocità per l'ordine selezionato. CTRL+clic lo imposta per tutti gli ordini STR_TIMETABLE_CLEAR_SPEED :{BLACK}Elimina limite di velocità -STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Elimina l'impostazione del limite di velocità per l'ordine selezionato +STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Elimina l'impostazione del limite di velocità per l'ordine selezionato. CTRL+clic rimuove la velocità da tutti gli ordini STR_TIMETABLE_RESET_LATENESS :{BLACK}Azzera ritardo STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Azzera il contatore del ritardo, in modo che il veicolo sia considerato in orario STR_TIMETABLE_AUTOFILL :{BLACK}Auto -STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Riempie automaticamente la tabella oraria con i tempi del prossimo viaggio (CTRL+clic per cercare di mantenere i tempi di attesa) +STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Riempie automaticamente la tabella oraria con i tempi del prossimo viaggio. CTRL+clic per cercare di mantenere i tempi di attesa STR_TIMETABLE_EXPECTED :{BLACK}Orari attesi STR_TIMETABLE_SCHEDULED :{BLACK}Orari programmati diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index a25cc0f0f7..151e5edec7 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -2852,6 +2852,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Localida STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Fundar uma localidade num local aleatório STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Várias localidades aleatórias STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Cobrir o mapa com localidades colocadas aleatoriamente +STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}Expandir todas as localidades +STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Fazer com que todas as localidades cresçam ligeiramente STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Nome da localidade: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Introduza o nome da localidade @@ -4402,7 +4404,7 @@ STR_ORDER_GO_TO_NEAREST_DEPOT :Ir para o depó STR_ORDER_GO_TO_NEAREST_HANGAR :Ir para o hangar mais próximo STR_ORDER_CONDITIONAL :Saltar ordem condicional STR_ORDER_SHARE :Partilhar ordens -STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Inserir nova ordem antes da ordem seleccionada, ou adicionar ao fim da lista. Ctrl torna em 'encher' as ordens em estações, em 'sem parar' as ordens de pontos de passagem e em 'serviço' as ordens em depósitos. 'Ordens Partilhadas' ou Ctrl permite que este veículos partilhe ordens com o veículo escolhido. Clicando em um veículo de copia as ordens desse veículo +STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Inserir nova ordem antes da ordem selecionada, ou adicionar ao fim da lista. Ctrl torna as ordens de estações em 'encher completamente qualquer carga'; as ordens em pontos de passagem 'sem parar'; e ordens de depósitos 'serviço'. 'Partilhar ordens' ou Ctrl permite que este veículo partilhe ordens com o veículo selecionado. Clicar num veículo copia as ordens desse veículo. Uma ordem para depósito desativa a manutenção programada (serviço) do veículo. STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Mostra todos os veículos que seguem este mesmo trajecto @@ -4512,22 +4514,22 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Data de STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Selecione uma data como ponto de partida deste horário. Ctrl+Clique distribui uniformemente todos os veiculos partilhando esta ordem pela sua ordem relativa, se a ordem for completamente calendarizada STR_TIMETABLE_CHANGE_TIME :{BLACK}Mudar Tempo -STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Muda o espaço de tempo que a ordem seleccionada deve durar +STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Mudar a duração do tempo que a ordem selecionada deve durar. Ctrl+Clique define o tempo para todas as ordens STR_TIMETABLE_CLEAR_TIME :{BLACK}Apagar Tempo -STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Apagar o tempo que dura a ordem seleccionada +STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Limpar a duração do tempo da ordem selecionada. Ctrl+Clique limpa os tempos para todas as ordens STR_TIMETABLE_CHANGE_SPEED :{BLACK}Alterar limite de velocidade -STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Mudar a velocidade maxima durante a viagem da ordem selecionada +STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Mudar a velocidade máxima durante a viagem da ordem selecionada. Ctrl+Clique define a velocidade para todas as ordens STR_TIMETABLE_CLEAR_SPEED :{BLACK}Remover limite de velocidade -STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Limpar a velocidade maxima durante a viagem da ordem selecionada +STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Limpar a velocidade máxima de viagem da ordem selecionada. Ctrl+Clique limpa as velocidades para todas as ordens. STR_TIMETABLE_RESET_LATENESS :{BLACK}Apagar Contador Atraso STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Limpar o contador de atraso, para que o veículo passe a estar a horas STR_TIMETABLE_AUTOFILL :{BLACK}Auto preencher -STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Preencher o horário automaticamente com os valores da próxima viagem (CTRL-clique para tentar manter os tempos de espera) +STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Preencher o horário automaticamente com os valores da próxima viagem. Ctrl+Clique para tentar manter os tempos de espera. STR_TIMETABLE_EXPECTED :{BLACK}Esperado STR_TIMETABLE_SCHEDULED :{BLACK}Marcado diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index c9c75ba695..887401417b 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -200,6 +200,15 @@ STR_UNITS_POWER_IMPERIAL :{COMMA}cp STR_UNITS_POWER_METRIC :{COMMA}cp STR_UNITS_POWER_SI :{COMMA}kW +STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_IMPERIAL :{DECIMAL}{NBSP}cp/t +STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_METRIC :{DECIMAL}{NBSP}cp/t +STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_SI :{DECIMAL}{NBSP}cp/kg +STR_UNITS_POWER_METRIC_TO_WEIGHT_IMPERIAL :{DECIMAL}{NBSP}cp/t +STR_UNITS_POWER_METRIC_TO_WEIGHT_METRIC :{DECIMAL}{NBSP}cp/t +STR_UNITS_POWER_METRIC_TO_WEIGHT_SI :{DECIMAL}{NBSP}cp/kg +STR_UNITS_POWER_SI_TO_WEIGHT_IMPERIAL :{DECIMAL}{NBSP}kW/t +STR_UNITS_POWER_SI_TO_WEIGHT_METRIC :{DECIMAL}{NBSP}kW/t +STR_UNITS_POWER_SI_TO_WEIGHT_SI :{DECIMAL}{NBSP}W/kg STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}t @@ -227,8 +236,8 @@ STR_UNITS_HEIGHT_SI :{COMMA} m # Common window strings STR_LIST_FILTER_TITLE :{BLACK}Filtru: -STR_LIST_FILTER_OSKTITLE :{BLACK}Filtru -STR_LIST_FILTER_TOOLTIP :{BLACK}Introduceți un cuvânt-cheie pentru filtrarea listei +STR_LIST_FILTER_OSKTITLE :{BLACK}Introduceți unul sau mai multe cuvinte cheie pentru a filtra lista +STR_LIST_FILTER_TOOLTIP :{BLACK}Introduceți unul sau mai multe cuvinte cheie pentru a filtra lista STR_TOOLTIP_GROUP_ORDER :{BLACK}Selectează ordinea de grupare STR_TOOLTIP_SORT_ORDER :{BLACK}Alegeți ordinea de sortare (ascendentă/descendentă) @@ -379,7 +388,7 @@ STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Construc STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Construcție tramvai STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plantează arbori. Shift comută între plantare/afişare cost estimat STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Plasează semn -STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Amplasează obiect. Shift comută între amplasare/afişare cost estimat +STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Plasați obiectul. Ctrl selectează zona în diagonală. Shift comută construirea/afișarea estimării costurilor # Scenario editor file menu ###length 7 @@ -396,6 +405,7 @@ STR_SCENEDIT_FILE_MENU_QUIT :Ieşire din joc STR_SETTINGS_MENU_GAME_OPTIONS :Opţiunile jocului STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Setări STR_SETTINGS_MENU_AI_SETTINGS :Setările AI +STR_SETTINGS_MENU_GAMESCRIPT_SETTINGS :Setări pentru scriptul jocului STR_SETTINGS_MENU_NEWGRF_SETTINGS :Setări NewGRF STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Opţiuni transparenţă STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Afişează numele oraşelor @@ -998,9 +1008,19 @@ STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Bifați STR_GAME_OPTIONS_VIDEO_DRIVER_INFO :{BLACK}Driver curent: {STRING} +STR_GAME_OPTIONS_GUI_SCALE_FRAME :{BLACK}Dimensiune interfaţă +STR_GAME_OPTIONS_GUI_SCALE_TOOLTIP :{BLACK}Trageți glisorul pentru a seta dimensiunea interfeței. Țineți apăsat Ctrl pentru ajustare continuă +STR_GAME_OPTIONS_GUI_SCALE_AUTO :{BLACK}Detectează automat dimensiunea +STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Bifați această căsuţă pentru a detecta automat dimensiunea interfeței +STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Scalează marginile +STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Bifați această casetă pentru a scala marginile în funcție de dimensiunea interfeței +STR_GAME_OPTIONS_GUI_SCALE_1X :1x STR_GAME_OPTIONS_GUI_SCALE_2X :2x +STR_GAME_OPTIONS_GUI_SCALE_3X :3x +STR_GAME_OPTIONS_GUI_SCALE_4X :4x +STR_GAME_OPTIONS_GUI_SCALE_5X :5x STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafică @@ -1413,6 +1433,7 @@ STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Grosimea liniil STR_CONFIG_SETTING_SHOW_NEWGRF_NAME :Afișează numele NewGRF în fereastra de construcție a vehiculului: {STRING} STR_CONFIG_SETTING_SHOW_NEWGRF_NAME_HELPTEXT :Adaugă o linie în fereastra de construcție a vehiculului, afișând din care NewGRF vine vehiculul selectat. STR_CONFIG_SETTING_SHOW_CARGO_IN_LISTS :Afișați mărfurile pe care vehiculele le pot transporta în ferestrele listei {STRING} +STR_CONFIG_SETTING_SHOW_CARGO_IN_LISTS_HELPTEXT :Dacă este activată, încărcătura transportabilă a vehiculului va apărea deasupra acestuia în listele de vehicule STR_CONFIG_SETTING_LANDSCAPE :Peisaj: {STRING} STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Peisajele definesc scenariile de bază a jocului cu cerințe diferite pentru încărcături și dezvoltare a orașelor. NewGRF și scripturile de joc permit un control mai fin @@ -1834,7 +1855,7 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :permis STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :permis, aspect particularizat al oraşului STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Modalitatea de generare a cargoului dintr-un oraș: {STRING} -STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Cât cargo este produs de casele dintr-un oraș, relativ la populația totală a orașului.{}Creștere pătratică: Un oraș de 2 ori mai mare generează de 4 ori mai mulți pasageri.{}Creștere liniară: Un oraș de 2 ori mai mare generează de 4 ori mai mulți pasageri. +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Câtă marfa este produsă de casele dintr-un oraș, relativ la populația totală a orașului.{}Creștere pătratică: Un oraș de 2 ori mai mare generează de 4 ori mai mulți pasageri.{}Creștere liniară: Un oraș de 2 ori mai mare generează de 4 ori mai mulți pasageri. ###length 2 STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :Pătratică (originală) STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Liniar @@ -2048,6 +2069,8 @@ STR_INTRO_HIGHSCORE :{BLACK}Tabela c STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Setări STR_INTRO_NEWGRF_SETTINGS :{BLACK}Setări NewGRF STR_INTRO_ONLINE_CONTENT :{BLACK}Resurse online +STR_INTRO_AI_SETTINGS :{BLACK}Setări AI +STR_INTRO_GAMESCRIPT_SETTINGS :{BLACK}Setări pentru scriptul jocului STR_INTRO_QUIT :{BLACK}Ieşire STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Începere joc nou. Ctrl+Click pentru a sări peste fereastra de configuraţie a harţii @@ -2067,6 +2090,8 @@ STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Afișeaz STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Setări afişare STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Afişează setările NewGRF STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Verifică dacă există resurse noi sau actualizate pentru descărcare +STR_INTRO_TOOLTIP_AI_SETTINGS :{BLACK}Afișează setările AI +STR_INTRO_TOOLTIP_GAMESCRIPT_SETTINGS :{BLACK}Afișează setările scriptului de joc STR_INTRO_TOOLTIP_QUIT :{BLACK}Ieși din 'OpenTTD' STR_INTRO_BASESET :{BLACK}Setul grafic actual are lipsă {NUM} {P sprite spriteuri "de spriteuri"}. Verificați actualizările pentru setul de bază. @@ -2457,13 +2482,13 @@ STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :se așteaptă p STR_NETWORK_MESSAGE_CLIENT_LEAVING :iese STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} a intrat în joc -STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} a intrat în joc (Clientul #{2:NUM}) -STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} a intrat în compania #{2:NUM} +STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {0:STRING} a intrat în joc (Clientul #{2:NUM}) +STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {0:STRING} a intrat în compania #{2:NUM} STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} a intrat ca spectator STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} a început o companie nouă (#{2:NUM}) -STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} a ieşit din joc ({2:STRING}) +STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {0:STRING} a ieşit din joc ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} și-a schimbat numele în {STRING} -STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} a dat {2:CURRENCY_LONG} către {1:STRING} +STR_NETWORK_MESSAGE_GIVE_MONEY :*** {0:STRING} a dat {2:CURRENCY_LONG} către {1:STRING} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Serverul a închis conexiunea STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Serverul este repornit...{}Vă rugăm aşteptaţi... STR_NETWORK_MESSAGE_KICKED :*** {STRING} a fost dat afară. Motiv: ({STRING}) @@ -2578,6 +2603,8 @@ STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLA STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}supraîncărcat # Linkgraph tooltip +STR_LINKGRAPH_STATS_TOOLTIP :{BLACK}{CARGO_LONG} care urmează să fie transportat pe lună de la {STATION} la {STATION} ({COMMA}% din capacitate){STRING} +STR_LINKGRAPH_STATS_TOOLTIP_RETURN_EXTENSION :{}{CARGO_LONG} de transportat înapoi ({COMMA}% din capacitate) # Base for station construction window(s) STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Aria de acoperire @@ -2587,6 +2614,7 @@ STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Nu arăt STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Arată aria de acoperire a locaţiei propuse STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Acceptă: {GOLD}{CARGO_LIST} STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Furnizează: {GOLD}{CARGO_LIST} +STR_STATION_BUILD_INFRASTRUCTURE_COST :{BLACK}Cost întreținere: {GOLD}{CURRENCY_SHORT}/an # Join station window STR_JOIN_STATION_CAPTION :{WHITE}Uneşte staţia @@ -2774,11 +2802,11 @@ STR_LANDSCAPING_TOOLBAR :{WHITE}Modifica STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Scade altitudinea unui punct de teren. Trage cu mouse-ul pentru a coborî primul punct de teren și a nivela restul zonei la noua înălțime a acestuia. Ctrl pentru selecţie pe diagonală. STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Creşte altitudinea unui punct de teren. Trage cu mouse-ul pentru a ridica primul punct de teren și a nivela restul zonei la noua înălțime a acestuia. Ctrl pentru selecţie pe diagonală. STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Nivelează terenul la înălțimea primului colț selectat. Ctrl pentru selecție pe diagonală -STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Cumpără teren pentru folosire ulterioară. Shift comută între cumpărare/afişare cost estimat +STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Cumpărați teren pentru utilizare ulterioară. Ctrl selectează zona în diagonală. Shift comută construirea/afișarea estimării costurilor # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Selecţia obiectelor -STR_OBJECT_BUILD_TOOLTIP :{BLACK}Selectaţi obiectele pentru construcţie. Shift comută între construire/afişare cost estimat +STR_OBJECT_BUILD_TOOLTIP :{BLACK}Selectați obiectul de construit. Ctrl selectează zona în diagonală. Shift comută construirea/afișarea estimării costurilor STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Selectează clasa obiectului de construit STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Previzualizarea obiectului STR_OBJECT_BUILD_SIZE :{BLACK}Dimensiune: {GOLD}{NUM} x {NUM} pătrăţele @@ -2822,6 +2850,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Oraş al STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Construieşte un oraş într-o locaţie aleatoare STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Mai multe oraşe aleatoare STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Umple harta cu oraşe generate aleator +STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}Extinde orasele +STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Fă toate orașele să crească ușor STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Nume oraş: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Introdu numele oraşului @@ -3086,7 +3116,7 @@ STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Detalii STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Nicio informaţie disponibilă STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} -STR_SAVELOAD_FILTER_TITLE :{BLACK}Filtrare după: +STR_SAVELOAD_FILTER_TITLE :{BLACK}Filtru: STR_SAVELOAD_OVERWRITE_TITLE :{WHITE}Suprascrie fișierul STR_SAVELOAD_OVERWRITE_WARNING :{YELLOW}Sigur vrei să suprascrii fișierul existent? STR_SAVELOAD_DIRECTORY :{STRING} (listă) @@ -3122,6 +3152,12 @@ STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Râuri: STR_MAPGEN_SMOOTHNESS :{BLACK}Netezime: STR_MAPGEN_VARIETY :{BLACK}Distribuţia varietăţii: STR_MAPGEN_GENERATE :{WHITE}Generează +STR_MAPGEN_NEWGRF_SETTINGS :{BLACK}Setări NewGRF +STR_MAPGEN_NEWGRF_SETTINGS_TOOLTIP :{BLACK}Afişează setările NewGRF +STR_MAPGEN_AI_SETTINGS :{BLACK}Configurație AI +STR_MAPGEN_AI_SETTINGS_TOOLTIP :{BLACK}Afișează setările AI +STR_MAPGEN_GS_SETTINGS :{BLACK}Setări pentru scriptul de joc +STR_MAPGEN_GS_SETTINGS_TOOLTIP :{BLACK}Afișează setările scriptului de joc ###length 21 STR_MAPGEN_TOWN_NAME_ORIGINAL_ENGLISH :Englezeşti (Original) @@ -3292,7 +3328,10 @@ STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Reprezen STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Mișcă imaginea schimbând distanțele pe axele X şi Y. Ctrl+Clic pentru mutarea imaginii câte opt unități la un pas ###length 2 +STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}Offset centrat +STR_SPRITE_ALIGNER_CENTRE_SPRITE :{BLACK}Centrază sprite +STR_SPRITE_ALIGNER_CROSSHAIR :{BLACK}Focus STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Resetează relativele STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Resetază limitele relative actuale @@ -3311,15 +3350,15 @@ STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SI STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}O eroare fatală NewGRF a avut loc:{}{STRING} STR_NEWGRF_ERROR_POPUP :{WHITE}O eroare NewGRF a avut loc:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} nu va funcţiona cu versiunea TTDPatch raportată de OpenTTD -STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} este pentru versiunea {STRING} a TTD -STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} este conceput pentru a fi folosit cu {STRING} -STR_NEWGRF_ERROR_INVALID_PARAMETER :Parametru invalid pentru {1:STRING}: parametrul {STRING} ({NUM}) -STR_NEWGRF_ERROR_LOAD_BEFORE :{1:STRING} trebuie să fie încărcat înaintea {STRING} -STR_NEWGRF_ERROR_LOAD_AFTER :{1:STRING} trebuie să fie încărcat după {STRING} -STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING} necesită OpenTTD versiunea {STRING} sau mai nouă +STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} este pentru versiunea {2:STRING} a TTD +STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} este conceput pentru a fi folosit cu {2:STRING} +STR_NEWGRF_ERROR_INVALID_PARAMETER :Parametru invalid pentru {1:STRING}: parametrul {2:STRING} ({3:NUM}) +STR_NEWGRF_ERROR_LOAD_BEFORE :{1:STRING} trebuie să fie încărcat înaintea {2:STRING} +STR_NEWGRF_ERROR_LOAD_AFTER :{1:STRING} trebuie să fie încărcat după {2:STRING} +STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING} necesită OpenTTD versiunea {2:STRING} sau mai nouă STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :fişierul GRF conceput pentru traducere STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Sunt încărcate prea multe NewGRF-uri -STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Încărcarea {1:STRING} ca un NewGRF static cu {STRING} ar putea cauza desincronizări +STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Încărcarea {1:STRING} ca un NewGRF static cu {2:STRING} ar putea cauza desincronizări STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Element grafic neașteptat (sprite {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Proprietate necunoscută pentru Acțiunea 0 {4:HEX} (sprite {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Încercare de a folosi un ID invalid (sprite {3:NUM}) @@ -3451,14 +3490,14 @@ STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Cumpără drept STR_LOCAL_AUTHORITY_ACTION_BRIBE :Mituieşte autoritatea locală ###length 8 -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Inițiază o campanie publicitară mică pentru a atrage mai mulți călători și mai multe mărfuri spre compania ta.{}Oferă temporar un spor la cotația stației tale pe o rază mică în jurul centrului orașului.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Inițiază o campanie publicitară medie pentru a atrage mai mulți călători și mai multe mărfuri spre compania ta.{}Oferă temporar un spor la cotația stației tale pe o rază medie în jurul centrului orașului.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Inițiază o mare campanie publicitară pentru a atrage mai mulți călători și mai multe mărfuri spre compania ta.{}Oferă temporar un spor la cotația stației tale pe o rază mare în jurul centrului orașului.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Finanțează reconstrucția rețelei locale de drumuri.{}Aceasta cauzează perturbări majore ale traficului rutier timp de până la 6 luni.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Construiește o statuie în cinstea companiei tale.{}Oferă un spor permanent la cotația stației tale în acest oraș.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Finanțează construcția de noi clădiri comerciale în oraș.{}Oferă un spor temporar dezvoltării în acest oraș.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Cumpără drepturi exclusive de transport în acest oraș, timp de un an.{}Autoritățile locale nu vor permite călătorilor și mărfurilor să folosească stațiile competitorilor.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Mituieşte autorităţile locale pentru a-ţi îmbunătăţi ratingul, dar cu riscul de a fi prins şi de a plăti amenzi serioase.{} Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{PUSH_COLOUR}{YELLOW}Inițiază o campanie publicitară mică pentru a atrage mai mulți călători și mai multe mărfuri spre compania ta.{}Oferă temporar un spor la cotația staților tale pe o rază mică în jurul centrului orașului.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{PUSH_COLOUR}{YELLOW}Inițiază o campanie publicitară medie pentru a atrage mai mulți călători și mai multe mărfuri spre compania ta.{}Oferă temporar un spor la cotația stațiilor tale pe o rază medie în jurul centrului orașului.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{PUSH_COLOUR}{YELLOW}Inițiază o mare campanie publicitară pentru a atrage mai mulți călători și mai multe mărfuri spre compania ta.{}Oferă temporar un spor la cotația stațiilor tale pe o rază mare în jurul centrului orașului.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{PUSH_COLOUR}{YELLOW}Finanțați reconstrucția rețelei de drumuri urbane.{}Provoacă perturbări considerabile ale traficului rutier timp de până la 6 luni.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{PUSH_COLOUR}{YELLOW}Construiește o statuie în onoarea companiei tale.{}Oferă un spor permanent pentru cotele stațiilor tale din acest oraș.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{PUSH_COLOUR}{YELLOW}Finanțează construcția de noi clădiri în oraș.{}Oferă un spor temporar dezvoltării în acest oraș.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{PUSH_COLOUR}{YELLOW}Cumpără drepturi exclusive de transport în acest oraș, timp de un an.{}Autoritățile locale nu vor permite călătorilor și mărfurilor să folosească stațiile competitorilor.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{PUSH_COLOUR}{YELLOW}Mituiți autoritatea locală pentru a vă crește ratingul, cu riscul unei sancțiuni severe dacă eşti prins.{}{POP_COLOUR}Cost: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} Scopuri @@ -3631,14 +3670,18 @@ STR_FINANCES_SECTION_SHIP_REVENUE :{GOLD}Nave STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Dobânda la credit STR_FINANCES_SECTION_OTHER :{GOLD}Altele +STR_FINANCES_TOTAL_CAPTION :{WHITE}Total STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG} +STR_FINANCES_ZERO_INCOME :{CURRENCY_LONG} STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG} +STR_FINANCES_PROFIT :{WHITE}Profit STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Balanţă curentă STR_FINANCES_OWN_FUNDS_TITLE :{WHITE}Fonduri proprii STR_FINANCES_LOAN_TITLE :{WHITE}Credite STR_FINANCES_INTEREST_RATE :{WHITE}Dobândā la credit: {BLACK}{NUM}% STR_FINANCES_MAX_LOAN :{WHITE}Limită credit: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} +STR_FINANCES_BANK_BALANCE :{WHITE}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}Împrumută {CURRENCY_LONG} STR_FINANCES_BORROW_TOOLTIP :{BLACK}Împrumută o nouă sumă de bani. Ctrl-click pentru a împrumuta suma maximă posibilă STR_FINANCES_REPAY_BUTTON :{BLACK}Plăteşte înapoi {CURRENCY_LONG} @@ -3739,7 +3782,7 @@ STR_INDUSTRY_VIEW_PRODUCES_N_CARGO :{BLACK}Produce: STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION :, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES :{BLACK}Necesită: -STR_INDUSTRY_VIEW_ACCEPT_CARGO :{YELLOW}{STRING}{BLACK}{3:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO :{YELLOW}{0:STRING}{BLACK}{3:STRING} STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT :{YELLOW}{STRING}{BLACK}: {CARGO_SHORT} așteaptă{STRING} STR_CONFIG_GAME_PRODUCTION :{WHITE}Schimba productia (multiplu de 8, până la 2040) @@ -3769,6 +3812,8 @@ STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Trimite STR_VEHICLE_LIST_REPLACE_VEHICLES :Inlocuieste vehiculele STR_VEHICLE_LIST_SEND_FOR_SERVICING :Trimite in service STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Profit anul acesta: {CURRENCY_LONG} (anul trecut: {CURRENCY_LONG}) +STR_VEHICLE_LIST_CARGO :{TINY_FONT}{BLACK}[{CARGO_LIST}] +STR_VEHICLE_LIST_NAME_AND_CARGO :{TINY_FONT}{BLACK}{STRING} {STRING} STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Trimite la depou STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Trimite la depou @@ -3861,6 +3906,9 @@ STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Rază ac STR_PURCHASE_INFO_AIRCRAFT_TYPE :{BLACK}Tip de aeronavă: {GOLD}{STRING} ###length 3 +STR_CARGO_TYPE_FILTER_ALL :Toate tipurile de marfă +STR_CARGO_TYPE_FILTER_FREIGHT :Marfă +STR_CARGO_TYPE_FILTER_NONE :Niciunul ###length VEHICLE_TYPES STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Lista de selectie a componentelor trenului - clic pe vehicule pt. informatii @@ -4030,7 +4078,7 @@ STR_ENGINE_PREVIEW_AIRCRAFT :aeronavă STR_ENGINE_PREVIEW_SHIP :navă STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cost: {CURRENCY_LONG} Greutate: {WEIGHT_SHORT}{}Viteză: {VELOCITY} Putere: {POWER}{}Mentenanță: {CURRENCY_LONG}/an{}Capacitate: {CARGO_LONG} -STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Greutate: {WEIGHT_SHORT}{}Viteză: {VELOCITY} Putere: {POWER} Ef. T. Max.: {6:FORCE}{}Mentenanță: {4:CURRENCY_LONG}/an{}Capacitate: {5:CARGO_LONG} +STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {0:CURRENCY_LONG} Greutate: {1:WEIGHT_SHORT}{}Viteză: {2:VELOCITY} Putere: {3:POWER} Ef. T. Max.: {6:FORCE}{}Cost operare: {4:CURRENCY_LONG}/an{}Capacitate: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Viteză max.: {VELOCITY}{}Capacitate: {CARGO_LONG}{}Mentenanță: {CURRENCY_LONG}/an STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_CAP_CAP_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Viteză max.: {VELOCITY}{}Tip de aeronavă: {STRING}{}Capacitate: {CARGO_LONG}, {CARGO_LONG}{}Mentenanță: {CURRENCY_LONG}/an STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_CAP_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Viteză max.: {VELOCITY}{}Tip aeronavă: {STRING}{}Capacitate: {CARGO_LONG}{}Mentenanță: {CURRENCY_LONG}/an @@ -4189,12 +4237,13 @@ STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Greutate STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Greutate: {LTBLUE}{WEIGHT_SHORT} {BLACK}Putere: {LTBLUE}{POWER}{BLACK} Viteză max.: {LTBLUE}{VELOCITY} {BLACK}Efort tractiv: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit pe anul curent: {LTBLUE}{CURRENCY_LONG} (anul precedent: {CURRENCY_LONG}) +STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR_MIN_PERFORMANCE :{BLACK}Profit anul curent: {LTBLUE}{CURRENCY_LONG} (anul trecut: {CURRENCY_LONG}) {BLACK}performanta minima: {LTBLUE}{POWER_TO_WEIGHT} STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Eficienţă: {LTBLUE}{COMMA}% {BLACK}Defecţiuni de la ultimul service: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Construit: {LTBLUE}{NUM}{BLACK} Valoare: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Capacitate: {LTBLUE}Nimic{STRING} -STR_VEHICLE_INFO_CAPACITY :{BLACK}Capacitate: {LTBLUE}{CARGO_LONG}{3:STRING} -STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Capacitate: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) +STR_VEHICLE_INFO_CAPACITY :{BLACK}Capacitate: {LTBLUE}{0:CARGO_LONG}{3:STRING} +STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Capacitate: {LTBLUE}{0:CARGO_LONG}{3:STRING} (x{4:NUM}) STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Capacitate: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Transferă Credit: {LTBLUE}{CURRENCY_LONG} @@ -4463,22 +4512,22 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Dată po STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Alege o dată ca punct de pornire pentru acest orar. Ctrl+clic distribuie toate vehiculele uniform de la data setată bazată pe comenzile relative, dacă comenzile au un orar complet STR_TIMETABLE_CHANGE_TIME :{BLACK}Modifică timpul -STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Modifică durata de timp alocată comenzii selectate +STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Modificați timpul pe care ar trebui să o dureze comanda evidențiată. Ctrl+Click setează ora pentru toate comenzile STR_TIMETABLE_CLEAR_TIME :{BLACK}Curata timp STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Elimină durata de timp pentru comanda selectată STR_TIMETABLE_CHANGE_SPEED :{BLACK}Schimbă limita de viteză -STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Schimbă limita maximă de viteză a comenzii selectate +STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Schimbă limita maximă de viteză a comenzii selectate. Ctrl+Click setează viteza pentru toate comenzile STR_TIMETABLE_CLEAR_SPEED :{BLACK}Şterge limita de viteză -STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Șterge limita maximă de viteză a comenzii selectate +STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Ștergeți viteza maximă de deplasare a comenzii evidențiate. Ctrl+Click șterge viteza pentru toate comenzile STR_TIMETABLE_RESET_LATENESS :{BLACK}Reinitializeaza contorul de intarziere STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reiniţializează contorul de întârziere, astfel ca vehiculul să ajungă la timp STR_TIMETABLE_AUTOFILL :{BLACK}Auto-completare -STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Completează automat tabela cu timpi cu valorile pentru urmatoarea călătorie (CTRL-clic pentru a încerca să păstraţi timpii de aşteptare) +STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Completați automat orarul cu valorile din următoarea călătorie. Ctrl+Click pentru a încerca să păstrați timpii de așteptare STR_TIMETABLE_EXPECTED :{BLACK}Estimat STR_TIMETABLE_SCHEDULED :{BLACK}Planificat @@ -4522,6 +4571,8 @@ STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}O Inteli STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}Fereastra pentru depanare IA / Script Joc este disponibilă doar serverului # AI configuration window +STR_AI_CONFIG_CAPTION_AI :{WHITE}Configurație AI +STR_AI_CONFIG_CAPTION_GAMESCRIPT :{WHITE}Configurarea scriptului de joc STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}Script Joc încărcat în jocul următor STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}Modulul de IA care va fi încărcat în jocul următor STR_AI_CONFIG_HUMAN_PLAYER :Jucator uman @@ -4535,10 +4586,11 @@ STR_AI_CONFIG_MOVE_DOWN :{BLACK}În jos STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Mută IA selectată jos în listă STR_AI_CONFIG_GAMESCRIPT :{SILVER}Script Joc +STR_AI_CONFIG_GAMESCRIPT_PARAM :{SILVER}Parametri STR_AI_CONFIG_AI :{SILVER}IA -STR_AI_CONFIG_CHANGE_AI :IA -STR_AI_CONFIG_CHANGE_GAMESCRIPT :Script Joc +STR_AI_CONFIG_CHANGE_AI :{BLACK}Selectați IA +STR_AI_CONFIG_CHANGE_GAMESCRIPT :{BLACK}Selectați Scriptul jocului STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Încarcă un alt script STR_AI_CONFIG_CONFIGURE :{BLACK}Configurază STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}Configurează parametrii scriptului @@ -4567,7 +4619,7 @@ STR_SCREENSHOT_HEIGHTMAP_SCREENSHOT :{BLACK}Captură STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}Captură de hartă a lumii # AI Parameters -STR_AI_SETTINGS_CAPTION_AI :IA +STR_AI_SETTINGS_CAPTION_AI :{WHITE}Parametrii IA STR_AI_SETTINGS_CLOSE :{BLACK}Închide STR_AI_SETTINGS_RESET :{BLACK}Resetează STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} @@ -5013,6 +5065,8 @@ STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Nu pot s STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... vehiculul nu poate ajunge la toate staţiile STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... vehiculul nu poate ajunge la acea staţie STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... un vehicul care are acest ordin nu poate ajunge la acea staţie +STR_ERROR_CAN_T_COPY_ORDER_VEHICLE_LIST :{WHITE}... nu toate vehiculele au aceleași comenzi +STR_ERROR_CAN_T_SHARE_ORDER_VEHICLE_LIST :{WHITE}... nu toate vehiculele împart comenzi STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Nu se poate trece la comenzi sincronizate... STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Nu pot opri sincronizarea listei de comenzi... diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 4d775ed2cf..49099af5fb 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -3026,6 +3026,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Случ STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Создать город в случайном месте STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Множество различных городов STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Разместить на карте различные города случайным образом +STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}Расширить все города +STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Увеличить размер всех городов STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Название города: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Введите название города @@ -4698,16 +4700,16 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Нача STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Выберите начальную дату для этого графика. Ctrl+щелчок равномерно распределит все транспортные средства, следующие по этому маршруту, если время движения по нему полностью рассчитано. STR_TIMETABLE_CHANGE_TIME :{BLACK}Изменить время -STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Изменить время для выделенного задания +STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Изменить время исполнения выделенного задания. Ctrl+щелчок устанавливает время для всех заданий. STR_TIMETABLE_CLEAR_TIME :{BLACK}Сбросить время -STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Сбросить время в выделенном задании +STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Сбросить время в выделенном задании. Ctrl+щелчок - сбросить время во всех заданиях. STR_TIMETABLE_CHANGE_SPEED :{BLACK}Изменить огранич. скорости -STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Изменить ограничение скорости движения для выбранного задания +STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Изменить ограничение скорости движения для выбранного задания. Ctrl+щелчок устанавливает скорость для всех заданий. STR_TIMETABLE_CLEAR_SPEED :{BLACK}Сбросить огранич. скорости -STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Сбросить ограничение скорости движения для выделенного задания +STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Сбросить ограничение скорости движения для выделенного задания. Ctrl+щелчок - сбросить время для всех заданий. STR_TIMETABLE_RESET_LATENESS :{BLACK}Сбросить счетчик опозд. STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Сбросить счётчик отклонения от графика, чтобы транспорт снова считался приходящим вовремя From 6caed5f15e7eec01a20fdc2e0781af6a9787a5a6 Mon Sep 17 00:00:00 2001 From: Francis Herne Date: Mon, 26 Dec 2022 21:06:21 +0100 Subject: [PATCH 19/20] Add: Slope-aware and roadtype-specific one-way sprites. (#10282) --- media/baseset/openttd.grf | Bin 508716 -> 509868 bytes media/baseset/openttd/oneway.nfo | 28 +++++++++++++++++++++------- media/baseset/openttd/oneway.png | Bin 1222 -> 7846 bytes src/newgrf.cpp | 10 +++++++++- src/road.h | 1 + src/road_cmd.cpp | 12 +++++++++++- src/table/sprites.h | 6 ++++-- 7 files changed, 46 insertions(+), 11 deletions(-) diff --git a/media/baseset/openttd.grf b/media/baseset/openttd.grf index e3ebf2dd675589b31cdab66116ae5db1d72520bf..9e08fb17c3a801a57391f8f6656f9240f5e3d2f0 100644 GIT binary patch delta 798 zcmZ9KPe>F|9LHyzx0$7o?&{9y#_`@J?@jpYMD>?@ix`PT!3Z zB6x4Ekr5(}kg5?PJtt%)wy6Q4xJ4G0y%lwjNuuh<7}+5$dOy|XIGK~ad&}ylI5{S+ zo%SV2w^&kRtt6;gpGBfhB}h+=k67g2azxAU`IqL^>&;b*;(RAH9SeE zWUv}mr*CAkpQC6p6g`O^Eo((Ezy^^kbV1ec;b}34*V?>VpQ#RQw$Jl!pH-vB@%#*UtUPl?r8bPl07Dnmm`xkv;$@}%sXQ38ypwicsxYNc! z*{MCD7(v!NCR=T8Ck{BB2y0>F^-;Wpf%o`|5+yW9. // -1 * 0 0C "One way road graphics" - -1 * 3 05 09 06 - -1 sprites/oneway.png 8bpp 34 8 24 16 -12 -8 normal - -1 sprites/oneway.png 8bpp 66 8 24 16 -12 -8 normal - -1 sprites/oneway.png 8bpp 98 8 24 16 -12 -8 normal - -1 sprites/oneway.png 8bpp 130 8 24 16 -12 -8 normal - -1 sprites/oneway.png 8bpp 162 8 24 16 -12 -8 normal - -1 sprites/oneway.png 8bpp 194 8 24 16 -12 -8 normal + -1 * 3 05 09 12 + -1 sprites/oneway.png 8bpp 34 8 24 16 -10 -9 normal + -1 sprites/oneway.png 8bpp 66 8 24 16 -13 -7 normal + -1 sprites/oneway.png 8bpp 98 8 24 16 -12 -8 normal + -1 sprites/oneway.png 8bpp 130 8 24 16 -15 -10 normal + -1 sprites/oneway.png 8bpp 162 8 24 16 -12 -9 normal + -1 sprites/oneway.png 8bpp 194 8 24 16 -11 -8 normal + + -1 sprites/oneway.png 8bpp 34 40 24 16 -13 -10 normal + -1 sprites/oneway.png 8bpp 66 40 24 16 -12 -8 normal + -1 sprites/oneway.png 8bpp 98 40 24 16 -12 -9 normal + -1 sprites/oneway.png 8bpp 130 40 24 16 -11 -8 normal + -1 sprites/oneway.png 8bpp 162 40 24 16 -9 -10 normal + -1 sprites/oneway.png 8bpp 194 40 24 16 -10 -9 normal + + -1 sprites/oneway.png 8bpp 34 72 24 16 -8 -11 normal + -1 sprites/oneway.png 8bpp 66 72 24 16 -11 -5 normal + -1 sprites/oneway.png 8bpp 98 72 24 16 -12 -8 normal + -1 sprites/oneway.png 8bpp 130 72 24 16 -12 -5 normal + -1 sprites/oneway.png 8bpp 162 72 24 16 -14 -10 normal + -1 sprites/oneway.png 8bpp 194 72 24 16 -12 -8 normal diff --git a/media/baseset/openttd/oneway.png b/media/baseset/openttd/oneway.png index 15542af8563cdcc8870d2a251d01ae0a8daf9e83..843747677fc0296025e49b4fc7b70c3a789c465f 100644 GIT binary patch literal 7846 zcmeHLdo+~$*MHK;J;PDtxIBhVD#IA#GSjGWt06R%G}XvlF&So>84QszR4QdEohZ3P zMN~Q|DiuXX-SshU1zQL{qM}0dDipn@7|xi_h;|@UEgQ+ zQoL7bsOqZ%0HEPcc3lSmvqAWtt~?vQHW+mm0D!V2%7-dm$A|z0LVf_3#{tEW0uIQL za0389(t0}8FWhYD+=Q2+d6y9g;@^*x1e(p+}c!_}G^<duZHXVYN6*pEjPuy(FRur_+$?O|J#^c$ zVq}N0|I$k%A4Rv%P3RB5oczGHN{RHSyFqr3K6d!!td#K+nb>Rc(Yn*yb5e#0rqRs< z^Hfwu{W5N?h)=B3xH36>#-B2}d@SzQ=wHVm*MjbPbl0lG&qpRp-WoqP)_pJnjb60b zIBwA8UmxKSU{tb8ynL4*8|q&*?VQ zn_14eN7F;@%hhSC&Lw!_fAb$-xE~qZzUG5LXPGeaWO2in>H-?n_oB0N>&m^%j_X^C znh)P*9cnH%J^$ABgtbVyB!E%0de4gXj1@5*>04A$_Qyz8{Akgw`@baZZ=2}0Lmv9# ze(shwbY%jf(bSatY6sAVoR|}i2?fv^l?Q4)cMd$5^owtJV*@N^Zd<6=m!+ELzLr~L z^48KBr6K(#`|Y~R@zT6*u$rc}q49FpGTUTv%~D^l^PB81Gen(hkzR%&gA7&@ zK23xj=*D(SRcn?_v@8hRnKK+W#D8v_^^0-ifLi_z*3`-amv6>um~8YOWX_?F<}19O za0ar!R9U1o9=8(eUdCZJWT$~c%=tpC*%j9pzB^>qp8>5LM2#d1c0^4mmOxXe5n9hA z^4je;!^;|9w?2w88NP7mM59mMttUCJ9u{P~a+|j@$6Eu3S~k_0M$CKCR&q3av(Cu? z)UD9e82LVL`m(M|>zAH-uKw)V>Byz|nuFYGqw7YFb`R^^Zk}l0u=2isWJZiQzn&T& zxCFD>(Cg`iJv~JGh}@8??;|&sN7b1xn_FE!->7DO)5aryhmWEQ((3&<#J&*+g!ujU{x8hR6d7hyrnzplykx*R%T(aQRs>s{%=1U#(fYw zE<%ULTr#5)*7&WZEq*vpbpFim?~YH_Z1oF05fFTB$k#Xi+4GX;v^P&1&J88*>fQ7> zx;rH2C#|SWN{X9X9n8k=p9*kqLI|$DM4T|*y>%6u&m~xt^j#(TWvlc?BEt_xwgJP)Y`VzFG@>%}{e#YfHI7b48hIB6B#c`o2X<**#L4 zP7@_4#{KDuI|PQi;e+2iJsd47^cl>;s|C8s{^O;;`t3#KXgOXk>q^@yA7)&>>X?rj zSU-|@(qPfr1$e6WMrB3R)rh7APnx5<4Sv7BB1S7`WaUT9+(N>#_0{3W`MvgU&u*YL zy{^n3$Kimz1L==9`uj?a$IwPg*8h&at~W{vJ9g+kMSl<(0+>irxrPr6^!KccXP?;; z@u1_b5!Pq%TH1w=3(YvD^jf=~DxchVak)-$KyK)L-Ii`d{hI8ih+>6THSL*4f+e>6 zFS+3;NQ?-GKO)w_M5+1h*NeMiKcBcZp;gwmdijK}hrdzDiha+<4Hc3@b13+(q@F~S z;{Jn2nn`ooPSh&nI9IJl@D9#L&p}zEOIO%ku6^Dyb$6nfRNJen4!#iGeh|1TN^j-8 zu!y|WQ{CGd)lPoZ`y^buY0i^J`*p4jtcy4QAeLw>cwad0WRr!Yef z-eDNum(41OuQWA{t2D0Zl6If+=w0~nIpXWdXYK=ZvbqQ8!qQh)sNF0~->ScBXL-Ts zh77cZW`Eg)`rw@Sco(E%*QzB;v>hW5^OC2~W`0E%6)T$O?ZA&~X`)VlY~31=gQWZP z4hpLM@5lvp8NTwC;tN*up9@Dl>!pFcfN1w4jm-C}9(ryszLu#T&6YbtzqcvqN+4{>QCapDT>B%kn8l-x$5hA&!<` z@0Gcqk7whL_{0al3-?z)Z6A9VBdXLKGAgMNSS|VtR*dg@vrO!vxjFQa-ZkSzT&cF7 zYHRG73(n2!w9L+z&i!SRmD|1~zbCC<7vT5rT&Kb7b|NOps=S>p^=9$2ak^`fEz)%! zXLyxv`*z`?j~Fxh2eFP2%zk9`omI&F_xexDzdE7^L7EhSJ}~^ehtiP4RG~ zyy{*}ML*%i6U|2Q8{WyQIC>bw<1XoG956lYBHt0w*w!9Ze1mw#D$V8Y)U(M^0)4@v4=WTV z)jVxt_k<;n*8;$-c&>{J#ofi_k245-@<@+4jW>ZDgrj1G)osiJ1?PB3N@gePxt5wm=XhEd$ z+nb`&kIP9xzG(qNW`I{ot>==(-2(;8o_P${eChJEP508xPQSWw>w{LuxLpE2M^zI&l;)PzWko_k>#Up z4s|1!-V}RFJ8T4}BcLn4V8-2}a&oE;O0z>cUSH2yyraBpE@psTeWu^TX-PH}(O%zk zVxasJ8dKC=dp_pi6D4r zM-p91v%Tv&5j?B;0T;YPl*%6tV*d>s(iUhk&0PQ9)v{fM8`65fNb-VPnY` z23lF;@pvl?)(VS7!y0H&WT==SL5GS=ry;&!xN<}+Ay**g@N$1BvVDmq5|EB#%?la1;mX{a7mCp*B4$s}y5jE|fz~-~KY{JYfi^F6E zuoit%MOoraIm#S2VmKD7(5Hd#s{!|fLJ5s!d=PW{TS6W6dQ(Ou^3EyoHZ8B zwub?59F7edkF|&6vS(P^Is`ZbV3_tZP;3@qC0`iAfXm4ZVFYrl1fhX53)6%XoG9*& zD6A#sFA0Um5C^~pjwnxVXqe=$1s`q*XT6v)&8D@TJr-kcZH>X%+t}J#hCn|1-K&|9YL` zgu4}btURLu{+}M8c>1^jz!VaRgxz5<7!rv@p-|Xtwpc7qNJvOYNy*F0D=jUp zuC8urY3b?dfglJ+B)fXjsB{4jR!K@t&nhe`t*m*}hOt19i0Twi9XicGA|a)uu#1Wk zYHISx76>X)Cx~JZ9Yjt|pp|Ax8p~1!+loj4f{H*2kYFN+%X086^WoJ5MYko$`_prw zvU2DV0QC?dNa|@0(22@oszIXIAw7{&l+LRxPIT1+=oSd6t8zLWSt`+MOb2^Pkx(N5 zeU(B`IfwvAI?6r4`i^ZenVAUTIr3s0TP0 z0AzCn6{j9V(u?-7NaB&Qq*PCHBps(Gb~R7*amb~UN(Gb}DZMd8(2*zYFH4~qAlT+Q z5(o1nPf`|}UYeL_X6}l?`H)C#3PsFjCnhB178aH_Hg=fn2uK!kDycBYvrwA908>RP!R^IWJ4{f%6e3FvmhN@ zw1I1qIW5;gQbtZ~VHbAL(s8^ZQgpSayo1&;2vzrgEpF>iC~Kjn77hY~L%`55FgyZ` zds_6>%l@LvAdU>Qn$K3Qq5x7F{6|4%$#y}b@Gw4zJK8t`WmA{ zdd1^58gA?hvIF{-ScJLR$dGiI7dd^k^Vd4oPbc=Yn@&~UDj8MFA|DxDZv)lEUTk)Z z&6>*Ag?|1_bUHq1yk~aNQ)zi!T#(al=c4=_?TyJ4gNi6c?ir}M6yVP>(nhFVaGIk~ zx?tzl8*}o1u8?k0oJB&?jhv1vTpTc_Z|>{M6aGa*4{ocF>gEe8E|s{O*>DY@Vucf#cjuTerQ`?WAuA)mgAKQ43*Z zUDdZ+_WbRQ7jG?1tHW~6tdw7kmC;q4LVX|a0=)flUm`wz7$3>J=;tlZK_w4oddPIf zlwK>QnMz0eZ{ND5CaW=_XUBq@s)xB2}&-275jU7ya3QgjxS*Z z-xhg3TRG>B;$BFuJ7J=osB8AgoIJR8KIkj&xSQ~Jk4apQpT+MloR9!wma+m80V0jKiR#i?Xa%Mfl*pjk|o(Vn5iD3Z6H3L6!$+uI_(& zfH*OD#x&MH23bgxTgLfbH|`kiY+5{Yb`wj{T1MwOeejO+#%r#}m+v2Ps*A54!Yy64 zYrQez-8{DBfc$}J`NSAFaj(kO+va*~2VT}V=MyX#QaGn6Td0_ysi5&xDL?&AzNV}S zv3HB>D!u~nSyof5v1JP>@PQo`X-V$fQ`Vz-sC+$QFF{p1CPh(l5PX-1aYGhTDs@QQ6zRq$2kcd=2`6BzZ9THfa=^DIA%nB15YRAAATewVwFGf@hBeRxcc7`kY#uDI}gh~4@X{FULAI)Qgzz- zQj3POO-lKGxdoasH^qF-j*2nx=rj?#5NTXh9Mw2isCss}@_a3`a4o}|DnO+w_KjV? zdY9%(zUl02nQLtI{z;@tf|_=uj@g*G8j@JG&(TvaMo&Ajy-L_-h=7OTdt-d-lop*S ZAS}Ca8E5c8FFe42yPLP`1!ubKe*k#%zwZD5 delta 433 zcmV;i0Z#s=J;n);7Z)H10{{R3-A3%k00001b5ch_0Itp)>9e>O4g-GybV)=(RCwC$ znq6+fFc1d!N)K&x%wyJG9@x?P&%OY_#R{LSKIYHx zSbRnP+5rAWxSb$&`LSMrQ3Hg@0n~!jO3-3)i+3m-f&B_%*Zjz~0=G&KLEw&ikV*kt zJs#bI#5x#2Q$YX#K>&Z+2x1P85(n6sAbDi%{Ao0Tz>5fy^XI^NL8jpuLEr@h8QZ~j zK?+?2LEz~G`EetAf*b}4g3R**f*j6sBM9tJkl*ex)VeqSQjo!_QWx1O2pt3-Vu>}k zf@M6VV=4%8KFK12O!*N6?jgux7wr^qo-2J(!0Gh<(WR0gqauH6^Jh;GCqIB*kQN2p zcW>Rv5u}BHPJRHjAdQwl$G%U|Q>y=#a8rH+f!hiq-bAYp0RW_ev^<85-g8`Yj0_+b zM0t^?zK8_S3nF|9qJGK(pcO>?m{9!~55#dCK+5CA|B00aR*5C8-LKo9@~0YDId br{WtE&P^u))G`fc00000NkvXXu0mjfMRc?2 diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 5f1991ae6e..692ef30850 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -6274,9 +6274,17 @@ static void GraphicsNew(ByteReader *buf) if (offset <= depot_no_track_offset && offset + num > depot_no_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NO_TRACK; } + /* If the baseset or grf only provides sprites for flat tiles (pre #10282), duplicate those for use on slopes. */ + bool dup_oneway_sprites = ((type == 0x09) && (offset + num <= SPR_ONEWAY_SLOPE_N_OFFSET)); + for (; num > 0; num--) { _cur.nfo_line++; - LoadNextSprite(replace == 0 ? _cur.spriteid++ : replace++, *_cur.file, _cur.nfo_line); + int load_index = (replace == 0 ? _cur.spriteid++ : replace++); + LoadNextSprite(load_index, *_cur.file, _cur.nfo_line); + if (dup_oneway_sprites) { + DupSprite(load_index, load_index + SPR_ONEWAY_SLOPE_N_OFFSET); + DupSprite(load_index, load_index + SPR_ONEWAY_SLOPE_S_OFFSET); + } } _cur.skip_sprites = skip_num; diff --git a/src/road.h b/src/road.h index c34579b5bb..c3fcc30ca9 100644 --- a/src/road.h +++ b/src/road.h @@ -66,6 +66,7 @@ enum RoadTypeSpriteGroup { ROTSG_DEPOT, ///< Optional: Depot images ROTSG_reserved3, ///< Placeholder, if we add road fences (for highways). ROTSG_ROADSTOP, ///< Required: Drive-in stop surface + ROTSG_ONEWAY, ///< Optional: One-way indicator images ROTSG_END, }; diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index dda2f2fa2a..94b4423a15 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -1606,7 +1606,17 @@ static void DrawRoadBits(TileInfo *ti) if (road_rti != nullptr) { DisallowedRoadDirections drd = GetDisallowedRoadDirections(ti->tile); if (drd != DRD_NONE) { - DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((road == ROAD_X) ? 0 : 3), PAL_NONE, 8, 8, GetPartialPixelZ(8, 8, ti->tileh)); + SpriteID oneway = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ONEWAY); + + if (oneway == 0) oneway = SPR_ONEWAY_BASE; + + if ((ti->tileh == SLOPE_NE) || (ti->tileh == SLOPE_NW)) { + oneway += SPR_ONEWAY_SLOPE_N_OFFSET; + } else if ((ti->tileh == SLOPE_SE) || (ti->tileh == SLOPE_SW)) { + oneway += SPR_ONEWAY_SLOPE_S_OFFSET; + } + + DrawGroundSpriteAt(oneway + drd - 1 + ((road == ROAD_X) ? 0 : 3), PAL_NONE, 8, 8, GetPartialPixelZ(8, 8, ti->tileh)); } } diff --git a/src/table/sprites.h b/src/table/sprites.h index b0e61b5d02..407a7a2d87 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -290,8 +290,10 @@ static const SpriteID SPR_TRAMWAY_DEPOT_NO_TRACK = SPR_TRAMWAY_BASE + 113; static const uint16 TRAMWAY_SPRITE_COUNT = 119; /** One way road sprites */ -static const SpriteID SPR_ONEWAY_BASE = SPR_TRAMWAY_BASE + TRAMWAY_SPRITE_COUNT; -static const uint16 ONEWAY_SPRITE_COUNT = 6; +static const SpriteID SPR_ONEWAY_BASE = SPR_TRAMWAY_BASE + TRAMWAY_SPRITE_COUNT; +static const SpriteID SPR_ONEWAY_SLOPE_N_OFFSET = 6; +static const SpriteID SPR_ONEWAY_SLOPE_S_OFFSET = 12; +static const uint16 ONEWAY_SPRITE_COUNT = 18; /** Tunnel sprites with grass only for custom railtype tunnel. */ static const SpriteID SPR_RAILTYPE_TUNNEL_BASE = SPR_ONEWAY_BASE + ONEWAY_SPRITE_COUNT; From f7e2b6ef12b259817d2a4a3705b33f0b09d0eff7 Mon Sep 17 00:00:00 2001 From: PeterN Date: Tue, 27 Dec 2022 18:39:37 +0000 Subject: [PATCH 20/20] Change: Make vehicle list dropdown buttons resize to fit strings. (#10286) --- src/gfx.cpp | 15 +++++++++++++++ src/gfx_func.h | 1 + src/group_gui.cpp | 39 ++++++++++++++++++++++++++++++--------- src/vehicle_gui.cpp | 41 ++++++++++++++++++++++++++++++----------- 4 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/gfx.cpp b/src/gfx.cpp index 147a717a85..43a2072d4a 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -922,6 +922,21 @@ Dimension GetStringBoundingBox(StringID strid, FontSize start_fontsize) return GetStringBoundingBox(buffer, start_fontsize); } +/** + * Get maximum width of a list of strings. + * @param list List of strings, terminated with INVALID_STRING_ID. + * @param fontsize Font size to use. + * @return Width of longest string within the list. + */ +uint GetStringListWidth(const StringID *list, FontSize fontsize) +{ + uint width = 0; + for (const StringID *str = list; *str != INVALID_STRING_ID; str++) { + width = std::max(width, GetStringBoundingBox(*str, fontsize).width); + } + return width; +} + /** * Get the leading corner of a character in a single-line string relative * to the start of the string. diff --git a/src/gfx_func.h b/src/gfx_func.h index 882f6482ec..78891e1dc7 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -148,6 +148,7 @@ static inline void GfxFillRect(const Rect &r, int colour, FillRectMode mode = FI Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize = FS_NORMAL); Dimension GetStringBoundingBox(const std::string &str, FontSize start_fontsize = FS_NORMAL); Dimension GetStringBoundingBox(StringID strid, FontSize start_fontsize = FS_NORMAL); +uint GetStringListWidth(const StringID *list, FontSize fontsize = FS_NORMAL); int GetStringHeight(const char *str, int maxw, FontSize fontsize = FS_NORMAL); int GetStringHeight(StringID str, int maxw); int GetStringLineCount(StringID str, int maxw); diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 5a423a7cde..6b50133880 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -27,6 +27,7 @@ #include "gui.h" #include "group_cmd.h" #include "vehicle_cmd.h" +#include "gfx_func.h" #include "widgets/group_widget.h" @@ -72,15 +73,21 @@ static const NWidgetPart _nested_group_widgets[] = { /* right part */ NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GL_GROUP_BY_ORDER), SetMinimalSize(81, 12), SetDataTip(STR_STATION_VIEW_GROUP, STR_TOOLTIP_GROUP_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_GROUP_BY_DROPDOWN), SetMinimalSize(167, 12), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetResize(1, 0), EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_SORT_BY_ORDER), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetMinimalSize(167, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_FILTER_BY_CARGO), SetMinimalSize(167, 12), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetResize(1, 0), EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GL_GROUP_BY_ORDER), SetFill(1, 0), SetMinimalSize(0, 12), SetDataTip(STR_STATION_VIEW_GROUP, STR_TOOLTIP_GROUP_ORDER), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_SORT_BY_ORDER), SetFill(1, 0), SetMinimalSize(0, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_GROUP_BY_DROPDOWN), SetFill(1, 0), SetMinimalSize(0, 12), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetFill(1, 0), SetMinimalSize(0, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_FILTER_BY_CARGO), SetMinimalSize(0, 12), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetResize(1, 0), EndContainer(), + EndContainer(), + EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_VEHICLE), SetMinimalSize(248, 0), SetMatrixDataTip(1, 0, STR_NULL), SetResize(1, 1), SetFill(1, 0), SetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR), @@ -406,6 +413,20 @@ public: size->height = 4 * resize->height; break; + case WID_GL_GROUP_BY_DROPDOWN: + size->width = GetStringListWidth(this->vehicle_group_by_names) + padding.width; + break; + + case WID_GL_SORT_BY_DROPDOWN: + size->width = GetStringListWidth(this->vehicle_group_none_sorter_names); + size->width = std::max(size->width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names)); + size->width += padding.width; + break; + + case WID_GL_FILTER_BY_CARGO: + size->width = GetStringListWidth(this->cargo_filter_texts) + padding.width; + break; + case WID_GL_MANAGE_VEHICLES_DROPDOWN: { Dimension d = this->GetActionDropdownSize(true, true); d.height += padding.height; diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index a0388a6c54..c7273a885a 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1504,18 +1504,23 @@ static const NWidgetPart _nested_vehicle_list[] = { EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_VL_GROUP_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_STATION_VIEW_GROUP, STR_TOOLTIP_GROUP_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_GROUP_BY_PULLDOWN), SetMinimalSize(167, 12), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(), - EndContainer(), - - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_SORT_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_SORT_BY_PULLDOWN), SetMinimalSize(167, 12), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VL_FILTER_BY_CARGO_SEL), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_FILTER_BY_CARGO), SetMinimalSize(167, 12), SetFill(0, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), + NWidget(NWID_VERTICAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_VL_GROUP_ORDER), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_STATION_VIEW_GROUP, STR_TOOLTIP_GROUP_ORDER), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_SORT_ORDER), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_GROUP_BY_PULLDOWN), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_SORT_BY_PULLDOWN), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VL_FILTER_BY_CARGO_SEL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_FILTER_BY_CARGO), SetMinimalSize(0, 12), SetFill(0, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(), + EndContainer(), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), @@ -1868,6 +1873,20 @@ public: break; } + case WID_VL_GROUP_BY_PULLDOWN: + size->width = GetStringListWidth(this->vehicle_group_by_names) + padding.width; + break; + + case WID_VL_SORT_BY_PULLDOWN: + size->width = GetStringListWidth(this->vehicle_group_none_sorter_names); + size->width = std::max(size->width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names)); + size->width += padding.width; + break; + + case WID_VL_FILTER_BY_CARGO: + size->width = GetStringListWidth(this->cargo_filter_texts) + padding.width; + break; + case WID_VL_MANAGE_VEHICLES_DROPDOWN: { Dimension d = this->GetActionDropdownSize(this->vli.type == VL_STANDARD, false); d.height += padding.height;