changeset 18834:573054818505 draft

(svn r23683) -Fix [FS#4912]-ish: when fitting another engine the cargo capacity of wagons could become lower, causing them to contain more than they should. This caused the cargo transfer from the replaced parts to put even more stuff in the already full wagon. Prevent this from happening by reducing the amount of cargo in the vehicle to the capacity when moving vehicles/wagons around, or when autoreplacing
author rubidium <rubidium@openttd.org>
date Wed, 28 Dec 2011 19:48:04 +0000
parents da4cf42b7840
children 2ad295ac58b9
files src/autoreplace_cmd.cpp src/command_type.h src/train_cmd.cpp src/vehicle_func.h
diffstat 4 files changed, 41 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/autoreplace_cmd.cpp
+++ b/src/autoreplace_cmd.cpp
@@ -90,6 +90,33 @@
 }
 
 /**
+ * Check the capacity of all vehicles in a chain and spread cargo if needed.
+ * @param v The vehicle to check.
+ */
+void CheckCargoCapacity(Vehicle *v)
+{
+	assert(v == NULL || v->First() == v);
+
+	for (Vehicle *src = v; src != NULL; src = src->Next()) {
+		/* Do we need to more cargo away? */
+		if (src->cargo.Count() <= src->cargo_cap) continue;
+
+		/* We need to move a particular amount. Try that on the other vehicles. */
+		uint to_spread = src->cargo.Count() - src->cargo_cap;
+		for (Vehicle *dest = v; dest != NULL && to_spread != 0; dest = dest->Next()) {
+			if (dest->cargo.Count() >= dest->cargo_cap || dest->cargo_type != src->cargo_type) continue;
+
+			uint amount = min(to_spread, dest->cargo_cap - dest->cargo.Count());
+			src->cargo.MoveTo(&dest->cargo, amount, VehicleCargoList::MTA_UNLOAD, NULL);
+			to_spread -= amount;
+		}
+
+		/* Any left-overs will be thrown away, but not their feeder share. */
+		src->cargo.Truncate(src->cargo_cap);
+	}
+}
+
+/**
  * Transfer cargo from a single (articulated )old vehicle to the new vehicle chain
  * @param old_veh Old vehicle that will be sold
  * @param new_head Head of the completely constructed new vehicle chain
@@ -297,7 +324,7 @@
  */
 static inline CommandCost CmdMoveVehicle(const Vehicle *v, const Vehicle *after, DoCommandFlag flags, bool whole_chain)
 {
-	return DoCommand(0, v->index | (whole_chain ? 1 : 0) << 20, after != NULL ? after->index : INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE);
+	return DoCommand(0, v->index | (whole_chain ? 1 : 0) << 20, after != NULL ? after->index : INVALID_VEHICLE, flags | DC_NO_CARGO_CAP_CHECK, CMD_MOVE_RAIL_VEHICLE);
 }
 
 /**
@@ -551,6 +578,8 @@
 						if (i == 0) old_head = NULL;
 					}
 				}
+
+				if ((flags & DC_EXEC) != 0) CheckCargoCapacity(new_head);
 			}
 
 			/* If we are not in DC_EXEC undo everything, i.e. rearrange old vehicles.
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -318,9 +318,10 @@
 	DC_NO_TEST_TOWN_RATING   = 0x020, ///< town rating does not disallow you from building
 	DC_BANKRUPT              = 0x040, ///< company bankrupts, skip money check, skip vehicle on tile check in some cases
 	DC_AUTOREPLACE           = 0x080, ///< autoreplace/autorenew is in progress, this shall disable vehicle limits when building, and ignore certain restrictions when undoing things (like vehicle attach callback)
-	DC_ALL_TILES             = 0x100, ///< allow this command also on MP_VOID tiles
-	DC_NO_MODIFY_TOWN_RATING = 0x200, ///< do not change town rating
-	DC_FORCE_CLEAR_TILE      = 0x400, ///< do not only remove the object on the tile, but also clear any water left on it
+	DC_NO_CARGO_CAP_CHECK    = 0x100, ///< when autoreplace/autorenew is in progress, this shall prevent truncating the amount of cargo in the vehicle to prevent testing the command to remove cargo
+	DC_ALL_TILES             = 0x200, ///< allow this command also on MP_VOID tiles
+	DC_NO_MODIFY_TOWN_RATING = 0x400, ///< do not change town rating
+	DC_FORCE_CLEAR_TILE      = 0x800, ///< do not only remove the object on the tile, but also clear any water left on it
 };
 DECLARE_ENUM_AS_BIT_SET(DoCommandFlag)
 
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -1281,6 +1281,11 @@
 		NormaliseTrainHead(src_head);
 		NormaliseTrainHead(dst_head);
 
+		if ((flags & DC_NO_CARGO_CAP_CHECK) == 0) {
+			CheckCargoCapacity(src_head);
+			CheckCargoCapacity(dst_head);
+		}
+
 		/* We are undoubtedly changing something in the depot and train list. */
 		InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
 		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
--- a/src/vehicle_func.h
+++ b/src/vehicle_func.h
@@ -173,4 +173,6 @@
 typedef SmallVector<VehicleID, 2> VehicleSet;
 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles);
 
+void CheckCargoCapacity(Vehicle *v);
+
 #endif /* VEHICLE_FUNC_H */