(svn r18498) -Fix [FS#2616]: cloning of vehicles could create vehicles with invalid cargo sub types for the build year of the vehicle. Fall back to another cargo sub type with the exact same name, otherwise fallback to cargo sub type 0.

pull/155/head
rubidium 15 years ago
parent 0cacd89042
commit 12732cf39d

@ -536,8 +536,10 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
if (flags & DC_EXEC) {
assert(w != NULL);
if (w->cargo_type != v->cargo_type || w->cargo_subtype != v->cargo_subtype) {
CommandCost cost = DoCommand(0, w->index, v->cargo_type | (v->cargo_subtype << 8) | 1U << 16, flags, GetCmdRefitVeh(v));
/* Find out what's the best sub type */
byte subtype = GetBestFittingSubType(v, w);
if (w->cargo_type != v->cargo_type || w->cargo_subtype != subtype) {
CommandCost cost = DoCommand(0, w->index, v->cargo_type | (subtype << 8) | 1U << 16, flags, GetCmdRefitVeh(v));
if (CmdSucceeded(cost)) total_cost.AddCost(cost);
}

@ -42,6 +42,7 @@ byte VehicleRandomBits();
void ResetVehiclePosHash();
void ResetVehicleColourMap();
byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for);
CommandCost RefitVehicle(Vehicle *v, bool only_this, CargoID new_cid, byte new_subtype, DoCommandFlag flags);
void ViewportAddVehicles(DrawPixelInfo *dpi);

@ -159,6 +159,69 @@ static void DrawVehicleProfitButton(const Vehicle *v, int x, int y)
/** Maximum number of refit cycles we try, to prevent infinite loops. */
static const int MAX_REFIT_CYCLE = 16;
/**
* Get the best fitting subtype when 'cloning'/'replacing' v_from with v_for.
* Assuming they are going to carry the same cargo ofcourse!
* @param v_from the vehicle to match the subtype from
* @param v_for the vehicle to get the subtype for
* @return the best sub type
*/
byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for)
{
const Engine *e_from = Engine::Get(v_from->engine_type);
const Engine *e_for = Engine::Get(v_for->engine_type);
/* If one them doesn't carry cargo, there's no need to find a sub type */
if (!e_from->CanCarryCargo() || !e_for->CanCarryCargo()) return 0;
if (!HasBit(e_from->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX) ||
!HasBit(e_for->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) {
/* One of the engines doesn't have cargo suffixes, i.e. sub types. */
return 0;
}
/* It has to be possible for v_for to carry the cargo of v_from. */
assert(HasBit(e_for->info.refit_mask, v_from->cargo_type));
StringID expected_string = GetCargoSubtypeText(v_from);
CargoID old_cargo_type = v_for->cargo_type;
byte old_cargo_subtype = v_for->cargo_subtype;
byte ret_refit_cyc = 0;
/* Set the 'destination' cargo */
v_for->cargo_type = v_from->cargo_type;
/* Cycle through the refits */
for (byte refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) {
v_for->cargo_subtype = refit_cyc;
/* Make sure we don't pick up anything cached. */
v_for->First()->InvalidateNewGRFCache();
v_for->InvalidateNewGRFCache();
uint16 callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, v_for->engine_type, v_for);
if (callback == 0xFF) callback = CALLBACK_FAILED;
if (callback == CALLBACK_FAILED) break;
if (GetCargoSubtypeText(v_for) != expected_string) continue;
/* We found something matching. */
ret_refit_cyc = refit_cyc;
break;
}
/* Reset the vehicle's cargo type */
v_for->cargo_type = old_cargo_type;
v_for->cargo_subtype = old_cargo_subtype;
/* Make sure we don't taint the vehicle. */
v_for->First()->InvalidateNewGRFCache();
v_for->InvalidateNewGRFCache();
return ret_refit_cyc;
}
struct RefitOption {
CargoID cargo;
byte subtype;

Loading…
Cancel
Save