Skip to content

Commit

Permalink
Fix OpenTTD#10032: Capacities of articulated vehicles in build window
Browse files Browse the repository at this point in the history
See also: OpenTTD#9954
  • Loading branch information
JGRennison authored and michicc committed Jan 27, 2023
1 parent af45954 commit 167ad16
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 93 deletions.
35 changes: 0 additions & 35 deletions src/articulated_vehicles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,41 +160,6 @@ CargoArray GetCapacityOfArticulatedParts(EngineID engine)
return capacity;
}

/**
* Get the default cargoes and refits of an articulated vehicle.
* The refits are linked to a cargo rather than an articulated part to prevent a long list of parts.
* @param engine Model to investigate.
* @param[out] cargoes Total amount of units that can be transported, summed by cargo.
* @param[out] refits Whether a (possibly partial) refit for each cargo is possible.
* @param cargo_type Selected refitted cargo type
* @param cargo_capacity Capacity of selected refitted cargo type
*/
void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits, CargoID cargo_type, uint cargo_capacity)
{
cargoes->Clear();
*refits = 0;

const Engine *e = Engine::Get(engine);

if (cargo_type < NUM_CARGO && cargo_capacity > 0) {
(*cargoes)[cargo_type] += cargo_capacity;
if (IsEngineRefittable(engine)) SetBit(*refits, cargo_type);
}

if (!e->IsGroundVehicle() || !HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return;

for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
EngineID artic_engine = GetNextArticulatedPart(i, engine);
if (artic_engine == INVALID_ENGINE) break;

cargo_capacity = GetVehicleDefaultCapacity(artic_engine, &cargo_type);
if (cargo_type < NUM_CARGO && cargo_capacity > 0) {
(*cargoes)[cargo_type] += cargo_capacity;
if (IsEngineRefittable(artic_engine)) SetBit(*refits, cargo_type);
}
}
}

/**
* Checks whether any of the articulated parts is refittable
* @param engine the first part
Expand Down
2 changes: 1 addition & 1 deletion src/autoreplace_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic

/* Build the new vehicle */
VehicleID new_veh_id;
std::tie(cost, new_veh_id, std::ignore, std::ignore) = Command<CMD_BUILD_VEHICLE>::Do(DC_EXEC | DC_AUTOREPLACE, old_veh->tile, e, true, CT_INVALID, INVALID_CLIENT_ID);
std::tie(cost, new_veh_id, std::ignore, std::ignore, std::ignore) = Command<CMD_BUILD_VEHICLE>::Do(DC_EXEC | DC_AUTOREPLACE, old_veh->tile, e, true, CT_INVALID, INVALID_CLIENT_ID);
if (cost.Failed()) return cost;

Vehicle *new_veh = Vehicle::Get(new_veh_id);
Expand Down
3 changes: 1 addition & 2 deletions src/autoreplace_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,7 @@ class ReplaceVehicleWindow : public Window {
const Engine *e = Engine::Get(this->sel_engine[side]);
TestedEngineDetails ted;
ted.cost = 0;
ted.cargo = e->GetDefaultCargoType();
ted.capacity = e->GetDisplayDefaultCapacity(&ted.mail_capacity);
ted.FillDefaultCapacities(e);

const Rect r = this->GetWidget<NWidgetBase>(side == 0 ? WID_RV_LEFT_DETAILS : WID_RV_RIGHT_DETAILS)->GetCurrentRect()
.Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect);
Expand Down
59 changes: 39 additions & 20 deletions src/build_vehicle_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -553,18 +553,29 @@ static GUIEngineList::FilterFunction * const _filter_funcs[] = {
&CargoAndEngineFilter,
};

static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine, TestedEngineDetails &te)
static uint GetCargoWeight(const CargoArray &cap, VehicleType vtype)
{
CargoArray cap;
CargoTypes refits;
GetArticulatedVehicleCargoesAndRefits(engine, &cap, &refits, te.cargo, te.capacity);
uint weight = 0;
for (CargoID c = 0; c < NUM_CARGO; c++) {
if (cap[c] != 0) {
if (vtype == VEH_TRAIN) {
weight += CargoSpec::Get(c)->WeightOfNUnitsInTrain(cap[c]);
} else {
weight += CargoSpec::Get(c)->WeightOfNUnits(cap[c]);
}
}
}
return weight;
}

