(svn r14096) -Codechange: merge the shared order's vehicle list management to a single location.
authorrubidium
Sun, 17 Aug 2008 19:56:17 +0000
changeset 9941 8549448b55fa
parent 9940 a3a283320355
child 9942 c3677fa5563f
(svn r14096) -Codechange: merge the shared order's vehicle list management to a single location.
src/group_cmd.cpp
src/oldloader.cpp
src/openttd.cpp
src/order_cmd.cpp
src/timetable_cmd.cpp
src/train_cmd.cpp
src/vehicle.cpp
src/vehicle_base.h
src/vehiclelist.cpp
--- a/src/group_cmd.cpp	Sun Aug 17 18:48:18 2008 +0000
+++ b/src/group_cmd.cpp	Sun Aug 17 19:56:17 2008 +0000
@@ -263,7 +263,7 @@
 				if (v->group_id != id_g) continue;
 
 				/* For each shared vehicles add it to the group */
-				for (Vehicle *v2 = GetFirstVehicleFromSharedList(v); v2 != NULL; v2 = v2->next_shared) {
+				for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
 					if (v2->group_id != id_g) CmdAddVehicleGroup(tile, flags, id_g, v2->index);
 				}
 			}
--- a/src/oldloader.cpp	Sun Aug 17 18:48:18 2008 +0000
+++ b/src/oldloader.cpp	Sun Aug 17 19:56:17 2008 +0000
@@ -372,8 +372,7 @@
 			/* If a vehicle has the same orders, add the link to eachother
 			 * in both vehicles */
 			if (v->orders == u->orders) {
-				v->next_shared = u;
-				u->prev_shared = v;
+				u->AddToShared(v);
 				break;
 			}
 		}
--- a/src/openttd.cpp	Sun Aug 17 18:48:18 2008 +0000
+++ b/src/openttd.cpp	Sun Aug 17 19:56:17 2008 +0000
@@ -2272,7 +2272,7 @@
 			if (v->orders != NULL && !v->orders->IsValid()) v->orders = NULL;
 
 			v->current_order.ConvertFromOldSavegame();
-			if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->prev_shared == NULL) {
+			if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->FirstShared() == v) {
 				FOR_VEHICLE_ORDERS(v, order) order->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
 			}
 		}
--- a/src/order_cmd.cpp	Sun Aug 17 18:48:18 2008 +0000
+++ b/src/order_cmd.cpp	Sun Aug 17 19:56:17 2008 +0000
@@ -506,7 +506,6 @@
 	}
 
 	if (flags & DC_EXEC) {
-		Vehicle *u;
 		Order *new_o = new Order();
 		new_o->AssignOrder(new_order);
 
@@ -537,9 +536,9 @@
 			}
 		}
 
-		u = GetFirstVehicleFromSharedList(v);
+		Vehicle *u = v->FirstShared();
 		DeleteOrderWarnings(u);
