changeset 18640:ce293485d2fe draft

(svn r23487) -Change/Fix: Make autoreplace, autorenew, cloning and autorefit check all articulated parts of a vehicle to find a shared cargo subtype.
author frosch <frosch@openttd.org>
date Sat, 10 Dec 2011 21:09:21 +0000
parents 14549b010f86
children 228730e55fb0
files src/autoreplace_cmd.cpp src/vehicle_cmd.cpp src/vehicle_func.h src/vehicle_gui.cpp
diffstat 4 files changed, 66 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/src/autoreplace_cmd.cpp
+++ b/src/autoreplace_cmd.cpp
@@ -182,15 +182,7 @@
 		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 @@
 
 		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 @@
 	*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);
 
-	if (refit_cargo != CT_NO_REFIT) {
 		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()
 	}
--- a/src/vehicle_cmd.cpp
+++ b/src/vehicle_cmd.cpp
@@ -842,7 +842,7 @@
 				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);
--- a/src/vehicle_func.h
+++ b/src/vehicle_func.h
@@ -47,7 +47,7 @@
 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);
 
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -210,71 +210,78 @@
 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();
-
-	/* 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;
+	v_from = v_from->GetFirstEnginePart();
+	v_for = v_for->GetFirstEnginePart();
+
+	/* Create a list of subtypes used by the various parts of v_for */
+	static SmallVector<StringID, 4> 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;
-
-	/* Set the 'destination' cargo */
-	v_for->cargo_type = dest_cargo_type;
-
-	/* Cycle through the refits */
-	for (uint 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 != 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;
+	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;
+
+			CargoID old_cargo_type = v->cargo_type;
+			byte old_cargo_subtype = v->cargo_subtype;
+
+			/* Set the 'destination' cargo */
+			v->cargo_type = dest_cargo_type;
+
+			/* Cycle through the refits */
+			for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) {
+				v->cargo_subtype = refit_cyc;
+
+				/* 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;
 }