static int DrawCargoCapacityInfo(int left, int right, int y, TestedEngineDetails &te, bool refittable)
{
for (CargoID c = 0; c < NUM_CARGO; c++) {
if (cap[c] == 0) continue;
if (te.all_capacities[c] == 0) continue;

SetDParam(0, c);
SetDParam(1, cap[c]);
SetDParam(2, HasBit(refits, c) ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
SetDParam(1, te.all_capacities[c]);
SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
y += FONT_HEIGHT_NORMAL;
}
Expand All @@ -591,8 +602,7 @@ static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine
/* Wagon weight - (including cargo) */
uint weight = e->GetDisplayWeight();
SetDParam(0, weight);
uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->WeightOfNUnitsInTrain(te.capacity) : 0);
SetDParam(1, cargo_weight + weight);
SetDParam(1, GetCargoWeight(te.all_capacities, VEH_TRAIN) + weight);
DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
y += FONT_HEIGHT_NORMAL;

Expand Down Expand Up @@ -685,8 +695,7 @@ static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_n
/* Road vehicle weight - (including cargo) */
int16 weight = e->GetDisplayWeight();
SetDParam(0, weight);
uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->WeightOfNUnits(te.capacity) : 0);
SetDParam(1, cargo_weight + weight);
SetDParam(1, GetCargoWeight(te.all_capacities, VEH_ROAD) + weight);
DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
y += FONT_HEIGHT_NORMAL;

Expand Down Expand Up @@ -868,6 +877,21 @@ static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
return result;
}

void TestedEngineDetails::FillDefaultCapacities(const Engine *e)
{
this->cargo = e->GetDefaultCargoType();
if (e->type == VEH_TRAIN || e->type == VEH_ROAD) {
this->all_capacities = GetCapacityOfArticulatedParts(e->index);
this->capacity = this->all_capacities[this->cargo];
this->mail_capacity = 0;
} else {
this->capacity = e->GetDisplayDefaultCapacity(&this->mail_capacity);
this->all_capacities[this->cargo] = this->capacity;
this->all_capacities[CT_MAIL] = this->mail_capacity;
}
if (this->all_capacities.GetCount() == 0) this->cargo = CT_INVALID;
}

/**
* Draw the purchase info details of a vehicle at a given location.
* @param left,right,y location where to draw the info
Expand Down Expand Up @@ -909,7 +933,7 @@ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number,

if (articulated_cargo) {
/* Cargo type + capacity, or N/A */
int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, te);
int new_y = DrawCargoCapacityInfo(left, right, y, te, refittable);

if (new_y == y) {
SetDParam(0, CT_INVALID);
Expand Down Expand Up @@ -1261,28 +1285,23 @@ struct BuildVehicleWindow : Window {
if (this->sel_engine == INVALID_ENGINE) return;

const Engine *e = Engine::Get(this->sel_engine);
if (!e->CanCarryCargo()) {
this->te.cost = 0;
this->te.cargo = CT_INVALID;
return;
}

if (!this->listview_mode) {
/* Query for cost and refitted capacity */
auto [ret, veh_id, refit_capacity, refit_mail] = Command<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, this->window_number, this->sel_engine, true, cargo, INVALID_CLIENT_ID);
auto [ret, veh_id, refit_capacity, refit_mail, cargo_capacities] = Command<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, this->window_number, this->sel_engine, true, cargo, INVALID_CLIENT_ID);
if (ret.Succeeded()) {
this->te.cost = ret.GetCost() - e->GetCost();
this->te.capacity = refit_capacity;
this->te.mail_capacity = refit_mail;
this->te.cargo = (cargo == CT_INVALID) ? e->GetDefaultCargoType() : cargo;
this->te.all_capacities = cargo_capacities;
return;
}
}

/* Purchase test was not possible or failed, fill in the defaults instead. */
this->te.cost = 0;
this->te.capacity = e->GetDisplayDefaultCapacity(&this->te.mail_capacity);
this->te.cargo = e->GetDefaultCargoType();
this->te.FillDefaultCapacities(e);
}