-		for (; u != NULL; u = u->next_shared) {
+		for (; u != NULL; u = u->NextShared()) {
 			/* Increase amount of orders */
 			u->num_orders++;
 
@@ -601,7 +600,7 @@
  * Remove the VehicleList that shows all the vehicles with the same shared
  *  orders.
  */
-static void RemoveSharedOrderVehicleList(Vehicle *v)
+void RemoveSharedOrderVehicleList(Vehicle *v)
 {
 	assert(v->orders != NULL);
 	WindowClass window_class = WC_NONE;
@@ -624,7 +623,7 @@
  */
 CommandCost CmdDeleteOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	Vehicle *v, *u;
+	Vehicle *v;
 	VehicleID veh_id = p1;
 	VehicleOrderID sel_ord = p2;
 	Order *order;
@@ -665,9 +664,9 @@
 		/* Give the item free */
 		order->Free();
 
-		u = GetFirstVehicleFromSharedList(v);
+		Vehicle *u = v->FirstShared();
 		DeleteOrderWarnings(u);
-		for (; u != NULL; u = u->next_shared) {
+		for (; u != NULL; u = u->NextShared()) {
 			u->num_orders--;
 
 			if (sel_ord < u->cur_order_index)
@@ -803,11 +802,11 @@
 		}
 
 		/* Update shared list */
-		Vehicle *u = GetFirstVehicleFromSharedList(v);
+		Vehicle *u = v->FirstShared();
 
 		DeleteOrderWarnings(u);
 
-		for (; u != NULL; u = u->next_shared) {
+		for (; u != NULL; u = u->NextShared()) {
 			/* Update the first order */
 			if (u->orders != v->orders) u->orders = v->orders;
 
@@ -1027,9 +1026,9 @@
 		}
 
 		/* Update the windows and full load flags, also for vehicles that share the same order list */
-		Vehicle *u = GetFirstVehicleFromSharedList(v);
+		Vehicle *u = v->FirstShared();
 		DeleteOrderWarnings(u);
-		for (; u != NULL; u = u->next_shared) {
+		for (; u != NULL; u = u->NextShared()) {
 			/* Toggle u->current_order "Full load" flag if it changed.
 			 * However, as the same flag is used for depot orders, check
 			 * whether we are not going to a depot as there are three
@@ -1090,13 +1089,7 @@
 			}
 
 			/* Is the vehicle already in the shared list? */
-			{
-				const Vehicle* u;
-
-				for (u = GetFirstVehicleFromSharedList(src); u != NULL; u = u->next_shared) {
-					if (u == dst) return CMD_ERROR;
-				}
-			}
+			if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
 
 			if (flags & DC_EXEC) {
 				/* If the destination vehicle had a OrderList, destroy it */
@@ -1106,10 +1099,7 @@
 				dst->num_orders = src->num_orders;
 
 				/* Link this vehicle in the shared-list */
-				dst->next_shared = src->next_shared;
-				dst->prev_shared = src;
-				if (src->next_shared != NULL) src->next_shared->prev_shared = dst;
-				src->next_shared = dst;
+				dst->AddToShared(src);
 
 				InvalidateVehicleOrder(dst);
 				InvalidateVehicleOrder(src);
@@ -1212,12 +1202,9 @@
 	if (order == NULL) return CMD_ERROR;
 
 	if (flags & DC_EXEC) {
-		Vehicle *u;
-
 		order->SetRefit(cargo, subtype);
 
-		u = GetFirstVehicleFromSharedList(v);
-		for (; u != NULL; u = u->next_shared) {
+		for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
 			/* Update any possible open window of the vehicle */
 			InvalidateVehicleOrder(u);
 
@@ -1253,7 +1240,7 @@
 
 	/* If we have shared orders, store it on a special way */
 	if (v->IsOrderListShared()) {
-		const Vehicle *u = (v->next_shared) ? v->next_shared : v->prev_shared;
+		const Vehicle *u = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
 
 		bak->clone = u->index;
 	} else {
@@ -1413,7 +1400,7 @@
 		return;
 
 	/* do nothing we we're not the first vehicle in a share-chain */
-	if (v->next_shared != NULL) return;
+	if (v->FirstShared() != v) return;
 
 	/* Only check every 20 days, so that we don't flood the message log */
 	if (v->owner == _local_player && v->day_counter % 20 == 0) {
@@ -1541,49 +1528,16 @@
 {
 	DeleteOrderWarnings(v);
 
-	/* If we have a shared order-list, don't delete the list, but just
-	    remove our pointer */
 	if (v->IsOrderListShared()) {
-		Vehicle *u = v;
-
-		v->orders = NULL;
-		v->num_orders = 0;
-
-		/* Unlink ourself */
-		if (v->prev_shared != NULL) {
-			v->prev_shared->next_shared = v->next_shared;
-			u = v->prev_shared;
-		}
-		if (v->next_shared != NULL) {
-			v->next_shared->prev_shared = v->prev_shared;
-			u = v->next_shared;
-		}
-		v->prev_shared = NULL;
-		v->next_shared = NULL;
-
-		/* If we are the only one left in the Shared Order Vehicle List,
-		 *  remove it, as we are no longer a Shared Order Vehicle */
-		if (u->prev_shared == NULL && u->next_shared == NULL && u->orders != NULL) RemoveSharedOrderVehicleList(u);
-
-		/* We only need to update this-one, because if there is a third
-		 *  vehicle which shares the same order-list, nothing will change. If
-		 *  this is the last vehicle, the last line of the order-window
-		 *  will change from Shared order list, to Order list, so it needs
-		 *  an update */
-		InvalidateVehicleOrder(u);
-		return;
+		/* Remove ourself from the shared order list. */
+		v->RemoveFromShared();
+	} else if (v->orders != NULL) {
+		/* Remove the orders */
+		v->orders->FreeChain();
 	}
 
-	/* Remove the orders */
-	Order *cur = v->orders;
-	/* Delete the vehicle list of shared orders, if any */
-	if (cur != NULL) RemoveSharedOrderVehicleList(v);
 	v->orders = NULL;
 	v->num_orders = 0;
-
-	if (cur != NULL) {
-		cur->FreeChain(); // Free the orders.
-	}
 }
 
 Date GetServiceIntervalClamped(uint index)
--- a/src/timetable_cmd.cpp	Sun Aug 17 18:48:18 2008 +0000
+++ b/src/timetable_cmd.cpp	Sun Aug 17 19:56:17 2008 +0000
@@ -32,7 +32,7 @@
 		}
 	}
 
-	for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
+	for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
 		InvalidateWindow(WC_VEHICLE_TIMETABLE, v->index);
 	}
 }
@@ -165,7 +165,7 @@
 		}
 	}
 
-	for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
+	for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
 		InvalidateWindow(WC_VEHICLE_TIMETABLE, v->index);
 	}
 
@@ -215,7 +215,7 @@
 
 	v->lateness_counter -= (timetabled - time_taken);
 
-	for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
+	for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
 		InvalidateWindow(WC_VEHICLE_TIMETABLE, v->index);
 	}
 }
--- a/src/train_cmd.cpp	Sun Aug 17 18:48:18 2008 +0000
+++ b/src/train_cmd.cpp	Sun Aug 17 19:56:17 2008 +0000
@@ -1427,27 +1427,13 @@
 					new_f->cur_order_index = first->cur_order_index;
 					new_f->orders          = first->orders;
 					new_f->num_orders      = first->num_orders;
+
+					/* Make sure the group counts stay correct. */
 					new_f->group_id        = first->group_id;
-
-					if (first->prev_shared != NULL) {
-						first->prev_shared->next_shared = new_f;
-						new_f->prev_shared = first->prev_shared;
-					}
-
-					if (first->next_shared != NULL) {
-						first->next_shared->prev_shared = new_f;
-						new_f->next_shared = first->next_shared;
-					}
-
-					/*
-					 * Remove all order information from the front train, to
-					 * prevent the order and the shared order list to be
-					 * destroyed by Destroy/DeleteVehicle.
-					 */
-					first->orders      = NULL;
-					first->prev_shared = NULL;
-					first->next_shared = NULL;
-					first->group_id    = DEFAULT_GROUP;
+					first->group_id        = DEFAULT_GROUP;
+
+					new_f->AddToShared(first);
+					first->RemoveFromShared();
 
 					/* If we deleted a window then open a new one for the 'new' train */
 					if (IsLocalPlayer() && w != NULL) ShowVehicleViewWindow(new_f);
--- a/src/vehicle.cpp	Sun Aug 17 18:48:18 2008 +0000
+++ b/src/vehicle.cpp	Sun Aug 17 19:56:17 2008 +0000
@@ -255,6 +255,7 @@
 	FOR_ALL_VEHICLES(v) {
 		/* Reinstate the previous pointer */
 		if (v->Next() != NULL) v->Next()->previous = v;
+		if (v->NextShared() != NULL) v->NextShared()->previous_shared = v;
 
 		v->UpdateDeltaXY(v->direction);
 
@@ -272,6 +273,13 @@
 			for (Vehicle *u = v; u != NULL; u = u->Next()) {
 				u->first = v;
 			}
+
+			/* Shared orders are only valid for first vehicles in chains. */
+			if (v->previous_shared == NULL) {
+				for (Vehicle *u = v; u != NULL; u = u->NextShared()) {
+					u->first_shared = v;
+				}
+			}
 		}
 	}
 
@@ -329,6 +337,7 @@
 	this->group_id           = DEFAULT_GROUP;
 	this->fill_percent_te_id = INVALID_TE_ID;
 	this->first              = this;
+	this->first_shared       = this;
 	this->colormap           = PAL_NONE;
 }
 
@@ -2155,7 +2164,8 @@
 	 SLE_CONDVAR(Vehicle, waiting_triggers,     SLE_UINT8,                 2, SL_MAX_VERSION),
 
 	 SLE_CONDREF(Vehicle, next_shared,        REF_VEHICLE,                 2, SL_MAX_VERSION),
-	 SLE_CONDREF(Vehicle, prev_shared,        REF_VEHICLE,                 2, SL_MAX_VERSION),
+	SLE_CONDNULL(2,                                                        2, 68),
+	SLE_CONDNULL(4,                                                       69, 100),
 
 	SLE_CONDVAR(Vehicle, group_id,             SLE_UINT16,                60, SL_MAX_VERSION),
 
@@ -2390,8 +2400,7 @@
 				/* If a vehicle has the same orders, add the link to eachother
 				 *  in both vehicles */
 				if (v->orders == u->orders) {
-					v->next_shared = u;
-					u->prev_shared = v;
+					u->AddToShared(v);
 					break;
 				}
 			}
