Compare commits

...

5 Commits

Author SHA1 Message Date
Jonathan G Rennison eccffec758 Version: Committing version data for tag: jgrpp-0.59.0 2 weeks ago
Peter Nelson 6de4fa921c Change: Use standard padding for company password window.
Also use now-established OnResize pattern for setting height of password warning widget.

(cherry picked from commit 0090431e99b8301c9e3ee14fb3435075708294d5)
3 weeks ago
Jonathan G Rennison f993e30850 Take cargo refit into account in build vehicle window capacity sort modes 3 weeks ago
Jonathan G Rennison 1e5c96ef87 De-duplicate filling TestedEngineDetails in build vehicle windows 3 weeks ago
Jonathan G Rennison fe374a1db0 Allow sorting by cargo capacity/running cost in dual pane train purchase window 3 weeks ago

@ -1,2 +1,2 @@
jgrpp-0.58.3 20240410 0 6642b7e12c203cba63246d57db760bf9c521769e 1 0 2024
ec66ffa6cab681f8f7d8bc388aaaac7e772591a41201d4854d07dcd7378ecac3 -
jgrpp-0.59.0 20240505 0 6de4fa921c8d3a7ad4204383e5f991f59ed9072e 1 0 2024
89f23ced2dbc6410527173a2bcf8427c1a2af35c5c29a7101aa43a0b55286ac3 -

