(svn r2423) - CodeChange: Include first_engine in the train cache, instead of calculating it all over the place.
authorhackykid
Mon, 06 Jun 2005 14:26:15 +0000
changeset 1917 74cab7e464d1
parent 1916 efad85af0599
child 1918 68d78ef6833d
(svn r2423) - CodeChange: Include first_engine in the train cache, instead of calculating it all over the place.
- Fix: Also recalculate the train cache values for 'wagon chains' (in the depot without an engine), to avoid possible desyncs later.
- Fix: Make CmdMoveRailVehicle update the caches of the correct trains in all cases.
train_cmd.c
vehicle.c
--- a/train_cmd.c	Mon Jun 06 14:11:15 2005 +0000
+++ b/train_cmd.c	Mon Jun 06 14:26:15 2005 +0000
@@ -60,19 +60,31 @@
 }
 
 /**
- * Recalculates the cached stuff of a train. Should be called each time a vehicle is added to/removed from
- * the consist, and when the game is loaded.
- * @param v First vehicle of the consist.
+ * Recalculates the cached stuff of a train. Should be called each time a vehicle is added
+ * to/removed from the chain, and when the game is loaded.
+ * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine)
+ * @param v First vehicle of the chain.
  */
 void TrainConsistChanged(Vehicle *v) {
-	const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type);
+	const RailVehicleInfo *rvi_v;
 	Vehicle *u;
 	uint16 max_speed = 0xFFFF;
 	uint32 power = 0;
+	EngineID first_engine;
+
+	assert(v->type == VEH_Train);
+
+	assert(v->subtype == TS_Front_Engine || v->subtype == TS_Free_Car);
+
+	rvi_v = RailVehInfo(v->engine_type);
+	first_engine = (v->subtype == TS_Front_Engine) ? v->engine_type : INVALID_VEHICLE;
 
 	for (u = v; u != NULL; u = u->next) {
 		const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
 
+		// update the 'first engine'
+		u->u.rail.first_engine = (v == u) ? INVALID_VEHICLE : first_engine;
+
 		// power is the sum of the powers of all engines and powered wagons in the consist
 		power += rvi_u->power;
 
@@ -449,11 +461,6 @@
 			if (u != NULL) {
 				u->next = v;
 				v->subtype = TS_Not_First;
-				v->u.rail.first_engine = u->u.rail.first_engine;
-				if (v->u.rail.first_engine == 0xffff && u->subtype == TS_Front_Engine)
-					v->u.rail.first_engine = u->engine_type;
-			} else {
-				v->u.rail.first_engine = 0xffff;
 			}
 
 			v->cargo_type = rvi->cargo_type;
@@ -471,6 +478,7 @@
 			_new_wagon_id = v->index;
 
 			VehiclePositionChanged(v);
+			TrainConsistChanged(GetFirstVehicleInChain(v));
 
 			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 		}
@@ -547,7 +555,6 @@
 	u->z_pos = v->z_pos;
 	u->z_height = 6;
 	u->u.rail.track = 0x80;
-	v->u.rail.first_engine = 0xffff;
 	u->vehstatus = v->vehstatus & ~VS_STOPPED;
 	u->subtype = TS_Not_First;
 	u->spritenum = v->spritenum + 1;
@@ -620,7 +627,6 @@
 			v->z_pos = GetSlopeZ(x,y);
 			v->z_height = 6;
 			v->u.rail.track = 0x80;
-			v->u.rail.first_engine = 0xffff;
 			v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
 			v->spritenum = rvi->image_index;
 			v->cargo_type = rvi->cargo_type;
@@ -705,14 +711,11 @@
 {
 	Vehicle *u;
 
-	v->u.rail.first_engine = INVALID_VEHICLE;
-
 	// unlinking the first vehicle of the chain?
 	if (v == first) {
 		v = v->next;
 		if (v == NULL) return NULL;
 
-		for (u = v; u != NULL; u = u->next) u->u.rail.first_engine = v->engine_type;
 		v->subtype = TS_Free_Car;
 		return v;
 	}
@@ -838,10 +841,12 @@
 				Vehicle *v = src_head;
 				while (v->next != src) v=v->next;
 				v->next = NULL;
+			} else {
+				src_head = NULL;
 			}
 		} else {
 			// unlink single wagon from linked list
-			UnlinkWagon(src, src_head);
+			src_head = UnlinkWagon(src, src_head);
 			src->next = NULL;
 		}
 
