From 2fe8e89a45c90a1bced09e8fbcfc7e5b526d54ed Mon Sep 17 00:00:00 2001 From: frosch Date: Sat, 10 Dec 2011 21:09:21 +0000 Subject: [PATCH] (svn r23487) -Change/Fix: Make autoreplace, autorenew, cloning and autorefit check all articulated parts of a vehicle to find a shared cargo subtype. --- src/autoreplace_cmd.cpp | 25 ++-------- src/vehicle_cmd.cpp | 2 +- src/vehicle_func.h | 2 +- src/vehicle_gui.cpp | 103 +++++++++++++++++++++------------------- 4 files changed, 61 insertions(+), 71 deletions(-) diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 39e294f6cf..593a5c49c7 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -182,15 +182,7 @@ static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, bool for (v = v->First(); v != NULL; v = v->Next()) { if (v->cargo_cap == 0) continue; /* Now we found a cargo type being carried on the train and we will see if it is possible to carry to this one */ - if (HasBit(available_cargo_types, v->cargo_type)) { - /* Do we have to refit the vehicle, or is it already carrying the right cargo? */ - CargoArray default_capacity = GetCapacityOfArticulatedParts(engine_type); - for (CargoID cid = 0; cid < NUM_CARGO; cid++) { - if (cid != v->cargo_type && default_capacity[cid] > 0) return v->cargo_type; - } - - return CT_NO_REFIT; - } + if (HasBit(available_cargo_types, v->cargo_type)) return v->cargo_type; } return CT_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one @@ -199,13 +191,7 @@ static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, bool if (part_of_chain && !VerifyAutoreplaceRefitForOrders(v, engine_type)) return CT_INVALID; // Some refit orders lose their effect - /* Do we have to refit the vehicle, or is it already carrying the right cargo? */ - CargoArray default_capacity = GetCapacityOfArticulatedParts(engine_type); - for (CargoID cid = 0; cid < NUM_CARGO; cid++) { - if (cid != cargo_type && default_capacity[cid] > 0) return cargo_type; - } - - return CT_NO_REFIT; + return cargo_type; } } @@ -275,12 +261,9 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic *new_vehicle = new_veh; /* Refit the vehicle if needed */ - byte subtype = GetBestFittingSubType(old_veh, new_veh); - /* If the subtype isn't zero and the refit cargo is not set, - * we're better off setting the refit cargo too. */ - if (subtype != 0 && refit_cargo == CT_NO_REFIT) refit_cargo = old_veh->cargo_type; - if (refit_cargo != CT_NO_REFIT) { + byte subtype = GetBestFittingSubType(old_veh, new_veh, refit_cargo); + cost.AddCost(DoCommand(0, new_veh->index, refit_cargo | (subtype << 8), DC_EXEC, GetCmdRefitVeh(new_veh))); assert(cost.Succeeded()); // This should be ensured by GetNewCargoTypeForReplace() } diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 4293e5f754..146b816598 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -842,7 +842,7 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint assert(w != NULL); /* Find out what's the best sub type */ - byte subtype = GetBestFittingSubType(v, w); + byte subtype = GetBestFittingSubType(v, w, v->cargo_type); if (w->cargo_type != v->cargo_type || w->cargo_subtype != subtype) { CommandCost cost = DoCommand(0, w->index, v->cargo_type | 1U << 7 | (subtype << 8), flags, GetCmdRefitVeh(v)); if (cost.Succeeded()) total_cost.AddCost(cost); diff --git a/src/vehicle_func.h b/src/vehicle_func.h index b8caaf2983..a41f3c4665 100644 --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -47,7 +47,7 @@ byte VehicleRandomBits(); void ResetVehiclePosHash(); void ResetVehicleColourMap(); -byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type = INVALID_CARGO); +byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type); void ViewportAddVehicles(DrawPixelInfo *dpi); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index ecd47a722b..c8918ce755 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -210,71 +210,78 @@ static void DrawVehicleProfitButton(const Vehicle *v, int x, int y) static const uint MAX_REFIT_CYCLE = 256; /** - * Get the best fitting subtype when 'cloning'/'replacing' v_from with v_for. - * Assuming they are going to carry the same cargo ofcourse! + * Get the best fitting subtype when 'cloning'/'replacing' \a v_from with \a v_for. + * All articulated parts of both vehicles are tested to find a possibly shared subtype. + * For \a v_for only vehicle refittable to \a dest_cargo_type are considered. * @param v_from the vehicle to match the subtype from * @param v_for the vehicle to get the subtype for - * @param dest_cargo_type Destination cargo type, taken from #v_from if set to #INVALID_CARGO. + * @param dest_cargo_type Destination cargo type. * @return the best sub type */ byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type) { - const Engine *e_from = v_from->GetEngine(); - const Engine *e_for = v_for->GetEngine(); + v_from = v_from->GetFirstEnginePart(); + v_for = v_for->GetFirstEnginePart(); - /* 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; + /* Create a list of subtypes used by the various parts of v_for */ + static SmallVector subtypes; + subtypes.Clear(); + for (; v_from != NULL; v_from = v_from->HasArticulatedPart() ? v_from->GetNextArticulatedPart() : NULL) { + const Engine *e_from = v_from->GetEngine(); + if (!e_from->CanCarryCargo() || !HasBit(e_from->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; + subtypes.Include(GetCargoSubtypeText(v_from)); } - if (dest_cargo_type == INVALID_CARGO) dest_cargo_type = v_from->cargo_type; - - /* It has to be possible for v_for to carry the cargo of v_from. */ - if (!HasBit(e_for->info.refit_mask, dest_cargo_type)) return 0; - - 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; + bool success = false; + if (subtypes.Length() > 0) { + /* Check whether any articulated part is refittable to 'dest_cargo_type' with a subtype listed in 'subtypes' */ + for (Vehicle *v = v_for; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) { + const Engine *e = v->GetEngine(); + if (!e->CanCarryCargo() || !HasBit(e->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; + if (!HasBit(e->info.refit_mask, dest_cargo_type) && v->cargo_type != dest_cargo_type) continue; - /* Set the 'destination' cargo */ - v_for->cargo_type = dest_cargo_type; + CargoID old_cargo_type = v->cargo_type; + byte old_cargo_subtype = v->cargo_subtype; - /* Cycle through the refits */ - for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) { - v_for->cargo_subtype = refit_cyc; + /* Set the 'destination' cargo */ + v->cargo_type = dest_cargo_type; - /* 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); + /* Cycle through the refits */ + for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) { + v->cargo_subtype = refit_cyc; - if (callback != CALLBACK_FAILED) { - if (callback > 0x400) ErrorUnknownCallbackResult(v_for->GetGRFID(), CBID_VEHICLE_CARGO_SUFFIX, callback); - if (callback >= 0x400 || (v_for->GetGRF()->grf_version < 8 && callback == 0xFF)) callback = CALLBACK_FAILED; + /* Make sure we don't pick up anything cached. */ + v->First()->InvalidateNewGRFCache(); + v->InvalidateNewGRFCache(); + uint16 callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, v->engine_type, v); + + if (callback != CALLBACK_FAILED) { + if (callback > 0x400) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_CARGO_SUFFIX, callback); + if (callback >= 0x400 || (v->GetGRF()->grf_version < 8 && callback == 0xFF)) callback = CALLBACK_FAILED; + } + if (callback == CALLBACK_FAILED) break; + + if (!subtypes.Contains(GetCargoSubtypeText(v))) continue; + + /* We found something matching. */ + ret_refit_cyc = refit_cyc; + success = true; + break; + } + + /* Reset the vehicle's cargo type */ + v->cargo_type = old_cargo_type; + v->cargo_subtype = old_cargo_subtype; + + /* Make sure we don't taint the vehicle. */ + v->First()->InvalidateNewGRFCache(); + v->InvalidateNewGRFCache(); + + if (success) break; } - 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; }