src/order_cmd.cpp
branchNewGRF_ports
changeset 10184 fcf5fb2548eb
parent 6878 7d1ff2f621c7
child 10192 195d7f6dcf71
--- a/src/order_cmd.cpp	Mon Apr 14 20:32:36 2008 +0000
+++ b/src/order_cmd.cpp	Tue Apr 15 00:47:19 2008 +0000
@@ -4,14 +4,14 @@
 
 #include "stdafx.h"
 #include "openttd.h"
-#include "order.h"
+#include "order_base.h"
+#include "order_func.h"
 #include "airport.h"
 #include "depot.h"
 #include "waypoint.h"
 #include "command_func.h"
-#include "station.h"
 #include "player_func.h"
-#include "news.h"
+#include "news_func.h"
 #include "saveload.h"
 #include "vehicle_gui.h"
 #include "cargotype.h"
@@ -22,41 +22,139 @@
 #include "window_func.h"
 #include "settings_type.h"
 #include "string_func.h"
+#include "newgrf_cargo.h"
+#include "timetable.h"
+#include "vehicle_func.h"
+#include "oldpool_func.h"
 
 #include "table/strings.h"
 
+/* DestinationID must be at least as large as every these below, because it can
+ * be any of them
+ */
+assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
+assert_compile(sizeof(DestinationID) >= sizeof(WaypointID));
+assert_compile(sizeof(DestinationID) >= sizeof(StationID));
+
 TileIndex _backup_orders_tile;
 BackuppedOrders _backup_orders_data;
 
-DEFINE_OLD_POOL_GENERIC(Order, Order)
+DEFINE_OLD_POOL_GENERIC(Order, Order);
 
-/**
- *
- * Unpacks a order from savegames made with TTD(Patch)
- *
- */
-Order UnpackOldOrder(uint16 packed)
+OrderLoadFlags Order::GetLoadType() const
 {
-	Order order;
-	order.type    = (OrderType)GB(packed, 0, 4);
-	order.flags   = GB(packed, 4, 4);
-	order.dest    = GB(packed, 8, 8);
-	order.next    = NULL;
+	if ((this->flags & OLFB_FULL_LOAD) == 0) return OLF_LOAD_IF_POSSIBLE;
+	return _patches.full_load_any ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD;
+}
 