@@ -854,11 +859,10 @@
 					assert(src->orders == NULL);
 					src->num_orders = 0;
 				}
-				dst_head = src;
 			} else {
 				src->subtype = TS_Free_Car;
 			}
-			src->u.rail.first_engine = 0xffff;
+			dst_head = src;
 		} else {
 			if (src->subtype == TS_Front_Engine) {
 				// the vehicle was previously a loco. need to free the order list and delete vehicle windows etc.
@@ -869,44 +873,42 @@
 			src->subtype = TS_Not_First;
 			src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
 
-			// setup first_engine
-			src->u.rail.first_engine = dst->u.rail.first_engine;
-			if (src->u.rail.first_engine == 0xffff && dst->subtype == TS_Front_Engine)
-				src->u.rail.first_engine = dst->engine_type;
-
 			// link in the wagon(s) in the chain.
 			{
 				Vehicle *v;
 
-				for (v = src; v->next != NULL; v = v->next) {
-					v->next->u.rail.first_engine = v->u.rail.first_engine;
-				}
+				for (v = src; v->next != NULL; v = v->next) {};
 				v->next = dst->next;
 			}
 			dst->next = src;
 		}
 
-		if (src_head->subtype == TS_Front_Engine) {
+		if (src_head) {
 			TrainConsistChanged(src_head);
-			UpdateTrainAcceleration(src_head);
-		}
-		InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index);
-		InvalidateWindow(WC_VEHICLE_REFIT, src_head->index);
+			if (src_head->subtype == TS_Front_Engine) {
+				UpdateTrainAcceleration(src_head);
+				InvalidateWindow(WC_VEHICLE_DETAILS, src_head->index);
+				/* Update the refit button and window */
+				InvalidateWindow(WC_VEHICLE_REFIT, src_head->index);
+				InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, 12);
+			}
+			/* Update the depot window */
+			InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile);
+		};
 
 		if (dst_head) {
+			TrainConsistChanged(dst_head);
 			if (dst_head->subtype == TS_Front_Engine) {
-				TrainConsistChanged(dst_head);
 				UpdateTrainAcceleration(dst_head);
+				InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index);
+				/* Update the refit button and window */
+				InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, 12);
+				InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index);
 			}
-			InvalidateWindow(WC_VEHICLE_DETAILS, dst_head->index);
-			/* Update the refit button and window */
-			InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, 12);
-			InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index);
+			/* Update the depot window */
+			InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile);
 		}
 
-		/* I added this to so that the refit buttons get updated */
-		InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, 12);
-		InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile);
 		RebuildVehicleLists();
 	}
 
@@ -1048,11 +1050,13 @@
 				if (switch_engine) first->subtype = TS_Front_Engine;
 
 				/* 5. If the train still exists, update its acceleration, window, etc. */
-				if (first != NULL && first->subtype == TS_Front_Engine) {
-					InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
-					InvalidateWindow(WC_VEHICLE_REFIT, first->index);
+				if (first != NULL) {
 					TrainConsistChanged(first);
-					UpdateTrainAcceleration(first);
+					if (first->subtype == TS_Front_Engine) {
+						InvalidateWindow(WC_VEHICLE_DETAILS, first->index);
+						InvalidateWindow(WC_VEHICLE_REFIT, first->index);
+						UpdateTrainAcceleration(first);
+					}
 				}
 
 
@@ -1103,9 +1107,10 @@
 			}
 
 			/* 3. If it is still a valid train after selling, update its acceleration and cached values */
-			if ((flags & DC_EXEC) && first != NULL && first->subtype == TS_Front_Engine) {
+			if ((flags & DC_EXEC) && first != NULL) {
 				TrainConsistChanged(first);
-				UpdateTrainAcceleration(first);
+				if (first->subtype == TS_Front_Engine)
+					UpdateTrainAcceleration(first);
 			}
 		} break;
 	}
