1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
8 /** @file order_cmd.cpp Handling of orders. */
9 
10 #include "stdafx.h"
11 #include "debug.h"
12 #include "cmd_helper.h"
13 #include "command_func.h"
14 #include "company_func.h"
15 #include "news_func.h"
16 #include "strings_func.h"
17 #include "timetable.h"
18 #include "vehicle_func.h"
19 #include "depot_base.h"
20 #include "core/pool_func.hpp"
21 #include "core/random_func.hpp"
22 #include "aircraft.h"
23 #include "roadveh.h"
24 #include "station_base.h"
25 #include "waypoint_base.h"
26 #include "company_base.h"
27 #include "order_backup.h"
28 #include "cheat_type.h"
29 
30 #include "table/strings.h"
31 
32 #include "safeguards.h"
33 
34 /* DestinationID must be at least as large as every these below, because it can
35  * be any of them
36  */
37 static_assert(sizeof(DestinationID) >= sizeof(DepotID));
38 static_assert(sizeof(DestinationID) >= sizeof(StationID));
39 
40 OrderPool _order_pool("Order");
41 INSTANTIATE_POOL_METHODS(Order)
42 OrderListPool _orderlist_pool("OrderList");
INSTANTIATE_POOL_METHODS(OrderList)43 INSTANTIATE_POOL_METHODS(OrderList)
44 
45 /** Clean everything up. */
46 Order::~Order()
47 {
48 	if (CleaningPool()) return;
49 
50 	/* We can visit oil rigs and buoys that are not our own. They will be shown in
51 	 * the list of stations. So, we need to invalidate that window if needed. */
52 	if (this->IsType(OT_GOTO_STATION) || this->IsType(OT_GOTO_WAYPOINT)) {
53 		BaseStation *bs = BaseStation::GetIfValid(this->GetDestination());
54 		if (bs != nullptr && bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0);
55 	}
56 }
57 
58 /**
59  * 'Free' the order
60  * @note ONLY use on "current_order" vehicle orders!
61  */
Free()62 void Order::Free()
63 {
64 	this->type  = OT_NOTHING;
65 	this->flags = 0;
66 	this->dest  = 0;
67 	this->next  = nullptr;
68 }
69 
70 /**
71  * Makes this order a Go To Station order.
72  * @param destination the station to go to.
73  */
MakeGoToStation(StationID destination)74 void Order::MakeGoToStation(StationID destination)
75 {
76 	this->type = OT_GOTO_STATION;
77 	this->flags = 0;
78 	this->dest = destination;
79 }
80 
81 /**
82  * Makes this order a Go To Depot order.
83  * @param destination   the depot to go to.
84  * @param order         is this order a 'default' order, or an overridden vehicle order?
85  * @param non_stop_type how to get to the depot?
86  * @param action        what to do in the depot?
87  * @param cargo         the cargo type to change to.
88  */
MakeGoToDepot(DepotID destination,OrderDepotTypeFlags order,OrderNonStopFlags non_stop_type,OrderDepotActionFlags action,CargoID cargo)89 void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo)
90 {
91 	this->type = OT_GOTO_DEPOT;
92 	this->SetDepotOrderType(order);
93 	this->SetDepotActionType(action);
94 	this->SetNonStopType(non_stop_type);
95 	this->dest = destination;
96 	this->SetRefit(cargo);
97 }
98 
99 /**
100  * Makes this order a Go To Waypoint order.
101  * @param destination the waypoint to go to.
102  */
MakeGoToWaypoint(StationID destination)103 void Order::MakeGoToWaypoint(StationID destination)
104 {
105 	this->type = OT_GOTO_WAYPOINT;
106 	this->flags = 0;
107 	this->dest = destination;
108 }
109 
110 /**
111  * Makes this order a Loading order.
112  * @param ordered is this an ordered stop?
113  */
MakeLoading(bool ordered)114 void Order::MakeLoading(bool ordered)
115 {
116 	this->type = OT_LOADING;
117 	if (!ordered) this->flags = 0;
118 }
119 
120 /**
121  * Makes this order a Leave Station order.
122  */
MakeLeaveStation()123 void Order::MakeLeaveStation()
124 {
125 	this->type = OT_LEAVESTATION;
126 	this->flags = 0;
127 }
128 
129 /**
130  * Makes this order a Dummy order.
131  */
MakeDummy()132 void Order::MakeDummy()
133 {
134 	this->type = OT_DUMMY;
135 	this->flags = 0;
136 }
137 
138 /**
139  * Makes this order an conditional order.
140  * @param order the order to jump to.
141  */
MakeConditional(VehicleOrderID order)142 void Order::MakeConditional(VehicleOrderID order)
143 {
144 	this->type = OT_CONDITIONAL;
145 	this->flags = order;
146 	this->dest = 0;
147 }
148 
149 /**
150  * Makes this order an implicit order.
151  * @param destination the station to go to.
152  */
MakeImplicit(StationID destination)153 void Order::MakeImplicit(StationID destination)
154 {
155 	this->type = OT_IMPLICIT;
156 	this->dest = destination;
157 }
158 
159 /**
160  * Make this depot/station order also a refit order.
161  * @param cargo   the cargo type to change to.
162  * @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION).
163  */
SetRefit(CargoID cargo)164 void Order::SetRefit(CargoID cargo)
165 {
166 	this->refit_cargo = cargo;
167 }
168 
169 /**
170  * Does this order have the same type, flags and destination?
171  * @param other the second order to compare to.
172  * @return true if the type, flags and destination match.
173  */
Equals(const Order & other) const174 bool Order::Equals(const Order &other) const
175 {
176 	/* In case of go to nearest depot orders we need "only" compare the flags
177 	 * with the other and not the nearest depot order bit or the actual
178 	 * destination because those get clear/filled in during the order
179 	 * evaluation. If we do not do this the order will continuously be seen as
180 	 * a different order and it will try to find a "nearest depot" every tick. */
181 	if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
182 			((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
183 			 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
184 		return this->GetDepotOrderType() == other.GetDepotOrderType() &&
185 				(this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
186 	}
187 
188 	return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
189 }
190 
191 /**
192  * Pack this order into a 32 bits integer, or actually only
193  * the type, flags and destination.
194  * @return the packed representation.
195  * @note unpacking is done in the constructor.
196  */
Pack() const197 uint32 Order::Pack() const
198 {
199 	return this->dest << 16 | this->flags << 8 | this->type;
200 }
201 
202 /**
203  * Pack this order into a 16 bits integer as close to the TTD
204  * representation as possible.
205  * @return the TTD-like packed representation.
206  */
MapOldOrder() const207 uint16 Order::MapOldOrder() const
208 {
209 	uint16 order = this->GetType();
210 	switch (this->type) {
211 		case OT_GOTO_STATION:
212 			if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
213 			if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
214 			if (this->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) SetBit(order, 7);
215 			order |= GB(this->GetDestination(), 0, 8) << 8;
216 			break;
217 		case OT_GOTO_DEPOT:
218 			if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
219 			SetBit(order, 7);
220 			order |= GB(this->GetDestination(), 0, 8) << 8;
221 			break;
222 		case OT_LOADING:
223 			if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
224 			break;
225 	}
226 	return order;
227 }
228 
229 /**
230  * Create an order based on a packed representation of that order.
231  * @param packed the packed representation.
232  */
Order(uint32 packed)233 Order::Order(uint32 packed)
234 {
235 	this->type    = (OrderType)GB(packed,  0,  8);
236 	this->flags   = GB(packed,  8,  8);
237 	this->dest    = GB(packed, 16, 16);
238 	this->next    = nullptr;
239 	this->refit_cargo   = CT_NO_REFIT;
240 	this->wait_time     = 0;
241 	this->travel_time   = 0;
242 	this->max_speed     = UINT16_MAX;
243 }
244 
245 /**
246  *
247  * Updates the widgets of a vehicle which contains the order-data
248  *
249  */
InvalidateVehicleOrder(const Vehicle * v,int data)250 void InvalidateVehicleOrder(const Vehicle *v, int data)
251 {
252 	SetWindowDirty(WC_VEHICLE_VIEW, v->index);
253 
254 	if (data != 0) {
255 		/* Calls SetDirty() too */
256 		InvalidateWindowData(WC_VEHICLE_ORDERS,    v->index, data);
257 		InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data);
258 		return;
259 	}
260 
261 	SetWindowDirty(WC_VEHICLE_ORDERS,    v->index);
262 	SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
263 }
264 
265 /**
266  *
267  * Assign data to an order (from another order)
268  *   This function makes sure that the index is maintained correctly
269  * @param other the data to copy (except next pointer).
270  *
271  */
AssignOrder(const Order & other)272 void Order::AssignOrder(const Order &other)
273 {
274 	this->type  = other.type;
275 	this->flags = other.flags;
276 	this->dest  = other.dest;
277 
278 	this->refit_cargo   = other.refit_cargo;
279 
280 	this->wait_time   = other.wait_time;
281 	this->travel_time = other.travel_time;
282 	this->max_speed   = other.max_speed;
283 }
284 
285 /**
286  * Recomputes everything.
287  * @param chain first order in the chain
288  * @param v one of vehicle that is using this orderlist
289  */
Initialize(Order * chain,Vehicle * v)290 void OrderList::Initialize(Order *chain, Vehicle *v)
291 {
292 	this->first = chain;
293 	this->first_shared = v;
294 
295 	this->num_orders = 0;
296 	this->num_manual_orders = 0;
297 	this->num_vehicles = 1;
298 	this->timetable_duration = 0;
299 
300 	for (Order *o = this->first; o != nullptr; o = o->next) {
301 		++this->num_orders;
302 		if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
303 		this->total_duration += o->GetWaitTime() + o->GetTravelTime();
304 	}
305 
306 	this->RecalculateTimetableDuration();
307 
308 	for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
309 		++this->num_vehicles;
310 		this->first_shared = u;
311 	}
312 
313 	for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
314 }
315 
316 /**
317  * Recomputes Timetable duration.
318  * Split out into a separate function so it can be used by afterload.
319  */
RecalculateTimetableDuration()320 void OrderList::RecalculateTimetableDuration()
321 {
322 	this->timetable_duration = 0;
323 	for (Order *o = this->first; o != nullptr; o = o->next) {
324 		this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
325 	}
326 }
327 
328 /**
329  * Free a complete order chain.
330  * @param keep_orderlist If this is true only delete the orders, otherwise also delete the OrderList.
331  * @note do not use on "current_order" vehicle orders!
332  */
FreeChain(bool keep_orderlist)333 void OrderList::FreeChain(bool keep_orderlist)
334 {
335 	Order *next;
336 	for (Order *o = this->first; o != nullptr; o = next) {
337 		next = o->next;
338 		delete o;
339 	}
340 
341 	if (keep_orderlist) {
342 		this->first = nullptr;
343 		this->num_orders = 0;
344 		this->num_manual_orders = 0;
345 		this->timetable_duration = 0;
346 	} else {
347 		delete this;
348 	}
349 }
350 
351 /**
352  * Get a certain order of the order chain.
353  * @param index zero-based index of the order within the chain.
354  * @return the order at position index.
355  */
GetOrderAt(int index) const356 Order *OrderList::GetOrderAt(int index) const
357 {
358 	if (index < 0) return nullptr;
359 
360 	Order *order = this->first;
361 
362 	while (order != nullptr && index-- > 0) {
363 		order = order->next;
364 	}
365 	return order;
366 }
367 
368 /**
369  * Get the next order which will make the given vehicle stop at a station
370  * or refit at a depot or evaluate a non-trivial condition.
371  * @param next The order to start looking at.
372  * @param hops The number of orders we have already looked at.
373  * @return Either of
374  *         \li a station order
375  *         \li a refitting depot order
376  *         \li a non-trivial conditional order
377  *         \li nullptr  if the vehicle won't stop anymore.
378  */
GetNextDecisionNode(const Order * next,uint hops) const379 const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
380 {
381 	if (hops > this->GetNumOrders() || next == nullptr) return nullptr;
382 
383 	if (next->IsType(OT_CONDITIONAL)) {
384 		if (next->GetConditionVariable() != OCV_UNCONDITIONALLY) return next;
385 
386 		/* We can evaluate trivial conditions right away. They're conceptually
387 		 * the same as regular order progression. */
388 		return this->GetNextDecisionNode(
389 				this->GetOrderAt(next->GetConditionSkipToOrder()),
390 				hops + 1);
391 	}
392 
393 	if (next->IsType(OT_GOTO_DEPOT)) {
394 		if (next->GetDepotActionType() == ODATFB_HALT) return nullptr;
395 		if (next->IsRefit()) return next;
396 	}
397 
398 	if (!next->CanLoadOrUnload()) {
399 		return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
400 	}
401 
402 	return next;
403 }
404 
405 /**
406  * Recursively determine the next deterministic station to stop at.
407  * @param v The vehicle we're looking at.
408  * @param first Order to start searching at or nullptr to start at cur_implicit_order_index + 1.
409  * @param hops Number of orders we have already looked at.
410  * @return Next stopping station or INVALID_STATION.
411  * @pre The vehicle is currently loading and v->last_station_visited is meaningful.
412  * @note This function may draw a random number. Don't use it from the GUI.
413  */
GetNextStoppingStation(const Vehicle * v,const Order * first,uint hops) const414 StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first, uint hops) const
415 {
416 
417 	const Order *next = first;
418 	if (first == nullptr) {
419 		next = this->GetOrderAt(v->cur_implicit_order_index);
420 		if (next == nullptr) {
421 			next = this->GetFirstOrder();
422 			if (next == nullptr) return INVALID_STATION;
423 		} else {
424 			/* GetNext never returns nullptr if there is a valid station in the list.
425 			 * As the given "next" is already valid and a station in the list, we
426 			 * don't have to check for nullptr here. */
427 			next = this->GetNext(next);
428 			assert(next != nullptr);
429 		}
430 	}
431 
432 	do {
433 		next = this->GetNextDecisionNode(next, ++hops);
434 
435 		/* Resolve possibly nested conditionals by estimation. */
436 		while (next != nullptr && next->IsType(OT_CONDITIONAL)) {
437 			/* We return both options of conditional orders. */
438 			const Order *skip_to = this->GetNextDecisionNode(
439 					this->GetOrderAt(next->GetConditionSkipToOrder()), hops);
440 			const Order *advance = this->GetNextDecisionNode(
441 					this->GetNext(next), hops);
442 			if (advance == nullptr || advance == first || skip_to == advance) {
443 				next = (skip_to == first) ? nullptr : skip_to;
444 			} else if (skip_to == nullptr || skip_to == first) {
445 				next = (advance == first) ? nullptr : advance;
446 			} else {
447 				StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
448 				StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
449 				while (!st2.IsEmpty()) st1.Push(st2.Pop());
450 				return st1;
451 			}
452 			++hops;
453 		}
454 
455 		/* Don't return a next stop if the vehicle has to unload everything. */
456 		if (next == nullptr || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) &&
457 				next->GetDestination() == v->last_station_visited &&
458 				(next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
459 			return INVALID_STATION;
460 		}
461 	} while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
462 
463 	return next->GetDestination();
464 }
465 
466 /**
467  * Insert a new order into the order chain.
468  * @param new_order is the order to insert into the chain.
469  * @param index is the position where the order is supposed to be inserted.
470  */
InsertOrderAt(Order * new_order,int index)471 void OrderList::InsertOrderAt(Order *new_order, int index)
472 {
473 	if (this->first == nullptr) {
474 		this->first = new_order;
475 	} else {
476 		if (index == 0) {
477 			/* Insert as first or only order */
478 			new_order->next = this->first;
479 			this->first = new_order;
480 		} else if (index >= this->num_orders) {
481 			/* index is after the last order, add it to the end */
482 			this->GetLastOrder()->next = new_order;
483 		} else {
484 			/* Put the new order in between */
485 			Order *order = this->GetOrderAt(index - 1);
486 			new_order->next = order->next;
487 			order->next = new_order;
488 		}
489 	}
490 	++this->num_orders;
491 	if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
492 	this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
493 	this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
494 
495 	/* We can visit oil rigs and buoys that are not our own. They will be shown in
496 	 * the list of stations. So, we need to invalidate that window if needed. */
497 	if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
498 		BaseStation *bs = BaseStation::Get(new_order->GetDestination());
499 		if (bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0);
500 	}
501 
502 }
503 
504 
505 /**
506  * Remove an order from the order list and delete it.
507  * @param index is the position of the order which is to be deleted.
508  */
DeleteOrderAt(int index)509 void OrderList::DeleteOrderAt(int index)
510 {
511 	if (index >= this->num_orders) return;
512 
513 	Order *to_remove;
514 
515 	if (index == 0) {
516 		to_remove = this->first;
517 		this->first = to_remove->next;
518 	} else {
519 		Order *prev = GetOrderAt(index - 1);
520 		to_remove = prev->next;
521 		prev->next = to_remove->next;
522 	}
523 	--this->num_orders;
524 	if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
525 	this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
526 	this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
527 	delete to_remove;
528 }
529 
530 /**
531  * Move an order to another position within the order list.
532  * @param from is the zero-based position of the order to move.
533  * @param to is the zero-based position where the order is moved to.
534  */
MoveOrder(int from,int to)535 void OrderList::MoveOrder(int from, int to)
536 {
537 	if (from >= this->num_orders || to >= this->num_orders || from == to) return;
538 
539 	Order *moving_one;
540 
541 	/* Take the moving order out of the pointer-chain */
542 	if (from == 0) {
543 		moving_one = this->first;
544 		this->first = moving_one->next;
545 	} else {
546 		Order *one_before = GetOrderAt(from - 1);
547 		moving_one = one_before->next;
548 		one_before->next = moving_one->next;
549 	}
550 
551 	/* Insert the moving_order again in the pointer-chain */
552 	if (to == 0) {
553 		moving_one->next = this->first;
554 		this->first = moving_one;
555 	} else {
556 		Order *one_before = GetOrderAt(to - 1);
557 		moving_one->next = one_before->next;
558 		one_before->next = moving_one;
559 	}
560 }
561 
562 /**
563  * Removes the vehicle from the shared order list.
564  * @note This is supposed to be called when the vehicle is still in the chain
565  * @param v vehicle to remove from the list
566  */
RemoveVehicle(Vehicle * v)567 void OrderList::RemoveVehicle(Vehicle *v)
568 {
569 	--this->num_vehicles;
570 	if (v == this->first_shared) this->first_shared = v->NextShared();
571 }
572 
573 /**
574  * Checks whether a vehicle is part of the shared vehicle chain.
575  * @param v is the vehicle to search in the shared vehicle chain.
576  */
IsVehicleInSharedOrdersList(const Vehicle * v) const577 bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
578 {
579 	for (const Vehicle *v_shared = this->first_shared; v_shared != nullptr; v_shared = v_shared->NextShared()) {
580 		if (v_shared == v) return true;
581 	}
582 
583 	return false;
584 }
585 
586 /**
587  * Gets the position of the given vehicle within the shared order vehicle list.
588  * @param v is the vehicle of which to get the position
589  * @return position of v within the shared vehicle chain.
590  */
GetPositionInSharedOrderList(const Vehicle * v) const591 int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
592 {
593 	int count = 0;
594 	for (const Vehicle *v_shared = v->PreviousShared(); v_shared != nullptr; v_shared = v_shared->PreviousShared()) count++;
595 	return count;
596 }
597 
598 /**
599  * Checks whether all orders of the list have a filled timetable.
600  * @return whether all orders have a filled timetable.
601  */
IsCompleteTimetable() const602 bool OrderList::IsCompleteTimetable() const
603 {
604 	for (Order *o = this->first; o != nullptr; o = o->next) {
605 		/* Implicit orders are, by definition, not timetabled. */
606 		if (o->IsType(OT_IMPLICIT)) continue;
607 		if (!o->IsCompletelyTimetabled()) return false;
608 	}
609 	return true;
610 }
611 
612 #ifdef WITH_ASSERT
613 /**
614  * Checks for internal consistency of order list. Triggers assertion if something is wrong.
615  */
DebugCheckSanity() const616 void OrderList::DebugCheckSanity() const
617 {
618 	VehicleOrderID check_num_orders = 0;
619 	VehicleOrderID check_num_manual_orders = 0;
620 	uint check_num_vehicles = 0;
621 	Ticks check_timetable_duration = 0;
622 	Ticks check_total_duration = 0;
623 
624 	Debug(misc, 6, "Checking OrderList {} for sanity...", this->index);
625 
626 	for (const Order *o = this->first; o != nullptr; o = o->next) {
627 		++check_num_orders;
628 		if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
629 		check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
630 		check_total_duration += o->GetWaitTime() + o->GetTravelTime();
631 	}
632 	assert(this->num_orders == check_num_orders);
633 	assert(this->num_manual_orders == check_num_manual_orders);
634 	assert(this->timetable_duration == check_timetable_duration);
635 	assert(this->total_duration == check_total_duration);
636 
637 	for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
638 		++check_num_vehicles;
639 		assert(v->orders.list == this);
640 	}
641 	assert(this->num_vehicles == check_num_vehicles);
642 	Debug(misc, 6, "... detected {} orders ({} manual), {} vehicles, {} timetabled, {} total",
643 			(uint)this->num_orders, (uint)this->num_manual_orders,
644 			this->num_vehicles, this->timetable_duration, this->total_duration);
645 }
646 #endif
647 
648 /**
649  * Checks whether the order goes to a station or not, i.e. whether the
650  * destination is a station
651  * @param v the vehicle to check for
652  * @param o the order to check
653  * @return true if the destination is a station
654  */
OrderGoesToStation(const Vehicle * v,const Order * o)655 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
656 {
657 	return o->IsType(OT_GOTO_STATION) ||
658 			(v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
659 }
660 
661 /**
662  * Delete all news items regarding defective orders about a vehicle
663  * This could kill still valid warnings (for example about void order when just
664  * another order gets added), but assume the company will notice the problems,
665  * when they're changing the orders.
666  */
DeleteOrderWarnings(const Vehicle * v)667 static void DeleteOrderWarnings(const Vehicle *v)
668 {
669 	DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
670 	DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
671 	DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
672 	DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
673 	DeleteVehicleNews(v->index, STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY);
674 }
675 
676 /**
677  * Returns a tile somewhat representing the order destination (not suitable for pathfinding).
678  * @param v The vehicle to get the location for.
679  * @param airport Get the airport tile and not the station location for aircraft.
680  * @return destination of order, or INVALID_TILE if none.
681  */
GetLocation(const Vehicle * v,bool airport) const682 TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
683 {
684 	switch (this->GetType()) {
685 		case OT_GOTO_WAYPOINT:
686 		case OT_GOTO_STATION:
687 		case OT_IMPLICIT:
688 			if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile;
689 			return BaseStation::Get(this->GetDestination())->xy;
690 
691 		case OT_GOTO_DEPOT:
692 			if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
693 			return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
694 
695 		default:
696 			return INVALID_TILE;
697 	}
698 }
699 
700 /**
701  * Get the distance between two orders of a vehicle. Conditional orders are resolved
702  * and the bigger distance of the two order branches is returned.
703  * @param prev Origin order.
704  * @param cur Destination order.
705  * @param v The vehicle to get the distance for.
706  * @param conditional_depth Internal param for resolving conditional orders.
707  * @return Maximum distance between the two orders.
708  */
GetOrderDistance(const Order * prev,const Order * cur,const Vehicle * v,int conditional_depth)709 uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
710 {
711 	if (cur->IsType(OT_CONDITIONAL)) {
712 		if (conditional_depth > v->GetNumOrders()) return 0;
713 
714 		conditional_depth++;
715 
716 		int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
717 		int dist2 = GetOrderDistance(prev, cur->next == nullptr ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
718 		return std::max(dist1, dist2);
719 	}
720 
721 	TileIndex prev_tile = prev->GetLocation(v, true);
722 	TileIndex cur_tile = cur->GetLocation(v, true);
723 	if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
724 	return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
725 }
726 
727 /**
728  * Add an order to the orderlist of a vehicle.
729  * @param tile unused
730  * @param flags operation to perform
731  * @param p1 various bitstuffed elements
732  * - p1 = (bit  0 - 19) - ID of the vehicle
733  * - p1 = (bit 24 - 31) - the selected order (if any). If the last order is given,
734  *                        the order will be inserted before that one
735  *                        the maximum vehicle order id is 254.
736  * @param p2 packed order to insert
737  * @param text unused
738  * @return the cost of this operation or an error
739  */
CmdInsertOrder(TileIndex tile,DoCommandFlag flags,uint32 p1,uint32 p2,const std::string & text)740 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
741 {
742 	VehicleID veh          = GB(p1,  0, 20);
743 	VehicleOrderID sel_ord = GB(p1, 20, 8);
744 	Order new_order(p2);
745 
746 	Vehicle *v = Vehicle::GetIfValid(veh);
747 	if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
748 
749 	CommandCost ret = CheckOwnership(v->owner);
750 	if (ret.Failed()) return ret;
751 
752 	/* Check if the inserted order is to the correct destination (owner, type),
753 	 * and has the correct flags if any */
754 	switch (new_order.GetType()) {
755 		case OT_GOTO_STATION: {
756 			const Station *st = Station::GetIfValid(new_order.GetDestination());
757 			if (st == nullptr) return CMD_ERROR;
758 
759 			if (st->owner != OWNER_NONE) {
760 				CommandCost ret = CheckOwnership(st->owner);
761 				if (ret.Failed()) return ret;
762 			}
763 
764 			if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
765 			for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
766 				if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
767 			}
768 
769 			/* Non stop only allowed for ground vehicles. */
770 			if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
771 
772 			/* Filter invalid load/unload types. */
773 			switch (new_order.GetLoadType()) {
774 				case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
775 				default: return CMD_ERROR;
776 			}
777 			switch (new_order.GetUnloadType()) {
778 				case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
779 				default: return CMD_ERROR;
780 			}
781 
782 			/* Filter invalid stop locations */
783 			switch (new_order.GetStopLocation()) {
784 				case OSL_PLATFORM_NEAR_END:
785 				case OSL_PLATFORM_MIDDLE:
786 					if (v->type != VEH_TRAIN) return CMD_ERROR;
787 					FALLTHROUGH;
788 
789 				case OSL_PLATFORM_FAR_END:
790 					break;
791 
792 				default:
793 					return CMD_ERROR;
794 			}
795 
796 			break;
797 		}
798 
799 		case OT_GOTO_DEPOT: {
800 			if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
801 				if (v->type == VEH_AIRCRAFT) {
802 					const Station *st = Station::GetIfValid(new_order.GetDestination());
803 
804 					if (st == nullptr) return CMD_ERROR;
805 
806 					CommandCost ret = CheckOwnership(st->owner);
807 					if (ret.Failed()) return ret;
808 
809 					if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
810 						return CMD_ERROR;
811 					}
812 				} else {
813 					const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
814 
815 					if (dp == nullptr) return CMD_ERROR;
816 
817 					CommandCost ret = CheckOwnership(GetTileOwner(dp->xy));
818 					if (ret.Failed()) return ret;
819 
820 					switch (v->type) {
821 						case VEH_TRAIN:
822 							if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
823 							break;
824 
825 						case VEH_ROAD:
826 							if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
827 							break;
828 
829 						case VEH_SHIP:
830 							if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
831 							break;
832 
833 						default: return CMD_ERROR;
834 					}
835 				}
836 			}
837 
838 			if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
839 			if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
840 			if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
841 			if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
842 			break;
843 		}
844 
845 		case OT_GOTO_WAYPOINT: {
846 			const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
847 			if (wp == nullptr) return CMD_ERROR;
848 
849 			switch (v->type) {
850 				default: return CMD_ERROR;
851 
852 				case VEH_TRAIN: {
853 					if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
854 
855 					CommandCost ret = CheckOwnership(wp->owner);
856 					if (ret.Failed()) return ret;
857 					break;
858 				}
859 
860 				case VEH_SHIP:
861 					if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
862 					if (wp->owner != OWNER_NONE) {
863 						CommandCost ret = CheckOwnership(wp->owner);
864 						if (ret.Failed()) return ret;
865 					}
866 					break;
867 			}
868 
869 			/* Order flags can be any of the following for waypoints:
870 			 * [non-stop]
871 			 * non-stop orders (if any) are only valid for trains */
872 			if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
873 			break;
874 		}
875 
876 		case OT_CONDITIONAL: {
877 			VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
878 			if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
879 			if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
880 
881 			OrderConditionComparator occ = new_order.GetConditionComparator();
882 			if (occ >= OCC_END) return CMD_ERROR;
883 			switch (new_order.GetConditionVariable()) {
884 				case OCV_REQUIRES_SERVICE:
885 					if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
886 					break;
887 
888 				case OCV_UNCONDITIONALLY:
889 					if (occ != OCC_EQUALS) return CMD_ERROR;
890 					if (new_order.GetConditionValue() != 0) return CMD_ERROR;
891 					break;
892 
893 				case OCV_LOAD_PERCENTAGE:
894 				case OCV_RELIABILITY:
895 					if (new_order.GetConditionValue() > 100) return CMD_ERROR;
896 					FALLTHROUGH;
897 
898 				default:
899 					if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
900 					break;
901 			}
902 			break;
903 		}
904 
905 		default: return CMD_ERROR;
906 	}
907 
908 	if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
909 
910 	if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
911 	if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
912 	if (v->orders.list == nullptr && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
913 
914 	if (flags & DC_EXEC) {
915 		Order *new_o = new Order();
916 		new_o->AssignOrder(new_order);
917 		InsertOrder(v, new_o, sel_ord);
918 	}
919 
920 	return CommandCost();
921 }
922 
923 /**
924  * Insert a new order but skip the validation.
925  * @param v       The vehicle to insert the order to.
926  * @param new_o   The new order.
927  * @param sel_ord The position the order should be inserted at.
928  */
InsertOrder(Vehicle * v,Order * new_o,VehicleOrderID sel_ord)929 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
930 {
931 	/* Create new order and link in list */
932 	if (v->orders.list == nullptr) {
933 		v->orders.list = new OrderList(new_o, v);
934 	} else {
935 		v->orders.list->InsertOrderAt(new_o, sel_ord);
936 	}
937 
938 	Vehicle *u = v->FirstShared();
939 	DeleteOrderWarnings(u);
940 	for (; u != nullptr; u = u->NextShared()) {
941 		assert(v->orders.list == u->orders.list);
942 
943 		/* If there is added an order before the current one, we need
944 		 * to update the selected order. We do not change implicit/real order indices though.
945 		 * If the new order is between the current implicit order and real order, the implicit order will
946 		 * later skip the inserted order. */
947 		if (sel_ord <= u->cur_real_order_index) {
948 			uint cur = u->cur_real_order_index + 1;
949 			/* Check if we don't go out of bound */
950 			if (cur < u->GetNumOrders()) {
951 				u->cur_real_order_index = cur;
952 			}
953 		}
954 		if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
955 			/* We are inserting an order just before the current implicit order.
956 			 * We do not know whether we will reach current implicit or the newly inserted order first.
957 			 * So, disable creation of implicit orders until we are on track again. */
958 			uint16 &gv_flags = u->GetGroundVehicleFlags();
959 			SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
960 		}
961 		if (sel_ord <= u->cur_implicit_order_index) {
962 			uint cur = u->cur_implicit_order_index + 1;
963 			/* Check if we don't go out of bound */
964 			if (cur < u->GetNumOrders()) {
965 				u->cur_implicit_order_index = cur;
966 			}
967 		}
968 		/* Update any possible open window of the vehicle */
969 		InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
970 	}
971 
972 	/* As we insert an order, the order to skip to will be 'wrong'. */
973 	VehicleOrderID cur_order_id = 0;
974 	for (Order *order : v->Orders()) {
975 		if (order->IsType(OT_CONDITIONAL)) {
976 			VehicleOrderID order_id = order->GetConditionSkipToOrder();
977 			if (order_id >= sel_ord) {
978 				order->SetConditionSkipToOrder(order_id + 1);
979 			}
980 			if (order_id == cur_order_id) {
981 				order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
982 			}
983 		}
984 		cur_order_id++;
985 	}
986 
987 	/* Make sure to rebuild the whole list */
988 	InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
989 }
990 
991 /**
992  * Declone an order-list
993  * @param *dst delete the orders of this vehicle
994  * @param flags execution flags
995  */
DecloneOrder(Vehicle * dst,DoCommandFlag flags)996 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
997 {
998 	if (flags & DC_EXEC) {
999 		DeleteVehicleOrders(dst);
1000 		InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
1001 		InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
1002 	}
1003 	return CommandCost();
1004 }
1005 
1006 /**
1007  * Delete an order from the orderlist of a vehicle.
1008  * @param tile unused
1009  * @param flags operation to perform
1010  * @param p1 the ID of the vehicle
1011  * @param p2 the order to delete (max 255)
1012  * @param text unused
1013  * @return the cost of this operation or an error
1014  */
CmdDeleteOrder(TileIndex tile,DoCommandFlag flags,uint32 p1,uint32 p2,const std::string & text)1015 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
1016 {
1017 	VehicleID veh_id = GB(p1, 0, 20);
1018 	VehicleOrderID sel_ord = GB(p2, 0, 8);
1019 
1020 	Vehicle *v = Vehicle::GetIfValid(veh_id);
1021 
1022 	if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1023 
1024 	CommandCost ret = CheckOwnership(v->owner);
1025 	if (ret.Failed()) return ret;
1026 
1027 	/* If we did not select an order, we maybe want to de-clone the orders */
1028 	if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
1029 
1030 	if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
1031 
1032 	if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
1033 	return CommandCost();
1034 }
1035 
1036 /**
1037  * Cancel the current loading order of the vehicle as the order was deleted.
1038  * @param v the vehicle
1039  */
CancelLoadingDueToDeletedOrder(Vehicle * v)1040 static void CancelLoadingDueToDeletedOrder(Vehicle *v)
1041 {
1042 	assert(v->current_order.IsType(OT_LOADING));
1043 	/* NON-stop flag is misused to see if a train is in a station that is
1044 	 * on its order list or not */
1045 	v->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
1046 	/* When full loading, "cancel" that order so the vehicle doesn't
1047 	 * stay indefinitely at this station anymore. */
1048 	if (v->current_order.GetLoadType() & OLFB_FULL_LOAD) v->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
1049 }
1050 
1051 /**
1052  * Delete an order but skip the parameter validation.
1053  * @param v       The vehicle to delete the order from.
1054  * @param sel_ord The id of the order to be deleted.
1055  */
DeleteOrder(Vehicle * v,VehicleOrderID sel_ord)1056 void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
1057 {
1058 	v->orders.list->DeleteOrderAt(sel_ord);
1059 
1060 	Vehicle *u = v->FirstShared();
1061 	DeleteOrderWarnings(u);
1062 	for (; u != nullptr; u = u->NextShared()) {
1063 		assert(v->orders.list == u->orders.list);
1064 
1065 		if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
1066 			CancelLoadingDueToDeletedOrder(u);
1067 		}
1068 
1069 		if (sel_ord < u->cur_real_order_index) {
1070 			u->cur_real_order_index--;
1071 		} else if (sel_ord == u->cur_real_order_index) {
1072 			u->UpdateRealOrderIndex();
1073 		}
1074 
1075 		if (sel_ord < u->cur_implicit_order_index) {
1076 			u->cur_implicit_order_index--;
1077 		} else if (sel_ord == u->cur_implicit_order_index) {
1078 			/* Make sure the index is valid */
1079 			if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
1080 
1081 			/* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
1082 			while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) {
1083 				u->cur_implicit_order_index++;
1084 				if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
1085 			}
1086 		}
1087 
1088 		/* Update any possible open window of the vehicle */
1089 		InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1090 	}
1091 
1092 	/* As we delete an order, the order to skip to will be 'wrong'. */
1093 	VehicleOrderID cur_order_id = 0;
1094 	for (Order *order : v->Orders()) {
1095 		if (order->IsType(OT_CONDITIONAL)) {
1096 			VehicleOrderID order_id = order->GetConditionSkipToOrder();
1097 			if (order_id >= sel_ord) {
1098 				order_id = std::max(order_id - 1, 0);
1099 			}
1100 			if (order_id == cur_order_id) {
1101 				order_id = (order_id + 1) % v->GetNumOrders();
1102 			}
1103 			order->SetConditionSkipToOrder(order_id);
1104 		}
1105 		cur_order_id++;
1106 	}
1107 
1108 	InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
1109 }
1110 
1111 /**
1112  * Goto order of order-list.
1113  * @param tile unused
1114  * @param flags operation to perform
1115  * @param p1 The ID of the vehicle which order is skipped
1116  * @param p2 the selected order to which we want to skip
1117  * @param text unused
1118  * @return the cost of this operation or an error
1119  */
CmdSkipToOrder(TileIndex tile,DoCommandFlag flags,uint32 p1,uint32 p2,const std::string & text)1120 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
1121 {
1122 	VehicleID veh_id = GB(p1, 0, 20);
1123 	VehicleOrderID sel_ord = GB(p2, 0, 8);
1124 
1125 	Vehicle *v = Vehicle::GetIfValid(veh_id);
1126 
1127 	if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1128 
1129 	CommandCost ret = CheckOwnership(v->owner);
1130 	if (ret.Failed()) return ret;
1131 
1132 	if (flags & DC_EXEC) {
1133 		if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1134 
1135 		v->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
1136 		v->UpdateRealOrderIndex();
1137 
1138 		InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
1139 
1140 		/* We have an aircraft/ship, they have a mini-schedule, so update them all */
1141 		if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
1142 		if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
1143 	}
1144 
1145 	return CommandCost();
1146 }
1147 
1148 /**
1149  * Move an order inside the orderlist
1150  * @param tile unused
1151  * @param flags operation to perform
1152  * @param p1 the ID of the vehicle
1153  * @param p2 order to move and target
1154  *           bit 0-15  : the order to move
1155  *           bit 16-31 : the target order
1156  * @param text unused
1157  * @return the cost of this operation or an error
1158  * @note The target order will move one place down in the orderlist
1159  *  if you move the order upwards else it'll move it one place down
1160  */
CmdMoveOrder(TileIndex tile,DoCommandFlag flags,uint32 p1,uint32 p2,const std::string & text)1161 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
1162 {
1163 	VehicleID veh = GB(p1, 0, 20);
1164 	VehicleOrderID moving_order = GB(p2,  0, 16);
1165 	VehicleOrderID target_order = GB(p2, 16, 16);
1166 
1167 	Vehicle *v = Vehicle::GetIfValid(veh);
1168 	if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1169 
1170 	CommandCost ret = CheckOwnership(v->owner);
1171 	if (ret.Failed()) return ret;
1172 
1173 	/* Don't make senseless movements */
1174 	if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1175 			moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1176 
1177 	Order *moving_one = v->GetOrder(moving_order);
1178 	/* Don't move an empty order */
1179 	if (moving_one == nullptr) return CMD_ERROR;
1180 
1181 	if (flags & DC_EXEC) {
1182 		v->orders.list->MoveOrder(moving_order, target_order);
1183 
1184 		/* Update shared list */
1185 		Vehicle *u = v->FirstShared();
1186 
1187 		DeleteOrderWarnings(u);
1188 
1189 		for (; u != nullptr; u = u->NextShared()) {
1190 			/* Update the current order.
1191 			 * There are multiple ways to move orders, which result in cur_implicit_order_index
1192 			 * and cur_real_order_index to not longer make any sense. E.g. moving another
1193 			 * real order between them.
1194 			 *
1195 			 * Basically one could choose to preserve either of them, but not both.
1196 			 * While both ways are suitable in this or that case from a human point of view, neither
1197 			 * of them makes really sense.
1198 			 * However, from an AI point of view, preserving cur_real_order_index is the most
1199 			 * predictable and transparent behaviour.
1200 			 *
1201 			 * With that decision it basically does not matter what we do to cur_implicit_order_index.
1202 			 * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1203 			 * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1204 			 * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1205 			 */
1206 			if (u->cur_real_order_index == moving_order) {
1207 				u->cur_real_order_index = target_order;
1208 			} else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1209 				u->cur_real_order_index--;
1210 			} else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1211 				u->cur_real_order_index++;
1212 			}
1213 
1214 			if (u->cur_implicit_order_index == moving_order) {
1215 				u->cur_implicit_order_index = target_order;
1216 			} else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1217 				u->cur_implicit_order_index--;
1218 			} else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1219 				u->cur_implicit_order_index++;
1220 			}
1221 
1222 			assert(v->orders.list == u->orders.list);
1223 			/* Update any possible open window of the vehicle */
1224 			InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1225 		}
1226 
1227 		/* As we move an order, the order to skip to will be 'wrong'. */
1228 		for (Order *order : v->Orders()) {
1229 			if (order->IsType(OT_CONDITIONAL)) {
1230 				VehicleOrderID order_id = order->GetConditionSkipToOrder();
1231 				if (order_id == moving_order) {
1232 					order_id = target_order;
1233 				} else if (order_id > moving_order && order_id <= target_order) {
1234 					order_id--;
1235 				} else if (order_id < moving_order && order_id >= target_order) {
1236 					order_id++;
1237 				}
1238 				order->SetConditionSkipToOrder(order_id);
1239 			}
1240 		}
1241 
1242 		/* Make sure to rebuild the whole list */
1243 		InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
1244 	}
1245 
1246 	return CommandCost();
1247 }
1248 
1249 /**
1250  * Modify an order in the orderlist of a vehicle.
1251  * @param tile unused
1252  * @param flags operation to perform
1253  * @param p1 various bitstuffed elements
1254  * - p1 = (bit  0 - 19) - ID of the vehicle
1255  * - p1 = (bit 24 - 31) - the selected order (if any). If the last order is given,
1256  *                        the order will be inserted before that one
1257  *                        the maximum vehicle order id is 254.
1258  * @param p2 various bitstuffed elements
1259  *  - p2 = (bit 0 -  3) - what data to modify (@see ModifyOrderFlags)
1260  *  - p2 = (bit 4 - 15) - the data to modify
1261  * @param text unused
1262  * @return the cost of this operation or an error
1263  */
CmdModifyOrder(TileIndex tile,DoCommandFlag flags,uint32 p1,uint32 p2,const std::string & text)1264 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
1265 {
1266 	VehicleOrderID sel_ord = GB(p1, 20,  8);
1267 	VehicleID veh          = GB(p1,  0, 20);
1268 	ModifyOrderFlags mof   = Extract<ModifyOrderFlags, 0, 4>(p2);
1269 	uint16 data            = GB(p2,  4, 11);
1270 
1271 	if (mof >= MOF_END) return CMD_ERROR;
1272 
1273 	Vehicle *v = Vehicle::GetIfValid(veh);
1274 	if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1275 
1276 	CommandCost ret = CheckOwnership(v->owner);
1277 	if (ret.Failed()) return ret;
1278 
1279 	/* Is it a valid order? */
1280 	if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1281 
1282 	Order *order = v->GetOrder(sel_ord);
1283 	switch (order->GetType()) {
1284 		case OT_GOTO_STATION:
1285 			if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1286 			break;
1287 
1288 		case OT_GOTO_DEPOT:
1289 			if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1290 			break;
1291 
1292 		case OT_GOTO_WAYPOINT:
1293 			if (mof != MOF_NON_STOP) return CMD_ERROR;
1294 			break;
1295 
1296 		case OT_CONDITIONAL:
1297 			if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1298 			break;
1299 
1300 		default:
1301 			return CMD_ERROR;
1302 	}
1303 
1304 	switch (mof) {
1305 		default: NOT_REACHED();
1306 
1307 		case MOF_NON_STOP:
1308 			if (!v->IsGroundVehicle()) return CMD_ERROR;
1309 			if (data >= ONSF_END) return CMD_ERROR;
1310 			if (data == order->GetNonStopType()) return CMD_ERROR;
1311 			break;
1312 
1313 		case MOF_STOP_LOCATION:
1314 			if (v->type != VEH_TRAIN) return CMD_ERROR;
1315 			if (data >= OSL_END) return CMD_ERROR;
1316 			break;
1317 
1318 		case MOF_UNLOAD:
1319 			if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return CMD_ERROR;
1320 			if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
1321 			/* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
1322 			if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
1323 			if (data == order->GetUnloadType()) return CMD_ERROR;
1324 			break;
1325 
1326 		case MOF_LOAD:
1327 			if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return CMD_ERROR;
1328 			if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
1329 			if (data == order->GetLoadType()) return CMD_ERROR;
1330 			break;
1331 
1332 		case MOF_DEPOT_ACTION:
1333 			if (data >= DA_END) return CMD_ERROR;
1334 			break;
1335 
1336 		case MOF_COND_VARIABLE:
1337 			if (data >= OCV_END) return CMD_ERROR;
1338 			break;
1339 
1340 		case MOF_COND_COMPARATOR:
1341 			if (data >= OCC_END) return CMD_ERROR;
1342 			switch (order->GetConditionVariable()) {
1343 				case OCV_UNCONDITIONALLY: return CMD_ERROR;
1344 
1345 				case OCV_REQUIRES_SERVICE:
1346 					if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
1347 					break;
1348 
1349 				default:
1350 					if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
1351 					break;
1352 			}
1353 			break;
1354 
1355 		case MOF_COND_VALUE:
1356 			switch (order->GetConditionVariable()) {
1357 				case OCV_UNCONDITIONALLY:
1358 				case OCV_REQUIRES_SERVICE:
1359 					return CMD_ERROR;
1360 
1361 				case OCV_LOAD_PERCENTAGE:
1362 				case OCV_RELIABILITY:
1363 					if (data > 100) return CMD_ERROR;
1364 					break;
1365 
1366 				default:
1367 					if (data > 2047) return CMD_ERROR;
1368 					break;
1369 			}
1370 			break;
1371 
1372 		case MOF_COND_DESTINATION:
1373 			if (data >= v->GetNumOrders()) return CMD_ERROR;
1374 			break;
1375 	}
1376 
1377 	if (flags & DC_EXEC) {
1378 		switch (mof) {
1379 			case MOF_NON_STOP:
1380 				order->SetNonStopType((OrderNonStopFlags)data);
1381 				if (data & ONSF_NO_STOP_AT_DESTINATION_STATION) {
1382 					order->SetRefit(CT_NO_REFIT);
1383 					order->SetLoadType(OLF_LOAD_IF_POSSIBLE);
1384 					order->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE);
1385 				}
1386 				break;
1387 
1388 			case MOF_STOP_LOCATION:
1389 				order->SetStopLocation((OrderStopLocation)data);
1390 				break;
1391 
1392 			case MOF_UNLOAD:
1393 				order->SetUnloadType((OrderUnloadFlags)data);
1394 				break;
1395 
1396 			case MOF_LOAD:
1397 				order->SetLoadType((OrderLoadFlags)data);
1398 				if (data & OLFB_NO_LOAD) order->SetRefit(CT_NO_REFIT);
1399 				break;
1400 
1401 			case MOF_DEPOT_ACTION: {
1402 				switch (data) {
1403 					case DA_ALWAYS_GO:
1404 						order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
1405 						order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
1406 						break;
1407 
1408 					case DA_SERVICE:
1409 						order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
1410 						order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
1411 						order->SetRefit(CT_NO_REFIT);
1412 						break;
1413 
1414 					case DA_STOP:
1415 						order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
1416 						order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
1417 						order->SetRefit(CT_NO_REFIT);
1418 						break;
1419 
1420 					default:
1421 						NOT_REACHED();
1422 				}
1423 				break;
1424 			}
1425 
1426 			case MOF_COND_VARIABLE: {
1427 				order->SetConditionVariable((OrderConditionVariable)data);
1428 
1429 				OrderConditionComparator occ = order->GetConditionComparator();
1430 				switch (order->GetConditionVariable()) {
1431 					case OCV_UNCONDITIONALLY:
1432 						order->SetConditionComparator(OCC_EQUALS);
1433 						order->SetConditionValue(0);
1434 						break;
1435 
1436 					case OCV_REQUIRES_SERVICE:
1437 						if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
1438 						order->SetConditionValue(0);
1439 						break;
1440 
1441 					case OCV_LOAD_PERCENTAGE:
1442 					case OCV_RELIABILITY:
1443 						if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1444 						FALLTHROUGH;
1445 
1446 					default:
1447 						if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
1448 						break;
1449 				}
1450 				break;
1451 			}
1452 
1453 			case MOF_COND_COMPARATOR:
1454 				order->SetConditionComparator((OrderConditionComparator)data);
1455 				break;
1456 
1457 			case MOF_COND_VALUE:
1458 				order->SetConditionValue(data);
1459 				break;
1460 
1461 			case MOF_COND_DESTINATION:
1462 				order->SetConditionSkipToOrder(data);
1463 				break;
1464 
1465 			default: NOT_REACHED();
1466 		}
1467 
1468 		/* Update the windows and full load flags, also for vehicles that share the same order list */
1469 		Vehicle *u = v->FirstShared();
1470 		DeleteOrderWarnings(u);
1471 		for (; u != nullptr; u = u->NextShared()) {
1472 			/* Toggle u->current_order "Full load" flag if it changed.
1473 			 * However, as the same flag is used for depot orders, check
1474 			 * whether we are not going to a depot as there are three
1475 			 * cases where the full load flag can be active and only
1476 			 * one case where the flag is used for depot orders. In the
1477 			 * other cases for the OrderType the flags are not used,
1478 			 * so do not care and those orders should not be active
1479 			 * when this function is called.
1480 			 */
1481 			if (sel_ord == u->cur_real_order_index &&
1482 					(u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1483 					u->current_order.GetLoadType() != order->GetLoadType()) {
1484 				u->current_order.SetLoadType(order->GetLoadType());
1485 			}
1486 			InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS);
1487 		}
1488 	}
1489 
1490 	return CommandCost();
1491 }
1492 
1493 /**
1494  * Check if an aircraft has enough range for an order list.
1495  * @param v_new Aircraft to check.
1496  * @param v_order Vehicle currently holding the order list.
1497  * @param first First order in the source order list.
1498  * @return True if the aircraft has enough range for the orders, false otherwise.
1499  */
CheckAircraftOrderDistance(const Aircraft * v_new,const Vehicle * v_order,const Order * first)1500 static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first)
1501 {
1502 	if (first == nullptr || v_new->acache.cached_max_range == 0) return true;
1503 
1504 	/* Iterate over all orders to check the distance between all
1505 	 * 'goto' orders and their respective next order (of any type). */
1506 	for (const Order *o = first; o != nullptr; o = o->next) {
1507 		switch (o->GetType()) {
1508 			case OT_GOTO_STATION:
1509 			case OT_GOTO_DEPOT:
1510 			case OT_GOTO_WAYPOINT:
1511 				/* If we don't have a next order, we've reached the end and must check the first order instead. */
1512 				if (GetOrderDistance(o, o->next != nullptr ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false;
1513 				break;
1514 
1515 			default: break;
1516 		}
1517 	}
1518 
1519 	return true;
1520 }
1521 
1522 /**
1523  * Clone/share/copy an order-list of another vehicle.
1524  * @param tile unused
1525  * @param flags operation to perform
1526  * @param p1 various bitstuffed elements
1527  * - p1 = (bit  0-19) - destination vehicle to clone orders to
1528  * - p1 = (bit 30-31) - action to perform
1529  * @param p2 source vehicle to clone orders from, if any (none for CO_UNSHARE)
1530  * @param text unused
1531  * @return the cost of this operation or an error
1532  */
CmdCloneOrder(TileIndex tile,DoCommandFlag flags,uint32 p1,uint32 p2,const std::string & text)1533 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
1534 {
1535 	VehicleID veh_src = GB(p2, 0, 20);
1536 	VehicleID veh_dst = GB(p1, 0, 20);
1537 
1538 	Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1539 	if (dst == nullptr || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1540 
1541 	CommandCost ret = CheckOwnership(dst->owner);
1542 	if (ret.Failed()) return ret;
1543 
1544 	switch (GB(p1, 30, 2)) {
1545 		case CO_SHARE: {
1546 			Vehicle *src = Vehicle::GetIfValid(veh_src);
1547 
1548 			/* Sanity checks */
1549 			if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1550 
1551 			CommandCost ret = CheckOwnership(src->owner);
1552 			if (ret.Failed()) return ret;
1553 
1554 			/* Trucks can't share orders with busses (and visa versa) */
1555 			if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1556 				return CMD_ERROR;
1557 			}
1558 
1559 			/* Is the vehicle already in the shared list? */
1560 			if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1561 
1562 			for (const Order *order : src->Orders()) {
1563 				if (!OrderGoesToStation(dst, order)) continue;
1564 
1565 				/* Allow copying unreachable destinations if they were already unreachable for the source.
1566 				 * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1567 				 * are temporarily invalid due to reconstruction. */
1568 				const Station *st = Station::Get(order->GetDestination());
1569 				if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1570 					return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
1571 				}
1572 			}
1573 
1574 			/* Check for aircraft range limits. */
1575 			if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1576 				return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1577 			}
1578 
1579 			if (src->orders.list == nullptr && !OrderList::CanAllocateItem()) {
1580 				return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1581 			}
1582 
1583 			if (flags & DC_EXEC) {
1584 				/* If the destination vehicle had a OrderList, destroy it.
1585 				 * We only reset the order indices, if the new orders are obviously different.
1586 				 * (We mainly do this to keep the order indices valid and in range.) */
1587 				DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1588 
1589 				dst->orders.list = src->orders.list;
1590 
1591 				/* Link this vehicle in the shared-list */
1592 				dst->AddToShared(src);
1593 
1594 				InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
1595 				InvalidateVehicleOrder(src, VIWD_MODIFY_ORDERS);
1596 
1597 				InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
1598 			}
1599 			break;
1600 		}
1601 
1602 		case CO_COPY: {
1603 			Vehicle *src = Vehicle::GetIfValid(veh_src);
1604 
1605 			/* Sanity checks */
1606 			if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1607 
1608 			CommandCost ret = CheckOwnership(src->owner);
1609 			if (ret.Failed()) return ret;
1610 
1611 			/* Trucks can't copy all the orders from busses (and visa versa),
1612 			 * and neither can helicopters and aircraft. */
1613 			for (const Order *order : src->Orders()) {
1614 				if (OrderGoesToStation(dst, order) &&
1615 						!CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
1616 					return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
1617 				}
1618 			}
1619 
1620 			/* Check for aircraft range limits. */
1621 			if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1622 				return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1623 			}
1624 
1625 			/* make sure there are orders available */
1626 			if (!Order::CanAllocateItem(src->GetNumOrders()) || !OrderList::CanAllocateItem()) {
1627 				return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1628 			}
1629 
1630 			if (flags & DC_EXEC) {
1631 				Order *first = nullptr;
1632 				Order **order_dst;
1633 
1634 				/* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1635 				 * We only reset the order indices, if the new orders are obviously different.
1636 				 * (We mainly do this to keep the order indices valid and in range.) */
1637 				DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1638 
1639 				order_dst = &first;
1640 				for (const Order *order : src->Orders()) {
1641 					*order_dst = new Order();
1642 					(*order_dst)->AssignOrder(*order);
1643 					order_dst = &(*order_dst)->next;
1644 				}
1645 				if (dst->orders.list == nullptr) {
1646 					dst->orders.list = new OrderList(first, dst);
1647 				} else {
1648 					assert(dst->orders.list->GetFirstOrder() == nullptr);
1649 					assert(!dst->orders.list->IsShared());
1650 					delete dst->orders.list;
1651 					assert(OrderList::CanAllocateItem());
1652 					dst->orders.list = new OrderList(first, dst);
1653 				}
1654 
1655 				InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
1656 
1657 				InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
1658 			}
1659 			break;
1660 		}
1661 
1662 		case CO_UNSHARE: return DecloneOrder(dst, flags);
1663 		default: return CMD_ERROR;
1664 	}
1665 
1666 	return CommandCost();
1667 }
1668 
1669 /**
1670  * Add/remove refit orders from an order
1671  * @param tile Not used
1672  * @param flags operation to perform
1673  * @param p1 VehicleIndex of the vehicle having the order
1674  * @param p2 bitmask
1675  *   - bit 0-7 CargoID
1676  *   - bit 16-23 number of order to modify
1677  * @param text unused
1678  * @return the cost of this operation or an error
1679  */
CmdOrderRefit(TileIndex tile,DoCommandFlag flags,uint32 p1,uint32 p2,const std::string & text)1680 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const std::string &text)
1681 {
1682 	VehicleID veh = GB(p1, 0, 20);
1683 	VehicleOrderID order_number  = GB(p2, 16, 8);
1684 	CargoID cargo = GB(p2, 0, 8);
1685 
1686 	if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT && cargo != CT_AUTO_REFIT) return CMD_ERROR;
1687 
1688 	const Vehicle *v = Vehicle::GetIfValid(veh);
1689 	if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1690 
1691 	CommandCost ret = CheckOwnership(v->owner);
1692 	if (ret.Failed()) return ret;
1693 
1694 	Order *order = v->GetOrder(order_number);
1695 	if (order == nullptr) return CMD_ERROR;
1696 
1697 	/* Automatic refit cargo is only supported for goto station orders. */
1698 	if (cargo == CT_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1699 
1700 	if (order->GetLoadType() & OLFB_NO_LOAD) return CMD_ERROR;
1701 
1702 	if (flags & DC_EXEC) {
1703 		order->SetRefit(cargo);
1704 
1705 		/* Make the depot order an 'always go' order. */
1706 		if (cargo != CT_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1707 			order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
1708 			order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
1709 		}
1710 
1711 		for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1712 			/* Update any possible open window of the vehicle */
1713 			InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS);
1714 
1715 			/* If the vehicle already got the current depot set as current order, then update current order as well */
1716 			if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
1717 				u->current_order.SetRefit(cargo);
1718 			}
1719 		}
1720 	}
1721 
1722 	return CommandCost();
1723 }
1724 
1725 
1726 /**
1727  *
1728  * Check the orders of a vehicle, to see if there are invalid orders and stuff
1729  *
1730  */
CheckOrders(const Vehicle * v)1731 void CheckOrders(const Vehicle *v)
1732 {
1733 	/* Does the user wants us to check things? */
1734 	if (_settings_client.gui.order_review_system == 0) return;
1735 
1736 	/* Do nothing for crashed vehicles */
1737 	if (v->vehstatus & VS_CRASHED) return;
1738 
1739 	/* Do nothing for stopped vehicles if setting is '1' */
1740 	if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
1741 
1742 	/* do nothing we we're not the first vehicle in a share-chain */
1743 	if (v->FirstShared() != v) return;
1744 
1745 	/* Only check every 20 days, so that we don't flood the message log */
1746 	if (v->owner == _local_company && v->day_counter % 20 == 0) {
1747 		StringID message = INVALID_STRING_ID;
1748 
1749 		/* Check the order list */
1750 		int n_st = 0;
1751 
1752 		for (const Order *order : v->Orders()) {
1753 			/* Dummy order? */
1754 			if (order->IsType(OT_DUMMY)) {
1755 				message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1756 				break;
1757 			}
1758 			/* Does station have a load-bay for this vehicle? */
1759 			if (order->IsType(OT_GOTO_STATION)) {
1760 				const Station *st = Station::Get(order->GetDestination());
1761 
1762 				n_st++;
1763 				if (!CanVehicleUseStation(v, st)) {
1764 					message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1765 				} else if (v->type == VEH_AIRCRAFT &&
1766 							(AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1767 							(st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) &&
1768 							!_cheats.no_jetcrash.value &&
1769 							message == INVALID_STRING_ID) {
1770 					message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1771 				}
1772 			}
1773 		}
1774 
1775 		/* Check if the last and the first order are the same */
1776 		if (v->GetNumOrders() > 1) {
1777 			const Order *last = v->GetLastOrder();
1778 
1779 			if (v->orders.list->GetFirstOrder()->Equals(*last)) {
1780 				message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1781 			}
1782 		}
1783 
1784 		/* Do we only have 1 station in our order list? */
1785 		if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1786 
1787 #ifdef WITH_ASSERT
1788 		if (v->orders.list != nullptr) v->orders.list->DebugCheckSanity();
1789 #endif
1790 
1791 		/* We don't have a problem */
1792 		if (message == INVALID_STRING_ID) return;
1793 
1794 		SetDParam(0, v->index);
1795 		AddVehicleAdviceNewsItem(message, v->index);
1796 	}
1797 }
1798 
1799 /**
1800  * Removes an order from all vehicles. Triggers when, say, a station is removed.
1801  * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
1802  * @param destination The destination. Can be a StationID, DepotID or WaypointID.
1803  * @param hangar Only used for airports in the destination.
1804  *               When false, remove airport and hangar orders.
1805  *               When true, remove either airport or hangar order.
1806  */
RemoveOrderFromAllVehicles(OrderType type,DestinationID destination,bool hangar)1807 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1808 {
1809 	/* Aircraft have StationIDs for depot orders and never use DepotIDs
1810 	 * This fact is handled specially below
1811 	 */
1812 
1813 	/* Go through all vehicles */
1814 	for (Vehicle *v : Vehicle::Iterate()) {
1815 		Order *order;
1816 
1817 		order = &v->current_order;
1818 		if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : order->GetType()) == type &&
1819 				(!hangar || v->type == VEH_AIRCRAFT) && v->current_order.GetDestination() == destination) {
1820 			order->MakeDummy();
1821 			SetWindowDirty(WC_VEHICLE_VIEW, v->index);
1822 		}
1823 
1824 		/* Clear the order from the order-list */
1825 		int id = -1;
1826 		for (Order *order : v->Orders()) {
1827 			id++;
1828 restart:
1829 
1830 			OrderType ot = order->GetType();
1831 			if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
1832 			if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) continue; // Not an aircraft? Can't have a hangar order.
1833 			if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1834 			if (ot == type && order->GetDestination() == destination) {
1835 				/* We want to clear implicit orders, but we don't want to make them
1836 				 * dummy orders. They should just vanish. Also check the actual order
1837 				 * type as ot is currently OT_GOTO_STATION. */
1838 				if (order->IsType(OT_IMPLICIT)) {
1839 					order = order->next; // DeleteOrder() invalidates current order
1840 					DeleteOrder(v, id);
1841 					if (order != nullptr) goto restart;
1842 					break;
1843 				}
1844 
1845 				/* Clear wait time */
1846 				v->orders.list->UpdateTotalDuration(-order->GetWaitTime());
1847 				if (order->IsWaitTimetabled()) {
1848 					v->orders.list->UpdateTimetableDuration(-order->GetTimetabledWait());
1849 					order->SetWaitTimetabled(false);
1850 				}
1851 				order->SetWaitTime(0);
1852 
1853 				/* Clear order, preserving travel time */
1854 				bool travel_timetabled = order->IsTravelTimetabled();
1855 				order->MakeDummy();
1856 				order->SetTravelTimetabled(travel_timetabled);
1857 
1858 				for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1859 					/* In GUI, simulate by removing the order and adding it back */
1860 					InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
1861 					InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
1862 				}
1863 			}
1864 		}
1865 	}
1866 
1867 	OrderBackup::RemoveOrder(type, destination, hangar);
1868 }
1869 
1870 /**
1871  * Checks if a vehicle has a depot in its order list.
1872  * @return True iff at least one order is a depot order.
1873  */
HasDepotOrder() const1874 bool Vehicle::HasDepotOrder() const
1875 {
1876 	for (const Order *order : this->Orders()) {
1877 		if (order->IsType(OT_GOTO_DEPOT)) return true;
1878 	}
1879 
1880 	return false;
1881 }
1882 
1883 /**
1884  * Delete all orders from a vehicle
1885  * @param v                   Vehicle whose orders to reset
1886  * @param keep_orderlist      If true, do not free the order list, only empty it.
1887  * @param reset_order_indices If true, reset cur_implicit_order_index and cur_real_order_index
1888  *                            and cancel the current full load order (if the vehicle is loading).
1889  *                            If false, _you_ have to make sure the order indices are valid after
1890  *                            your messing with them!
1891  */
DeleteVehicleOrders(Vehicle * v,bool keep_orderlist,bool reset_order_indices)1892 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1893 {
1894 	DeleteOrderWarnings(v);
1895 
1896 	if (v->IsOrderListShared()) {
1897 		/* Remove ourself from the shared order list. */
1898 		v->RemoveFromShared();
1899 		v->orders.list = nullptr;
1900 	} else if (v->orders.list != nullptr) {
1901 		/* Remove the orders */
1902 		v->orders.list->FreeChain(keep_orderlist);
1903 		if (!keep_orderlist) v->orders.list = nullptr;
1904 	}
1905 
1906 	if (reset_order_indices) {
1907 		v->cur_implicit_order_index = v->cur_real_order_index = 0;
1908 		if (v->current_order.IsType(OT_LOADING)) {
1909 			CancelLoadingDueToDeletedOrder(v);
1910 		}
1911 	}
1912 }
1913 
1914 /**
1915  * Clamp the service interval to the correct min/max. The actual min/max values
1916  * depend on whether it's in percent or days.
1917  * @param interval proposed service interval
1918  * @return Clamped service interval
1919  */
GetServiceIntervalClamped(uint interval,bool ispercent)1920 uint16 GetServiceIntervalClamped(uint interval, bool ispercent)
1921 {
1922 	return ispercent ? Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1923 }
1924 
1925 /**
1926  *
1927  * Check if a vehicle has any valid orders
1928  *
1929  * @return false if there are no valid orders
1930  * @note Conditional orders are not considered valid destination orders
1931  *
1932  */
CheckForValidOrders(const Vehicle * v)1933 static bool CheckForValidOrders(const Vehicle *v)
1934 {
1935 	for (const Order *order : v->Orders()) {
1936 		switch (order->GetType()) {
1937 			case OT_GOTO_STATION:
1938 			case OT_GOTO_DEPOT:
1939 			case OT_GOTO_WAYPOINT:
1940 				return true;
1941 
1942 			default:
1943 				break;
1944 		}
1945 	}
1946 
1947 	return false;
1948 }
1949 
1950 /**
1951  * Compare the variable and value based on the given comparator.
1952  */
OrderConditionCompare(OrderConditionComparator occ,int variable,int value)1953 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1954 {
1955 	switch (occ) {
1956 		case OCC_EQUALS:      return variable == value;
1957 		case OCC_NOT_EQUALS:  return variable != value;
1958 		case OCC_LESS_THAN:   return variable <  value;
1959 		case OCC_LESS_EQUALS: return variable <= value;
1960 		case OCC_MORE_THAN:   return variable >  value;
1961 		case OCC_MORE_EQUALS: return variable >= value;
1962 		case OCC_IS_TRUE:     return variable != 0;
1963 		case OCC_IS_FALSE:    return variable == 0;
1964 		default: NOT_REACHED();
1965 	}
1966 }
1967 
1968 /**
1969  * Process a conditional order and determine the next order.
1970  * @param order the order the vehicle currently has
1971  * @param v the vehicle to update
1972  * @return index of next order to jump to, or INVALID_VEH_ORDER_ID to use the next order
1973  */
ProcessConditionalOrder(const Order * order,const Vehicle * v)1974 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
1975 {
1976 	if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1977 
1978 	bool skip_order = false;
1979 	OrderConditionComparator occ = order->GetConditionComparator();
1980 	uint16 value = order->GetConditionValue();
1981 
1982 	switch (order->GetConditionVariable()) {
1983 		case OCV_LOAD_PERCENTAGE:    skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1984 		case OCV_RELIABILITY:        skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability),       value); break;
1985 		case OCV_MAX_RELIABILITY:    skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability),   value); break;
1986 		case OCV_MAX_SPEED:          skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1987 		case OCV_AGE:                skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR,        value); break;
1988 		case OCV_REQUIRES_SERVICE:   skip_order = OrderConditionCompare(occ, v->NeedsServicing(),               value); break;
1989 		case OCV_UNCONDITIONALLY:    skip_order = true; break;
1990 		case OCV_REMAINING_LIFETIME: skip_order = OrderConditionCompare(occ, std::max(v->max_age - v->age + DAYS_IN_LEAP_YEAR - 1, 0) / DAYS_IN_LEAP_YEAR, value); break;
1991 		default: NOT_REACHED();
1992 	}
1993 
1994 	return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1995 }
1996 
1997 /**
1998  * Update the vehicle's destination tile from an order.
1999  * @param order the order the vehicle currently has
2000  * @param v the vehicle to update
2001  * @param conditional_depth the depth (amount of steps) to go with conditional orders. This to prevent infinite loops.
2002  * @param pbs_look_ahead Whether we are forecasting orders for pbs reservations in advance. If true, the order indices must not be modified.
2003  */
UpdateOrderDest(Vehicle * v,const Order * order,int conditional_depth,bool pbs_look_ahead)2004 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
2005 {
2006 	if (conditional_depth > v->GetNumOrders()) {
2007 		v->current_order.Free();
2008 		v->SetDestTile(0);
2009 		return false;
2010 	}
2011 
2012 	switch (order->GetType()) {
2013 		case OT_GOTO_STATION:
2014 			v->SetDestTile(v->GetOrderStationLocation(order->GetDestination()));
2015 			return true;
2016 
2017 		case OT_GOTO_DEPOT:
2018 			if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
2019 				assert(!pbs_look_ahead);
2020 				UpdateVehicleTimetable(v, true);
2021 				v->IncrementRealOrderIndex();
2022 				break;
2023 			}
2024 
2025 			if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
2026 				/* We need to search for the nearest depot (hangar). */
2027 				TileIndex location;
2028 				DestinationID destination;
2029 				bool reverse;
2030 
2031 				if (v->FindClosestDepot(&location, &destination, &reverse)) {
2032 					/* PBS reservations cannot reverse */
2033 					if (pbs_look_ahead && reverse) return false;
2034 
2035 					v->SetDestTile(location);
2036 					v->current_order.MakeGoToDepot(destination, v->current_order.GetDepotOrderType(), v->current_order.GetNonStopType(), (OrderDepotActionFlags)(v->current_order.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT), v->current_order.GetRefitCargo());
2037 
2038 					/* If there is no depot in front, reverse automatically (trains only) */
2039 					if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
2040 
2041 					if (v->type == VEH_AIRCRAFT) {
2042 						Aircraft *a = Aircraft::From(v);
2043 						if (a->state == FLYING && a->targetairport != destination) {
2044 							/* The aircraft is now heading for a different hangar than the next in the orders */
2045 							extern void AircraftNextAirportPos_and_Order(Aircraft *a);
2046 							AircraftNextAirportPos_and_Order(a);
2047 						}
2048 					}
2049 					return true;
2050 				}
2051 
2052 				/* If there is no depot, we cannot help PBS either. */
2053 				if (pbs_look_ahead) return false;
2054 
2055 				UpdateVehicleTimetable(v, true);
2056 				v->IncrementRealOrderIndex();
2057 			} else {
2058 				if (v->type != VEH_AIRCRAFT) {
2059 					v->SetDestTile(Depot::Get(order->GetDestination())->xy);
2060 				} else {
2061 					Aircraft *a = Aircraft::From(v);
2062 					DestinationID destination = a->current_order.GetDestination();
2063 					if (a->targetairport != destination) {
2064 						/* The aircraft is now heading for a different hangar than the next in the orders */
2065 						a->SetDestTile(a->GetOrderStationLocation(destination));
2066 					}
2067 				}
2068 				return true;
2069 			}
2070 			break;
2071 
2072 		case OT_GOTO_WAYPOINT:
2073 			v->SetDestTile(Waypoint::Get(order->GetDestination())->xy);
2074 			return true;
2075 
2076 		case OT_CONDITIONAL: {
2077 			assert(!pbs_look_ahead);
2078 			VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2079 			if (next_order != INVALID_VEH_ORDER_ID) {
2080 				/* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2081 				 * cur_real_order_index might come after next_order. */
2082 				UpdateVehicleTimetable(v, false);
2083 				v->cur_implicit_order_index = v->cur_real_order_index = next_order;
2084 				v->UpdateRealOrderIndex();
2085 				v->current_order_time += v->GetOrder(v->cur_real_order_index)->GetTimetabledTravel();
2086 
2087 				/* Disable creation of implicit orders.
2088 				 * When inserting them we do not know that we would have to make the conditional orders point to them. */
2089 				if (v->IsGroundVehicle()) {
2090 					uint16 &gv_flags = v->GetGroundVehicleFlags();
2091 					SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
2092 				}
2093 			} else {
2094 				UpdateVehicleTimetable(v, true);
2095 				v->IncrementRealOrderIndex();
2096 			}
2097 			break;
2098 		}
2099 
2100 		default:
2101 			v->SetDestTile(0);
2102 			return false;
2103 	}
2104 
2105 	assert(v->cur_implicit_order_index < v->GetNumOrders());
2106 	assert(v->cur_real_order_index < v->GetNumOrders());
2107 
2108 	/* Get the current order */
2109 	order = v->GetOrder(v->cur_real_order_index);
2110 	if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2111 		assert(v->GetNumManualOrders() == 0);
2112 		order = nullptr;
2113 	}
2114 
2115 	if (order == nullptr) {
2116 		v->current_order.Free();
2117 		v->SetDestTile(0);
2118 		return false;
2119 	}
2120 
2121 	v->current_order = *order;
2122 	return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2123 }
2124 
2125 /**
2126  * Handle the orders of a vehicle and determine the next place
2127  * to go to if needed.
2128  * @param v the vehicle to do this for.
2129  * @return true *if* the vehicle is eligible for reversing
2130  *              (basically only when leaving a station).
2131  */
ProcessOrders(Vehicle * v)2132 bool ProcessOrders(Vehicle *v)
2133 {
2134 	switch (v->current_order.GetType()) {
2135 		case OT_GOTO_DEPOT:
2136 			/* Let a depot order in the orderlist interrupt. */
2137 			if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
2138 			break;
2139 
2140 		case OT_LOADING:
2141 			return false;
2142 
2143 		case OT_LEAVESTATION:
2144 			if (v->type != VEH_AIRCRAFT) return false;
2145 			break;
2146 
2147 		default: break;
2148 	}
2149 
2150 	/**
2151 	 * Reversing because of order change is allowed only just after leaving a
2152 	 * station (and the difficulty setting to allowed, of course)
2153 	 * this can be detected because only after OT_LEAVESTATION, current_order
2154 	 * will be reset to nothing. (That also happens if no order, but in that case
2155 	 * it won't hit the point in code where may_reverse is checked)
2156 	 */
2157 	bool may_reverse = v->current_order.IsType(OT_NOTHING);
2158 
2159 	/* Check if we've reached a 'via' destination. */
2160 	if (((v->current_order.IsType(OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) || v->current_order.IsType(OT_GOTO_WAYPOINT)) &&
2161 			IsTileType(v->tile, MP_STATION) &&
2162 			v->current_order.GetDestination() == GetStationIndex(v->tile)) {
2163 		v->DeleteUnreachedImplicitOrders();
2164 		/* We set the last visited station here because we do not want
2165 		 * the train to stop at this 'via' station if the next order
2166 		 * is a no-non-stop order; in that case not setting the last
2167 		 * visited station will cause the vehicle to still stop. */
2168 		v->last_station_visited = v->current_order.GetDestination();
2169 		UpdateVehicleTimetable(v, true);
2170 		v->IncrementImplicitOrderIndex();
2171 	}
2172 
2173 	/* Get the current order */
2174 	assert(v->cur_implicit_order_index == 0 || v->cur_implicit_order_index < v->GetNumOrders());
2175 	v->UpdateRealOrderIndex();
2176 
2177 	const Order *order = v->GetOrder(v->cur_real_order_index);
2178 	if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2179 		assert(v->GetNumManualOrders() == 0);
2180 		order = nullptr;
2181 	}
2182 
2183 	/* If no order, do nothing. */
2184 	if (order == nullptr || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
2185 		if (v->type == VEH_AIRCRAFT) {
2186 			/* Aircraft do something vastly different here, so handle separately */
2187 			extern void HandleMissingAircraftOrders(Aircraft *v);
2188 			HandleMissingAircraftOrders(Aircraft::From(v));
2189 			return false;
2190 		}
2191 
2192 		v->current_order.Free();
2193 		v->SetDestTile(0);
2194 		return false;
2195 	}
2196 
2197 	/* If it is unchanged, keep it. */
2198 	if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
2199 			(v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->ship_station.tile != INVALID_TILE)) {
2200 		return false;
2201 	}
2202 
2203 	/* Otherwise set it, and determine the destination tile. */
2204 	v->current_order = *order;
2205 
2206 	InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
2207 	switch (v->type) {
2208 		default:
2209 			NOT_REACHED();
2210 
2211 		case VEH_ROAD:
2212 		case VEH_TRAIN:
2213 			break;
2214 
2215 		case VEH_AIRCRAFT:
2216 		case VEH_SHIP:
2217 			SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
2218 			break;
2219 	}
2220 
2221 	return UpdateOrderDest(v, order) && may_reverse;
2222 }
2223 
2224 /**
2225  * Check whether the given vehicle should stop at the given station
2226  * based on this order and the non-stop settings.
2227  * @param v       the vehicle that might be stopping.
2228  * @param station the station to stop at.
2229  * @return true if the vehicle should stop.
2230  */
ShouldStopAtStation(const Vehicle * v,StationID station) const2231 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2232 {
2233 	bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2234 
2235 	return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
2236 			v->last_station_visited != station && // Do stop only when we've not just been there
2237 			/* Finally do stop when there is no non-stop flag set for this type of station. */
2238 			!(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
2239 }
2240 
CanLoadOrUnload() const2241 bool Order::CanLoadOrUnload() const
2242 {
2243 	return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2244 			(this->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0 &&
2245 			((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
2246 			(this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
2247 }
2248 
2249 /**
2250  * A vehicle can leave the current station with cargo if:
2251  * 1. it can load cargo here OR
2252  * 2a. it could leave the last station with cargo AND
2253  * 2b. it doesn't have to unload all cargo here.
2254  */
CanLeaveWithCargo(bool has_cargo) const2255 bool Order::CanLeaveWithCargo(bool has_cargo) const
2256 {
2257 	return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
2258 			(this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
2259 }
2260