-	order.refit_cargo   = CT_NO_REFIT;
-	order.refit_subtype = 0;
-	order.wait_time     = 0;
-	order.travel_time   = 0;
-	order.index = 0; // avoid compiler warning
-
-	// Sanity check
-	// TTD stores invalid orders as OT_NOTHING with non-zero flags/station
-	if (!order.IsValid() && (order.flags != 0 || order.dest != 0)) {
-		order.type = OT_DUMMY;
-		order.flags = 0;
+OrderNonStopFlags Order::GetNonStopType() const
+{
+	if (_patches.new_nonstop) {
+		return (this->flags & 0x08) ? ONSF_NO_STOP_AT_ANY_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS;
 	}
 
-	return order;
+	return (this->flags & 0x08) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE;
+}
+
+void Order::Free()
+{
+	this->type  = OT_NOTHING;
+	this->flags = 0;
+	this->dest  = 0;
+	this->next  = NULL;
+}
+
+void Order::MakeGoToStation(StationID destination)
+{
+	this->type = OT_GOTO_STATION;
+	this->flags = 0;
+	this->dest = destination;
+}
+
+void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, CargoID cargo, byte subtype)
+{
+	this->type = OT_GOTO_DEPOT;
+	this->flags = 0;
+	this->SetDepotOrderType(order);
+	if (!(order & ODTFB_PART_OF_ORDERS)) {
+		this->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
+	}
+	this->dest = destination;
+	this->SetRefit(cargo, subtype);
+}
+
+void Order::MakeGoToWaypoint(WaypointID destination)
+{
+	this->type = OT_GOTO_WAYPOINT;
+	this->flags = 0;
+	this->dest = destination;
+}
+
+void Order::MakeLoading(bool ordered)
+{
+	this->type = OT_LOADING;
+	if (!ordered) this->flags = 0;
+}
+
+void Order::MakeLeaveStation()
+{
+	this->type = OT_LEAVESTATION;
+	this->flags = 0;
+}
+
+void Order::MakeDummy()
+{
+	this->type = OT_DUMMY;
+	this->flags = 0;
+}
+
+void Order::SetRefit(CargoID cargo, byte subtype)
+{
+	this->refit_cargo = cargo;
+	this->refit_subtype = subtype;
+}
+
+void Order::FreeChain()
+{
+	if (next != NULL) next->FreeChain();
+	delete this;
+}
+
+bool Order::Equals(const Order &other) const
+{
+	return
+			this->type  == other.type &&
+			this->flags == other.flags &&
+			this->dest  == other.dest;
+}
+
+static bool HasOrderPoolFree(uint amount)
+{
+	const Order *order;
+
+	/* There is always room if not all blocks in the pool are reserved */
+	if (_Order_pool.CanAllocateMoreBlocks()) return true;
+
+	FOR_ALL_ORDERS(order) if (!order->IsValid() && --amount == 0) return true;
+
+	return false;
+}
+
+uint32 Order::Pack() const
+{
+	return this->dest << 16 | this->flags << 8 | this->type;
+}
+
+Order::Order(uint32 packed)
+{
+	this->type    = (OrderType)GB(packed,  0,  8);
+	this->flags   = GB(packed,  8,  8);
+	this->dest    = GB(packed, 16, 16);
+	this->next    = NULL;
+	this->refit_cargo   = CT_NO_REFIT;
+	this->refit_subtype = 0;
+	this->wait_time     = 0;
+	this->travel_time   = 0;
 }
 
 /**
@@ -66,16 +164,26 @@
  */
 static Order UnpackVersion4Order(uint16 packed)
 {
-	Order order;
-	order.type  = (OrderType)GB(packed, 0, 4);
-	order.flags = GB(packed, 4, 4);
-	order.dest  = GB(packed, 8, 8);
-	order.next  = NULL;
-	order.index = 0; // avoid compiler warning
-	order.refit_cargo   = CT_NO_REFIT;
-	order.refit_subtype = 0;
-	order.wait_time     = 0;
-	order.travel_time   = 0;
+	return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4));
+}
+
+/**
+ *
+ * Unpacks a order from savegames made with TTD(Patch)
+ *
+ */
+Order UnpackOldOrder(uint16 packed)
+{
+	Order order = UnpackVersion4Order(packed);
+
+	/*
+	 * Sanity check
+	 * TTD stores invalid orders as OT_NOTHING with non-zero flags/station
+	 */
+	if (!order.IsValid() && (order.GetLoadType() != 0 || order.GetUnloadType() != 0 || order.GetDestination() != 0)) {
+		order.MakeDummy();
+	}
+
 	return order;
 }
 
@@ -101,9 +209,9 @@
 	Order temp_order;
 
 	temp_order = *order1;
-	AssignOrder(order1, *order2);
+	order1->AssignOrder(*order2);
 	order1->next = order2->next;
-	AssignOrder(order2, temp_order);
+	order2->AssignOrder(temp_order);
 	order2->next = temp_order.next;
 }
 
@@ -113,17 +221,17 @@
  *   This function makes sure that the index is maintained correctly
  *
  */
-void AssignOrder(Order *order, Order data)
+void Order::AssignOrder(const Order &other)
 {
-	order->type  = data.type;
-	order->flags = data.flags;
-	order->dest  = data.dest;
+	this->type  = other.type;
+	this->flags = other.flags;
+	this->dest  = other.dest;
 
-	order->refit_cargo   = data.refit_cargo;
-	order->refit_subtype = data.refit_subtype;
+	this->refit_cargo   = other.refit_cargo;
+	this->refit_subtype = other.refit_subtype;
 
-	order->wait_time   = data.wait_time;
-	order->travel_time = data.travel_time;
+	this->wait_time   = other.wait_time;
+	this->travel_time = other.travel_time;
 }
 
 
