summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2009-12-14 19:17:18 +0000
committerrubidium <rubidium@openttd.org>2009-12-14 19:17:18 +0000
commita190ae9a71cd51d50c03be53d7695b8b85f2bdc0 (patch)
tree9839c6593863802f54fd6ce0d3cdd3201c94e317 /src
parent620ca5e6c18cc0929f255d5ced094f214c6df15a (diff)
downloadopenttd-a190ae9a71cd51d50c03be53d7695b8b85f2bdc0.tar.xz
(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.
Diffstat (limited to 'src')
-rw-r--r--src/vehicle_cmd.cpp6
-rw-r--r--src/vehicle_func.h1
-rw-r--r--src/vehicle_gui.cpp63
3 files changed, 68 insertions, 2 deletions
diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp
index e710b905d..f696d1153 100644
--- a/src/vehicle_cmd.cpp
+++ b/src/vehicle_cmd.cpp
@@ -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);
}
diff --git a/src/vehicle_func.h b/src/vehicle_func.h
index b709dba14..b37f8e56e 100644
--- a/src/vehicle_func.h
+++ b/src/vehicle_func.h
@@ -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);
diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp
index 614259e34..a9401784f 100644
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -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;