order_cmd.c
changeset 1024 5e446b5b3ec5
parent 1020 59ee8ceac74c
child 1043 44508ede2f92
equal deleted inserted replaced
1023:1ae7b7a78602 1024:5e446b5b3ec5
     4 #include "vehicle.h"
     4 #include "vehicle.h"
     5 #include "command.h"
     5 #include "command.h"
     6 #include "station.h"
     6 #include "station.h"
     7 #include "player.h"
     7 #include "player.h"
     8 #include "news.h"
     8 #include "news.h"
     9 
     9 #include "saveload.h"
    10 /* p1 & 0xFFFF = vehicle
    10 
    11  * p1 >> 16 = index in order list
    11 /**
    12  * p2 = order command to insert
    12  *
    13  */
    13  * Unpacks a order from savegames made with TTD(Patch)
    14 int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
    14  *
    15 {
    15  */
    16 	Vehicle *v = GetVehicle(p1 & 0xFFFF);
    16 Order UnpackOldOrder(uint16 packed)
    17 	int sel = p1 >> 16;
    17 {
    18 	Order new_order = UnpackOrder(p2);
    18 	Order order;
    19 
    19 	order.type    = (packed & 0x000F);
    20 	if (sel > v->num_orders) return_cmd_error(STR_EMPTY);
    20 	order.flags   = (packed & 0x00F0) >> 4;
    21 	if (_ptr_to_next_order == endof(_order_array)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
    21 	order.station = (packed & 0xFF00) >> 8;
    22 	if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
    22 	order.next    = NULL;
    23 
    23 
    24 	// for ships, make sure that the station is not too far away from the previous destination.
    24 	// Sanity check
       
    25 	// TTD stores invalid orders as OT_NOTHING with non-zero flags/station
       
    26 	if (order.type == OT_NOTHING && (order.flags != 0 || order.station != 0)) {
       
    27 		order.type = OT_DUMMY;
       
    28 		order.flags = 0;
       
    29 	}
       
    30 
       
    31 	return order;
       
    32 }
       
    33 
       
    34 /**
       
    35  *
       
    36  * Unpacks a order from savegames with version 4 and lower
       
    37  *
       
    38  */
       
    39 Order UnpackVersion4Order(uint16 packed)
       
    40 {
       
    41 	Order order;
       
    42 	order.type    = (packed & 0x000F);
       
    43 	order.flags   = (packed & 0x00F0) >> 4;
       
    44 	order.station = (packed & 0xFF00) >> 8;
       
    45 	order.next    = NULL;
       
    46 	return order;
       
    47 }
       
    48 
       
    49 /**
       
    50  *
       
    51  * Updates the widgets of a vehicle which contains the order-data
       
    52  *
       
    53  */
       
    54 void InvalidateVehicleOrder(const Vehicle *v)
       
    55 {
       
    56 	InvalidateWindow(WC_VEHICLE_VIEW,   v->index);
       
    57 	InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
       
    58 }
       
    59 
       
    60 /**
       
    61  *
       
    62  * Swap two orders
       
    63  *
       
    64  */
       
    65 static void SwapOrders(Order *order1, Order *order2)
       
    66 {
       
    67 	Order temp_order;
       
    68 
       
    69 	temp_order = *order1;
       
    70 	*order1 = *order2;
       
    71 	*order2 = temp_order;
       
    72 }
       
    73 
       
    74 /**
       
    75  *
       
    76  * Allocate a new order
       
    77  *
       
    78  * @return Order* if a free space is found, else NULL.
       
    79  *
       
    80  */
       
    81 static Order *AllocateOrder()
       
    82 {
       
    83 	Order *order;
       
    84 
       
    85 	FOR_ALL_ORDERS(order) {
       
    86 		if (order->type == OT_NOTHING) {
       
    87 			uint index = order->index;
       
    88 			memset(order, 0, sizeof(Order));
       
    89 			order->index = index;
       
    90 			return order;
       
    91 		}
       
    92 	}
       
    93 
       
    94 	return NULL;
       
    95 }
       
    96 
       
    97 /**
       
    98  *
       
    99  * Assign data to an order (from an other order)
       
   100  *   This function makes sure that the index is maintained correctly
       
   101  *
       
   102  */
       
   103 void AssignOrder(Order *order, Order data)
       
   104 {
       
   105 	order->type    = data.type;
       
   106 	order->flags   = data.flags;
       
   107 	order->station = data.station;
       
   108 }
       
   109 
       
   110 /**
       
   111  *
       
   112  * Add an order to the orderlist of a vehicle
       
   113  *
       
   114  * @param veh_sel      First 16 bits are the ID of the vehicle. The next 16 are the selected order (if any)
       
   115  *                       If the lastone is given, order will be inserted above thatone
       
   116  * @param packed_order Packed order to insert
       
   117  *
       
   118  */
       
   119 int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 veh_sel, uint32 packed_order)
       
   120 {
       
   121 	Vehicle *v      = GetVehicle(veh_sel & 0xFFFF);
       
   122 	int sel         = veh_sel >> 16;
       
   123 	Order new_order = UnpackOrder(packed_order);
       
   124 
       
   125 	if (sel > v->num_orders)
       
   126 		return_cmd_error(STR_EMPTY);
       
   127 
       
   128 	if (IsOrderPoolFull())
       
   129 		return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
       
   130 
       
   131 	/* XXX - This limit is only here because the backuppedorders can't
       
   132 	    handle any more then this.. */
       
   133 	if (v->num_orders >= 40)
       
   134 		return_cmd_error(STR_8832_TOO_MANY_ORDERS);
       
   135 
       
   136 	/* For ships, make sure that the station is not too far away from the previous destination. */
    25 	if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) &&
   137 	if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) &&
    26 			sel != 0 && v->schedule_ptr[sel - 1].type == OT_GOTO_STATION) {
   138 		sel != 0 && GetVehicleOrder(v, sel - 1)->type == OT_GOTO_STATION) {
    27 
   139 
    28 		int dist = GetTileDist(
   140 		int dist = GetTileDist(
    29 			GetStation(v->schedule_ptr[sel - 1].station)->xy,
   141 			GetStation(GetVehicleOrder(v, sel - 1)->station)->xy,
    30 			GetStation(new_order.station)->xy
   142 			GetStation(new_order.station)->xy
    31 		);
   143 		);
    32 		if (dist >= 130)
   144 		if (dist >= 130)
    33 			return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
   145 			return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
    34 	}
   146 	}
    35 
   147 
    36 	if (flags & DC_EXEC) {
   148 	if (flags & DC_EXEC) {
    37 		Order *s1;
   149 		Order *new;
    38 		Order *s2;
       
    39 		Vehicle *u;
   150 		Vehicle *u;
    40 
   151 
    41 		s1 = &v->schedule_ptr[sel];
   152 		new = AllocateOrder();
    42 		s2 = _ptr_to_next_order++;
   153 		AssignOrder(new, new_order);
    43 		do s2[1] = s2[0]; while (--s2 >= s1);
   154 
    44 		*s1 = new_order;
   155 		/* Create new order and link in list */
    45 
   156 		if (v->orders == NULL) {
    46 		s1 = v->schedule_ptr;
   157 			v->orders = new;
    47 
   158 		} else {
    48 		FOR_ALL_VEHICLES(u) {
   159 			/* Try to get the previous item (we are inserting above the
    49 			if (u->type != 0 && u->schedule_ptr != NULL) {
   160 			    selected) */
    50 				if (s1 < u->schedule_ptr) {
   161 			Order *order = GetVehicleOrder(v, sel - 1);
    51 					u->schedule_ptr++;
   162 
    52 				} else if (s1 == u->schedule_ptr) { // handle shared orders
   163 			if (order == NULL && GetVehicleOrder(v, sel) != NULL) {
    53 					u->num_orders++;
   164 				/* There is no previous item, so we are altering v->orders itself
    54 
   165 				    But because the orders can be shared, we copy the info over
    55 					if ((byte)sel <= u->cur_order_index) {
   166 				    the v->orders, so we don't have to change the pointers of
    56 						sel++;
   167 				    all vehicles */
    57 						if ((byte)sel < u->num_orders)
   168 				SwapOrders(v->orders, new);
    58 							u->cur_order_index = sel;
   169 				/* Now update the next pointers */
    59 					}
   170 				v->orders->next = new;
    60 					InvalidateWindow(WC_VEHICLE_VIEW, u->index);
   171 			} else if (order == NULL) {
    61 					InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
   172 				/* 'sel' is a non-existing order, add him to the end */
    62 				}
   173 				order = GetLastVehicleOrder(v);
    63 			}
   174 				order->next = new;
    64 		}
   175 			} else {
    65 
   176 				/* Put the new order in between */
       
   177 				new->next = order->next;
       
   178 				order->next = new;
       
   179 			}
       
   180 		}
       
   181 
       
   182 		u = GetFirstVehicleFromSharedList(v);
       
   183 		while (u != NULL) {
       
   184 			/* Increase amount of orders */
       
   185 			u->num_orders++;
       
   186 
       
   187 			/* If the orderlist was empty, assign it */
       
   188 			if (u->orders == NULL)
       
   189 				u->orders = v->orders;
       
   190 
       
   191 			assert(v->orders == u->orders);
       
   192 
       
   193 			/* If there is added an order before the current one, we need
       
   194 			to update the selected order */
       
   195 			if (sel <= u->cur_order_index) {
       
   196 				uint cur = u->cur_order_index + 1;
       
   197 				/* Check if we don't go out of bound */
       
   198 				if (cur < u->num_orders)
       
   199 					u->cur_order_index = cur;
       
   200 			}
       
   201 			/* Update any possible open window of the vehicle */
       
   202 			InvalidateVehicleOrder(u);
       
   203 
       
   204 			u = u->next_shared;
       
   205 		}
       
   206 
       
   207 		/* Make sure to rebuild the whole list */
    66 		RebuildVehicleLists();
   208 		RebuildVehicleLists();
    67 	}
   209 	}
    68 
   210 
    69 	return 0;
   211 	return 0;
    70 }
   212 }
    71 
   213 
       
   214 /**
       
   215  *
       
   216  * Declone an order-list
       
   217  *
       
   218  */
    72 static int32 DecloneOrder(Vehicle *dst, uint32 flags)
   219 static int32 DecloneOrder(Vehicle *dst, uint32 flags)
    73 {
   220 {
    74 	if (_ptr_to_next_order == endof(_order_array))
       
    75 		return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
       
    76 
       
    77 	if (flags & DC_EXEC) {
   221 	if (flags & DC_EXEC) {
    78 		DeleteVehicleSchedule(dst);
   222 		/* Delete orders from vehicle */
    79 
   223 		DeleteVehicleOrders(dst);
    80 		dst->num_orders = 0;
   224 
    81 		_ptr_to_next_order->type = OT_NOTHING;
   225 		InvalidateVehicleOrder(dst);
    82 		_ptr_to_next_order->flags = 0;
       
    83 		dst->schedule_ptr = _ptr_to_next_order++;
       
    84 
       
    85 		InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
       
    86 
       
    87 		RebuildVehicleLists();
   226 		RebuildVehicleLists();
    88 	}
   227 	}
    89 	return 0;
   228 	return 0;
    90 }
   229 }
    91 
   230 
    92 /* p1 = vehicle
   231 /**
    93  * p2 = sel
   232  *
    94  */
   233  * Delete an order from the orderlist of a vehicle
    95 int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   234  *
    96 {
   235  * @param vehicle_id The ID of the vehicle
    97 	Vehicle *v = GetVehicle(p1), *u;
   236  * @param selected   The order to delete
    98 	uint sel = (uint)p2;
   237  *
    99 
   238  */
       
   239 int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 vehicle_id, uint32 selected)
       
   240 {
       
   241 	Vehicle *v = GetVehicle(vehicle_id), *u;
       
   242 	uint sel   = selected;
       
   243 	Order *order;
       
   244 
       
   245 	/* XXX -- Why is this here? :s */
   100 	_error_message = STR_EMPTY;
   246 	_error_message = STR_EMPTY;
       
   247 
       
   248 	/* If we did not select an order, we maybe want to de-clone the orders */
   101 	if (sel >= v->num_orders)
   249 	if (sel >= v->num_orders)
   102 		return DecloneOrder(v, flags);
   250 		return DecloneOrder(v, flags);
   103 
   251 
       
   252 	order = GetVehicleOrder(v, sel);
       
   253 	if (order == NULL)
       
   254 		return CMD_ERROR;
       
   255 
   104 	if (flags & DC_EXEC) {
   256 	if (flags & DC_EXEC) {
   105 		Order *s1 = &v->schedule_ptr[sel];
   257 		if (GetVehicleOrder(v, sel - 1) == NULL) {
   106 
   258 			if (GetVehicleOrder(v, sel + 1) != NULL) {
   107 		// copy all orders to get rid of the hole
   259 				/* First item, but not the last, so we need to alter v->orders
   108 		do s1[0] = s1[1]; while (++s1 != _ptr_to_next_order);
   260 				    Because we can have shared order, we copy the data
   109 		_ptr_to_next_order--;
   261 				    from the next item over the deleted */
   110 
   262 				order = GetVehicleOrder(v, sel + 1);
   111 		s1 = v->schedule_ptr;
   263 				SwapOrders(v->orders, order);
   112 
   264 			} else {
   113 		FOR_ALL_VEHICLES(u) {
   265 				/* Last item, so clean the list */
   114 			if (u->type != 0 && u->schedule_ptr != NULL) {
   266 				v->orders = NULL;
   115 				if (s1 < u->schedule_ptr) {
   267 			}
   116 					u->schedule_ptr--;
   268 		} else {
   117 				} else if (s1 == u->schedule_ptr) {// handle shared orders
   269 			GetVehicleOrder(v, sel - 1)->next = order->next;
   118 					u->num_orders--;
   270 		}
   119 					if ((byte)sel < u->cur_order_index)
   271 
   120 						u->cur_order_index--;
   272 		/* Give the item free */
   121 
   273 		order->type = OT_NOTHING;
   122 					if ((byte)sel == u->cur_order_index &&
   274 
   123 							u->current_order.type == OT_LOADING &&
   275 		u = GetFirstVehicleFromSharedList(v);
   124 							u->current_order.flags & OF_NON_STOP) {
   276 		while (u != NULL) {
   125 						u->current_order.flags = 0;
   277 			u->num_orders--;
   126 					}
   278 
   127 
   279 			if (sel < u->cur_order_index)
   128 					InvalidateWindow(WC_VEHICLE_VIEW, u->index);
   280 				u->cur_order_index--;
   129 					InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
   281 
   130 				}
   282 			/* If we removed the last order, make sure the shared vehicles
   131 			}
   283 			    also set their orders to NULL */
       
   284 			if (v->orders == NULL)
       
   285 				u->orders = NULL;
       
   286 
       
   287 			assert(v->orders == u->orders);
       
   288 
       
   289 			/* NON-stop flag is misused to see if a train is in a station that is
       
   290 			    on his order list or not */
       
   291 			if (sel == u->cur_order_index &&
       
   292 					u->current_order.type == OT_LOADING &&
       
   293 					HASBIT(u->current_order.flags, OFB_NON_STOP)) {
       
   294 				u->current_order.flags = 0;
       
   295 			}
       
   296 
       
   297 			/* Update any possible open window of the vehicle */
       
   298 			InvalidateVehicleOrder(u);
       
   299 
       
   300 			u = u->next_shared;
   132 		}
   301 		}
   133 
   302 
   134 		RebuildVehicleLists();
   303 		RebuildVehicleLists();
   135 	}
   304 	}
   136 
   305 
   137 	return 0;
   306 	return 0;
   138 }
   307 }
   139 
   308 
   140 /* p1 = vehicle */
   309 /**
   141 int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   310  *
   142 {
   311  * Goto next order of order-list
   143 	Vehicle *v = GetVehicle(p1);
   312  *
       
   313  * @param vehicle_id The ID of the vehicle
       
   314  *
       
   315  */
       
   316 int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 vehicle_id, uint32 not_used)
       
   317 {
       
   318 	Vehicle *v = GetVehicle(vehicle_id);
   144 
   319 
   145 	if (flags & DC_EXEC) {
   320 	if (flags & DC_EXEC) {
       
   321 		/* Goto next order */
   146 		{
   322 		{
   147 			byte b = v->cur_order_index + 1;
   323 			byte b = v->cur_order_index + 1;
   148 			if (b >= v->num_orders) b = 0;
   324 			if (b >= v->num_orders)
       
   325 				b = 0;
       
   326 
   149 			v->cur_order_index = b;
   327 			v->cur_order_index = b;
   150 
   328 
   151 			if (v->type == VEH_Train)
   329 			if (v->type == VEH_Train)
   152 				v->u.rail.days_since_order_progr = 0;
   330 				v->u.rail.days_since_order_progr = 0;
   153 		}
   331 		}
   154 
   332 
       
   333 		/* NON-stop flag is misused to see if a train is in a station that is
       
   334 		    on his order list or not */
   155 		if (v->current_order.type == OT_LOADING &&
   335 		if (v->current_order.type == OT_LOADING &&
   156 				v->current_order.flags & OF_NON_STOP) {
   336 				HASBIT(v->current_order.flags, OFB_NON_STOP)) {
   157 			v->current_order.flags = 0;
   337 			v->current_order.flags = 0;
   158 		}
   338 		}
   159 
   339 
   160 		InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
   340 		InvalidateVehicleOrder(v);
   161 	}
   341 	}
   162 
   342 
   163 	//we have an aircraft, they have a mini-schedule, so update them all
   343 	/* We have an aircraft/ship, they have a mini-schedule, so update them all */
   164 	if (v->type == VEH_Aircraft) InvalidateAircraftWindows(v);
   344 	if (v->type == VEH_Aircraft) InvalidateAircraftWindows(v);
   165 
       
   166 	//same goes for ships
       
   167 	if (v->type == VEH_Ship) InvalidateShipWindows(v);
   345 	if (v->type == VEH_Ship) InvalidateShipWindows(v);
   168 
   346 
   169 	return 0;
   347 	return 0;
   170 }
   348 }
   171 
   349 
   172 /* p1 = vehicle
   350 
   173  * p2&0xFF = sel
   351 /**
   174  * p2>>8 = mode
   352  *
   175  */
   353  * Add an order to the orderlist of a vehicle
   176 int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   354  *
   177 {
   355  * @param veh_sel      First 16 bits are the ID of the vehicle. The next 16 are the selected order (if any)
   178 	Vehicle *v = GetVehicle(p1);
   356  *                       If the lastone is given, order will be inserted above thatone
   179 	byte sel = (byte)p2;
   357  * @param mode         Mode to change the order to
   180 	Order *sched;
   358  *
   181 
   359  */
       
   360 int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 veh_sel, uint32 mode)
       
   361 {
       
   362 	Vehicle *v = GetVehicle(veh_sel & 0xFFFF);
       
   363 	byte sel = veh_sel >> 16;
       
   364 	Order *order;
       
   365 
       
   366 	/* Is it a valid order? */
   182 	if (sel >= v->num_orders)
   367 	if (sel >= v->num_orders)
   183 		return CMD_ERROR;
   368 		return CMD_ERROR;
   184 
   369 
   185 	sched = &v->schedule_ptr[sel];
   370 	order = GetVehicleOrder(v, sel);
   186 	if (sched->type != OT_GOTO_STATION &&
   371 	if (order->type != OT_GOTO_STATION &&
   187 			(sched->type != OT_GOTO_DEPOT || (p2 >> 8) == 1) &&
   372 			(order->type != OT_GOTO_DEPOT || mode == OFB_UNLOAD) &&
   188 			(sched->type != OT_GOTO_WAYPOINT || (p2 >> 8) != 2))
   373 			(order->type != OT_GOTO_WAYPOINT || mode != OFB_NON_STOP))
   189 		return CMD_ERROR;
   374 		return CMD_ERROR;
   190 
   375 
   191 	if (flags & DC_EXEC) {
   376 	if (flags & DC_EXEC) {
   192 		switch (p2 >> 8) {
   377 		switch (mode) {
   193 		case 0: // full load
   378 		case OFB_FULL_LOAD:
   194 			sched->flags ^= OF_FULL_LOAD;
   379 			TOGGLEBIT(order->flags, OFB_FULL_LOAD);
   195 			if (sched->type != OT_GOTO_DEPOT) sched->flags &= ~OF_UNLOAD;
   380 			if (order->type != OT_GOTO_DEPOT)
       
   381 				CLRBIT(order->flags, OFB_UNLOAD);
   196 			break;
   382 			break;
   197 		case 1: // unload
   383 		case OFB_UNLOAD:
   198 			sched->flags ^= OF_UNLOAD;
   384 			TOGGLEBIT(order->flags, OFB_UNLOAD);
   199 			sched->flags &= ~OF_FULL_LOAD;
   385 			CLRBIT(order->flags, OFB_FULL_LOAD);
   200 			break;
   386 			break;
   201 		case 2: // non stop
   387 		case OFB_NON_STOP:
   202 			sched->flags ^= OF_NON_STOP;
   388 			TOGGLEBIT(order->flags, OFB_NON_STOP);
   203 			break;
   389 			break;
   204 		}
   390 		}
   205 		sched = v->schedule_ptr;
   391 
   206 
   392 		/* Update the windows, also for vehicles that share the same order list */
   207 		FOR_ALL_VEHICLES(v) {
   393 		{
   208 			if (v->schedule_ptr == sched)
   394 			Vehicle *u = GetFirstVehicleFromSharedList(v);
   209 				InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
   395 			while (u != NULL) {
   210 		}
   396 				InvalidateVehicleOrder(u);
   211 
   397 				u = u->next_shared;
       
   398 			}
       
   399 		}
   212 	}
   400 	}
   213 
   401 
   214 	return 0;
   402 	return 0;
   215 }
   403 }
   216 
   404 
   217 // Clone an order
   405 /**
   218 // p1 & 0xFFFF is destination vehicle
   406  *
   219 // p1 >> 16 is source vehicle
   407  * Clone/share/copy an order-list of an other vehicle
   220 
   408  *
   221 // p2 is
   409  * @param veh1_veh2 First 16 bits are of destination vehicle, last 16 of source vehicle
   222 //   0 - clone
   410  * @param mode      Mode of cloning (CO_SHARE, CO_COPY, CO_UNSHARE)
   223 //   1 - copy
   411  *
   224 //   2 - unclone
   412  */
   225 
   413 int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 veh1_veh2, uint32 mode)
   226 
   414 {
   227 int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   415 	Vehicle *dst = GetVehicle(veh1_veh2 & 0xFFFF);
   228 {
   416 
   229 	Vehicle *dst = GetVehicle(p1 & 0xFFFF);
   417 	if (dst->type == 0 || dst->owner != _current_player)
   230 
       
   231 	if (!(dst->type && dst->owner == _current_player))
       
   232 		return CMD_ERROR;
   418 		return CMD_ERROR;
   233 
   419 
   234 	switch(p2) {
   420 	switch(mode) {
   235 
   421 		case CO_SHARE: {
   236 	// share vehicle orders?
   422 			Vehicle *src = GetVehicle(veh1_veh2 >> 16);
   237 	case 0: {
   423 
   238 		Vehicle *src = GetVehicle(p1 >> 16);
   424 			/* Sanity checks */
   239 
   425 			if (src->type == 0 || src->owner != _current_player || dst->type != src->type || dst == src)
   240 		// sanity checks
       
   241 		if (!(src->owner == _current_player && dst->type == src->type && dst != src))
       
   242 			return CMD_ERROR;
       
   243 
       
   244 		// let's see what happens with road vehicles
       
   245 		if (src->type == VEH_Road) {
       
   246 			if (src->cargo_type != dst->cargo_type && (src->cargo_type == CT_PASSENGERS || dst->cargo_type == CT_PASSENGERS))
       
   247 				return CMD_ERROR;
   426 				return CMD_ERROR;
   248 		}
   427 
   249 
   428 			/* Trucks can't share orders with busses (and visa versa) */
   250 		if (flags & DC_EXEC) {
   429 			if (src->type == VEH_Road) {
   251 			DeleteVehicleSchedule(dst);
   430 				if (src->cargo_type != dst->cargo_type && (src->cargo_type == CT_PASSENGERS || dst->cargo_type == CT_PASSENGERS))
   252 			dst->schedule_ptr = src->schedule_ptr;
   431 					return CMD_ERROR;
   253 			dst->num_orders = src->num_orders;
   432 			}
   254 
   433 
   255 			InvalidateWindow(WC_VEHICLE_ORDERS, src->index);
   434 			/* Is the vehicle already in the shared list? */
   256 			InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
   435 			{
   257 
   436 				Vehicle *u = GetFirstVehicleFromSharedList(src);
   258 			RebuildVehicleLists();
   437 				while (u != NULL) {
   259 		}
   438 					if (u == dst)
   260 		break;
       
   261 	}
       
   262 
       
   263 	// copy vehicle orders?
       
   264 	case 1: {
       
   265 		Vehicle *src = GetVehicle(p1 >> 16);
       
   266 		int delta;
       
   267 
       
   268 		// sanity checks
       
   269 		if (!(src->owner == _current_player && dst->type == src->type && dst != src))
       
   270 			return CMD_ERROR;
       
   271 
       
   272 		// let's see what happens with road vehicles
       
   273 		if (src->type == VEH_Road) {
       
   274 			const Order *i;
       
   275 			TileIndex required_dst;
       
   276 
       
   277 			for (i = src->schedule_ptr; i->type != OT_NOTHING; ++i) {
       
   278 				if (i->type == OT_GOTO_STATION) {
       
   279 					const Station *st = GetStation(i->station);
       
   280 					required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile;
       
   281 					if ( !required_dst )
       
   282 						return CMD_ERROR;
   439 						return CMD_ERROR;
       
   440 					u = u->next_shared;
   283 				}
   441 				}
   284 			}
   442 			}
   285 		}
   443 
   286 
   444 			if (flags & DC_EXEC) {
   287 		// make sure there's orders available
   445 				/* If the destination vehicle had a OrderList, destroy it */
   288 		delta = IsScheduleShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
   446 				DeleteVehicleOrders(dst);
   289 		if (delta > endof(_order_array) - _ptr_to_next_order)
   447 
   290 			return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
   448 				dst->orders = src->orders;
   291 
   449 				dst->num_orders = src->num_orders;
   292 		if (flags & DC_EXEC) {
   450 
   293 			DeleteVehicleSchedule(dst);
   451 				/* Link this vehicle in the shared-list */
   294 			dst->schedule_ptr = _ptr_to_next_order;
   452 				dst->next_shared = src->next_shared;
   295 			dst->num_orders = src->num_orders;
   453 				dst->prev_shared = src;
   296 			_ptr_to_next_order += src->num_orders + 1;
   454 				if (src->next_shared != NULL)
   297 			memcpy(dst->schedule_ptr, src->schedule_ptr, (src->num_orders + 1) * sizeof(Order));
   455 					src->next_shared->prev_shared = dst;
   298 
   456 				src->next_shared = dst;
   299 			InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
   457 
   300 
   458 				InvalidateVehicleOrder(dst);
   301 			RebuildVehicleLists();
   459 				InvalidateVehicleOrder(src);
   302 		}
   460 
   303 		break;
   461 				RebuildVehicleLists();
   304 	}
   462 			}
   305 
   463 		} break;
   306 	// declone vehicle orders?
   464 
   307 	case 2: return DecloneOrder(dst, flags);
   465 		case CO_COPY: {
       
   466 			Vehicle *src = GetVehicle(veh1_veh2 >> 16);
       
   467 			int delta;
       
   468 
       
   469 			/* Sanity checks */
       
   470 			if (src->type == 0 || src->owner != _current_player || dst->type != src->type || dst == src)
       
   471 				return CMD_ERROR;
       
   472 
       
   473 			/* Trucks can't copy all the orders from busses (and visa versa) */
       
   474 			if (src->type == VEH_Road) {
       
   475 				const Order *order;
       
   476 				TileIndex required_dst;
       
   477 
       
   478 				FOR_VEHICLE_ORDERS(src, order) {
       
   479 					if (order->type == OT_GOTO_STATION) {
       
   480 						const Station *st = GetStation(order->station);
       
   481 						required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile;
       
   482 						/* This station has not the correct road-bay, so we can't copy! */
       
   483 						if (!required_dst)
       
   484 							return CMD_ERROR;
       
   485 					}
       
   486 				}
       
   487 			}
       
   488 
       
   489 			/* make sure there are orders available */
       
   490 			delta = IsOrderListShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
       
   491 			if (!HasOrderPoolFree(delta))
       
   492 				return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
       
   493 
       
   494 			if (flags & DC_EXEC) {
       
   495 				const Order *order;
       
   496 				Order **order_dst;
       
   497 
       
   498 				/* If the destination vehicle had a OrderList, destroy it */
       
   499 				DeleteVehicleOrders(dst);
       
   500 
       
   501 				order_dst = &dst->orders;
       
   502 				FOR_VEHICLE_ORDERS(src, order) {
       
   503 					*order_dst = AllocateOrder();
       
   504 					AssignOrder(*order_dst, *order);
       
   505 					order_dst = &(*order_dst)->next;
       
   506 				}
       
   507 
       
   508 				dst->num_orders = src->num_orders;
       
   509 
       
   510 				InvalidateVehicleOrder(dst);
       
   511 
       
   512 				RebuildVehicleLists();
       
   513 			}
       
   514 		} break;
       
   515 
       
   516 		case CO_UNSHARE:
       
   517 			return DecloneOrder(dst, flags);
   308 	}
   518 	}
   309 
   519 
   310 	return 0;
   520 	return 0;
   311 }
   521 }
   312 
   522 
       
   523 /**
       
   524  *
       
   525  * Backup a vehicle order-list, so you can replace a vehicle
       
   526  *  without loosing the order-list
       
   527  *
       
   528  */
   313 void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak)
   529 void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak)
   314 {
   530 {
   315 	Vehicle *u = IsScheduleShared(v);
   531 	bool shared = IsOrderListShared(v);
   316 
   532 
   317 	bak->orderindex = v->cur_order_index;
   533 	/* Save general info */
       
   534 	bak->orderindex       = v->cur_order_index;
   318 	bak->service_interval = v->service_interval;
   535 	bak->service_interval = v->service_interval;
   319 
   536 
       
   537 	/* Safe custom string, if any */
   320 	if ((v->string_id & 0xF800) != 0x7800) {
   538 	if ((v->string_id & 0xF800) != 0x7800) {
   321 		bak->name[0] = 0;
   539 		bak->name[0] = 0;
   322 	} else {
   540 	} else {
   323 		GetName(v->string_id & 0x7FF, bak->name);
   541 		GetName(v->string_id & 0x7FF, bak->name);
   324 	}
   542 	}
   325 
   543 
   326 	// stored shared orders in this special way?
   544 	/* If we have shared orders, store it on a special way */
   327 	if (u != NULL) {
   545 	if (shared) {
       
   546 		Vehicle *u;
       
   547 		if (v->next_shared)
       
   548 			u = v->next_shared;
       
   549 		else
       
   550 			u = v->prev_shared;
       
   551 
   328 		bak->clone = u->index;
   552 		bak->clone = u->index;
   329 	} else {
   553 	} else {
   330 		Order *sched = v->schedule_ptr;
   554 		/* Else copy the orders */
   331 		Order *os = bak->order;
   555 		Order *order, *dest;
   332 
   556 
       
   557 		dest  = bak->order;
       
   558 
       
   559 		/* We do not have shared orders */
   333 		bak->clone = INVALID_VEHICLE;
   560 		bak->clone = INVALID_VEHICLE;
   334 
   561 
   335 		do {
   562 		/* Copy the orders */
   336 			*os++ = *sched++;
   563 		FOR_VEHICLE_ORDERS(v, order) {
   337 		} while (sched->type != OT_NOTHING);
   564 			*dest = *order;
   338 		/* Make sure the last item is OT_NOTHING */
   565 			dest++;
   339 		os->type = OT_NOTHING;
   566 		}
   340 	}
   567 		/* End the list with an OT_NOTHING */
   341 }
   568 		dest->type = OT_NOTHING;
   342 
   569 	}
       
   570 }
       
   571 
       
   572 /**
       
   573  *
       
   574  * Restore vehicle orders that are backupped via BackupVehicleOrders
       
   575  *
       
   576  */
   343 void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
   577 void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
   344 {
   578 {
   345 	int i;
   579 	int i;
   346 
   580 
   347 	if (bak->name[0]) {
   581 	/* If we have a custom name, process that */
       
   582 	if (bak->name[0] != 0) {
   348 		strcpy((char*)_decode_parameters, bak->name);
   583 		strcpy((char*)_decode_parameters, bak->name);
   349 		DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
   584 		DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
   350 	}
   585 	}
   351 
   586 
   352 	DoCommandP(0, v->index, bak->orderindex|(bak->service_interval<<16) , NULL, CMD_RESTORE_ORDER_INDEX);
   587 	/* Restore vehicle number and service interval */
   353 
   588 	DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , NULL, CMD_RESTORE_ORDER_INDEX);
       
   589 
       
   590 	/* If we had shared orders, recover that */
   354 	if (bak->clone != INVALID_VEHICLE) {
   591 	if (bak->clone != INVALID_VEHICLE) {
   355 		DoCommandP(0, v->index | bak->clone << 16, 0, NULL, CMD_CLONE_ORDER);
   592 		DoCommandP(0, v->index | (bak->clone << 16), 0, NULL, CMD_CLONE_ORDER);
   356 		return;
   593 		return;
   357 	}
   594 	}
   358 
   595 
   359 	// CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
   596 	/* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
   360 	//  order number is one more than the current amount of orders, and because
   597 	    order number is one more than the current amount of orders, and because
   361 	//  in network the commands are queued before send, the second insert always
   598 	    in network the commands are queued before send, the second insert always
   362 	//  fails in test mode. By bypassing the test-mode, that no longer is a problem.
   599 	    fails in test mode. By bypassing the test-mode, that no longer is a problem. */
   363 	for (i = 0; bak->order[i].type != OT_NOTHING; ++i)
   600 	for (i = 0; bak->order[i].type != OT_NOTHING; i++)
   364 		if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
   601 		if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
   365 			break;
   602 			break;
   366 }
   603 }
   367 
   604 
   368 /*	p1 = vehicle
   605 /**
   369  *	upper 16 bits p2 = service_interval
   606  *
   370  *	lower 16 bits p2 = cur_order_index
   607  * Restore the current-order-index of a vehicle and sets service-interval
   371  */
   608  *
   372 int32 CmdRestoreOrderIndex(int x, int y, uint32 flags, uint32 p1, uint32 p2)
   609  * @param vehicle_id The ID of the vehicle
   373 {
   610  * @param data       First 16 bits are the current-order-index
   374 	// nonsense to update the windows, since, train rebought will have its window deleted
   611  *                   The last 16 bits are the service-interval
       
   612  *
       
   613  */
       
   614 int32 CmdRestoreOrderIndex(int x, int y, uint32 flags, uint32 vehicle_id, uint32 data)
       
   615 {
   375 	if (flags & DC_EXEC) {
   616 	if (flags & DC_EXEC) {
   376 		Vehicle *v = GetVehicle(p1);
   617 		Vehicle *v = GetVehicle(vehicle_id);
   377 		v->service_interval = (uint16)(p2>>16);
   618 		v->service_interval = data >> 16;
   378 		v->cur_order_index = (byte)(p2&0xFFFF);
   619 		v->cur_order_index = data & 0xFFFF;
   379 	}
   620 	}
       
   621 
   380 	return 0;
   622 	return 0;
   381 }
   623 }
   382 
   624 
   383 int CheckOrders(Vehicle *v)
   625 /**
   384 {
   626  *
   385 	if (!_patches.order_review_system)	//User doesn't want things to be checked
   627  * Check the orders of a vehicle, to see if there are invalid orders and stuff
   386 		return 0;
   628  *
   387 
   629  */
       
   630 bool CheckOrders(const Vehicle *v)
       
   631 {
       
   632 	/* Does the user wants us to check things? */
       
   633 	if (_patches.order_review_system == 0)
       
   634 		return false;
       
   635 
       
   636 	/* Do nothing for crashed vehicles */
   388 	if(v->vehstatus & VS_CRASHED)
   637 	if(v->vehstatus & VS_CRASHED)
   389 		return 0;
   638 		return false;
   390 
   639 
       
   640 	/* Do nothing for stopped vehicles if setting is '1' */
   391 	if ( (_patches.order_review_system == 1) && (v->vehstatus & VS_STOPPED) )
   641 	if ( (_patches.order_review_system == 1) && (v->vehstatus & VS_STOPPED) )
   392 		return 0;
   642 		return false;
   393 
   643 
   394 	/* only check every 20 days, so that we don't flood the message log */
   644 	/* Only check every 20 days, so that we don't flood the message log */
   395 	if ( ( ( v->day_counter % 20) == 0 ) && (v->owner == _local_player) ) {
   645 	if ( ( ( v->day_counter % 20) == 0 ) && (v->owner == _local_player) ) {
   396 		Order order;
   646 		int n_st, problem_type = -1;
   397 		Order old_order;
   647 		const Order *order;
   398 		int i, n_st, problem_type = -1;
   648 		const Station *st;
   399 		Station *st;
   649 		int message = 0;
   400 		int message=0;
   650 
   401 		TileIndex required_tile=-1;
   651 		/* Check the order list */
   402 
       
   403 		/* check the order list */
       
   404 		order = v->schedule_ptr[0];
       
   405 		n_st = 0;
   652 		n_st = 0;
   406 
   653 
   407 		old_order.type = OT_NOTHING;
   654 		FOR_VEHICLE_ORDERS(v, order) {
   408 		old_order.flags = 0;
   655 			/* Dummy order? */
   409 		for (i = 0; order.type != OT_NOTHING; i++) {
   656 			if (order->type == OT_DUMMY) {
   410 			order = v->schedule_ptr[i];
       
   411 			if (order.type == old_order.type &&
       
   412 					order.flags == old_order.flags &&
       
   413 					order.station == old_order.station) {
       
   414 				problem_type = 2;
       
   415 				break;
       
   416 			}
       
   417 			if (order.type == OT_DUMMY) {
       
   418 				problem_type = 1;
   657 				problem_type = 1;
   419 				break;
   658 				break;
   420 			}
   659 			}
   421 			if (order.type == OT_GOTO_STATION /*&& (order != old_order) */) {
   660 			/* Does station have a load-bay for this vehicle? */
   422 				//I uncommented this in order not to get two error messages
   661 			if (order->type == OT_GOTO_STATION) {
   423 				//when two identical entries are in the list
   662 				TileIndex required_tile;
       
   663 
   424 				n_st++;
   664 				n_st++;
   425 				st = GetStation(order.station);
   665 				st = GetStation(order->station);
   426 				required_tile = GetStationTileForVehicle(v,st);
   666 				required_tile = GetStationTileForVehicle(v, st);
   427 				if (!required_tile) problem_type = 3;
   667 				if (!required_tile)
   428 			}
   668 					problem_type = 3;
   429 			old_order = order; //store the old order
   669 			}
   430 		}
   670 		}
   431 
   671 
   432 		//Now, check the last and the first order
   672 		/* Check if the last and the first order are the same */
   433 		//as the last order is the end of order marker, jump back 2
   673 		if (v->num_orders > 1 &&
   434 		if (i > 2 &&
   674 				v->orders->type    == GetLastVehicleOrder(v)->type &&
   435 				v->schedule_ptr[0].type == v->schedule_ptr[i - 2].type &&
   675 				v->orders->flags   == GetLastVehicleOrder(v)->flags &&
   436 				v->schedule_ptr[0].flags == v->schedule_ptr[i - 2].flags &&
   676 				v->orders->station == GetLastVehicleOrder(v)->station)
   437 				v->schedule_ptr[0].station == v->schedule_ptr[i - 2].station)
       
   438 			problem_type = 2;
   677 			problem_type = 2;
   439 
   678 
   440 		if ( (n_st < 2) && (problem_type == -1) ) problem_type = 0;
   679 		/* Do we only have 1 station in our order list? */
       
   680 		if ((n_st < 2) && (problem_type == -1))
       
   681 			problem_type = 0;
       
   682 
       
   683 		/* We don't have a problem */
       
   684 		if (problem_type < 0)
       
   685 			return false;
       
   686 
       
   687 		message = (STR_TRAIN_HAS_TOO_FEW_ORDERS) + (((v->type) - VEH_Train) << 2) + problem_type;
   441 
   688 
   442 		SetDParam(0, v->unitnumber);
   689 		SetDParam(0, v->unitnumber);
   443 
       
   444 		message = (STR_TRAIN_HAS_TOO_FEW_ORDERS) + (((v->type) - VEH_Train) << 2) + problem_type;
       
   445 
       
   446 		if (problem_type < 0) return 0;
       
   447 
       
   448 		AddNewsItem(
   690 		AddNewsItem(
   449 			message,
   691 			message,
   450 			NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
   692 			NEWS_FLAGS(NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, 0),
   451 			v->index,
   693 			v->index,
   452 			0);
   694 			0);
   453 	}
   695 	}
   454 	// End of order check
   696 
   455 
   697 	return true;
   456 	return 1;
   698 }
   457 }
   699 
       
   700 /**
       
   701  *
       
   702  * Delete a destination (like station, waypoint, ..) from the orders of vehicles
       
   703  *
       
   704  * @param dest type and station has to be set. This order will be removed from all orders of vehicles
       
   705  *
       
   706  */
       
   707 void DeleteDestinationFromVehicleOrder(Order dest)
       
   708 {
       
   709 	Vehicle *v;
       
   710 	Order *order;
       
   711 	bool need_invalidate;
       
   712 
       
   713 	/* Go through all vehicles */
       
   714 	FOR_ALL_VEHICLES(v) {
       
   715 		if (v->type == 0 || v->orders == NULL)
       
   716 			continue;
       
   717 
       
   718 		/* Forget about this station if this station is removed */
       
   719 		if (v->last_station_visited == dest.station && dest.type == OT_GOTO_STATION)
       
   720 			v->last_station_visited = 0xFFFF;
       
   721 
       
   722 		/* Check the current order */
       
   723 		if (v->current_order.type    == dest.type &&
       
   724 				v->current_order.station == dest.station) {
       
   725 			/* Mark the order as DUMMY */
       
   726 			v->current_order.type = OT_DUMMY;
       
   727 			v->current_order.flags = 0;
       
   728 			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
       
   729 		}
       
   730 
       
   731 		/* Clear the order from the order-list */
       
   732 		need_invalidate = false;
       
   733 		FOR_VEHICLE_ORDERS(v, order) {
       
   734 			if (order->type == dest.type && order->station == dest.station) {
       
   735 				/* Mark the order as DUMMY */
       
   736 				order->type = OT_DUMMY;
       
   737 				order->flags = 0;
       
   738 
       
   739 				need_invalidate = true;
       
   740 			}
       
   741 		}
       
   742 
       
   743 		/* Only invalidate once, and if needed */
       
   744 		if (need_invalidate)
       
   745 			InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
       
   746 	}
       
   747 }
       
   748 
       
   749 /**
       
   750  *
       
   751  * Checks if a vehicle has a GOTO_DEPOT in his order list
       
   752  *
       
   753  * @return True if this is true (lol ;))
       
   754  *
       
   755  */
       
   756 bool VehicleHasDepotOrders(const Vehicle *v)
       
   757 {
       
   758 	const Order *order;
       
   759 
       
   760 	FOR_VEHICLE_ORDERS(v, order) {
       
   761 		if (order->type == OT_GOTO_DEPOT)
       
   762 			return true;
       
   763 	}
       
   764 
       
   765 	return false;
       
   766 }
       
   767 
       
   768 /**
       
   769  *
       
   770  * Delete all orders from a vehicle
       
   771  *
       
   772  */
       
   773 void DeleteVehicleOrders(Vehicle *v)
       
   774 {
       
   775 	Order *order, *cur;
       
   776 
       
   777 	/* If we have a shared order-list, don't delete the list, but just
       
   778 	    remove our pointer */
       
   779 	if (IsOrderListShared(v)) {
       
   780 		const Vehicle *u = v;
       
   781 
       
   782 		v->orders = NULL;
       
   783 		v->num_orders = 0;
       
   784 
       
   785 		/* Unlink ourself */
       
   786 		if (v->prev_shared != NULL) {
       
   787 			v->prev_shared->next_shared = v->next_shared;
       
   788 			u = v->prev_shared;
       
   789 		}
       
   790 		if (v->next_shared != NULL) {
       
   791 			v->next_shared->prev_shared = v->prev_shared;
       
   792 			u = v->next_shared;
       
   793 		}
       
   794 		v->prev_shared = NULL;
       
   795 		v->next_shared = NULL;
       
   796 
       
   797 		/* We only need to update this-one, because if there is a third
       
   798 		    vehicle which shares the same order-list, nothing will change. If
       
   799 		    this is the last vehicle, the last line of the order-window
       
   800 		    will change from Shared order list, to Order list, so it needs
       
   801 		    an update */
       
   802 		InvalidateVehicleOrder(u);
       
   803 		return;
       
   804 	}
       
   805 
       
   806 	/* Remove the orders */
       
   807 	cur = v->orders;
       
   808 	v->orders = NULL;
       
   809 	v->num_orders = 0;
       
   810 
       
   811 	order = NULL;
       
   812 	while (cur != NULL) {
       
   813 		if (order != NULL) {
       
   814 			order->type = OT_NOTHING;
       
   815 			order->next = NULL;
       
   816 		}
       
   817 
       
   818 		order = cur;
       
   819 		cur = cur->next;
       
   820 	}
       
   821 
       
   822 	if (order != NULL) {
       
   823 		order->type = OT_NOTHING;
       
   824 		order->next = NULL;
       
   825 	}
       
   826 }
       
   827 
       
   828 /**
       
   829  *
       
   830  * Check if we share our orders with an other vehicle
       
   831  *
       
   832  * @return Returns the vehicle who has the same order
       
   833  *
       
   834  */
       
   835 bool IsOrderListShared(const Vehicle *v)
       
   836 {
       
   837 	if (v->next_shared != NULL)
       
   838 		return true;
       
   839 
       
   840 	if (v->prev_shared != NULL)
       
   841 		return true;
       
   842 
       
   843 	return false;
       
   844 }
       
   845 
       
   846 /**
       
   847  *
       
   848  * Check if a vehicle has any valid orders
       
   849  *
       
   850  * @return false if there are no valid orders
       
   851  *
       
   852  */
       
   853 bool CheckForValidOrders(Vehicle *v)
       
   854 {
       
   855 	const Order *order;
       
   856 
       
   857 	FOR_VEHICLE_ORDERS(v, order)
       
   858 		if (order->type != OT_DUMMY)
       
   859 			return true;
       
   860 
       
   861 	return false;
       
   862 }
       
   863 
       
   864 void InitializeOrders(void)
       
   865 {
       
   866 	Order *order;
       
   867 	int i;
       
   868 
       
   869 	memset(&_orders, 0, sizeof(_orders[0]) * _orders_size);
       
   870 
       
   871 	i = 0;
       
   872 	FOR_ALL_ORDERS(order)
       
   873 		order->index = i++;
       
   874 
       
   875 	_backup_orders_tile = 0;
       
   876 }
       
   877 
       
   878 static const byte _order_desc[] = {
       
   879 	SLE_VAR(Order,type,					SLE_UINT8),
       
   880 	SLE_VAR(Order,flags,				SLE_UINT8),
       
   881 	SLE_VAR(Order,station,			SLE_UINT16),
       
   882 	SLE_REF(Order,next,					REF_ORDER),
       
   883 
       
   884 	// reserve extra space in savegame here. (currently 10 bytes)
       
   885 	SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 10, 5, 255),
       
   886 	SLE_END()
       
   887 };
       
   888 
       
   889 static void Save_ORDR()
       
   890 {
       
   891 	Order *order;
       
   892 
       
   893 	FOR_ALL_ORDERS(order) {
       
   894 		if (order->type != OT_NOTHING) {
       
   895 			SlSetArrayIndex(order->index);
       
   896 			SlObject(order, _order_desc);
       
   897 		}
       
   898 	}
       
   899 }
       
   900 
       
   901 static void Load_ORDR()
       
   902 {
       
   903 	if (_sl.full_version <= 0x501) {
       
   904 		/* Version older than 0x502 did not have a ->next pointer. Convert them
       
   905 		    (in the old days, the orderlist was 5000 items big) */
       
   906 		uint len = SlGetFieldLength();
       
   907 		uint i;
       
   908 
       
   909 		if (_sl.version < 5) {
       
   910 			/* Pre-version 5 had an other layout for orders
       
   911 			    (uint16 instead of uint32) */
       
   912 			uint16 orders[5000];
       
   913 
       
   914 			len /= sizeof(uint16);
       
   915 			assert (len <= _orders_size);
       
   916 
       
   917 			SlArray(orders, len, SLE_UINT16);
       
   918 
       
   919 			for (i = 0; i < len; ++i) {
       
   920 				AssignOrder(GetOrder(i), UnpackVersion4Order(orders[i]));
       
   921 			}
       
   922 		} else if (_sl.full_version <= 0x501) {
       
   923 			uint32 orders[5000];
       
   924 
       
   925 			len /= sizeof(uint32);
       
   926 			assert (len <= _orders_size);
       
   927 
       
   928 			SlArray(orders, len, SLE_UINT32);
       
   929 
       
   930 			for (i = 0; i < len; ++i) {
       
   931 				AssignOrder(GetOrder(i), UnpackOrder(orders[i]));
       
   932 			}
       
   933 		}
       
   934 
       
   935 		/* Update all the next pointer */
       
   936 		for (i = 1; i < len; ++i) {
       
   937 			/* The orders were built like this:
       
   938 			     Vehicle one had order[0], and as long as order++.type was not
       
   939 			     OT_NOTHING, it was part of the order-list of that vehicle */
       
   940 			if (GetOrder(i)->type != OT_NOTHING)
       
   941 				GetOrder(i - 1)->next = GetOrder(i);
       
   942 		}
       
   943 	} else {
       
   944 		int index;
       
   945 
       
   946 		while ((index = SlIterateArray()) != -1) {
       
   947 			Order *order = GetOrder(index);
       
   948 
       
   949 			SlObject(order, _order_desc);
       
   950 		}
       
   951 	}
       
   952 }
       
   953 
       
   954 const ChunkHandler _order_chunk_handlers[] = {
       
   955 	{ 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY | CH_LAST},
       
   956 };