@@ -144,10 +252,10 @@
 
 static TileIndex GetOrderLocation(const Order& o)
 {
-	switch (o.type) {
+	switch (o.GetType()) {
 		default: NOT_REACHED();
-		case OT_GOTO_STATION: return GetStation(o.dest)->xy;
-		case OT_GOTO_DEPOT:   return GetDepot(o.dest)->xy;
+		case OT_GOTO_STATION: return GetStation(o.GetDestination())->xy;
+		case OT_GOTO_DEPOT:   return GetDepot(o.GetDestination())->xy;
 	}
 }
 
@@ -167,7 +275,7 @@
 	Vehicle *v;
 	VehicleID veh   = GB(p1,  0, 16);
 	VehicleOrderID sel_ord = GB(p1, 16, 16);
-	Order new_order = UnpackOrder(p2);
+	Order new_order(p2);
 
 	if (!IsValidVehicleID(veh)) return CMD_ERROR;
 
@@ -177,12 +285,11 @@
 
 	/* Check if the inserted order is to the correct destination (owner, type),
 	 * and has the correct flags if any */
-	switch (new_order.type) {
+	switch (new_order.GetType()) {
 		case OT_GOTO_STATION: {
-			const Station *st;
+			if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR;
 
-			if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
-			st = GetStation(new_order.dest);
+			const Station *st = GetStation(new_order.GetDestination());
 
 			if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) {
 				return CMD_ERROR;
@@ -214,38 +321,26 @@
 				default: return CMD_ERROR;
 			}
 
-			/* Order flags can be any of the following for stations:
-			 * [full-load | unload] [+ transfer] [+ non-stop]
-			 * non-stop orders (if any) are only valid for trains */
-			switch (new_order.flags) {
-				case 0:
-				case OFB_FULL_LOAD:
-				case OFB_FULL_LOAD | OFB_TRANSFER:
-				case OFB_UNLOAD:
-				case OFB_UNLOAD | OFB_TRANSFER:
-				case OFB_TRANSFER:
-					break;
+			/* Non stop not allowed for non-trains. */
+			// TODO: implement properly once savegame bump is done. if ((new_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) != 0 && v->type != VEH_TRAIN) return CMD_ERROR;
 
-				case OFB_NON_STOP:
-				case OFB_NON_STOP | OFB_FULL_LOAD:
-				case OFB_NON_STOP | OFB_FULL_LOAD | OFB_TRANSFER:
-				case OFB_NON_STOP | OFB_UNLOAD:
-				case OFB_NON_STOP | OFB_UNLOAD | OFB_TRANSFER:
-				case OFB_NON_STOP | OFB_TRANSFER:
-					if (v->type != VEH_TRAIN) return CMD_ERROR;
-					break;
+			/* Full load and unload are mutual exclusive. */
+			if ((new_order.GetLoadType() & OLFB_FULL_LOAD) && (new_order.GetUnloadType() & OUFB_UNLOAD)) return CMD_ERROR;
 
+			/* Filter invalid load/unload types. */
+			switch (new_order.GetLoadType()) {
+				case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: break;
 				default: return CMD_ERROR;
 			}
+			if (new_order.GetUnloadType() & ~(OUFB_UNLOAD | OUFB_TRANSFER)) return CMD_ERROR;
 			break;
 		}
 
 		case OT_GOTO_DEPOT: {
 			if (v->type == VEH_AIRCRAFT) {
-				const Station* st;
+				if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR;
 
-				if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
-				st = GetStation(new_order.dest);
+				const Station *st = GetStation(new_order.GetDestination());
 
 				if (!CheckOwnership(st->owner) ||
 						!(st->facilities & FACIL_AIRPORT) ||
@@ -254,10 +349,9 @@
 					return CMD_ERROR;
 				}
 			} else {
-				const Depot* dp;
+				if (!IsValidDepotID(new_order.GetDestination())) return CMD_ERROR;
 
-				if (!IsValidDepotID(new_order.dest)) return CMD_ERROR;
-				dp = GetDepot(new_order.dest);
+				const Depot *dp = GetDepot(new_order.GetDestination());
 
 				if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
 
@@ -278,46 +372,26 @@
 				}
 			}
 
-			/* Order flags can be any of the following for depots:
-			 * order [+ halt] [+ non-stop]
-			 * non-stop orders (if any) are only valid for trains */
-			switch (new_order.flags) {
-				case OFB_PART_OF_ORDERS:
-				case OFB_PART_OF_ORDERS | OFB_HALT_IN_DEPOT:
-					break;
-
-				case OFB_NON_STOP | OFB_PART_OF_ORDERS:
-				case OFB_NON_STOP | OFB_PART_OF_ORDERS | OFB_HALT_IN_DEPOT:
-					if (v->type != VEH_TRAIN) return CMD_ERROR;
-					break;
-
-				default: return CMD_ERROR;
-			}
+			// TODO: implement properly once savegame bump is done. if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
+			if (new_order.GetDepotOrderType() & ~ODTFB_PART_OF_ORDERS) return CMD_ERROR;
+			if (new_order.GetDepotActionType() & ~ODATFB_HALT) return CMD_ERROR;
 			break;
 		}
 
 		case OT_GOTO_WAYPOINT: {
-			const Waypoint* wp;
 
 			if (v->type != VEH_TRAIN) return CMD_ERROR;
 
-			if (!IsValidWaypointID(new_order.dest)) return CMD_ERROR;
-			wp = GetWaypoint(new_order.dest);
+			if (!IsValidWaypointID(new_order.GetDestination())) return CMD_ERROR;
+			const Waypoint *wp = GetWaypoint(new_order.GetDestination());
 
 			if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR;
 
 			/* Order flags can be any of the following for waypoints:
 			 * [non-stop]
 			 * non-stop orders (if any) are only valid for trains */
-			switch (new_order.flags) {
-				case 0: break;
+			// TODO: implement properly once savegame bump is done. if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
 
-				case OFB_NON_STOP:
-					if (v->type != VEH_TRAIN) return CMD_ERROR;
-					break;
-
-				default: return CMD_ERROR;
-			}
 			break;
 		}
 
@@ -337,7 +411,7 @@
 		 * If the order is to be inserted at the beginning of the order list this
 		 * finds the last order in the list. */
 		for (const Order *o = v->orders; o != NULL; o = o->next) {
-			if (o->type == OT_GOTO_STATION || o->type == OT_GOTO_DEPOT) prev = o;
+			if (o->IsType(OT_GOTO_STATION) || o->IsType(OT_GOTO_DEPOT)) prev = o;
 			if (++n == sel_ord && prev != NULL) break;
 		}
 		if (prev != NULL) {
@@ -354,7 +428,7 @@
 	if (flags & DC_EXEC) {
 		Vehicle *u;
 		Order *new_o = new Order();
-		AssignOrder(new_o, new_order);
+		new_o->AssignOrder(new_order);
 
 		/* Create new order and link in list */
 		if (v->orders == NULL) {
@@ -511,9 +585,8 @@
 
 			/* NON-stop flag is misused to see if a train is in a station that is
 			 * on his order list or not */
-			if (sel_ord == u->cur_order_index && u->current_order.type == OT_LOADING &&
-					HasBit(u->current_order.flags, OF_NON_STOP)) {
-				u->current_order.flags = 0;
+			if (sel_ord == u->cur_order_index && u->current_order.IsType(OT_LOADING)) {
+				u->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
 			}
 
 			/* Update any possible open window of the vehicle */
@@ -550,12 +623,7 @@
 
 		if (v->type == VEH_ROAD) ClearSlot(v);
 
-		if (v->current_order.type == OT_LOADING) {
-			v->LeaveStation();
-			/* NON-stop flag is misused to see if a train is in a station that is
-			 * on his order list or not */
-			if (HasBit(v->current_order.flags, OF_NON_STOP)) v->current_order.flags = 0;
-		}
+		if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
 
 		InvalidateVehicleOrder(v);
 	}
@@ -661,74 +729,112 @@
  * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
  *                        the order will be inserted before that one
  *                        only the first 8 bits used currently (bit 16 - 23) (max 255)
- * @param p2 mode to change the order to (always set)
+ * @param p2 various bitstuffed elements
+ *  - p2 = (bit 0 - 1) - what data to modify (@see ModifyOrderFlags)
+ *  - p2 = (bit 2 - 5) - the data to modify
  */
 CommandCost CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	Vehicle *v;
-	Order *order;
 	VehicleOrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
-	VehicleID veh   = GB(p1,  0, 16);
+	VehicleID veh          = GB(p1,  0, 16);
+	ModifyOrderFlags mof   = (ModifyOrderFlags)GB(p2,  0,  2);
+	uint8 data             = GB(p2,  2,  4);
 
 	if (!IsValidVehicleID(veh)) return CMD_ERROR;
-	if (p2 != OF_FULL_LOAD && p2 != OF_UNLOAD && p2 != OF_NON_STOP && p2 != OF_TRANSFER) return CMD_ERROR;
 
-	v = GetVehicle(veh);
-
+	Vehicle *v = GetVehicle(veh);
 	if (!CheckOwnership(v->owner)) return CMD_ERROR;
 
 	/* Is it a valid order? */
 	if (sel_ord >= v->num_orders) return CMD_ERROR;
 
-	order = GetVehicleOrder(v, sel_ord);
-	if ((order->type != OT_GOTO_STATION  || GetStation(order->dest)->IsBuoy()) &&
-			(order->type != OT_GOTO_DEPOT    || p2 == OF_UNLOAD) &&
-			(order->type != OT_GOTO_WAYPOINT || p2 != OF_NON_STOP)) {
-		return CMD_ERROR;
+	Order *order = GetVehicleOrder(v, sel_ord);
+	switch (order->GetType()) {
+		case OT_GOTO_STATION:
+			if (mof == MOF_DEPOT_ACTION || GetStation(order->GetDestination())->IsBuoy()) return CMD_ERROR;
+			break;
+
+		case OT_GOTO_DEPOT:
+			if (mof == MOF_UNLOAD || mof == MOF_LOAD) return CMD_ERROR;
+			break;
+
+		case OT_GOTO_WAYPOINT:
+			if (mof != MOF_NON_STOP) return CMD_ERROR;
+			break;
+
+		default:
+			return CMD_ERROR;
+	}
+
+	switch (mof) {
+		case MOF_NON_STOP:
+			if (data >= ONSF_END) return CMD_ERROR;
+			if (data == order->GetNonStopType()) return CMD_ERROR;
+			break;
+
+		case MOF_UNLOAD:
+			if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER)) != 0) return CMD_ERROR;
+			if (data == order->GetUnloadType()) return CMD_ERROR;
+			break;
+
+		case MOF_LOAD:
+			if ((data & ~OLFB_FULL_LOAD) != 0) return CMD_ERROR;
+			if (data == order->GetLoadType()) return CMD_ERROR;
+			break;
+
+		case MOF_DEPOT_ACTION:
+			if (data != 0) return CMD_ERROR;
+			break;
 	}
 
 	if (flags & DC_EXEC) {
-		switch (p2) {
-		case OF_FULL_LOAD:
-			ToggleBit(order->flags, OF_FULL_LOAD);
-			if (order->type != OT_GOTO_DEPOT) ClrBit(order->flags, OF_UNLOAD);
-			break;
-		case OF_UNLOAD:
-			ToggleBit(order->flags, OF_UNLOAD);
-			ClrBit(order->flags, OF_FULL_LOAD);
-			break;
-		case OF_NON_STOP:
-			ToggleBit(order->flags, OF_NON_STOP);
-			break;
-		case OF_TRANSFER:
-			ToggleBit(order->flags, OF_TRANSFER);
-			break;
-		default: NOT_REACHED();
+		switch (mof) {
+			case MOF_NON_STOP:
+				order->SetNonStopType((OrderNonStopFlags)data);
+				break;
+
+			case MOF_UNLOAD:
+				order->SetUnloadType((OrderUnloadFlags)data);
+				/* Full loading gets disabled when un loading! */
+				if ((data & OUFB_UNLOAD) != 0) {
+					order->SetLoadType((OrderLoadFlags)(order->GetLoadType() & ~(OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)));
+				}
+				break;
+
+			case MOF_LOAD:
+				order->SetLoadType((OrderLoadFlags)data);
+				/* Unloading gets disabled when full loading! */
+				if ((data & OLFB_FULL_LOAD) != 0) {
+					order->SetUnloadType((OrderUnloadFlags)(order->GetUnloadType() & ~OUFB_UNLOAD));
+				}
+				break;
+
+			case MOF_DEPOT_ACTION:
+				order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() ^ ODTFB_SERVICE));
+				break;
+
+			default: NOT_REACHED();
 		}
 
 		/* Update the windows and full load flags, also for vehicles that share the same order list */
-		{
-			Vehicle* u;
-
-			u = GetFirstVehicleFromSharedList(v);
-			DeleteOrderWarnings(u);
-			for (; u != NULL; u = u->next_shared) {
-				/* 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
-				 * cases where the full load flag can be active and only
-				 * one case where the flag is used for depot orders. In the
-				 * other cases for the OrderTypeByte the flags are not used,
-				 * so do not care and those orders should not be active
-				 * when this function is called.
-				 */
-				if (sel_ord == u->cur_order_index &&
-						u->current_order.type != OT_GOTO_DEPOT &&
-						HasBit(u->current_order.flags, OF_FULL_LOAD) != HasBit(order->flags, OF_FULL_LOAD)) {
-					ToggleBit(u->current_order.flags, OF_FULL_LOAD);
-				}
-				InvalidateVehicleOrder(u);
+		Vehicle *u = GetFirstVehicleFromSharedList(v);
+		DeleteOrderWarnings(u);
+		for (; u != NULL; u = u->next_shared) {
+			/* 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
+			 * cases where the full load flag can be active and only
+			 * one case where the flag is used for depot orders. In the
+			 * other cases for the OrderTypeByte the flags are not used,
+			 * so do not care and those orders should not be active
+			 * when this function is called.
+			 */
+			if (sel_ord == u->cur_order_index &&
+					(u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
+					u->current_order.GetLoadType() != order->GetLoadType()) {
+				u->current_order.SetLoadType(order->GetLoadType());
 			}
+			InvalidateVehicleOrder(u);
 		}
 	}
 
@@ -820,8 +926,8 @@
 				TileIndex required_dst = INVALID_TILE;
 
 				FOR_VEHICLE_ORDERS(src, order) {
-					if (order->type == OT_GOTO_STATION) {
-						const Station *st = GetStation(order->dest);
+					if (order->IsType(OT_GOTO_STATION)) {
+						const Station *st = GetStation(order->GetDestination());
 						if (IsCargoInClass(dst->cargo_type, CC_PASSENGERS)) {
 							if (st->bus_stops != NULL) required_dst = st->bus_stops->xy;
 						} else {
@@ -849,7 +955,7 @@
 				order_dst = &dst->orders;
 				FOR_VEHICLE_ORDERS(src, order) {
 					*order_dst = new Order();
-					AssignOrder(*order_dst, *order);
+					(*order_dst)->AssignOrder(*order);
 					order_dst = &(*order_dst)->next;
 				}
 
@@ -898,8 +1004,7 @@
 	if (flags & DC_EXEC) {
 		Vehicle *u;
 
-		order->refit_cargo = cargo;
-		order->refit_subtype = subtype;
+		order->SetRefit(cargo, subtype);
 
 		u = GetFirstVehicleFromSharedList(v);
 		for (; u != NULL; u = u->next_shared) {
@@ -907,9 +1012,8 @@
 			InvalidateVehicleOrder(u);
 
 			/* If the vehicle already got the current depot set as current order, then update current order as well */
-			if (u->cur_order_index == order_number && HasBit(u->current_order.flags, OF_PART_OF_ORDERS)) {
-				u->current_order.refit_cargo = cargo;
-				u->current_order.refit_subtype = subtype;
+			if (u->cur_order_index == order_number && u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
+				u->current_order.SetRefit(cargo, subtype);
 			}
 		}
 	}
@@ -992,7 +1096,7 @@
 		 *  in network the commands are queued before send, the second insert always
 		 *  fails in test mode. By bypassing the test-mode, that no longer is a problem. */
 		for (uint i = 0; bak->order[i].IsValid(); i++) {
-			if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL,
+			if (!DoCommandP(0, v->index + (i << 16), bak->order[i].Pack(), NULL,
 					CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
 				break;
 			}
@@ -1098,13 +1202,13 @@
 
 		FOR_VEHICLE_ORDERS(v, order) {
 			/* Dummy order? */
-			if (order->type == OT_DUMMY) {
+			if (order->IsType(OT_DUMMY)) {
 				problem_type = 1;
 				break;
 			}
 			/* Does station have a load-bay for this vehicle? */
-			if (order->type == OT_GOTO_STATION) {
-				const Station* st = GetStation(order->dest);
+			if (order->IsType(OT_GOTO_STATION)) {
+				const Station* st = GetStation(order->GetDestination());
 				TileIndex required_tile = GetStationTileForVehicle(v, st);
 
 				n_st++;
@@ -1116,9 +1220,7 @@
 		if (v->num_orders > 1) {
 			const Order* last = GetLastVehicleOrder(v);
 
-			if (v->orders->type  == last->type &&
-					v->orders->flags == last->flags &&
-					v->orders->dest  == last->dest) {
+			if (v->orders->Equals(*last)) {
 				problem_type = 2;
 			}
 		}
@@ -1135,7 +1237,7 @@
 		SetDParam(0, v->unitnumber);
 		AddNewsItem(
 			message,
-			NEWS_FLAGS(NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, 0),
+			NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE,
 			v->index,
 			0
 		);
@@ -1166,20 +1268,18 @@
 		}
 
 		order = &v->current_order;
-		if ((v->type == VEH_AIRCRAFT && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
-				v->current_order.dest == destination) {
-			order->type = OT_DUMMY;
-			order->flags = 0;
+		if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
+				v->current_order.GetDestination() == destination) {
+			order->MakeDummy();
 			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
 		}
 
 		/* Clear the order from the order-list */
 		invalidate = false;
 		FOR_VEHICLE_ORDERS(v, order) {
-			if ((v->type == VEH_AIRCRAFT && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
-					order->dest == destination) {
-				order->type = OT_DUMMY;
-				order->flags = 0;
+			if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
+					order->GetDestination() == destination) {
+				order->MakeDummy();
 				invalidate = true;
 			}
 		}
@@ -1201,7 +1301,7 @@
 	const Order *order;
 
 	FOR_VEHICLE_ORDERS(v, order) {
-		if (order->type == OT_GOTO_DEPOT)
+		if (order->IsType(OT_GOTO_DEPOT))
 			return true;
 	}
 
@@ -1267,7 +1367,6 @@
 	return (_patches.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
 }
 
-
 /**
  *
  * Check if a vehicle has any valid orders
@@ -1275,15 +1374,149 @@
  * @return false if there are no valid orders
  *
  */
-bool CheckForValidOrders(const Vehicle* v)
+static bool CheckForValidOrders(const Vehicle *v)
 {
 	const Order *order;
 
-	FOR_VEHICLE_ORDERS(v, order) if (order->type != OT_DUMMY) return true;
+	FOR_VEHICLE_ORDERS(v, order) if (!order->IsType(OT_DUMMY)) return true;
 
 	return false;
 }
 
+/**
+ * Handle the orders of a vehicle and determine the next place
+ * to go to if needed.
+ * @param v the vehicle to do this for.
+ * @return true *if* the vehicle is eligible for reversing
+ *              (basically only when leaving a station).
+ */
+bool ProcessOrders(Vehicle *v)
+{
+	switch (v->current_order.GetType()) {
+		case OT_GOTO_DEPOT:
+			/* Let a depot order in the orderlist interrupt. */
+			if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
+
+			if ((v->current_order.GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
+				UpdateVehicleTimetable(v, true);
+				v->cur_order_index++;
+			}
+			break;
+
+		case OT_LOADING:
+			return false;
+
+		case OT_LEAVESTATION:
+			if (v->type != VEH_AIRCRAFT) return false;
+			break;
+
+		default: break;
+	}
+
+	/**
+	 * Reversing because of order change is allowed only just after leaving a
+	 * station (and the difficulty setting to allowed, of course)
+	 * this can be detected because only after OT_LEAVESTATION, current_order
+	 * will be reset to nothing. (That also happens if no order, but in that case
+	 * it won't hit the point in code where may_reverse is checked)
+	 */
+	bool may_reverse = v->current_order.IsType(OT_NOTHING);
+
+	/* Check if we've reached the waypoint? */
+	if (v->current_order.IsType(OT_GOTO_WAYPOINT) && v->tile == v->dest_tile) {
+		UpdateVehicleTimetable(v, true);
+		v->cur_order_index++;
+	}
+
+	/* Check if we've reached a non-stop station.. */
+	if ((v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
+			IsTileType(v->tile, MP_STATION) &&
+			v->current_order.GetDestination() == GetStationIndex(v->tile)) {
+		v->last_station_visited = v->current_order.GetDestination();
+		UpdateVehicleTimetable(v, true);
+		v->cur_order_index++;
+	}
+
+	/* Get the current order */
+	if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
+
+	const Order *order = GetVehicleOrder(v, v->cur_order_index);
+
+	/* If no order, do nothing. */
+	if (order == NULL || (v->type == VEH_AIRCRAFT && order->IsType(OT_DUMMY) && !CheckForValidOrders(v))) {
+		if (v->type == VEH_AIRCRAFT) {
+			/* Aircraft do something vastly different here, so handle separately */
+			extern void HandleMissingAircraftOrders(Vehicle *v);
+			HandleMissingAircraftOrders(v);
+			return false;
+		}
+
+		v->current_order.Free();
+		v->dest_tile = 0;
+		if (v->type == VEH_ROAD) ClearSlot(v);
+		return false;
+	}
+
+	/* If it is unchanged, keep it. */
+	if (order->Equals(v->current_order) &&
+			(v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || GetStation(order->GetDestination())->dock_tile != 0)) {
+		return false;
+	}
+
+	/* Otherwise set it, and determine the destination tile. */
+	v->current_order = *order;
+
+	InvalidateVehicleOrder(v);
+	switch (v->type) {
+		default:
+			NOT_REACHED();
+
+		case VEH_ROAD:
+		case VEH_TRAIN:
+			break;
+
+		case VEH_AIRCRAFT:
+		case VEH_SHIP:
+			InvalidateWindowClasses(v->GetVehicleListWindowClass());
+			break;
+	}
+
+	switch (order->GetType()) {
+		case OT_GOTO_STATION:
+			v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
+			break;
+
+		case OT_GOTO_DEPOT:
+			if (v->type != VEH_AIRCRAFT) v->dest_tile = GetDepot(order->GetDestination())->xy;
+			break;
+
+		case OT_GOTO_WAYPOINT:
+			v->dest_tile = GetWaypoint(order->GetDestination())->xy;
+			break;
+
+		default:
+			v->dest_tile = 0;
+			return false;
+	}
+
+	return may_reverse;
+}
+
+/**
+ * Check whether the given vehicle should stop at the given station
+ * based on this order and the non-stop settings.
+ * @param v       the vehicle that might be stopping.
+ * @param station the station to stop at.
+ * @return true if the vehicle should stop.
+ */
+bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
+{
+	return
+			v->last_station_visited != station && // Do stop only when we've not just been there
+			/* Finally do stop when there is no non-stop flag set for this type of station. */
+			!(this->GetNonStopType() & ((this->dest == station) ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
+}
+
 void InitializeOrders()
 {
 	_Order_pool.CleanPool();
@@ -1292,6 +1525,7 @@
 	_backup_orders_tile = 0;
 }
 
+const SaveLoad *GetOrderDescription() {
 static const SaveLoad _order_desc[] = {
 	SLE_VAR(Order, type,  SLE_UINT8),
 	SLE_VAR(Order, flags, SLE_UINT8),
@@ -1307,6 +1541,8 @@
 	SLE_CONDNULL(10, 5, 35),
 	SLE_END()
 };
+	return _order_desc;
+}
 
 static void Save_ORDR()
 {
@@ -1314,7 +1550,7 @@
 
 	FOR_ALL_ORDERS(order) {
 		SlSetArrayIndex(order->index);
-		SlObject(order, _order_desc);
+		SlObject(order, GetOrderDescription());
 	}
 }
 
@@ -1336,7 +1572,7 @@
 
 			for (i = 0; i < len; ++i) {
 				Order *order = new (i) Order();
-				AssignOrder(order, UnpackVersion4Order(orders[i]));
+				order->AssignOrder(UnpackVersion4Order(orders[i]));
 			}
 
 			free(orders);
@@ -1347,8 +1583,7 @@
 			SlArray(orders, len, SLE_UINT32);
 
 			for (i = 0; i < len; ++i) {
-				Order *order = new (i) Order();
-				AssignOrder(order, UnpackOrder(orders[i]));
+				new (i) Order(orders[i]);
 			}
 
 			free(orders);
@@ -1367,7 +1602,7 @@
 
 		while ((index = SlIterateArray()) != -1) {
 			Order *order = new (index) Order();
-			SlObject(order, _order_desc);
+			SlObject(order, GetOrderDescription());
 		}
 	}
 }