@ -1,4 +1,4 @@
## JGR's Patchpack version 0.58.3
## JGR's Patchpack version 0.59.0
This is a collection of features and other modifications applied to [OpenTTD](http://www.openttd.org/).
It's a separate version of the game which can be installed and played alongside the standard game, not a loadable mod (NewGRF, script, or so on).

@ -2,6 +2,28 @@
* * *
### v0.59.0 (2024-05-05)
* Fix loading recent vanilla savegame versions resulting in incorrect industry cargoes.
* Fix incorrect station catchment/acceptance which could occur when an oil rig/water industry completed construction, which could cause multiplayer desyncs.
* Fix AI construction of block signals when using realistic braking.
* Fix incorrect train weights being used for calculating infrastructure sharing track fees.
* Fix vehicles leaving dots behind in viewport map mode in some cases.
* Fix NewGRF train motion animations for some NewGRFs which use articulated engines.
* Fix template-based train replacement not triggering replacements for companies nominally in debt when using the infinite money setting.
* Fix text filters in dual-pane train purchase window when using NewGRFs with variable vehicle names.
* Road vehicles no longer remaining loading when the next order is for the same station if the next order has a different required direction.
* Enable the cargo capacity/running cost sort mode in the dual pane train purchase window.
* The vehicle capacity sort modes in the build vehicle windows now take into account the selected refit cargo.
* Timekeeping:
* The day length factor setting is now enabled in wallclock timekeeping mode. This scales the economy speed, but not the calendar speed.
* Fix timing of engine preview offers in wallclock timekeeping mode.
* Scheduled dispatch:
* When using scheduled dispatch and timetable automation at the same time, vehicle lateness values are no longer reset when congestion is detected.
* The number of vehicles required text is now clarified to be an estimate.
* Further increase effect size of cargo dist effect of distance on demand setting for values greater than 100%.
* Further reduce the possibility of stuttering when playing sound effects on Windows.
* Bump trunk base from commit 3e625b5b1a81b00f774ca87b48d3e4f4e9d014c3 to commit bd7120bae41b6e7ac86c664c8220b59cd57242bb.
### v0.58.3 (2024-04-10)
* Fix stuttering when playing sound effects on Windows.
* Fix incorrect cargo payment calculations for cargo in the mail compartment of aircraft and in non-first parts of multi-part ships.

@ -8,6 +8,7 @@
/** @file articulated_vehicles.cpp Implementation of articulated vehicles. */
#include "stdafx.h"
#include "articulated_vehicles.h"
#include "core/bitmath_func.hpp"
#include "core/random_func.hpp"
#include "train.h"
@ -141,15 +142,23 @@ void GetArticulatedPartsEngineIDs(EngineID engine_type, bool purchase_window, st
* Returns the default (non-refitted) capacity of a specific EngineID.
* @param engine the EngineID of interest
* @param cargo_type returns the default cargo type, if needed
* @param attempt_refit cargo ID to attempt to use
* @return capacity
*/
static inline uint16_t GetVehicleDefaultCapacity(EngineID engine, CargoID *cargo_type)
static inline uint16_t GetVehicleDefaultCapacity(EngineID engine, CargoID *cargo_type, CargoID attempt_refit = INVALID_CARGO)
{
const Engine *e = Engine::Get(engine);
CargoID cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : INVALID_CARGO);
CargoID cargo = INVALID_CARGO;
if (e->CanCarryCargo()) {
if (attempt_refit != INVALID_CARGO && HasBit(e->info.refit_mask, attempt_refit)) {
cargo = attempt_refit;
} else {
cargo = e->GetDefaultCargoType();
}
}
if (cargo_type != nullptr) *cargo_type = cargo;
if (cargo == INVALID_CARGO) return 0;
return e->GetDisplayDefaultCapacity();
return e->GetDisplayDefaultCapacity(nullptr, cargo);
}
/**
@ -175,16 +184,20 @@ static inline CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool inc
/**
* Get the capacity of the parts of a given engine.
* @param engine The engine to get the capacities from.
* @param attempt_refit Attempt to get capacity when refitting to this cargo.
* @return The cargo capacities.
*/
CargoArray GetCapacityOfArticulatedParts(EngineID engine)
CargoArray GetCapacityOfArticulatedParts(EngineID engine, CargoID attempt_refit)
{
CargoArray capacity{};
const Engine *e = Engine::Get(engine);
CargoID cargo_type;
uint16_t cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type);
if (cargo_type < NUM_CARGO) capacity[cargo_type] = cargo_capacity;
auto get_engine_cargo = [&capacity, attempt_refit](EngineID eng) {
CargoID cargo_type;
uint16_t cargo_capacity = GetVehicleDefaultCapacity(eng, &cargo_type, attempt_refit);
if (cargo_type < NUM_CARGO) capacity[cargo_type] += cargo_capacity;
};
get_engine_cargo(engine);
if (!e->IsArticulatedCallbackVehicleType()) return capacity;
@ -194,8 +207,7 @@ CargoArray GetCapacityOfArticulatedParts(EngineID engine)
EngineID artic_engine = GetNextArticulatedPart(i, engine);
if (artic_engine == INVALID_ENGINE) break;
cargo_capacity = GetVehicleDefaultCapacity(artic_engine, &cargo_type);
if (cargo_type < NUM_CARGO) capacity[cargo_type] += cargo_capacity;
get_engine_cargo(artic_engine);
}
return capacity;

@ -16,7 +16,7 @@
uint CountArticulatedParts(EngineID engine_type, bool purchase_window);
void GetArticulatedPartsEngineIDs(EngineID engine_type, bool purchase_window, std::vector<EngineID> &ids);
CargoArray GetCapacityOfArticulatedParts(EngineID engine);
CargoArray GetCapacityOfArticulatedParts(EngineID engine, CargoID attempt_refit = INVALID_CARGO);
CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine);
void AddArticulatedParts(Vehicle *first);
void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, CargoTypes *union_mask, CargoTypes *intersection_mask);

