src/order_cmd.c
changeset 5475 2e6990a8c7c4
parent 5380 8ea58542b6e0
equal deleted inserted replaced
5474:ac55aefc54f3 5475:2e6990a8c7c4
       
     1 /* $Id$ */
       
     2 
       
     3 #include "stdafx.h"
       
     4 #include "openttd.h"
       
     5 #include "order.h"
       
     6 #include "airport.h"
       
     7 #include "depot.h"
       
     8 #include "functions.h"
       
     9 #include "table/strings.h"
       
    10 #include "vehicle.h"
       
    11 #include "waypoint.h"
       
    12 #include "command.h"
       
    13 #include "station.h"
       
    14 #include "player.h"
       
    15 #include "news.h"
       
    16 #include "saveload.h"
       
    17 #include "vehicle_gui.h"
       
    18 
       
    19 /**
       
    20  * Called if a new block is added to the order-pool
       
    21  */
       
    22 static void OrderPoolNewBlock(uint start_item)
       
    23 {
       
    24 	Order *order;
       
    25 
       
    26 	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
       
    27 	 * TODO - This is just a temporary stage, this will be removed. */
       
    28 	for (order = GetOrder(start_item); order != NULL; order = (order->index + 1U < GetOrderPoolSize()) ? GetOrder(order->index + 1U) : NULL) order->index = start_item++;
       
    29 }
       
    30 
       
    31 DEFINE_OLD_POOL(Order, Order, OrderPoolNewBlock, NULL)
       
    32 
       
    33 /**
       
    34  *
       
    35  * Unpacks a order from savegames made with TTD(Patch)
       
    36  *
       
    37  */
       
    38 Order UnpackOldOrder(uint16 packed)
       
    39 {
       
    40 	Order order;
       
    41 	order.type    = GB(packed, 0, 4);
       
    42 	order.flags   = GB(packed, 4, 4);
       
    43 	order.dest    = GB(packed, 8, 8);
       
    44 	order.next    = NULL;
       
    45 
       
    46 	order.refit_cargo   = CT_NO_REFIT;
       
    47 	order.refit_subtype = 0;
       
    48 	order.index = 0; // avoid compiler warning
       
    49 
       
    50 	// Sanity check
       
    51 	// TTD stores invalid orders as OT_NOTHING with non-zero flags/station
       
    52 	if (order.type == OT_NOTHING && (order.flags != 0 || order.dest != 0)) {
       
    53 		order.type = OT_DUMMY;
       
    54 		order.flags = 0;
       
    55 	}
       
    56 
       
    57 	return order;
       
    58 }
       
    59 
       
    60 /**
       
    61  *
       
    62  * Unpacks a order from savegames with version 4 and lower
       
    63  *
       
    64  */
       
    65 static Order UnpackVersion4Order(uint16 packed)
       
    66 {
       
    67 	Order order;
       
    68 	order.type  = GB(packed, 0, 4);
       
    69 	order.flags = GB(packed, 4, 4);
       
    70 	order.dest  = GB(packed, 8, 8);
       
    71 	order.next  = NULL;
       
    72 	order.index = 0; // avoid compiler warning
       
    73 	order.refit_cargo   = CT_NO_REFIT;
       
    74 	order.refit_subtype = 0;
       
    75 	return order;
       
    76 }
       
    77 
       
    78 /**
       
    79  *
       
    80  * Updates the widgets of a vehicle which contains the order-data
       
    81  *
       
    82  */
       
    83 void InvalidateVehicleOrder(const Vehicle *v)
       
    84 {
       
    85 	InvalidateWindow(WC_VEHICLE_VIEW,   v->index);
       
    86 	InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
       
    87 }
       
    88 
       
    89 /**
       
    90  *
       
    91  * Swap two orders
       
    92  *
       
    93  */
       
    94 static void SwapOrders(Order *order1, Order *order2)
       
    95 {
       
    96 	Order temp_order;
       
    97 
       
    98 	temp_order = *order1;
       
    99 	AssignOrder(order1, *order2);
       
   100 	order1->next = order2->next;
       
   101 	AssignOrder(order2, temp_order);
       
   102 	order2->next = temp_order.next;
       
   103 }
       
   104 
       
   105 /**
       
   106  *
       
   107  * Allocate a new order
       
   108  *
       
   109  * @return Order* if a free space is found, else NULL.
       
   110  *
       
   111  */
       
   112 static Order *AllocateOrder(void)
       
   113 {
       
   114 	Order *order;
       
   115 
       
   116 	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
       
   117 	 * TODO - This is just a temporary stage, this will be removed. */
       
   118 	for (order = GetOrder(0); order != NULL; order = (order->index + 1U < GetOrderPoolSize()) ? GetOrder(order->index + 1U) : NULL) {
       
   119 		if (!IsValidOrder(order)) {
       
   120 			OrderID index = order->index;
       
   121 
       
   122 			memset(order, 0, sizeof(*order));
       
   123 			order->index = index;
       
   124 			order->next = NULL;
       
   125 			order->refit_cargo   = CT_NO_REFIT;
       
   126 			order->refit_subtype = 0;
       
   127 
       
   128 			return order;
       
   129 		}
       
   130 	}
       
   131 
       
   132 	/* Check if we can add a block to the pool */
       
   133 	if (AddBlockToPool(&_Order_pool)) return AllocateOrder();
       
   134 
       
   135 	return NULL;
       
   136 }
       
   137 
       
   138 /**
       
   139  *
       
   140  * Assign data to an order (from an other order)
       
   141  *   This function makes sure that the index is maintained correctly
       
   142  *
       
   143  */
       
   144 void AssignOrder(Order *order, Order data)
       
   145 {
       
   146 	order->type  = data.type;
       
   147 	order->flags = data.flags;
       
   148 	order->dest  = data.dest;
       
   149 
       
   150 	order->refit_cargo   = data.refit_cargo;
       
   151 	order->refit_subtype = data.refit_subtype;
       
   152 }
       
   153 
       
   154 
       
   155 /**
       
   156  * Delete all news items regarding defective orders about a vehicle
       
   157  * This could kill still valid warnings (for example about void order when just
       
   158  * another order gets added), but assume the player will notice the problems,
       
   159  * when (s)he's changing the orders.
       
   160  */
       
   161 static void DeleteOrderWarnings(const Vehicle* v)
       
   162 {
       
   163 	DeleteVehicleNews(v->index, STR_TRAIN_HAS_TOO_FEW_ORDERS  + (v->type - VEH_Train) * 4);
       
   164 	DeleteVehicleNews(v->index, STR_TRAIN_HAS_VOID_ORDER      + (v->type - VEH_Train) * 4);
       
   165 	DeleteVehicleNews(v->index, STR_TRAIN_HAS_DUPLICATE_ENTRY + (v->type - VEH_Train) * 4);
       
   166 	DeleteVehicleNews(v->index, STR_TRAIN_HAS_INVALID_ENTRY   + (v->type - VEH_Train) * 4);
       
   167 }
       
   168 
       
   169 
       
   170 /** Add an order to the orderlist of a vehicle.
       
   171  * @param tile unused
       
   172  * @param p1 various bitstuffed elements
       
   173  * - p1 = (bit  0 - 15) - ID of the vehicle
       
   174  * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
       
   175  *                        the order will be inserted before that one
       
   176  *                        only the first 8 bits used currently (bit 16 - 23) (max 255)
       
   177  * @param p2 packed order to insert
       
   178  */
       
   179 int32 CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   180 {
       
   181 	Vehicle *v;
       
   182 	VehicleID veh   = GB(p1,  0, 16);
       
   183 	VehicleOrderID sel_ord = GB(p1, 16, 16);
       
   184 	Order new_order = UnpackOrder(p2);
       
   185 
       
   186 	if (!IsValidVehicleID(veh)) return CMD_ERROR;
       
   187 
       
   188 	v = GetVehicle(veh);
       
   189 
       
   190 	if (!CheckOwnership(v->owner)) return CMD_ERROR;
       
   191 
       
   192 	/* Check if the inserted order is to the correct destination (owner, type),
       
   193 	 * and has the correct flags if any */
       
   194 	switch (new_order.type) {
       
   195 		case OT_GOTO_STATION: {
       
   196 			const Station *st;
       
   197 
       
   198 			if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
       
   199 			st = GetStation(new_order.dest);
       
   200 
       
   201 			if (st->airport_type != AT_OILRIG && !IsBuoy(st) && !CheckOwnership(st->owner)) {
       
   202 				return CMD_ERROR;
       
   203 			}
       
   204 
       
   205 			switch (v->type) {
       
   206 				case VEH_Train:
       
   207 					if (!(st->facilities & FACIL_TRAIN)) return CMD_ERROR;
       
   208 					break;
       
   209 
       
   210 				case VEH_Road:
       
   211 					if (v->cargo_type == CT_PASSENGERS) {
       
   212 						if (!(st->facilities & FACIL_BUS_STOP)) return CMD_ERROR;
       
   213 					} else {
       
   214 						if (!(st->facilities & FACIL_TRUCK_STOP)) return CMD_ERROR;
       
   215 					}
       
   216 					break;
       
   217 
       
   218 				case VEH_Ship:
       
   219 					if (!(st->facilities & FACIL_DOCK)) return CMD_ERROR;
       
   220 					break;
       
   221 
       
   222 				case VEH_Aircraft:
       
   223 					if (!(st->facilities & FACIL_AIRPORT)) return CMD_ERROR;
       
   224 					break;
       
   225 
       
   226 				default: return CMD_ERROR;
       
   227 			}
       
   228 
       
   229 			/* Order flags can be any of the following for stations:
       
   230 			 * [full-load | unload] [+ transfer] [+ non-stop]
       
   231 			 * non-stop orders (if any) are only valid for trains */
       
   232 			switch (new_order.flags) {
       
   233 				case 0:
       
   234 				case OF_FULL_LOAD:
       
   235 				case OF_FULL_LOAD | OF_TRANSFER:
       
   236 				case OF_UNLOAD:
       
   237 				case OF_UNLOAD | OF_TRANSFER:
       
   238 				case OF_TRANSFER:
       
   239 					break;
       
   240 
       
   241 				case OF_NON_STOP:
       
   242 				case OF_NON_STOP | OF_FULL_LOAD:
       
   243 				case OF_NON_STOP | OF_FULL_LOAD | OF_TRANSFER:
       
   244 				case OF_NON_STOP | OF_UNLOAD:
       
   245 				case OF_NON_STOP | OF_UNLOAD | OF_TRANSFER:
       
   246 				case OF_NON_STOP | OF_TRANSFER:
       
   247 					if (v->type != VEH_Train) return CMD_ERROR;
       
   248 					break;
       
   249 
       
   250 				default: return CMD_ERROR;
       
   251 			}
       
   252 			break;
       
   253 		}
       
   254 
       
   255 		case OT_GOTO_DEPOT: {
       
   256 			if (v->type == VEH_Aircraft) {
       
   257 				const Station* st;
       
   258 
       
   259 				if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
       
   260 				st = GetStation(new_order.dest);
       
   261 
       
   262 				if ((st->airport_type != AT_OILRIG && !CheckOwnership(st->owner)) ||
       
   263 						!(st->facilities & FACIL_AIRPORT) ||
       
   264 						GetAirport(st->airport_type)->nof_depots == 0) {
       
   265 					return CMD_ERROR;
       
   266 				}
       
   267 			} else {
       
   268 				const Depot* dp;
       
   269 
       
   270 				if (!IsValidDepotID(new_order.dest)) return CMD_ERROR;
       
   271 				dp = GetDepot(new_order.dest);
       
   272 
       
   273 				if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
       
   274 
       
   275 				switch (v->type) {
       
   276 					case VEH_Train:
       
   277 						if (!IsTileDepotType(dp->xy, TRANSPORT_RAIL)) return CMD_ERROR;
       
   278 						break;
       
   279 
       
   280 					case VEH_Road:
       
   281 						if (!IsTileDepotType(dp->xy, TRANSPORT_ROAD)) return CMD_ERROR;
       
   282 						break;
       
   283 
       
   284 					case VEH_Ship:
       
   285 						if (!IsTileDepotType(dp->xy, TRANSPORT_WATER)) return CMD_ERROR;
       
   286 						break;
       
   287 
       
   288 					default: return CMD_ERROR;
       
   289 				}
       
   290 			}
       
   291 
       
   292 			/* Order flags can be any of the following for depots:
       
   293 			 * order [+ halt] [+ non-stop]
       
   294 			 * non-stop orders (if any) are only valid for trains */
       
   295 			switch (new_order.flags) {
       
   296 				case OF_PART_OF_ORDERS:
       
   297 				case OF_PART_OF_ORDERS | OF_HALT_IN_DEPOT:
       
   298 					break;
       
   299 
       
   300 				case OF_NON_STOP | OF_PART_OF_ORDERS:
       
   301 				case OF_NON_STOP | OF_PART_OF_ORDERS | OF_HALT_IN_DEPOT:
       
   302 					if (v->type != VEH_Train) return CMD_ERROR;
       
   303 					break;
       
   304 
       
   305 				default: return CMD_ERROR;
       
   306 			}
       
   307 			break;
       
   308 		}
       
   309 
       
   310 		case OT_GOTO_WAYPOINT: {
       
   311 			const Waypoint* wp;
       
   312 
       
   313 			if (v->type != VEH_Train) return CMD_ERROR;
       
   314 
       
   315 			if (!IsValidWaypointID(new_order.dest)) return CMD_ERROR;
       
   316 			wp = GetWaypoint(new_order.dest);
       
   317 
       
   318 			if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR;
       
   319 
       
   320 			/* Order flags can be any of the following for waypoints:
       
   321 			 * [non-stop]
       
   322 			 * non-stop orders (if any) are only valid for trains */
       
   323 			switch (new_order.flags) {
       
   324 				case 0: break;
       
   325 
       
   326 				case OF_NON_STOP:
       
   327 					if (v->type != VEH_Train) return CMD_ERROR;
       
   328 					break;
       
   329 
       
   330 				default: return CMD_ERROR;
       
   331 			}
       
   332 			break;
       
   333 		}
       
   334 
       
   335 		default: return CMD_ERROR;
       
   336 	}
       
   337 
       
   338 	if (sel_ord > v->num_orders) return CMD_ERROR;
       
   339 
       
   340 	if (IsOrderPoolFull()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
       
   341 
       
   342 	/* XXX - This limit is only here because the backuppedorders can't
       
   343 	 * handle any more then this.. */
       
   344 	if (v->num_orders >= MAX_BACKUP_ORDER_COUNT) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
       
   345 
       
   346 	/* For ships, make sure that the station is not too far away from the
       
   347 	 * previous destination, for human players with new pathfinding disabled */
       
   348 	if (v->type == VEH_Ship && IsHumanPlayer(v->owner) &&
       
   349 		sel_ord != 0 && GetVehicleOrder(v, sel_ord - 1)->type == OT_GOTO_STATION
       
   350 		&& !_patches.new_pathfinding_all) {
       
   351 
       
   352 		int dist = DistanceManhattan(
       
   353 			GetStation(GetVehicleOrder(v, sel_ord - 1)->dest)->xy,
       
   354 			GetStation(new_order.dest)->xy // XXX type != OT_GOTO_STATION?
       
   355 		);
       
   356 		if (dist >= 130)
       
   357 			return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
       
   358 	}
       
   359 
       
   360 	if (flags & DC_EXEC) {
       
   361 		Vehicle *u;
       
   362 		Order *new = AllocateOrder();
       
   363 		AssignOrder(new, new_order);
       
   364 
       
   365 		/* Create new order and link in list */
       
   366 		if (v->orders == NULL) {
       
   367 			v->orders = new;
       
   368 		} else {
       
   369 			/* Try to get the previous item (we are inserting above the
       
   370 			    selected) */
       
   371 			Order *order = GetVehicleOrder(v, sel_ord - 1);
       
   372 
       
   373 			if (order == NULL && GetVehicleOrder(v, sel_ord) != NULL) {
       
   374 				/* There is no previous item, so we are altering v->orders itself
       
   375 				    But because the orders can be shared, we copy the info over
       
   376 				    the v->orders, so we don't have to change the pointers of
       
   377 				    all vehicles */
       
   378 				SwapOrders(v->orders, new);
       
   379 				/* Now update the next pointers */
       
   380 				v->orders->next = new;
       
   381 			} else if (order == NULL) {
       
   382 				/* 'sel' is a non-existing order, add him to the end */
       
   383 				order = GetLastVehicleOrder(v);
       
   384 				order->next = new;
       
   385 			} else {
       
   386 				/* Put the new order in between */
       
   387 				new->next = order->next;
       
   388 				order->next = new;
       
   389 			}
       
   390 		}
       
   391 
       
   392 		u = GetFirstVehicleFromSharedList(v);
       
   393 		DeleteOrderWarnings(u);
       
   394 		for (; u != NULL; u = u->next_shared) {
       
   395 			/* Increase amount of orders */
       
   396 			u->num_orders++;
       
   397 
       
   398 			/* If the orderlist was empty, assign it */
       
   399 			if (u->orders == NULL) u->orders = v->orders;
       
   400 
       
   401 			assert(v->orders == u->orders);
       
   402 
       
   403 			/* If there is added an order before the current one, we need
       
   404 			to update the selected order */
       
   405 			if (sel_ord <= u->cur_order_index) {
       
   406 				uint cur = u->cur_order_index + 1;
       
   407 				/* Check if we don't go out of bound */
       
   408 				if (cur < u->num_orders)
       
   409 					u->cur_order_index = cur;
       
   410 			}
       
   411 			/* Update any possible open window of the vehicle */
       
   412 			InvalidateVehicleOrder(u);
       
   413 		}
       
   414 
       
   415 		/* Make sure to rebuild the whole list */
       
   416 		RebuildVehicleLists();
       
   417 	}
       
   418 
       
   419 	return 0;
       
   420 }
       
   421 
       
   422 /** Declone an order-list
       
   423  * @param *dst delete the orders of this vehicle
       
   424  * @param flags execution flags
       
   425  */
       
   426 static int32 DecloneOrder(Vehicle *dst, uint32 flags)
       
   427 {
       
   428 	if (flags & DC_EXEC) {
       
   429 		DeleteVehicleOrders(dst);
       
   430 		InvalidateVehicleOrder(dst);
       
   431 		RebuildVehicleLists();
       
   432 	}
       
   433 	return 0;
       
   434 }
       
   435 
       
   436 /** Delete an order from the orderlist of a vehicle.
       
   437  * @param tile unused
       
   438  * @param p1 the ID of the vehicle
       
   439  * @param p2 the order to delete (max 255)
       
   440  */
       
   441 int32 CmdDeleteOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   442 {
       
   443 	Vehicle *v, *u;
       
   444 	VehicleID veh_id = p1;
       
   445 	VehicleOrderID sel_ord = p2;
       
   446 	Order *order;
       
   447 
       
   448 	if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
       
   449 
       
   450 	v = GetVehicle(veh_id);
       
   451 
       
   452 	if (!CheckOwnership(v->owner)) return CMD_ERROR;
       
   453 
       
   454 	/* If we did not select an order, we maybe want to de-clone the orders */
       
   455 	if (sel_ord >= v->num_orders)
       
   456 		return DecloneOrder(v, flags);
       
   457 
       
   458 	order = GetVehicleOrder(v, sel_ord);
       
   459 	if (order == NULL) return CMD_ERROR;
       
   460 
       
   461 	if (flags & DC_EXEC) {
       
   462 		if (GetVehicleOrder(v, sel_ord - 1) == NULL) {
       
   463 			if (GetVehicleOrder(v, sel_ord + 1) != NULL) {
       
   464 				/* First item, but not the last, so we need to alter v->orders
       
   465 				    Because we can have shared order, we copy the data
       
   466 				    from the next item over the deleted */
       
   467 				order = GetVehicleOrder(v, sel_ord + 1);
       
   468 				SwapOrders(v->orders, order);
       
   469 			} else {
       
   470 				/* Last item, so clean the list */
       
   471 				v->orders = NULL;
       
   472 			}
       
   473 		} else {
       
   474 			GetVehicleOrder(v, sel_ord - 1)->next = order->next;
       
   475 		}
       
   476 
       
   477 		/* Give the item free */
       
   478 		order->type = OT_NOTHING;
       
   479 		order->next = NULL;
       
   480 
       
   481 		u = GetFirstVehicleFromSharedList(v);
       
   482 		DeleteOrderWarnings(u);
       
   483 		for (; u != NULL; u = u->next_shared) {
       
   484 			u->num_orders--;
       
   485 
       
   486 			if (sel_ord < u->cur_order_index)
       
   487 				u->cur_order_index--;
       
   488 
       
   489 			/* If we removed the last order, make sure the shared vehicles
       
   490 			 * also set their orders to NULL */
       
   491 			if (v->orders == NULL) u->orders = NULL;
       
   492 
       
   493 			assert(v->orders == u->orders);
       
   494 
       
   495 			/* NON-stop flag is misused to see if a train is in a station that is
       
   496 			 * on his order list or not */
       
   497 			if (sel_ord == u->cur_order_index && u->current_order.type == OT_LOADING &&
       
   498 					HASBIT(u->current_order.flags, OFB_NON_STOP)) {
       
   499 				u->current_order.flags = 0;
       
   500 			}
       
   501 
       
   502 			/* Update any possible open window of the vehicle */
       
   503 			InvalidateVehicleOrder(u);
       
   504 		}
       
   505 
       
   506 		RebuildVehicleLists();
       
   507 	}
       
   508 
       
   509 	return 0;
       
   510 }
       
   511 
       
   512 /** Goto next order of order-list.
       
   513  * @param tile unused
       
   514  * @param p1 The ID of the vehicle which order is skipped
       
   515  * @param p2 unused
       
   516  */
       
   517 int32 CmdSkipOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   518 {
       
   519 	Vehicle *v;
       
   520 	VehicleID veh_id = p1;
       
   521 
       
   522 	if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
       
   523 
       
   524 	v = GetVehicle(veh_id);
       
   525 
       
   526 	if (!CheckOwnership(v->owner)) return CMD_ERROR;
       
   527 
       
   528 	if (flags & DC_EXEC) {
       
   529 		/* Goto next order */
       
   530 		VehicleOrderID b = v->cur_order_index + 1;
       
   531 		if (b >= v->num_orders) b = 0;
       
   532 
       
   533 		v->cur_order_index = b;
       
   534 
       
   535 		if (v->type == VEH_Train) v->u.rail.days_since_order_progr = 0;
       
   536 
       
   537 		if (v->type == VEH_Road) ClearSlot(v);
       
   538 
       
   539 		/* NON-stop flag is misused to see if a train is in a station that is
       
   540 		 * on his order list or not */
       
   541 		if (v->current_order.type == OT_LOADING && HASBIT(v->current_order.flags, OFB_NON_STOP))
       
   542 			v->current_order.flags = 0;
       
   543 
       
   544 		InvalidateVehicleOrder(v);
       
   545 	}
       
   546 
       
   547 	/* We have an aircraft/ship, they have a mini-schedule, so update them all */
       
   548 	if (v->type == VEH_Aircraft) InvalidateWindowClasses(WC_AIRCRAFT_LIST);
       
   549 	if (v->type == VEH_Ship) InvalidateWindowClasses(WC_SHIPS_LIST);
       
   550 
       
   551 	return 0;
       
   552 }
       
   553 
       
   554 
       
   555 /** Modify an order in the orderlist of a vehicle.
       
   556  * @param tile unused
       
   557  * @param p1 various bitstuffed elements
       
   558  * - p1 = (bit  0 - 15) - ID of the vehicle
       
   559  * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
       
   560  *                        the order will be inserted before that one
       
   561  *                        only the first 8 bits used currently (bit 16 - 23) (max 255)
       
   562  * @param p2 mode to change the order to (always set)
       
   563  */
       
   564 int32 CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   565 {
       
   566 	Vehicle *v;
       
   567 	Order *order;
       
   568 	VehicleOrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
       
   569 	VehicleID veh   = GB(p1,  0, 16);
       
   570 
       
   571 	if (!IsValidVehicleID(veh)) return CMD_ERROR;
       
   572 	if (p2 != OFB_FULL_LOAD && p2 != OFB_UNLOAD && p2 != OFB_NON_STOP && p2 != OFB_TRANSFER) return CMD_ERROR;
       
   573 
       
   574 	v = GetVehicle(veh);
       
   575 
       
   576 	if (!CheckOwnership(v->owner)) return CMD_ERROR;
       
   577 
       
   578 	/* Is it a valid order? */
       
   579 	if (sel_ord >= v->num_orders) return CMD_ERROR;
       
   580 
       
   581 	order = GetVehicleOrder(v, sel_ord);
       
   582 	if (order->type != OT_GOTO_STATION &&
       
   583 			(order->type != OT_GOTO_DEPOT    || p2 == OFB_UNLOAD) &&
       
   584 			(order->type != OT_GOTO_WAYPOINT || p2 != OFB_NON_STOP)) {
       
   585 		return CMD_ERROR;
       
   586 	}
       
   587 
       
   588 	if (flags & DC_EXEC) {
       
   589 		switch (p2) {
       
   590 		case OFB_FULL_LOAD:
       
   591 			TOGGLEBIT(order->flags, OFB_FULL_LOAD);
       
   592 			if (order->type != OT_GOTO_DEPOT) CLRBIT(order->flags, OFB_UNLOAD);
       
   593 			break;
       
   594 		case OFB_UNLOAD:
       
   595 			TOGGLEBIT(order->flags, OFB_UNLOAD);
       
   596 			CLRBIT(order->flags, OFB_FULL_LOAD);
       
   597 			break;
       
   598 		case OFB_NON_STOP:
       
   599 			TOGGLEBIT(order->flags, OFB_NON_STOP);
       
   600 			break;
       
   601 		case OFB_TRANSFER:
       
   602 			TOGGLEBIT(order->flags, OFB_TRANSFER);
       
   603 			break;
       
   604 		default: NOT_REACHED();
       
   605 		}
       
   606 
       
   607 		/* Update the windows and full load flags, also for vehicles that share the same order list */
       
   608 		{
       
   609 			Vehicle* u;
       
   610 
       
   611 			u = GetFirstVehicleFromSharedList(v);
       
   612 			DeleteOrderWarnings(u);
       
   613 			for (; u != NULL; u = u->next_shared) {
       
   614 				/* Toggle u->current_order "Full load" flag if it changed.
       
   615 				 * However, as the same flag is used for depot orders, check
       
   616 				 * whether we are not going to a depot as there are three
       
   617 				 * cases where the full load flag can be active and only
       
   618 				 * one case where the flag is used for depot orders. In the
       
   619 				 * other cases for the OrderType the flags are not used,
       
   620 				 * so do not care and those orders should not be active
       
   621 				 * when this function is called.
       
   622 				 */
       
   623 				if (sel_ord == u->cur_order_index &&
       
   624 						u->current_order.type != OT_GOTO_DEPOT &&
       
   625 						HASBIT(u->current_order.flags, OFB_FULL_LOAD) != HASBIT(order->flags, OFB_FULL_LOAD)) {
       
   626 					TOGGLEBIT(u->current_order.flags, OFB_FULL_LOAD);
       
   627 				}
       
   628 				InvalidateVehicleOrder(u);
       
   629 			}
       
   630 		}
       
   631 	}
       
   632 
       
   633 	return 0;
       
   634 }
       
   635 
       
   636 /** Clone/share/copy an order-list of an other vehicle.
       
   637  * @param p1 various bitstuffed elements
       
   638  * - p1 = (bit  0-15) - destination vehicle to clone orders to (p1 & 0xFFFF)
       
   639  * - p1 = (bit 16-31) - source vehicle to clone orders from, if any (none for CO_UNSHARE)
       
   640  * @param p2 mode of cloning: CO_SHARE, CO_COPY, or CO_UNSHARE
       
   641  */
       
   642 int32 CmdCloneOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   643 {
       
   644 	Vehicle *dst;
       
   645 	VehicleID veh_src = GB(p1, 16, 16);
       
   646 	VehicleID veh_dst = GB(p1,  0, 16);
       
   647 
       
   648 	if (!IsValidVehicleID(veh_dst)) return CMD_ERROR;
       
   649 
       
   650 	dst = GetVehicle(veh_dst);
       
   651 
       
   652 	if (!CheckOwnership(dst->owner)) return CMD_ERROR;
       
   653 
       
   654 	switch (p2) {
       
   655 		case CO_SHARE: {
       
   656 			Vehicle *src;
       
   657 
       
   658 			if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
       
   659 
       
   660 			src = GetVehicle(veh_src);
       
   661 
       
   662 			/* Sanity checks */
       
   663 			if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
       
   664 				return CMD_ERROR;
       
   665 
       
   666 			/* Trucks can't share orders with busses (and visa versa) */
       
   667 			if (src->type == VEH_Road) {
       
   668 				if (src->cargo_type != dst->cargo_type && (src->cargo_type == CT_PASSENGERS || dst->cargo_type == CT_PASSENGERS))
       
   669 					return CMD_ERROR;
       
   670 			}
       
   671 
       
   672 			/* Is the vehicle already in the shared list? */
       
   673 			{
       
   674 				const Vehicle* u;
       
   675 
       
   676 				for (u = GetFirstVehicleFromSharedList(src); u != NULL; u = u->next_shared) {
       
   677 					if (u == dst) return CMD_ERROR;
       
   678 				}
       
   679 			}
       
   680 
       
   681 			if (flags & DC_EXEC) {
       
   682 				/* If the destination vehicle had a OrderList, destroy it */
       
   683 				DeleteVehicleOrders(dst);
       
   684 
       
   685 				dst->orders = src->orders;
       
   686 				dst->num_orders = src->num_orders;
       
   687 
       
   688 				/* Link this vehicle in the shared-list */
       
   689 				dst->next_shared = src->next_shared;
       
   690 				dst->prev_shared = src;
       
   691 				if (src->next_shared != NULL) src->next_shared->prev_shared = dst;
       
   692 				src->next_shared = dst;
       
   693 
       
   694 				InvalidateVehicleOrder(dst);
       
   695 				InvalidateVehicleOrder(src);
       
   696 
       
   697 				RebuildVehicleLists();
       
   698 			}
       
   699 		} break;
       
   700 
       
   701 		case CO_COPY: {
       
   702 			Vehicle *src;
       
   703 			int delta;
       
   704 
       
   705 			if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
       
   706 
       
   707 			src = GetVehicle(veh_src);
       
   708 
       
   709 			/* Sanity checks */
       
   710 			if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
       
   711 				return CMD_ERROR;
       
   712 
       
   713 			/* Trucks can't copy all the orders from busses (and visa versa) */
       
   714 			if (src->type == VEH_Road) {
       
   715 				const Order *order;
       
   716 				TileIndex required_dst = INVALID_TILE;
       
   717 
       
   718 				FOR_VEHICLE_ORDERS(src, order) {
       
   719 					if (order->type == OT_GOTO_STATION) {
       
   720 						const Station *st = GetStation(order->dest);
       
   721 						if (dst->cargo_type == CT_PASSENGERS) {
       
   722 							if (st->bus_stops != NULL) required_dst = st->bus_stops->xy;
       
   723 						} else {
       
   724 							if (st->truck_stops != NULL) required_dst = st->truck_stops->xy;
       
   725 						}
       
   726 						/* This station has not the correct road-bay, so we can't copy! */
       
   727 						if (required_dst == INVALID_TILE)
       
   728 							return CMD_ERROR;
       
   729 					}
       
   730 				}
       
   731 			}
       
   732 
       
   733 			/* make sure there are orders available */
       
   734 			delta = IsOrderListShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
       
   735 			if (!HasOrderPoolFree(delta))
       
   736 				return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
       
   737 
       
   738 			if (flags & DC_EXEC) {
       
   739 				const Order *order;
       
   740 				Order **order_dst;
       
   741 
       
   742 				/* If the destination vehicle had a OrderList, destroy it */
       
   743 				DeleteVehicleOrders(dst);
       
   744 
       
   745 				order_dst = &dst->orders;
       
   746 				FOR_VEHICLE_ORDERS(src, order) {
       
   747 					*order_dst = AllocateOrder();
       
   748 					AssignOrder(*order_dst, *order);
       
   749 					order_dst = &(*order_dst)->next;
       
   750 				}
       
   751 
       
   752 				dst->num_orders = src->num_orders;
       
   753 
       
   754 				InvalidateVehicleOrder(dst);
       
   755 
       
   756 				RebuildVehicleLists();
       
   757 			}
       
   758 		} break;
       
   759 
       
   760 		case CO_UNSHARE: return DecloneOrder(dst, flags);
       
   761 		default: return CMD_ERROR;
       
   762 	}
       
   763 
       
   764 	return 0;
       
   765 }
       
   766 
       
   767 /** Add/remove refit orders from an order
       
   768  * @param tile Not used
       
   769  * @param p1 VehicleIndex of the vehicle having the order
       
   770  * @param p2 bitmask
       
   771  *   - bit 0-7 CargoID
       
   772  *   - bit 8-15 Cargo subtype
       
   773  *   - bit 16-23 number of order to modify
       
   774  */
       
   775 int32 CmdOrderRefit(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   776 {
       
   777 	const Vehicle *v;
       
   778 	Order *order;
       
   779 	VehicleID veh = GB(p1, 0, 16);
       
   780 	VehicleOrderID order_number  = GB(p2, 16, 8);
       
   781 	CargoID cargo = GB(p2, 0, 8);
       
   782 	byte subtype  = GB(p2, 8, 8);
       
   783 
       
   784 	if (!IsValidVehicleID(veh)) return CMD_ERROR;
       
   785 
       
   786 	v = GetVehicle(veh);
       
   787 
       
   788 	if (!CheckOwnership(v->owner)) return CMD_ERROR;
       
   789 
       
   790 	order = GetVehicleOrder(v, order_number);
       
   791 	if (order == NULL) return CMD_ERROR;
       
   792 
       
   793 	if (flags & DC_EXEC) {
       
   794 		Vehicle *u;
       
   795 
       
   796 		order->refit_cargo = cargo;
       
   797 		order->refit_subtype = subtype;
       
   798 
       
   799 		u = GetFirstVehicleFromSharedList(v);
       
   800 		for (; u != NULL; u = u->next_shared) {
       
   801 			/* Update any possible open window of the vehicle */
       
   802 			InvalidateVehicleOrder(u);
       
   803 
       
   804 			/* If the vehicle already got the current depot set as current order, then update current order as well */
       
   805 			if (u->cur_order_index == order_number && HASBIT(u->current_order.flags, OFB_PART_OF_ORDERS)) {
       
   806 				u->current_order.refit_cargo = cargo;
       
   807 				u->current_order.refit_subtype = subtype;
       
   808 			}
       
   809 		}
       
   810 	}
       
   811 
       
   812 	return 0;
       
   813 }
       
   814 
       
   815 /**
       
   816  *
       
   817  * Backup a vehicle order-list, so you can replace a vehicle
       
   818  *  without loosing the order-list
       
   819  *
       
   820  */
       
   821 void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
       
   822 {
       
   823 	/* Save general info */
       
   824 	bak->orderindex       = v->cur_order_index;
       
   825 	bak->service_interval = v->service_interval;
       
   826 
       
   827 	/* Safe custom string, if any */
       
   828 	if (!IsCustomName(v->string_id)) {
       
   829 		bak->name[0] = '\0';
       
   830 	} else {
       
   831 		GetName(bak->name, v->string_id & 0x7FF, lastof(bak->name));
       
   832 	}
       
   833 
       
   834 	/* If we have shared orders, store it on a special way */
       
   835 	if (IsOrderListShared(v)) {
       
   836 		const Vehicle *u = (v->next_shared) ? v->next_shared : v->prev_shared;
       
   837 
       
   838 		bak->clone = u->index;
       
   839 	} else {
       
   840 		/* Else copy the orders */
       
   841 		Order *order, *dest;
       
   842 
       
   843 		dest = bak->order;
       
   844 
       
   845 		/* We do not have shared orders */
       
   846 		bak->clone = INVALID_VEHICLE;
       
   847 
       
   848 		/* Copy the orders */
       
   849 		FOR_VEHICLE_ORDERS(v, order) {
       
   850 			*dest = *order;
       
   851 			dest++;
       
   852 		}
       
   853 		/* End the list with an OT_NOTHING */
       
   854 		dest->type = OT_NOTHING;
       
   855 		dest->next = NULL;
       
   856 	}
       
   857 }
       
   858 
       
   859 /**
       
   860  *
       
   861  * Restore vehicle orders that are backupped via BackupVehicleOrders
       
   862  *
       
   863  */
       
   864 void RestoreVehicleOrders(const Vehicle* v, const BackuppedOrders* bak)
       
   865 {
       
   866 	uint i;
       
   867 
       
   868 	/* If we have a custom name, process that */
       
   869 	if (bak->name[0] != 0) {
       
   870 		_cmd_text = bak->name;
       
   871 		DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
       
   872 	}
       
   873 
       
   874 	/* If we had shared orders, recover that */
       
   875 	if (bak->clone != INVALID_VEHICLE) {
       
   876 		DoCommandP(0, v->index | (bak->clone << 16), 0, NULL, CMD_CLONE_ORDER);
       
   877 		return;
       
   878 	}
       
   879 
       
   880 	/* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
       
   881 	 *  order number is one more than the current amount of orders, and because
       
   882 	 *  in network the commands are queued before send, the second insert always
       
   883 	 *  fails in test mode. By bypassing the test-mode, that no longer is a problem. */
       
   884 	for (i = 0; bak->order[i].type != OT_NOTHING; i++) {
       
   885 		if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
       
   886 			break;
       
   887 	}
       
   888 
       
   889 	/* Restore vehicle order-index and service interval */
       
   890 	DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , NULL, CMD_RESTORE_ORDER_INDEX);
       
   891 }
       
   892 
       
   893 /** Restore the current order-index of a vehicle and sets service-interval.
       
   894  * @param tile unused
       
   895  * @param p1 the ID of the vehicle
       
   896  * @param p2 various bistuffed elements
       
   897  * - p2 = (bit  0-15) - current order-index (p2 & 0xFFFF)
       
   898  * - p2 = (bit 16-31) - service interval (p2 >> 16)
       
   899  * @todo Unfortunately you cannot safely restore the unitnumber or the old vehicle
       
   900  * as far as I can see. We can store it in BackuppedOrders, and restore it, but
       
   901  * but we have no way of seeing it has been tampered with or not, as we have no
       
   902  * legit way of knowing what that ID was.@n
       
   903  * If we do want to backup/restore it, just add UnitID uid to BackuppedOrders, and
       
   904  * restore it as parameter 'y' (ugly hack I know) for example. "v->unitnumber = y;"
       
   905  */
       
   906 int32 CmdRestoreOrderIndex(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   907 {
       
   908 	Vehicle *v;
       
   909 	VehicleOrderID cur_ord = GB(p2,  0, 16);
       
   910 	uint16 serv_int = GB(p2, 16, 16);
       
   911 
       
   912 	if (!IsValidVehicleID(p1)) return CMD_ERROR;
       
   913 
       
   914 	v = GetVehicle(p1);
       
   915 
       
   916 	/* Check the vehicle type and ownership, and if the service interval and order are in range */
       
   917 	if (!CheckOwnership(v->owner)) return CMD_ERROR;
       
   918 	if (serv_int != GetServiceIntervalClamped(serv_int) || cur_ord >= v->num_orders) return CMD_ERROR;
       
   919 
       
   920 	if (flags & DC_EXEC) {
       
   921 		v->cur_order_index = cur_ord;
       
   922 		v->service_interval = serv_int;
       
   923 	}
       
   924 
       
   925 	return 0;
       
   926 }
       
   927 
       
   928 
       
   929 static TileIndex GetStationTileForVehicle(const Vehicle* v, const Station* st)
       
   930 {
       
   931 	switch (v->type) {
       
   932 		default: NOT_REACHED();
       
   933 		case VEH_Train:     return st->train_tile;
       
   934 		case VEH_Aircraft:  return st->airport_tile;
       
   935 		case VEH_Ship:      return st->dock_tile;
       
   936 		case VEH_Road:
       
   937 			if (v->cargo_type == CT_PASSENGERS) {
       
   938 				return (st->bus_stops != NULL) ? st->bus_stops->xy : 0;
       
   939 			} else {
       
   940 				return (st->truck_stops != NULL) ? st->truck_stops->xy : 0;
       
   941 			}
       
   942 	}
       
   943 }
       
   944 
       
   945 
       
   946 /**
       
   947  *
       
   948  * Check the orders of a vehicle, to see if there are invalid orders and stuff
       
   949  *
       
   950  */
       
   951 void CheckOrders(const Vehicle* v)
       
   952 {
       
   953 	/* Does the user wants us to check things? */
       
   954 	if (_patches.order_review_system == 0) return;
       
   955 
       
   956 	/* Do nothing for crashed vehicles */
       
   957 	if (v->vehstatus & VS_CRASHED) return;
       
   958 
       
   959 	/* Do nothing for stopped vehicles if setting is '1' */
       
   960 	if (_patches.order_review_system == 1 && v->vehstatus & VS_STOPPED)
       
   961 		return;
       
   962 
       
   963 	/* do nothing we we're not the first vehicle in a share-chain */
       
   964 	if (v->next_shared != NULL) return;
       
   965 
       
   966 	/* Only check every 20 days, so that we don't flood the message log */
       
   967 	if (v->owner == _local_player && v->day_counter % 20 == 0) {
       
   968 		int n_st, problem_type = -1;
       
   969 		const Order *order;
       
   970 		int message = 0;
       
   971 
       
   972 		/* Check the order list */
       
   973 		n_st = 0;
       
   974 
       
   975 		FOR_VEHICLE_ORDERS(v, order) {
       
   976 			/* Dummy order? */
       
   977 			if (order->type == OT_DUMMY) {
       
   978 				problem_type = 1;
       
   979 				break;
       
   980 			}
       
   981 			/* Does station have a load-bay for this vehicle? */
       
   982 			if (order->type == OT_GOTO_STATION) {
       
   983 				const Station* st = GetStation(order->dest);
       
   984 				TileIndex required_tile = GetStationTileForVehicle(v, st);
       
   985 
       
   986 				n_st++;
       
   987 				if (required_tile == 0) problem_type = 3;
       
   988 			}
       
   989 		}
       
   990 
       
   991 		/* Check if the last and the first order are the same */
       
   992 		if (v->num_orders > 1) {
       
   993 			const Order* last = GetLastVehicleOrder(v);
       
   994 
       
   995 			if (v->orders->type  == last->type &&
       
   996 					v->orders->flags == last->flags &&
       
   997 					v->orders->dest  == last->dest) {
       
   998 				problem_type = 2;
       
   999 			}
       
  1000 		}
       
  1001 
       
  1002 		/* Do we only have 1 station in our order list? */
       
  1003 		if (n_st < 2 && problem_type == -1) problem_type = 0;
       
  1004 
       
  1005 		/* We don't have a problem */
       
  1006 		if (problem_type < 0) return;
       
  1007 
       
  1008 		message = STR_TRAIN_HAS_TOO_FEW_ORDERS + ((v->type - VEH_Train) << 2) + problem_type;
       
  1009 		//DEBUG(misc, 3, "Triggered News Item for vehicle %d", v->index);
       
  1010 
       
  1011 		SetDParam(0, v->unitnumber);
       
  1012 		AddNewsItem(
       
  1013 			message,
       
  1014 			NEWS_FLAGS(NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, 0),
       
  1015 			v->index,
       
  1016 			0
       
  1017 		);
       
  1018 	}
       
  1019 }
       
  1020 
       
  1021 /**
       
  1022  * Removes an order from all vehicles. Triggers when, say, a station is removed.
       
  1023  * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
       
  1024  * @param destination The destination. Can be a StationID, DepotID or WaypointID.
       
  1025  */
       
  1026 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
       
  1027 {
       
  1028 	Vehicle *v;
       
  1029 
       
  1030 	/* Aircraft have StationIDs for depot orders and never use DepotIDs
       
  1031 	 * This fact is handled specially below
       
  1032 	 */
       
  1033 
       
  1034 	/* Go through all vehicles */
       
  1035 	FOR_ALL_VEHICLES(v) {
       
  1036 		Order *order;
       
  1037 		bool invalidate;
       
  1038 
       
  1039 		/* Forget about this station if this station is removed */
       
  1040 		if (v->last_station_visited == destination && type == OT_GOTO_STATION) {
       
  1041 			v->last_station_visited = INVALID_STATION;
       
  1042 		}
       
  1043 
       
  1044 		order = &v->current_order;
       
  1045 		if ((v->type == VEH_Aircraft && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
       
  1046 				v->current_order.dest == destination) {
       
  1047 			order->type = OT_DUMMY;
       
  1048 			order->flags = 0;
       
  1049 			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
       
  1050 		}
       
  1051 
       
  1052 		/* Clear the order from the order-list */
       
  1053 		invalidate = false;
       
  1054 		FOR_VEHICLE_ORDERS(v, order) {
       
  1055 			if ((v->type == VEH_Aircraft && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
       
  1056 					order->dest == destination) {
       
  1057 				order->type = OT_DUMMY;
       
  1058 				order->flags = 0;
       
  1059 				invalidate = true;
       
  1060 			}
       
  1061 		}
       
  1062 
       
  1063 		/* Only invalidate once, and if needed */
       
  1064 		if (invalidate) InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
       
  1065 	}
       
  1066 }
       
  1067 
       
  1068 /**
       
  1069  *
       
  1070  * Checks if a vehicle has a GOTO_DEPOT in his order list
       
  1071  *
       
  1072  * @return True if this is true (lol ;))
       
  1073  *
       
  1074  */
       
  1075 bool VehicleHasDepotOrders(const Vehicle *v)
       
  1076 {
       
  1077 	const Order *order;
       
  1078 
       
  1079 	FOR_VEHICLE_ORDERS(v, order) {
       
  1080 		if (order->type == OT_GOTO_DEPOT)
       
  1081 			return true;
       
  1082 	}
       
  1083 
       
  1084 	return false;
       
  1085 }
       
  1086 
       
  1087 /**
       
  1088  *
       
  1089  * Delete all orders from a vehicle
       
  1090  *
       
  1091  */
       
  1092 void DeleteVehicleOrders(Vehicle *v)
       
  1093 {
       
  1094 	Order *cur, *next;
       
  1095 
       
  1096 	DeleteOrderWarnings(v);
       
  1097 
       
  1098 	/* If we have a shared order-list, don't delete the list, but just
       
  1099 	    remove our pointer */
       
  1100 	if (IsOrderListShared(v)) {
       
  1101 		const Vehicle *u = v;
       
  1102 
       
  1103 		v->orders = NULL;
       
  1104 		v->num_orders = 0;
       
  1105 
       
  1106 		/* Unlink ourself */
       
  1107 		if (v->prev_shared != NULL) {
       
  1108 			v->prev_shared->next_shared = v->next_shared;
       
  1109 			u = v->prev_shared;
       
  1110 		}
       
  1111 		if (v->next_shared != NULL) {
       
  1112 			v->next_shared->prev_shared = v->prev_shared;
       
  1113 			u = v->next_shared;
       
  1114 		}
       
  1115 		v->prev_shared = NULL;
       
  1116 		v->next_shared = NULL;
       
  1117 
       
  1118 		/* We only need to update this-one, because if there is a third
       
  1119 		 *  vehicle which shares the same order-list, nothing will change. If
       
  1120 		 *  this is the last vehicle, the last line of the order-window
       
  1121 		 *  will change from Shared order list, to Order list, so it needs
       
  1122 		 *  an update */
       
  1123 		InvalidateVehicleOrder(u);
       
  1124 		return;
       
  1125 	}
       
  1126 
       
  1127 	/* Remove the orders */
       
  1128 	cur = v->orders;
       
  1129 	v->orders = NULL;
       
  1130 	v->num_orders = 0;
       
  1131 
       
  1132 	if (cur != NULL) {
       
  1133 		/* Delete the vehicle list of shared orders, if any */
       
  1134 		int window_type = 0;
       
  1135 
       
  1136 		switch (v->type) {
       
  1137 			case VEH_Train:    window_type = WC_TRAINS_LIST;   break;
       
  1138 			case VEH_Road:     window_type = WC_ROADVEH_LIST;  break;
       
  1139 			case VEH_Ship:     window_type = WC_SHIPS_LIST;    break;
       
  1140 			case VEH_Aircraft: window_type = WC_AIRCRAFT_LIST; break;
       
  1141 			default: NOT_REACHED();
       
  1142 		}
       
  1143 		DeleteWindowById(window_type, (cur->index << 16) | (v->type << 11) | VLW_SHARED_ORDERS | v->owner);
       
  1144 	}
       
  1145 
       
  1146 	while (cur != NULL) {
       
  1147 		next = cur->next;
       
  1148 		DeleteOrder(cur);
       
  1149 		cur = next;
       
  1150 	}
       
  1151 }
       
  1152 
       
  1153 /**
       
  1154  *
       
  1155  * Check if we share our orders with an other vehicle
       
  1156  *
       
  1157  * @return Returns the vehicle who has the same order
       
  1158  *
       
  1159  */
       
  1160 bool IsOrderListShared(const Vehicle *v)
       
  1161 {
       
  1162 	return v->next_shared != NULL || v->prev_shared != NULL;
       
  1163 }
       
  1164 
       
  1165 /**
       
  1166  *
       
  1167  * Check if a vehicle has any valid orders
       
  1168  *
       
  1169  * @return false if there are no valid orders
       
  1170  *
       
  1171  */
       
  1172 bool CheckForValidOrders(const Vehicle* v)
       
  1173 {
       
  1174 	const Order *order;
       
  1175 
       
  1176 	FOR_VEHICLE_ORDERS(v, order) if (order->type != OT_DUMMY) return true;
       
  1177 
       
  1178 	return false;
       
  1179 }
       
  1180 
       
  1181 void InitializeOrders(void)
       
  1182 {
       
  1183 	CleanPool(&_Order_pool);
       
  1184 	AddBlockToPool(&_Order_pool);
       
  1185 
       
  1186 	_backup_orders_tile = 0;
       
  1187 }
       
  1188 
       
  1189 static const SaveLoad _order_desc[] = {
       
  1190 	SLE_VAR(Order, type,  SLE_UINT8),
       
  1191 	SLE_VAR(Order, flags, SLE_UINT8),
       
  1192 	SLE_VAR(Order, dest,  SLE_UINT16),
       
  1193 	SLE_REF(Order, next,  REF_ORDER),
       
  1194 	SLE_CONDVAR(Order, refit_cargo,    SLE_UINT8, 36, SL_MAX_VERSION),
       
  1195 	SLE_CONDVAR(Order, refit_subtype,  SLE_UINT8, 36, SL_MAX_VERSION),
       
  1196 
       
  1197 	/* Leftover from the minor savegame version stuff
       
  1198 	 * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
       
  1199 	SLE_CONDNULL(10, 5, 35),
       
  1200 	SLE_END()
       
  1201 };
       
  1202 
       
  1203 static void Save_ORDR(void)
       
  1204 {
       
  1205 	Order *order;
       
  1206 
       
  1207 	FOR_ALL_ORDERS(order) {
       
  1208 		SlSetArrayIndex(order->index);
       
  1209 		SlObject(order, _order_desc);
       
  1210 	}
       
  1211 }
       
  1212 
       
  1213 static void Load_ORDR(void)
       
  1214 {
       
  1215 	if (CheckSavegameVersionOldStyle(5, 2)) {
       
  1216 		/* Version older than 5.2 did not have a ->next pointer. Convert them
       
  1217 		    (in the old days, the orderlist was 5000 items big) */
       
  1218 		uint len = SlGetFieldLength();
       
  1219 		uint i;
       
  1220 
       
  1221 		if (CheckSavegameVersion(5)) {
       
  1222 			/* Pre-version 5 had an other layout for orders
       
  1223 			    (uint16 instead of uint32) */
       
  1224 			uint16 orders[5000];
       
  1225 
       
  1226 			len /= sizeof(uint16);
       
  1227 			assert (len <= lengthof(orders));
       
  1228 
       
  1229 			SlArray(orders, len, SLE_UINT16);
       
  1230 
       
  1231 			for (i = 0; i < len; ++i) {
       
  1232 				if (!AddBlockIfNeeded(&_Order_pool, i))
       
  1233 					error("Orders: failed loading savegame: too many orders");
       
  1234 
       
  1235 				AssignOrder(GetOrder(i), UnpackVersion4Order(orders[i]));
       
  1236 			}
       
  1237 		} else if (CheckSavegameVersionOldStyle(5, 2)) {
       
  1238 			uint32 orders[5000];
       
  1239 
       
  1240 			len /= sizeof(uint32);
       
  1241 			assert (len <= lengthof(orders));
       
  1242 
       
  1243 			SlArray(orders, len, SLE_UINT32);
       
  1244 
       
  1245 			for (i = 0; i < len; ++i) {
       
  1246 				if (!AddBlockIfNeeded(&_Order_pool, i))
       
  1247 					error("Orders: failed loading savegame: too many orders");
       
  1248 
       
  1249 				AssignOrder(GetOrder(i), UnpackOrder(orders[i]));
       
  1250 			}
       
  1251 		}
       
  1252 
       
  1253 		/* Update all the next pointer */
       
  1254 		for (i = 1; i < len; ++i) {
       
  1255 			/* The orders were built like this:
       
  1256 			 *   Vehicle one had order[0], and as long as order++.type was not
       
  1257 			 *   OT_NOTHING, it was part of the order-list of that vehicle */
       
  1258 			if (GetOrder(i)->type != OT_NOTHING)
       
  1259 				GetOrder(i - 1)->next = GetOrder(i);
       
  1260 		}
       
  1261 	} else {
       
  1262 		int index;
       
  1263 
       
  1264 		while ((index = SlIterateArray()) != -1) {
       
  1265 			Order *order;
       
  1266 
       
  1267 			if (!AddBlockIfNeeded(&_Order_pool, index))
       
  1268 				error("Orders: failed loading savegame: too many orders");
       
  1269 
       
  1270 			order = GetOrder(index);
       
  1271 			SlObject(order, _order_desc);
       
  1272 		}
       
  1273 	}
       
  1274 }
       
  1275 
       
  1276 const ChunkHandler _order_chunk_handlers[] = {
       
  1277 	{ 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY | CH_LAST},
       
  1278 };