--- a/vehicle.c	Mon Jun 06 14:11:15 2005 +0000
+++ b/vehicle.c	Mon Jun 06 14:26:15 2005 +0000
@@ -188,7 +188,7 @@
 			v->left_coord = INVALID_COORD;
 			VehiclePositionChanged(v);
 
-			if (v->type == VEH_Train && v->subtype == TS_Front_Engine)
+			if (v->type == VEH_Train && (v->subtype == TS_Front_Engine || v->subtype == TS_Free_Car))
 				TrainConsistChanged(v);
 		}
 	}
@@ -1392,12 +1392,12 @@
 		if ( old_engine_type != new_engine_type ) {
 
 			// prevent that the rear engine can get replaced to something else than the front engine
-			if ( v->u.rail.first_engine != 0xffff && RailVehInfo(old_engine_type)->flags & RVI_MULTIHEAD && RailVehInfo(old_engine_type)->flags ) {
+			if ( v->u.rail.first_engine != INVALID_VEHICLE && RailVehInfo(old_engine_type)->flags & RVI_MULTIHEAD && RailVehInfo(old_engine_type)->flags ) {
 				if ( first->engine_type != new_engine_type ) return CMD_ERROR;
 			}
 
 			// checks if the engine is the first one
-			if ( v->u.rail.first_engine == 0xffff ) {
+			if ( v->u.rail.first_engine == INVALID_VEHICLE ) {
 				if ( RailVehInfo(new_engine_type)->flags & RVI_MULTIHEAD ) {
 					if ( u->engine_type == old_engine_type && v->next != NULL) {
 						rear_engine_cost = build_cost - u->value;
@@ -1471,7 +1471,7 @@
 				v->spritenum = rvi->image_index + (( rvi->flags & RVI_MULTIHEAD && sprite - rvi2->image_index) ? 1 : 0);
 
 				// turn the last engine in a multiheaded train if needed
-				if ( v->next == NULL && v->u.rail.first_engine != 0xffff && rvi->flags & RVI_MULTIHEAD && v->spritenum == rvi->image_index )
+				if ( v->next == NULL && v->u.rail.first_engine != INVALID_VEHICLE && rvi->flags & RVI_MULTIHEAD && v->spritenum == rvi->image_index )
 					v->spritenum++;
 
 				v->cargo_type = rvi->cargo_type;
@@ -1517,14 +1517,8 @@
 				}
 #endif
 
-				// updates the id of the front engine in the other units, since the front engine just got a new engine_id
-				// this is needed for wagon override
-				if ( v->u.rail.first_engine == 0xffff && v->next != NULL ) {
-					Vehicle *veh = v->next;
-					do {
-						veh->u.rail.first_engine = new_engine_type;
-					} while ( (veh=veh->next) != NULL );
-				}
+				// recalculate changed train values
+				TrainConsistChanged(first);
 				InvalidateWindowClasses(WC_TRAINS_LIST);
 				UpdateTrainAcceleration(first);
 				break;
@@ -2089,9 +2083,6 @@
 		v = GetVehicle(index);
 		SlObject(v, _veh_descs[SlReadByte()]);
 
-		if (v->type == VEH_Train)
-			v->u.rail.first_engine = 0xffff;
-
 		/* Old savegames used 'last_station_visited = 0xFF', should be 0xFFFF */
 		if (_sl.version < 5 && v->last_station_visited == 0xFF)
 			v->last_station_visited = 0xFFFF;
@@ -2104,17 +2095,6 @@
 		}
 	}
 
-	// Iterate through trains and set first_engine appropriately.
-	FOR_ALL_VEHICLES(v) {
-		Vehicle *w;
-
-		if (v->type != VEH_Train || v->subtype != TS_Front_Engine)
-			continue;
-
-		for (w = v->next; w; w = w->next)
-			w->u.rail.first_engine = v->engine_type;
-	}
-
 	/* Check for shared order-lists (we now use pointers for that) */
 	if (_sl.full_version < 0x502) {
 		FOR_ALL_VEHICLES(v) {