@ -36,6 +36,7 @@
#include "querystring_gui.h"
#include "stringfilter_type.h"
#include "hotkeys.h"
#include "3rdparty/cpp-btree/btree_map.h"
#include "widgets/build_vehicle_widget.h"
@ -205,6 +206,29 @@ bool _engine_sort_show_hidden_locos = false; ///< Las
bool _engine_sort_show_hidden_wagons = false; ///< Last set 'show hidden wagons' setting.
static CargoID _engine_sort_last_cargo_criteria[] = {CargoFilterCriteria::CF_ANY, CargoFilterCriteria::CF_ANY, CargoFilterCriteria::CF_ANY, CargoFilterCriteria::CF_ANY}; ///< Last set filter criteria, for each vehicle type.
struct BuildVehicleWindowBase;
struct EngineCapacityCache {
const BuildVehicleWindowBase *parent = nullptr;
CargoID current_cargo = INVALID_CARGO;
btree::btree_map<EngineID, uint> capacities;
void UpdateCargoFilter(const BuildVehicleWindowBase *parent, CargoID cargo_filter_criteria)
{
this->parent = parent;
if (cargo_filter_criteria >= NUM_CARGO) cargo_filter_criteria = INVALID_CARGO;
if (cargo_filter_criteria != this->current_cargo) {
this->current_cargo = cargo_filter_criteria;
this->capacities.clear();
}
}
uint GetArticulatedCapacity(EngineID eng, bool dual_headed = false);
};
static EngineCapacityCache *_engine_sort_capacity_cache = nullptr;
static byte _last_sort_criteria_loco = 0;
static bool _last_sort_order_loco = false;
static CargoID _last_filter_criteria_loco = CargoFilterCriteria::CF_ANY;
@ -449,8 +473,8 @@ static bool TrainEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngin
const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id);
const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id);
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 va = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id, rvi_a->railveh_type == RAILVEH_MULTIHEAD);
int vb = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id, rvi_b->railveh_type == RAILVEH_MULTIHEAD);
int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
@ -469,8 +493,8 @@ static bool TrainEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, c
const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id);
const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id);
uint va = GetTotalCapacityOfArticulatedParts(a.engine_id) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
uint vb = GetTotalCapacityOfArticulatedParts(b.engine_id) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
uint va = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id, rvi_a->railveh_type == RAILVEH_MULTIHEAD);
uint vb = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id, rvi_b->railveh_type == RAILVEH_MULTIHEAD);
return GenericEngineValueVsRunningCostSorter(a, va, b, vb);
}
@ -502,8 +526,8 @@ static bool TrainEnginesThenWagonsSorter(const GUIEngineListItem &a, const GUIEn
*/
static bool RoadVehEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
{
int va = GetTotalCapacityOfArticulatedParts(a.engine_id);
int vb = GetTotalCapacityOfArticulatedParts(b.engine_id);
int va = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id);
int vb = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id);
int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
@ -519,7 +543,9 @@ static bool RoadVehEngineCapacitySorter(const GUIEngineListItem &a, const GUIEng
*/
static bool RoadVehEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
{
return GenericEngineValueVsRunningCostSorter(a, GetTotalCapacityOfArticulatedParts(a.engine_id), b, GetTotalCapacityOfArticulatedParts(b.engine_id));
int capacity_a = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id);
int capacity_b = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id);
return GenericEngineValueVsRunningCostSorter(a, capacity_a, b, capacity_b);
}
/* Ship vehicle sorting functions */
@ -532,8 +558,8 @@ static bool RoadVehEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a,
*/
static bool ShipEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
{
int va = GetTotalCapacityOfArticulatedParts(a.engine_id);
int vb = GetTotalCapacityOfArticulatedParts(b.engine_id);
int va = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id);
int vb = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id);
int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
@ -549,7 +575,9 @@ static bool ShipEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngine
*/
static bool ShipEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
{
return GenericEngineValueVsRunningCostSorter(a, GetTotalCapacityOfArticulatedParts(a.engine_id), b, GetTotalCapacityOfArticulatedParts(b.engine_id));
int capacity_a = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id);
int capacity_b = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id);
return GenericEngineValueVsRunningCostSorter(a, capacity_a, b, capacity_b);
}
/* Aircraft sorting functions */
@ -1425,8 +1453,74 @@ struct BuildVehicleWindowBase : Window {
return list;
}
void FillTestedEngineCapacity(EngineID engine, CargoID cargo, TestedEngineDetails &te) const
{
const Engine *e = Engine::Get(engine);
if (!e->CanPossiblyCarryCargo()) {
te.cost = 0;
te.cargo = INVALID_CARGO;
te.all_capacities.Clear();
return;
}
if (this->virtual_train_mode) {
if (cargo != INVALID_CARGO && cargo != e->GetDefaultCargoType()) {
SavedRandomSeeds saved_seeds;
SaveRandomSeeds(&saved_seeds);
StringID err;
Train *t = BuildVirtualRailVehicle(engine, err, 0, false);
if (t != nullptr) {
const CommandCost ret = CmdRefitVehicle(0, DC_QUERY_COST, t->index, cargo | (1 << 16), nullptr);
te.cost = ret.GetCost();
te.capacity = _returned_refit_capacity;
te.mail_capacity = _returned_mail_refit_capacity;
te.cargo = (cargo == INVALID_CARGO) ? e->GetDefaultCargoType() : cargo;
te.all_capacities = _returned_vehicle_capacities;
delete t;
RestoreRandomSeeds(saved_seeds);
return;
} else {
RestoreRandomSeeds(saved_seeds);
}
}
} else if (!this->listview_mode) {
/* Query for cost and refitted capacity */
CommandCost ret = DoCommand(this->window_number, engine | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr);
if (ret.Succeeded()) {
te.cost = ret.GetCost() - e->GetCost();
te.capacity = _returned_refit_capacity;
te.mail_capacity = _returned_mail_refit_capacity;
te.cargo = (cargo == INVALID_CARGO) ? e->GetDefaultCargoType() : cargo;
te.all_capacities = _returned_vehicle_capacities;
return;
}
}
/* Purchase test was not possible or failed, fill in the defaults instead. */
te = {};
te.FillDefaultCapacities(e);
}
};
uint EngineCapacityCache::GetArticulatedCapacity(EngineID eng, bool dual_headed)
{
auto iter = this->capacities.insert({ eng, 0 });
if (iter.second) {
/* New cache entry */
const Engine *e = Engine::Get(eng);
if (this->current_cargo != INVALID_CARGO && this->current_cargo != e->GetDefaultCargoType() && HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) && e->refit_capacity_values == nullptr) {
/* Expensive path simulating vehicle construction is required to determine capacity */
TestedEngineDetails te{};
this->parent->FillTestedEngineCapacity(eng, this->current_cargo, te);
iter.first->second = te.all_capacities.GetSum<uint>();
} else {
iter.first->second = GetTotalCapacityOfArticulatedParts(eng, this->current_cargo) * (dual_headed ? 2 : 1);
}
}
return iter.first->second;
}
/** GUI for building vehicles. */
struct BuildVehicleWindow : BuildVehicleWindowBase {
union {
@ -1443,6 +1537,7 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
int details_height; ///< Minimal needed height of the details panels, in text lines (found so far).
Scrollbar *vscroll;
TestedEngineDetails te; ///< Tested cost and capacity after refit.
EngineCapacityCache capacity_cache; ///< Engine capacity cache.
StringFilter string_filter; ///< Filter for vehicle name
QueryString vehicle_editbox; ///< Filter editbox
@ -1579,50 +1674,7 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
if (this->sel_engine == INVALID_ENGINE) return;
const Engine *e = Engine::Get(this->sel_engine);
if (!e->CanPossiblyCarryCargo()) {
this->te.cost = 0;
this->te.cargo = INVALID_CARGO;
this->te.all_capacities.Clear();
return;
}
if (this->virtual_train_mode) {
if (cargo != INVALID_CARGO && cargo != e->GetDefaultCargoType()) {
SavedRandomSeeds saved_seeds;
SaveRandomSeeds(&saved_seeds);
StringID err;
Train *t = BuildVirtualRailVehicle(this->sel_engine, err, 0, false);
if (t != nullptr) {
const CommandCost ret = CmdRefitVehicle(0, DC_QUERY_COST, t->index, cargo | (1 << 16), nullptr);
this->te.cost = ret.GetCost();
this->te.capacity = _returned_refit_capacity;
this->te.mail_capacity = _returned_mail_refit_capacity;
this->te.cargo = (cargo == INVALID_CARGO) ? e->GetDefaultCargoType() : cargo;
this->te.all_capacities = _returned_vehicle_capacities;
delete t;
RestoreRandomSeeds(saved_seeds);
return;
} else {
RestoreRandomSeeds(saved_seeds);
}
}
} else if (!this->listview_mode) {
/* Query for cost and refitted capacity */
CommandCost ret = DoCommand(this->window_number, this->sel_engine | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr);
if (ret.Succeeded()) {
this->te.cost = ret.GetCost() - e->GetCost();
this->te.capacity = _returned_refit_capacity;
this->te.mail_capacity = _returned_mail_refit_capacity;
this->te.cargo = (cargo == INVALID_CARGO) ? e->GetDefaultCargoType() : cargo;
this->te.all_capacities = _returned_vehicle_capacities;
return;
}
}
/* Purchase test was not possible or failed, fill in the defaults instead. */
this->te = {};
this->te.FillDefaultCapacities(e);
this->FillTestedEngineCapacity(this->sel_engine, cargo, this->te);
}
void OnInit() override
@ -1722,6 +1774,10 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
/* invalidate cached values for name sorter - engine names could change */
_last_engine[0] = _last_engine[1] = INVALID_ENGINE;
/* setup engine capacity cache */
this->capacity_cache.UpdateCargoFilter(this, this->cargo_filter_criteria);
_engine_sort_capacity_cache = &(this->capacity_cache);
/* make engines first, and then wagons, sorted by selected sort_criteria */
_engine_sort_direction = false;
EngList_Sort(list, TrainEnginesThenWagonsSorter);
@ -1859,6 +1915,10 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
}
}
/* setup engine capacity cache */
this->capacity_cache.UpdateCargoFilter(this, this->cargo_filter_criteria);
_engine_sort_capacity_cache = &(this->capacity_cache);
_engine_sort_direction = this->descending_sort_order;
EngList_Sort(this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
@ -2192,7 +2252,7 @@ static Hotkey buildvehicle_hotkeys[] = {
};
HotkeyList BuildVehicleWindow::hotkeys("buildvehicle", buildvehicle_hotkeys);
static EngList_SortTypeFunction * const _sorter_loco[11] = {
static EngList_SortTypeFunction * const _sorter_loco[12] = {
/* Locomotives */
&EngineNumberSorter,
&EngineCostSorter,
@ -2204,10 +2264,11 @@ static EngList_SortTypeFunction * const _sorter_loco[11] = {
&EngineRunningCostSorter,
&EnginePowerVsRunningCostSorter,
&EngineReliabilitySorter,
&TrainEngineCapacitySorter
&TrainEngineCapacitySorter,
&TrainEngineCapacityVsRunningCostSorter
};
static EngList_SortTypeFunction * const _sorter_wagon[7] = {
static EngList_SortTypeFunction * const _sorter_wagon[8] = {
/* Wagons */
&EngineNumberSorter,
&EngineCostSorter,
@ -2215,10 +2276,11 @@ static EngList_SortTypeFunction * const _sorter_wagon[7] = {
&EngineIntroDateSorter,
&EngineNameSorter,
&EngineRunningCostSorter,
&TrainEngineCapacitySorter
&TrainEngineCapacitySorter,
&TrainEngineCapacityVsRunningCostSorter
};
static const StringID _sort_listing_loco[12] = {
static const StringID _sort_listing_loco[13] = {
/* Locomotives */
STR_SORT_BY_ENGINE_ID,
STR_SORT_BY_COST,
@ -2231,10 +2293,11 @@ static const StringID _sort_listing_loco[12] = {
STR_SORT_BY_POWER_VS_RUNNING_COST,
STR_SORT_BY_RELIABILITY,
STR_SORT_BY_CARGO_CAPACITY,
STR_SORT_BY_CARGO_CAPACITY_VS_RUNNING_COST,
INVALID_STRING_ID
};
static const StringID _sort_listing_wagon[8] = {
static const StringID _sort_listing_wagon[9] = {
/* Wagons */
STR_SORT_BY_ENGINE_ID,
STR_SORT_BY_COST,
@ -2243,6 +2306,7 @@ static const StringID _sort_listing_wagon[8] = {
STR_SORT_BY_NAME,
STR_SORT_BY_RUNNING_COST,
STR_SORT_BY_CARGO_CAPACITY,
STR_SORT_BY_CARGO_CAPACITY_VS_RUNNING_COST,
INVALID_STRING_ID
};
@ -2294,6 +2358,7 @@ struct BuildVehicleWindowTrainAdvanced final : BuildVehicleWindowBase {
bool show_hidden; ///< State of the 'show hidden' button.
int details_height; ///< Minimal needed height of the details panels (found so far).
TestedEngineDetails te; ///< Tested cost and capacity after refit.
EngineCapacityCache capacity_cache; ///< Engine capacity cache.
StringFilter string_filter; ///< Filter for vehicle name
QueryString vehicle_editbox { MAX_LENGTH_VEHICLE_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_VEHICLE_NAME_CHARS }; ///< Filter editbox
};
@ -2482,50 +2547,7 @@ struct BuildVehicleWindowTrainAdvanced final : BuildVehicleWindowBase {
if (state.sel_engine == INVALID_ENGINE) return;
const Engine *e = Engine::Get(state.sel_engine);
if (!e->CanPossiblyCarryCargo()) {
state.te.cost = 0;
state.te.cargo = INVALID_CARGO;
state.te.all_capacities.Clear();
return;
}
if (this->virtual_train_mode) {
if (cargo != INVALID_CARGO && cargo != e->GetDefaultCargoType()) {
SavedRandomSeeds saved_seeds;
SaveRandomSeeds(&saved_seeds);
StringID err;
Train *t = BuildVirtualRailVehicle(state.sel_engine, err, 0, false);
if (t != nullptr) {
const CommandCost ret = CmdRefitVehicle(0, DC_QUERY_COST, t->index, cargo | (1 << 16), nullptr);
state.te.cost = ret.GetCost();
state.te.capacity = _returned_refit_capacity;
state.te.mail_capacity = _returned_mail_refit_capacity;
state.te.cargo = (cargo == INVALID_CARGO) ? e->GetDefaultCargoType() : cargo;
state.te.all_capacities = _returned_vehicle_capacities;
delete t;
RestoreRandomSeeds(saved_seeds);
return;
} else {
RestoreRandomSeeds(saved_seeds);
}
}
} else if (!this->listview_mode) {
/* Query for cost and refitted capacity */
const CommandCost ret = DoCommand(this->window_number, state.sel_engine | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr);
if (ret.Succeeded()) {
state.te.cost = ret.GetCost() - e->GetCost();
state.te.capacity = _returned_refit_capacity;
state.te.mail_capacity = _returned_mail_refit_capacity;
state.te.cargo = (cargo == INVALID_CARGO) ? e->GetDefaultCargoType() : cargo;
state.te.all_capacities = _returned_vehicle_capacities;
return;
}
}
/* Purchase test was not possible or failed, fill in the defaults instead. */
state.te = {};
state.te.FillDefaultCapacities(e);
this->FillTestedEngineCapacity(state.sel_engine, cargo, state.te);
}
void SelectColumn(bool wagon)
@ -2641,6 +2663,10 @@ struct BuildVehicleWindowTrainAdvanced final : BuildVehicleWindowBase {
/* invalidate cached values for name sorter - engine names could change */
_last_engine[0] = _last_engine[1] = INVALID_ENGINE;
/* setup engine capacity cache */
state.capacity_cache.UpdateCargoFilter(this, state.cargo_filter_criteria);
_engine_sort_capacity_cache = &(state.capacity_cache);
/* Sort */
_engine_sort_direction = state.descending_sort_order;
EngList_Sort(list, sorters[state.sort_criteria]);

@ -223,9 +223,10 @@ bool Engine::CanPossiblyCarryCargo() const
* For aircraft the main capacity is determined. Mail might be present as well.
* @param v Vehicle of interest; nullptr in purchase list
* @param mail_capacity returns secondary cargo (mail) capacity of aircraft
* @param attempt_refit cargo ID to attempt to use, when v is nullptr
* @return Capacity
*/
uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity, CargoID attempt_refit) const
{
assert(v == nullptr || this->index == v->engine_type);
if (mail_capacity != nullptr) *mail_capacity = 0;
@ -234,7 +235,16 @@ uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
bool new_multipliers = HasBit(this->info.misc_flags, EF_NO_DEFAULT_CARGO_MULTIPLIER);
CargoID default_cargo = this->GetDefaultCargoType();
CargoID cargo_type = (v != nullptr) ? v->cargo_type : default_cargo;
CargoID cargo_type;
if (v != nullptr) {
cargo_type = v->cargo_type;
} else {
if (attempt_refit != INVALID_CARGO && HasBit(this->info.refit_mask, attempt_refit)) {
cargo_type = attempt_refit;
} else {
cargo_type = default_cargo;
}
}
if (mail_capacity != nullptr && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CC_PASSENGERS)) {
*mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v);

@ -112,7 +112,7 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
return this->info.cargo_type;
}
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity = nullptr) const;
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity = nullptr, CargoID attempt_refit = INVALID_CARGO) const;
bool CanCarryCargo() const;
bool CanPossiblyCarryCargo() const;
@ -125,12 +125,13 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
* For articulated engines use GetCapacityOfArticulatedParts
*
* @param mail_capacity returns secondary cargo (mail) capacity of aircraft
* @param attempt_refit cargo ID to attempt to use
* @return The default capacity
* @see GetDefaultCargoType
*/
uint GetDisplayDefaultCapacity(uint16_t *mail_capacity = nullptr) const
uint GetDisplayDefaultCapacity(uint16_t *mail_capacity = nullptr, CargoID attempt_refit = INVALID_CARGO) const
{
return this->DetermineCapacity(nullptr, mail_capacity);
return this->DetermineCapacity(nullptr, mail_capacity, attempt_refit);
}
Money GetRunningCost() const;

@ -29,6 +29,6 @@ void SetYearEngineAgingStops();
void CalcEngineReliability(Engine *e, bool new_month);
void StartupOneEngine(Engine *e, const CalTime::YearMonthDay &aging_ymd, const CalTime::YearMonthDay &expire_stop_ymd, uint32_t seed, CalTime::Date no_introduce_after_date);
uint GetTotalCapacityOfArticulatedParts(EngineID engine);
uint GetTotalCapacityOfArticulatedParts(EngineID engine, CargoID attempt_refit = INVALID_CARGO);
#endif /* ENGINE_FUNC_H */

@ -159,11 +159,12 @@ void ShowEnginePreviewWindow(EngineID engine)
/**
* Get the capacity of an engine with articulated parts.
* @param engine The engine to get the capacity of.
* @param attempt_refit Attempt to get capacity when refitting to this cargo.
* @return The capacity.
*/
uint GetTotalCapacityOfArticulatedParts(EngineID engine)
uint GetTotalCapacityOfArticulatedParts(EngineID engine, CargoID attempt_refit)
{
CargoArray cap = GetCapacityOfArticulatedParts(engine);
CargoArray cap = GetCapacityOfArticulatedParts(engine, attempt_refit);
return cap.GetSum<uint>();
}

@ -2264,13 +2264,10 @@ void ShowNetworkNeedPassword(NetworkPasswordType npt)
struct NetworkCompanyPasswordWindow : public Window {
QueryString password_editbox; ///< Password editbox.
Dimension warning_size; ///< How much space to use for the warning text
NetworkCompanyPasswordWindow(WindowDesc *desc, Window *parent) : Window(desc), password_editbox(NETWORK_PASSWORD_LENGTH)
{
this->InitNested(0);
this->UpdateWarningStringSize();
this->parent = parent;
this->querystrings[WID_NCP_PASSWORD] = &this->password_editbox;
this->password_editbox.cancel_button = WID_NCP_CANCEL;
@ -2278,29 +2275,21 @@ struct NetworkCompanyPasswordWindow : public Window {
this->SetFocusedWidget(WID_NCP_PASSWORD);
}
void UpdateWarningStringSize()
void OnResize() override
{
assert(this->nested_root->smallest_x > 0);
this->warning_size.width = this->nested_root->current_x - (WidgetDimensions::scaled.framerect.Horizontal()) * 2;
this->warning_size.height = GetStringHeight(STR_WARNING_PASSWORD_SECURITY, this->warning_size.width);
this->warning_size.height += (WidgetDimensions::scaled.framerect.Vertical()) * 2;
bool changed = false;
this->ReInit();
}
auto nwid = this->GetWidget<NWidgetResizeBase>(WID_NCP_WARNING);
changed |= nwid->UpdateVerticalSize(GetStringHeight(STR_WARNING_PASSWORD_SECURITY, nwid->current_x));
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
{
if (widget == WID_NCP_WARNING) {
*size = this->warning_size;
}
if (changed) this->ReInit(0, 0, this->flags & WF_CENTERED);
}
void DrawWidget(const Rect &r, WidgetID widget) const override
{
if (widget != WID_NCP_WARNING) return;
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.framerect),
STR_WARNING_PASSWORD_SECURITY, TC_FROMSTRING, SA_CENTER);
DrawStringMultiLine(r, STR_WARNING_PASSWORD_SECURITY, TC_FROMSTRING, SA_CENTER);
}
void OnOk()
@ -2337,19 +2326,21 @@ static constexpr NWidgetPart _nested_network_company_password_window_widgets[] =
NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_COMPANY_PASSWORD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_BACKGROUND),
NWidget(NWID_VERTICAL), SetPIP(5, 5, 5),
NWidget(NWID_HORIZONTAL), SetPIP(5, 5, 5),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0), SetPadding(WidgetDimensions::unscaled.frametext),
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0),
NWidget(WWT_TEXT, COLOUR_GREY, WID_NCP_LABEL), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_NULL),
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NCP_PASSWORD), SetFill(1, 0), SetMinimalSize(194, 12), SetDataTip(STR_COMPANY_VIEW_SET_PASSWORD, STR_NULL),
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NCP_PASSWORD), SetFill(1, 0), SetMinimalSize(194, 0), SetDataTip(STR_COMPANY_VIEW_SET_PASSWORD, STR_NULL),
EndContainer(),
NWidget(NWID_HORIZONTAL), SetPIP(5, 0, 5),
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0),
NWidget(NWID_SPACER), SetFill(1, 0),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_NCP_SAVE_AS_DEFAULT_PASSWORD), SetMinimalSize(194, 12),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_NCP_SAVE_AS_DEFAULT_PASSWORD), SetMinimalSize(194, 0),
SetDataTip(STR_COMPANY_PASSWORD_MAKE_DEFAULT, STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP),
EndContainer(),
EndContainer(),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_WARNING), EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NCP_WARNING), SetPadding(WidgetDimensions::unscaled.frametext),
EndContainer(),
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_COMPANY_PASSWORD_CANCEL),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_OK), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_COMPANY_PASSWORD_OK),

Loading…
Cancel
Save