Changeset - r28159:2f140179d2ed
[Not reviewed]
master
0 4 0
Jonathan G Rennison - 5 months ago 2023-11-20 13:16:28
j.g.rennison@gmail.com
Fix: Trivial autoreplace of mixed cargo articulated engines (#11253)

Do not fail autoreplace/autorenew of mixed cargo articulated engines
due to an inability to refit to mixed cargoes, when no refit is
required because the target engine already has a suitable set of cargoes.
Notably, this allows autorenew (autoreplace to same engine type)
to succeed.
4 files changed with 66 insertions and 15 deletions:
0 comments (0 inline, 0 general)
src/articulated_vehicles.cpp
Show inline comments
 
@@ -8,6 +8,7 @@
 
/** @file articulated_vehicles.cpp Implementation of articulated vehicles. */
 

	
 
#include "stdafx.h"
 
#include "core/bitmath_func.hpp"
 
#include "core/random_func.hpp"
 
#include "train.h"
 
#include "roadveh.h"
 
@@ -162,6 +163,35 @@ CargoArray GetCapacityOfArticulatedParts
 
}
 

	
 
/**
 
 * Get the cargo mask of the parts of a given engine.
 
 * @param engine The engine to get the capacities from.
 
 * @return The cargo mask.
 
 */
 
CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine)
 
{
 
	CargoTypes cargoes = 0;
 
	const Engine *e = Engine::Get(engine);
 

	
 
	CargoID cargo_type;
 
	uint16_t cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type);
 
	if (cargo_type < NUM_CARGO && cargo_capacity > 0) SetBit(cargoes, cargo_type);
 

	
 
	if (!e->IsGroundVehicle()) return cargoes;
 

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

	
 
	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) SetBit(cargoes, cargo_type);
 
	}
 

	
 
	return cargoes;
 
}
 

	
 
/**
 
 * Checks whether any of the articulated parts is refittable
 
 * @param engine the first part
 
 * @return true if refittable
 
@@ -226,22 +256,26 @@ CargoTypes GetUnionOfArticulatedRefitMas
 
}
 

	
 
/**
 
 * Tests if all parts of an articulated vehicle are refitted to the same cargo.
 
 * Get cargo mask of all cargoes carried by an articulated vehicle.
 
 * Note: Vehicles not carrying anything are ignored
 
 * @param v the first vehicle in the chain
 
 * @param cargo_type returns the common CargoID if needed. (CT_INVALID if no part is carrying something or they are carrying different things)
 
 * @return true if some parts are carrying different cargoes, false if all parts are carrying the same (nothing is also the same)
 
 * @return cargo mask, may be 0 if the no vehicle parts have cargo capacity
 
 */
 
bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *cargo_type)
 
CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoID *cargo_type)
 
{
 
	CargoTypes cargoes = 0;
 
	CargoID first_cargo = CT_INVALID;
 

	
 
	do {
 
		if (IsValidCargoID(v->cargo_type) && v->GetEngine()->CanCarryCargo()) {
 
			SetBit(cargoes, v->cargo_type);
 
			if (!IsValidCargoID(first_cargo)) first_cargo = v->cargo_type;
 
			if (first_cargo != v->cargo_type) {
 
				if (cargo_type != nullptr) *cargo_type = CT_INVALID;
 
				return true;
 
				if (cargo_type != nullptr) {
 
					*cargo_type = CT_INVALID;
 
					cargo_type = nullptr;
 
				}
 
			}
 
		}
 

	
 
@@ -249,7 +283,7 @@ bool IsArticulatedVehicleCarryingDiffere
 
	} while (v != nullptr);
 

	
 
	if (cargo_type != nullptr) *cargo_type = first_cargo;
 
	return false;
 
	return cargoes;
 
}
 

	
 
/**
src/articulated_vehicles.h
Show inline comments
 
@@ -15,10 +15,11 @@
 

	
 
uint CountArticulatedParts(EngineID engine_type, bool purchase_window);
 
CargoArray GetCapacityOfArticulatedParts(EngineID engine);
 
CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine);
 
void AddArticulatedParts(Vehicle *first);
 
void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, CargoTypes *union_mask, CargoTypes *intersection_mask);
 
CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type);
 
bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *cargo_type);
 
CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoID *cargo_type);
 
bool IsArticulatedVehicleRefittable(EngineID engine);
 
bool IsArticulatedEngine(EngineID engine_type);
 
void CheckConsistencyOfArticulatedVehicle(const Vehicle *v);
src/autoreplace_cmd.cpp
Show inline comments
 
@@ -16,6 +16,7 @@
 
#include "autoreplace_func.h"
 
#include "autoreplace_gui.h"
 
#include "articulated_vehicles.h"
 
#include "core/bitmath_func.hpp"
 
#include "core/random_func.hpp"
 
#include "vehiclelist.h"
 
#include "road.h"
 
@@ -236,7 +237,15 @@ static CargoID GetNewCargoTypeForReplace
 
	if (union_mask == 0) return CT_NO_REFIT; // Don't try to refit an engine with no cargo capacity
 

	
 
	CargoID cargo_type;
 
	if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) return CT_INVALID; // We cannot refit to mixed cargoes in an automated way
 
	CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type);
 
	if (!HasAtMostOneBit(cargo_mask)) {
 
		CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(engine_type);
 
		if ((cargo_mask & new_engine_default_cargoes) == cargo_mask) {
 
			return CT_NO_REFIT; // engine_type is already a mixed cargo type which matches the incoming vehicle by default, no refit required
 
		}
 

	
 
		return CT_INVALID; // We cannot refit to mixed cargoes in an automated way
 
	}
 

	
 
	if (!IsValidCargoID(cargo_type)) {
 
		if (v->type != VEH_TRAIN) return CT_NO_REFIT; // If the vehicle does not carry anything at all, every replacement is fine.
src/vehicle.cpp
Show inline comments
 
@@ -229,13 +229,20 @@ bool Vehicle::NeedsServicing() const
 
		/* Is there anything to refit? */
 
		if (union_mask != 0) {
 
			CargoID cargo_type;
 
			/* We cannot refit to mixed cargoes in an automated way */
 
			if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) continue;
 

	
 
			/* Did the old vehicle carry anything? */
 
			if (IsValidCargoID(cargo_type)) {
 
				/* We can't refit the vehicle to carry the cargo we want */
 
				if (!HasBit(available_cargo_types, cargo_type)) continue;
 
			CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type);
 
			if (!HasAtMostOneBit(cargo_mask)) {
 
				CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(new_engine);
 
				if ((cargo_mask & new_engine_default_cargoes) != cargo_mask) {
 
					/* We cannot refit to mixed cargoes in an automated way */
 
					continue;
 
				}
 
				/* engine_type is already a mixed cargo type which matches the incoming vehicle by default, no refit required */
 
			} else {
 
				/* Did the old vehicle carry anything? */
 
				if (IsValidCargoID(cargo_type)) {
 
					/* We can't refit the vehicle to carry the cargo we want */
 
					if (!HasBit(available_cargo_types, cargo_type)) continue;
 
				}
 
			}
 
		}
 

	
0 comments (0 inline, 0 general)