@@ -2574,6 +2583,49 @@
 	}
 }
 
+void Vehicle::AddToShared(Vehicle *shared_chain)
+{
+	assert(!this->IsOrderListShared());
+
+	this->next_shared     = shared_chain->next_shared;
+	this->previous_shared = shared_chain;
+	this->first_shared    = shared_chain->first_shared;
+
+	shared_chain->next_shared = this;
+
+	if (this->next_shared != NULL) this->next_shared->previous_shared = this;
+}
+
+void Vehicle::RemoveFromShared()
+{
+	Vehicle *new_first;
+
+	if (this->FirstShared() == this) {
+		/* We are the first shared one, so update all the first pointers of our next shared ones. */
+		new_first = this->NextShared();
+		for (Vehicle *u = new_first; u != NULL; u = u->NextShared()) {
+			u->first_shared = new_first;
+		}
+	} else {
+		/* We are not the first shared one, so only relink our previous one. */
+		new_first = this->FirstShared();
+		this->previous_shared->next_shared = this->NextShared();
+	}
+
+	if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
+
+	if (new_first->NextShared() == NULL) {
+		/* When there is only one vehicle, remove the shared order list window. */
+		extern void RemoveSharedOrderVehicleList(Vehicle *v);
+		if (new_first->orders != NULL) RemoveSharedOrderVehicleList(new_first);
+		InvalidateVehicleOrder(new_first);
+	}
+
+	this->first_shared    = this;
+	this->next_shared     = NULL;
+	this->previous_shared = NULL;
+}
+
 void StopAllVehicles()
 {
 	Vehicle *v;
--- a/src/vehicle_base.h	Sun Aug 17 18:48:18 2008 +0000
+++ b/src/vehicle_base.h	Sun Aug 17 19:56:17 2008 +0000
@@ -202,6 +202,10 @@
 	Vehicle *next;           ///< pointer to the next vehicle in the chain
 	Vehicle *previous;       ///< NOSAVE: pointer to the previous vehicle in the chain
 	Vehicle *first;          ///< NOSAVE: pointer to the first vehicle in the chain
+
+	Vehicle *next_shared;     ///< pointer to the next vehicle that shares the order
+	Vehicle *previous_shared; ///< NOSAVE: pointer to the previous vehicle in the shared order chain
+	Vehicle *first_shared;    ///< NOSAVE: pointer to the first vehicle in the shared order chain
 public:
 	friend const SaveLoad *GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code
 	friend void AfterLoadVehicles(bool clear_te_id);              ///< So we can set the previous and first pointers while loading
@@ -214,9 +218,6 @@
 	TileIndex tile;          ///< Current tile index
 	TileIndex dest_tile;     ///< Heading for this tile
 
-	Vehicle *next_shared;    ///< If not NULL, this points to the next vehicle that shared the order
-	Vehicle *prev_shared;    ///< If not NULL, this points to the prev vehicle that shared the order
-
 	Money profit_this_year;        ///< Profit this year << 8, low 8 bits are fract
 	Money profit_last_year;        ///< Profit last year << 8, low 8 bits are fract
 	Money value;
@@ -476,12 +477,37 @@
 	 */
 	inline Vehicle *First() const { return this->first; }
 
+
+	/**
+	 * Adds this vehicle to a shared vehicle chain.
+	 * @param shared_chain a vehicle of the chain with shared vehicles.
+	 * @pre !this->IsOrderListShared()
+	 */
+	void AddToShared(Vehicle *shared_chain);
+
+	/**
+	 * Removes the vehicle from the shared order list.
+	 */
+	void RemoveFromShared();
+
+	/**
+	 * Get the next vehicle of this vehicle.
+	 * @note articulated parts are also counted as vehicles.
+	 * @return the next vehicle or NULL when there isn't a next vehicle.
+	 */
+	inline Vehicle *NextShared() const { return this->next_shared; }
+
+	/**
+	 * Get the first vehicle of this vehicle chain.
+	 * @return the first vehicle of the chain.
+	 */
+	inline Vehicle *FirstShared() const { return this->first_shared; }
+
 	/**
 	 * Check if we share our orders with another vehicle.
-	 * This is done by checking the previous and next pointers in the shared chain.
 	 * @return true if there are other vehicles sharing the same order
 	 */
-	inline bool IsOrderListShared() const { return this->next_shared != NULL || this->prev_shared != NULL; };
+	inline bool IsOrderListShared() const { return this->previous_shared != NULL || this->next_shared != NULL; };
 
 	/**
 	 * Copy certain configurations and statistics of a vehicle after successful autoreplace/renew
@@ -648,18 +674,6 @@
 	return order;
 }
 
-/** Get the first vehicle of a shared-list, so we only have to walk forwards
- * @param v Vehicle to query
- * @return first vehicle of a shared-list
- */
-static inline Vehicle *GetFirstVehicleFromSharedList(const Vehicle *v)
-{
-	Vehicle *u = (Vehicle *)v;
-	while (u->prev_shared != NULL) u = u->prev_shared;
-
-	return u;
-}
-
 /**
  * Returns the Trackdir on which the vehicle is currently located.
  * Works for trains and ships.
--- a/src/vehiclelist.cpp	Sun Aug 17 18:48:18 2008 +0000
+++ b/src/vehiclelist.cpp	Sun Aug 17 19:56:17 2008 +0000
@@ -97,7 +97,7 @@
 				/* Find a vehicle with the order in question */
 				if (v->orders != NULL && v->orders->index == index) {
 					/* Add all vehicles from this vehicle's shared order list */
-					for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
+					for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
 						*list->Append() = v;
 					}
 					break;