void OnInit() override
Expand Down
2 changes: 1 addition & 1 deletion src/economy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1494,7 +1494,7 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station
if (st->goods[cid].cargo.HasCargoFor(next_station)) {
/* Try to find out if auto-refitting would succeed. In case the refit is allowed,
* the returned refit capacity will be greater than zero. */
auto [cc, refit_capacity, mail_capacity] = Command<CMD_REFIT_VEHICLE>::Do(DC_QUERY_COST, v_start->index, cid, 0xFF, true, false, 1); // Auto-refit and only this vehicle including artic parts.
auto [cc, refit_capacity, mail_capacity, cargo_capacities] = Command<CMD_REFIT_VEHICLE>::Do(DC_QUERY_COST, v_start->index, cid, 0xFF, true, false, 1); // Auto-refit and only this vehicle including artic parts.
/* Try to balance different loadable cargoes between parts of the consist, so that
* all of them can be loaded. Avoid a situation where all vehicles suddenly switch
* to the first loadable cargo for which there is only one packet. If the capacities
Expand Down
1 change: 0 additions & 1 deletion src/engine_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ extern const uint8 _engine_offsets[4];

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, uint32 seed);
Expand Down
4 changes: 2 additions & 2 deletions src/script/api/script_vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
if (!ScriptEngine::IsBuildable(engine_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo)) return -1;

auto [res, veh_id, refit_capacity, refit_mail] = ::Command<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, depot, engine_id, true, cargo, INVALID_CLIENT_ID);
auto [res, veh_id, refit_capacity, refit_mail, cargo_capacities] = ::Command<CMD_BUILD_VEHICLE>::Do(DC_QUERY_COST, depot, engine_id, true, cargo, INVALID_CLIENT_ID);
return res.Succeeded() ? refit_capacity : -1;
}

Expand Down Expand Up @@ -143,7 +143,7 @@
if (!IsValidVehicle(vehicle_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo)) return -1;

auto [res, refit_capacity, refit_mail] = ::Command<CMD_REFIT_VEHICLE>::Do(DC_QUERY_COST, vehicle_id, cargo, 0, false, false, 0);
auto [res, refit_capacity, refit_mail, cargo_capacities] = ::Command<CMD_REFIT_VEHICLE>::Do(DC_QUERY_COST, vehicle_id, cargo, 0, false, false, 0);
return res.Succeeded() ? refit_capacity : -1;
}

Expand Down
2 changes: 1 addition & 1 deletion src/train_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ DEF_CMD_TRAIT(CMD_MOVE_RAIL_VEHICLE, CmdMoveRailVehicle, 0, CMDT_VEH
DEF_CMD_TRAIT(CMD_FORCE_TRAIN_PROCEED, CmdForceTrainProceed, 0, CMDT_VEHICLE_MANAGEMENT)
DEF_CMD_TRAIT(CMD_REVERSE_TRAIN_DIRECTION, CmdReverseTrainDirection, 0, CMDT_VEHICLE_MANAGEMENT)

void CcBuildWagon(Commands cmd, const CommandCost &result, VehicleID new_veh_id, uint, uint16, TileIndex tile, EngineID, bool, CargoID, ClientID);
void CcBuildWagon(Commands cmd, const CommandCost &result, VehicleID new_veh_id, uint, uint16, CargoArray, TileIndex tile, EngineID, bool, CargoID, ClientID);

#endif /* TRAIN_CMD_H */
2 changes: 1 addition & 1 deletion src/train_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* @param new_veh_id ID of the ne vehicle.
* @param tile The tile the command was executed on.
*/
void CcBuildWagon(Commands cmd, const CommandCost &result, VehicleID new_veh_id, uint, uint16, TileIndex tile, EngineID, bool, CargoID, ClientID)
void CcBuildWagon(Commands cmd, const CommandCost &result, VehicleID new_veh_id, uint, uint16, CargoArray, TileIndex tile, EngineID, bool, CargoID, ClientID)
{
if (result.Failed()) return;

Expand Down

0 comments on commit 167ad16

Please sign in to comment.