OpenTTD Source 20241222-master-gc72542431a
order_cmd.cpp
Go to the documentation of this file.
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
10#include "stdafx.h"
11#include "debug.h"
12#include "command_func.h"
13#include "company_func.h"
14#include "news_func.h"
15#include "strings_func.h"
16#include "timetable.h"
17#include "vehicle_func.h"
18#include "depot_base.h"
19#include "core/pool_func.hpp"
20#include "core/random_func.hpp"
21#include "aircraft.h"
22#include "roadveh.h"
23#include "station_base.h"
24#include "waypoint_base.h"
25#include "company_base.h"
26#include "order_backup.h"
27#include "cheat_type.h"
28#include "order_cmd.h"
29#include "train_cmd.h"
30
31#include "table/strings.h"
32
33#include "safeguards.h"
34
35/* DestinationID must be at least as large as every these below, because it can
36 * be any of them
37 */
38static_assert(sizeof(DestinationID) >= sizeof(DepotID));
39static_assert(sizeof(DestinationID) >= sizeof(StationID));
40
41OrderPool _order_pool("Order");
43OrderListPool _orderlist_pool("OrderList");
45
46
48{
49 if (CleaningPool()) return;
50
51 /* We can visit oil rigs and buoys that are not our own. They will be shown in
52 * the list of stations. So, we need to invalidate that window if needed. */
53 if (this->IsType(OT_GOTO_STATION) || this->IsType(OT_GOTO_WAYPOINT)) {
54 BaseStation *bs = BaseStation::GetIfValid(this->GetDestination());
55 if (bs != nullptr && bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0);
56 }
57}
58
64{
65 this->type = OT_NOTHING;
66 this->flags = 0;
67 this->dest = 0;
68 this->next = nullptr;
69}
70
75void Order::MakeGoToStation(StationID destination)
76{
77 this->type = OT_GOTO_STATION;
78 this->flags = 0;
79 this->dest = destination;
80}
81
91{
92 this->type = OT_GOTO_DEPOT;
93 this->SetDepotOrderType(order);
94 this->SetDepotActionType(action);
95 this->SetNonStopType(non_stop_type);
96 this->dest = destination;
97 this->SetRefit(cargo);
98}
99
104void Order::MakeGoToWaypoint(StationID destination)
105{
106 this->type = OT_GOTO_WAYPOINT;
107 this->flags = 0;
108 this->dest = destination;
109}
110
115void Order::MakeLoading(bool ordered)
116{
117 this->type = OT_LOADING;
118 if (!ordered) this->flags = 0;
119}
120
125{
126 this->type = OT_LEAVESTATION;
127 this->flags = 0;
128}
129
134{
135 this->type = OT_DUMMY;
136 this->flags = 0;
137}
138
144{
145 this->type = OT_CONDITIONAL;
146 this->flags = order;
147 this->dest = 0;
148}
149
154void Order::MakeImplicit(StationID destination)
155{
156 this->type = OT_IMPLICIT;
157 this->dest = destination;
158}
159
166{
167 this->refit_cargo = cargo;
168}
169
175bool Order::Equals(const Order &other) const
176{
177 /* In case of go to nearest depot orders we need "only" compare the flags
178 * with the other and not the nearest depot order bit or the actual
179 * destination because those get clear/filled in during the order
180 * evaluation. If we do not do this the order will continuously be seen as
181 * a different order and it will try to find a "nearest depot" every tick. */
182 if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
183 ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
184 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
185 return this->GetDepotOrderType() == other.GetDepotOrderType() &&
186 (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
187 }
188
189 return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
190}
191
198uint32_t Order::Pack() const
199{
200 return this->dest << 16 | this->flags << 8 | this->type;
201}
202
208uint16_t Order::MapOldOrder() const
209{
210 uint16_t order = this->GetType();
211 switch (this->type) {
212 case OT_GOTO_STATION:
213 if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
214 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
216 order |= GB(this->GetDestination(), 0, 8) << 8;
217 break;
218 case OT_GOTO_DEPOT:
219 if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
220 SetBit(order, 7);
221 order |= GB(this->GetDestination(), 0, 8) << 8;
222 break;
223 case OT_LOADING:
224 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
225 break;
226 }
227 return order;
228}
229
235void InvalidateVehicleOrder(const Vehicle *v, int data)
236{
238
239 if (data != 0) {
240 /* Calls SetDirty() too */
243 return;
244 }
245
248}
249
257void Order::AssignOrder(const Order &other)
258{
259 this->type = other.type;
260 this->flags = other.flags;
261 this->dest = other.dest;
262
263 this->refit_cargo = other.refit_cargo;
264
265 this->wait_time = other.wait_time;
266 this->travel_time = other.travel_time;
267 this->max_speed = other.max_speed;
268}
269
276{
277 this->first = chain;
278 this->first_shared = v;
279
280 this->num_orders = 0;
281 this->num_manual_orders = 0;
282 this->num_vehicles = 1;
283 this->timetable_duration = 0;
284
285 for (Order *o = this->first; o != nullptr; o = o->next) {
286 ++this->num_orders;
287 if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
288 this->total_duration += o->GetWaitTime() + o->GetTravelTime();
289 }
290
292
293 for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
294 ++this->num_vehicles;
295 this->first_shared = u;
296 }
297
298 for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
299}
300
306{
307 this->timetable_duration = 0;
308 for (Order *o = this->first; o != nullptr; o = o->next) {
309 this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
310 }
311}
312
318void OrderList::FreeChain(bool keep_orderlist)
319{
320 Order *next;
321 for (Order *o = this->first; o != nullptr; o = next) {
322 next = o->next;
323 delete o;
324 }
325
326 if (keep_orderlist) {
327 this->first = nullptr;
328 this->num_orders = 0;
329 this->num_manual_orders = 0;
330 this->timetable_duration = 0;
331 } else {
332 delete this;
333 }
334}
335
342{
343 if (index < 0) return nullptr;
344
345 Order *order = this->first;
346
347 while (order != nullptr && index-- > 0) {
348 order = order->next;
349 }
350 return order;
351}
352
364const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
365{
366 if (hops > this->GetNumOrders() || next == nullptr) return nullptr;
367
368 if (next->IsType(OT_CONDITIONAL)) {
369 if (next->GetConditionVariable() != OCV_UNCONDITIONALLY) return next;
370
371 /* We can evaluate trivial conditions right away. They're conceptually
372 * the same as regular order progression. */
373 return this->GetNextDecisionNode(
374 this->GetOrderAt(next->GetConditionSkipToOrder()),
375 hops + 1);
376 }
377
378 if (next->IsType(OT_GOTO_DEPOT)) {
379 if ((next->GetDepotActionType() & ODATFB_HALT) != 0) return nullptr;
380 if (next->IsRefit()) return next;
381 }
382
383 if (!next->CanLoadOrUnload()) {
384 return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
385 }
386
387 return next;
388}
389
399StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first, uint hops) const
400{
401
402 const Order *next = first;
403 if (first == nullptr) {
404 next = this->GetOrderAt(v->cur_implicit_order_index);
405 if (next == nullptr) {
406 next = this->GetFirstOrder();
407 if (next == nullptr) return INVALID_STATION;
408 } else {
409 /* GetNext never returns nullptr if there is a valid station in the list.
410 * As the given "next" is already valid and a station in the list, we
411 * don't have to check for nullptr here. */
412 next = this->GetNext(next);
413 assert(next != nullptr);
414 }
415 }
416
417 do {
418 next = this->GetNextDecisionNode(next, ++hops);
419
420 /* Resolve possibly nested conditionals by estimation. */
421 while (next != nullptr && next->IsType(OT_CONDITIONAL)) {
422 /* We return both options of conditional orders. */
423 const Order *skip_to = this->GetNextDecisionNode(
424 this->GetOrderAt(next->GetConditionSkipToOrder()), hops);
425 const Order *advance = this->GetNextDecisionNode(
426 this->GetNext(next), hops);
427 if (advance == nullptr || advance == first || skip_to == advance) {
428 next = (skip_to == first) ? nullptr : skip_to;
429 } else if (skip_to == nullptr || skip_to == first) {
430 next = (advance == first) ? nullptr : advance;
431 } else {
432 StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
433 StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
434 while (!st2.IsEmpty()) st1.Push(st2.Pop());
435 return st1;
436 }
437 ++hops;
438 }
439
440 /* Don't return a next stop if the vehicle has to unload everything. */
441 if (next == nullptr || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) &&
442 next->GetDestination() == v->last_station_visited &&
443 (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
444 return INVALID_STATION;
445 }
446 } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
447
448 return next->GetDestination();
449}
450
456void OrderList::InsertOrderAt(Order *new_order, int index)
457{
458 if (this->first == nullptr) {
459 this->first = new_order;
460 } else {
461 if (index == 0) {
462 /* Insert as first or only order */
463 new_order->next = this->first;
464 this->first = new_order;
465 } else if (index >= this->num_orders) {
466 /* index is after the last order, add it to the end */
467 this->GetLastOrder()->next = new_order;
468 } else {
469 /* Put the new order in between */
470 Order *order = this->GetOrderAt(index - 1);
471 new_order->next = order->next;
472 order->next = new_order;
473 }
474 }
475 ++this->num_orders;
476 if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
477 this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
478 this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
479
480 /* We can visit oil rigs and buoys that are not our own. They will be shown in
481 * the list of stations. So, we need to invalidate that window if needed. */
482 if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
483 BaseStation *bs = BaseStation::Get(new_order->GetDestination());
485 }
486
487}
488
489
495{
496 if (index >= this->num_orders) return;
497
498 Order *to_remove;
499
500 if (index == 0) {
501 to_remove = this->first;
502 this->first = to_remove->next;
503 } else {
504 Order *prev = GetOrderAt(index - 1);
505 to_remove = prev->next;
506 prev->next = to_remove->next;
507 }
508 --this->num_orders;
509 if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
510 this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
511 this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
512 delete to_remove;
513}
514
520void OrderList::MoveOrder(int from, int to)
521{
522 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
523
524 Order *moving_one;
525
526 /* Take the moving order out of the pointer-chain */
527 if (from == 0) {
528 moving_one = this->first;
529 this->first = moving_one->next;
530 } else {
531 Order *one_before = GetOrderAt(from - 1);
532 moving_one = one_before->next;
533 one_before->next = moving_one->next;
534 }
535
536 /* Insert the moving_order again in the pointer-chain */
537 if (to == 0) {
538 moving_one->next = this->first;
539 this->first = moving_one;
540 } else {
541 Order *one_before = GetOrderAt(to - 1);
542 moving_one->next = one_before->next;
543 one_before->next = moving_one;
544 }
545}
546
553{
554 --this->num_vehicles;
555 if (v == this->first_shared) this->first_shared = v->NextShared();
556}
557
563{
564 for (Order *o = this->first; o != nullptr; o = o->next) {
565 /* Implicit orders are, by definition, not timetabled. */
566 if (o->IsType(OT_IMPLICIT)) continue;
567 if (!o->IsCompletelyTimetabled()) return false;
568 }
569 return true;
570}
571
572#ifdef WITH_ASSERT
576void OrderList::DebugCheckSanity() const
577{
578 VehicleOrderID check_num_orders = 0;
579 VehicleOrderID check_num_manual_orders = 0;
580 uint check_num_vehicles = 0;
581 TimerGameTick::Ticks check_timetable_duration = 0;
582 TimerGameTick::Ticks check_total_duration = 0;
583
584 Debug(misc, 6, "Checking OrderList {} for sanity...", this->index);
585
586 for (const Order *o = this->first; o != nullptr; o = o->next) {
587 ++check_num_orders;
588 if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
589 check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
590 check_total_duration += o->GetWaitTime() + o->GetTravelTime();
591 }
592 assert(this->num_orders == check_num_orders);
593 assert(this->num_manual_orders == check_num_manual_orders);
594 assert(this->timetable_duration == check_timetable_duration);
595 assert(this->total_duration == check_total_duration);
596
597 for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
598 ++check_num_vehicles;
599 assert(v->orders == this);
600 }
601 assert(this->num_vehicles == check_num_vehicles);
602 Debug(misc, 6, "... detected {} orders ({} manual), {} vehicles, {} timetabled, {} total",
603 (uint)this->num_orders, (uint)this->num_manual_orders,
605}
606#endif
607
615static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
616{
617 return o->IsType(OT_GOTO_STATION) ||
618 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && o->GetDestination() != INVALID_STATION);
619}
620
627static void DeleteOrderWarnings(const Vehicle *v)
628{
629 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
630 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
631 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
632 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
633 DeleteVehicleNews(v->index, STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY);
634}
635
642TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
643{
644 switch (this->GetType()) {
645 case OT_GOTO_WAYPOINT:
646 case OT_GOTO_STATION:
647 case OT_IMPLICIT:
648 if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile;
649 return BaseStation::Get(this->GetDestination())->xy;
650
651 case OT_GOTO_DEPOT:
652 if (this->GetDestination() == INVALID_DEPOT) return INVALID_TILE;
653 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
654
655 default:
656 return INVALID_TILE;
657 }
658}
659
669uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
670{
671 if (cur->IsType(OT_CONDITIONAL)) {
672 if (conditional_depth > v->GetNumOrders()) return 0;
673
674 conditional_depth++;
675
676 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
677 int dist2 = GetOrderDistance(prev, cur->next == nullptr ? v->orders->GetFirstOrder() : cur->next, v, conditional_depth);
678 return std::max(dist1, dist2);
679 }
680
681 TileIndex prev_tile = prev->GetLocation(v, true);
682 TileIndex cur_tile = cur->GetLocation(v, true);
683 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
684 return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
685}
686
698{
700 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
701
703 if (ret.Failed()) return ret;
704
705 /* Validate properties we don't want to have different from default as they are set by other commands. */
706 if (new_order.GetRefitCargo() != CARGO_NO_REFIT || new_order.GetWaitTime() != 0 || new_order.GetTravelTime() != 0 || new_order.GetMaxSpeed() != UINT16_MAX) return CMD_ERROR;
707
708 /* Check if the inserted order is to the correct destination (owner, type),
709 * and has the correct flags if any */
710 switch (new_order.GetType()) {
711 case OT_GOTO_STATION: {
712 const Station *st = Station::GetIfValid(new_order.GetDestination());
713 if (st == nullptr) return CMD_ERROR;
714
715 if (st->owner != OWNER_NONE) {
716 ret = CheckOwnership(st->owner);
717 if (ret.Failed()) return ret;
718 }
719
720 if (!CanVehicleUseStation(v, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, GetVehicleCannotUseStationReason(v, st));
721 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
722 if (!CanVehicleUseStation(u, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER_SHARED, GetVehicleCannotUseStationReason(u, st));
723 }
724
725 /* Non stop only allowed for ground vehicles. */
726 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
727
728 /* Filter invalid load/unload types. */
729 switch (new_order.GetLoadType()) {
731 case OLFB_NO_LOAD:
732 break;
733
734 case OLFB_FULL_LOAD:
736 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
737 break;
738
739 default:
740 return CMD_ERROR;
741 }
742 switch (new_order.GetUnloadType()) {
744 default: return CMD_ERROR;
745 }
746
747 /* Filter invalid stop locations */
748 switch (new_order.GetStopLocation()) {
751 if (v->type != VEH_TRAIN) return CMD_ERROR;
752 [[fallthrough]];
753
755 break;
756
757 default:
758 return CMD_ERROR;
759 }
760
761 break;
762 }
763
764 case OT_GOTO_DEPOT: {
765 if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
766 if (v->type == VEH_AIRCRAFT) {
767 const Station *st = Station::GetIfValid(new_order.GetDestination());
768
769 if (st == nullptr) return CMD_ERROR;
770
771 ret = CheckOwnership(st->owner);
772 if (ret.Failed()) return ret;
773
774 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
775 return CMD_ERROR;
776 }
777 } else {
778 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
779
780 if (dp == nullptr) return CMD_ERROR;
781
782 ret = CheckOwnership(GetTileOwner(dp->xy));
783 if (ret.Failed()) return ret;
784
785 switch (v->type) {
786 case VEH_TRAIN:
787 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
788 break;
789
790 case VEH_ROAD:
791 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
792 break;
793
794 case VEH_SHIP:
795 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
796 break;
797
798 default: return CMD_ERROR;
799 }
800 }
801 }
802
803 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
804 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
806
807 /* Vehicles cannot have a "service if needed" order that also has a depot action. */
808 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & (ODATFB_HALT | ODATFB_UNBUNCH))) return CMD_ERROR;
809
810 /* Check if we're allowed to have a new unbunching order. */
811 if ((new_order.GetDepotActionType() & ODATFB_UNBUNCH)) {
812 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
813 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
814 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
815 }
816 break;
817 }
818
819 case OT_GOTO_WAYPOINT: {
820 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
821 if (wp == nullptr) return CMD_ERROR;
822
823 switch (v->type) {
824 default: return CMD_ERROR;
825
826 case VEH_TRAIN: {
827 if (!(wp->facilities & FACIL_TRAIN)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_RAIL_WAYPOINT);
828
829 ret = CheckOwnership(wp->owner);
830 if (ret.Failed()) return ret;
831 break;
832 }
833
834 case VEH_ROAD: {
835 if (!(wp->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP))) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_ROAD_WAYPOINT);
836
837 ret = CheckOwnership(wp->owner);
838 if (ret.Failed()) return ret;
839 break;
840 }
841
842 case VEH_SHIP:
843 if (!(wp->facilities & FACIL_DOCK)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_BUOY);
844 if (wp->owner != OWNER_NONE) {
845 ret = CheckOwnership(wp->owner);
846 if (ret.Failed()) return ret;
847 }
848 break;
849 }
850
851 /* Order flags can be any of the following for waypoints:
852 * [non-stop]
853 * non-stop orders (if any) are only valid for trains and road vehicles */
854 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
855 break;
856 }
857
858 case OT_CONDITIONAL: {
859 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
860 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
861 if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
862 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_CONDITIONAL);
863
865 if (occ >= OCC_END) return CMD_ERROR;
866 switch (new_order.GetConditionVariable()) {
868 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
869 break;
870
872 if (occ != OCC_EQUALS) return CMD_ERROR;
873 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
874 break;
875
877 case OCV_RELIABILITY:
878 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
879 [[fallthrough]];
880
881 default:
882 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
883 break;
884 }
885 break;
886 }
887
888 default: return CMD_ERROR;
889 }
890
891 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
892
893 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return CommandCost(STR_ERROR_TOO_MANY_ORDERS);
894 if (!Order::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
895 if (v->orders == nullptr && !OrderList::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
896
897 if (flags & DC_EXEC) {
898 Order *new_o = new Order();
899 new_o->AssignOrder(new_order);
900 InsertOrder(v, new_o, sel_ord);
901 }
902
903 return CommandCost();
904}
905
912void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
913{
914 /* Create new order and link in list */
915 if (v->orders == nullptr) {
916 v->orders = new OrderList(new_o, v);
917 } else {
918 v->orders->InsertOrderAt(new_o, sel_ord);
919 }
920
921 Vehicle *u = v->FirstShared();
923 for (; u != nullptr; u = u->NextShared()) {
924 assert(v->orders == u->orders);
925
926 /* If there is added an order before the current one, we need
927 * to update the selected order. We do not change implicit/real order indices though.
928 * If the new order is between the current implicit order and real order, the implicit order will
929 * later skip the inserted order. */
930 if (sel_ord <= u->cur_real_order_index) {
931 uint cur = u->cur_real_order_index + 1;
932 /* Check if we don't go out of bound */
933 if (cur < u->GetNumOrders()) {
934 u->cur_real_order_index = cur;
935 }
936 }
937 if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
938 /* We are inserting an order just before the current implicit order.
939 * We do not know whether we will reach current implicit or the newly inserted order first.
940 * So, disable creation of implicit orders until we are on track again. */
941 uint16_t &gv_flags = u->GetGroundVehicleFlags();
943 }
944 if (sel_ord <= u->cur_implicit_order_index) {
945 uint cur = u->cur_implicit_order_index + 1;
946 /* Check if we don't go out of bound */
947 if (cur < u->GetNumOrders()) {
949 }
950 }
951 /* Unbunching data is no longer valid. */
953
954 /* Update any possible open window of the vehicle */
955 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
956 }
957
958 /* As we insert an order, the order to skip to will be 'wrong'. */
959 VehicleOrderID cur_order_id = 0;
960 for (Order *order : v->Orders()) {
961 if (order->IsType(OT_CONDITIONAL)) {
962 VehicleOrderID order_id = order->GetConditionSkipToOrder();
963 if (order_id >= sel_ord) {
964 order->SetConditionSkipToOrder(order_id + 1);
965 }
966 if (order_id == cur_order_id) {
967 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
968 }
969 }
970 cur_order_id++;
971 }
972
973 /* Make sure to rebuild the whole list */
975}
976
991
1000{
1001 Vehicle *v = Vehicle::GetIfValid(veh_id);
1002
1003 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1004
1006 if (ret.Failed()) return ret;
1007
1008 /* If we did not select an order, we maybe want to de-clone the orders */
1009 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
1010
1011 if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
1012
1013 if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
1014 return CommandCost();
1015}
1016
1022{
1023 assert(v->current_order.IsType(OT_LOADING));
1024 /* NON-stop flag is misused to see if a train is in a station that is
1025 * on its order list or not */
1027 /* When full loading, "cancel" that order so the vehicle doesn't
1028 * stay indefinitely at this station anymore. */
1030}
1031
1038{
1039 v->orders->DeleteOrderAt(sel_ord);
1040
1041 Vehicle *u = v->FirstShared();
1043 for (; u != nullptr; u = u->NextShared()) {
1044 assert(v->orders == u->orders);
1045
1046 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
1048 }
1049
1050 if (sel_ord < u->cur_real_order_index) {
1052 } else if (sel_ord == u->cur_real_order_index) {
1054 }
1055
1056 if (sel_ord < u->cur_implicit_order_index) {
1058 } else if (sel_ord == u->cur_implicit_order_index) {
1059 /* Make sure the index is valid */
1061
1062 /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
1066 }
1067 }
1068 /* Unbunching data is no longer valid. */
1070
1071 /* Update any possible open window of the vehicle */
1072 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1073 }
1074
1075 /* As we delete an order, the order to skip to will be 'wrong'. */
1076 VehicleOrderID cur_order_id = 0;
1077 for (Order *order : v->Orders()) {
1078 if (order->IsType(OT_CONDITIONAL)) {
1079 VehicleOrderID order_id = order->GetConditionSkipToOrder();
1080 if (order_id >= sel_ord) {
1081 order_id = std::max(order_id - 1, 0);
1082 }
1083 if (order_id == cur_order_id) {
1084 order_id = (order_id + 1) % v->GetNumOrders();
1085 }
1086 order->SetConditionSkipToOrder(order_id);
1087 }
1088 cur_order_id++;
1089 }
1090
1092}
1093
1102{
1103 Vehicle *v = Vehicle::GetIfValid(veh_id);
1104
1105 if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1106
1108 if (ret.Failed()) return ret;
1109
1110 if (flags & DC_EXEC) {
1111 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1112
1115
1116 /* Unbunching data is no longer valid. */
1118
1120
1121 /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1124 }
1125
1126 return CommandCost();
1127}
1128
1140{
1141 Vehicle *v = Vehicle::GetIfValid(veh);
1142 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1143
1145 if (ret.Failed()) return ret;
1146
1147 /* Don't make senseless movements */
1148 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1149 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1150
1151 Order *moving_one = v->GetOrder(moving_order);
1152 /* Don't move an empty order */
1153 if (moving_one == nullptr) return CMD_ERROR;
1154
1155 if (flags & DC_EXEC) {
1156 v->orders->MoveOrder(moving_order, target_order);
1157
1158 /* Update shared list */
1159 Vehicle *u = v->FirstShared();
1160
1162
1163 for (; u != nullptr; u = u->NextShared()) {
1164 /* Update the current order.
1165 * There are multiple ways to move orders, which result in cur_implicit_order_index
1166 * and cur_real_order_index to not longer make any sense. E.g. moving another
1167 * real order between them.
1168 *
1169 * Basically one could choose to preserve either of them, but not both.
1170 * While both ways are suitable in this or that case from a human point of view, neither
1171 * of them makes really sense.
1172 * However, from an AI point of view, preserving cur_real_order_index is the most
1173 * predictable and transparent behaviour.
1174 *
1175 * With that decision it basically does not matter what we do to cur_implicit_order_index.
1176 * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1177 * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1178 * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1179 */
1180 if (u->cur_real_order_index == moving_order) {
1181 u->cur_real_order_index = target_order;
1182 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1184 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1186 }
1187
1188 if (u->cur_implicit_order_index == moving_order) {
1189 u->cur_implicit_order_index = target_order;
1190 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1192 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1194 }
1195 /* Unbunching data is no longer valid. */
1197
1198
1199 assert(v->orders == u->orders);
1200 /* Update any possible open window of the vehicle */
1201 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1202 }
1203
1204 /* As we move an order, the order to skip to will be 'wrong'. */
1205 for (Order *order : v->Orders()) {
1206 if (order->IsType(OT_CONDITIONAL)) {
1207 VehicleOrderID order_id = order->GetConditionSkipToOrder();
1208 if (order_id == moving_order) {
1209 order_id = target_order;
1210 } else if (order_id > moving_order && order_id <= target_order) {
1211 order_id--;
1212 } else if (order_id < moving_order && order_id >= target_order) {
1213 order_id++;
1214 }
1215 order->SetConditionSkipToOrder(order_id);
1216 }
1217 }
1218
1219 /* Make sure to rebuild the whole list */
1221 }
1222
1223 return CommandCost();
1224}
1225
1238{
1239 if (mof >= MOF_END) return CMD_ERROR;
1240
1241 Vehicle *v = Vehicle::GetIfValid(veh);
1242 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1243
1245 if (ret.Failed()) return ret;
1246
1247 /* Is it a valid order? */
1248 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1249
1250 Order *order = v->GetOrder(sel_ord);
1251 assert(order != nullptr);
1252 switch (order->GetType()) {
1253 case OT_GOTO_STATION:
1254 if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1255 break;
1256
1257 case OT_GOTO_DEPOT:
1258 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1259 break;
1260
1261 case OT_GOTO_WAYPOINT:
1262 if (mof != MOF_NON_STOP) return CMD_ERROR;
1263 break;
1264
1265 case OT_CONDITIONAL:
1266 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1267 break;
1268
1269 default:
1270 return CMD_ERROR;
1271 }
1272
1273 switch (mof) {
1274 default: NOT_REACHED();
1275
1276 case MOF_NON_STOP:
1277 if (!v->IsGroundVehicle()) return CMD_ERROR;
1278 if (data >= ONSF_END) return CMD_ERROR;
1279 if (data == order->GetNonStopType()) return CMD_ERROR;
1280 break;
1281
1282 case MOF_STOP_LOCATION:
1283 if (v->type != VEH_TRAIN) return CMD_ERROR;
1284 if (data >= OSL_END) return CMD_ERROR;
1285 break;
1286
1287 case MOF_UNLOAD:
1289 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
1290 /* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
1291 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
1292 if (data == order->GetUnloadType()) return CMD_ERROR;
1293 break;
1294
1295 case MOF_LOAD:
1297 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
1298 if (data == order->GetLoadType()) return CMD_ERROR;
1299 if ((data & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) && v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
1300 break;
1301
1302 case MOF_DEPOT_ACTION:
1303 if (data >= DA_END) return CMD_ERROR;
1304 /* Check if we are allowed to add unbunching. We are always allowed to remove it. */
1305 if (data == DA_UNBUNCH) {
1306 /* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */
1307 if (v->HasUnbunchingOrder() && !(order->GetDepotActionType() & ODATFB_UNBUNCH)) return CommandCost(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
1308 /* We don't allow unbunching if the vehicle has a conditional order. */
1309 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
1310 /* We don't allow unbunching if the vehicle has a full load order. */
1311 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
1312 }
1313 break;
1314
1315 case MOF_COND_VARIABLE:
1316 if (data >= OCV_END) return CMD_ERROR;
1317 break;
1318
1320 if (data >= OCC_END) return CMD_ERROR;
1321 switch (order->GetConditionVariable()) {
1322 case OCV_UNCONDITIONALLY: return CMD_ERROR;
1323
1325 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
1326 break;
1327
1328 default:
1329 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
1330 break;
1331 }
1332 break;
1333
1334 case MOF_COND_VALUE:
1335 switch (order->GetConditionVariable()) {
1338 return CMD_ERROR;
1339
1341 case OCV_RELIABILITY:
1342 if (data > 100) return CMD_ERROR;
1343 break;
1344
1345 default:
1346 if (data > 2047) return CMD_ERROR;
1347 break;
1348 }
1349 break;
1350
1352 if (data >= v->GetNumOrders()) return CMD_ERROR;
1353 break;
1354 }
1355
1356 if (flags & DC_EXEC) {
1357 switch (mof) {
1358 case MOF_NON_STOP:
1359 order->SetNonStopType((OrderNonStopFlags)data);
1361 order->SetRefit(CARGO_NO_REFIT);
1364 }
1365 break;
1366
1367 case MOF_STOP_LOCATION:
1368 order->SetStopLocation((OrderStopLocation)data);
1369 break;
1370
1371 case MOF_UNLOAD:
1372 order->SetUnloadType((OrderUnloadFlags)data);
1373 break;
1374
1375 case MOF_LOAD:
1376 order->SetLoadType((OrderLoadFlags)data);
1377 if (data & OLFB_NO_LOAD) order->SetRefit(CARGO_NO_REFIT);
1378 break;
1379
1380 case MOF_DEPOT_ACTION: {
1381 switch (data) {
1382 case DA_ALWAYS_GO:
1386 break;
1387
1388 case DA_SERVICE:
1392 order->SetRefit(CARGO_NO_REFIT);
1393 break;
1394
1395 case DA_STOP:
1399 order->SetRefit(CARGO_NO_REFIT);
1400 break;
1401
1402 case DA_UNBUNCH:
1406 break;
1407
1408 default:
1409 NOT_REACHED();
1410 }
1411 break;
1412 }
1413
1414 case MOF_COND_VARIABLE: {
1416
1418 switch (order->GetConditionVariable()) {
1421 order->SetConditionValue(0);
1422 break;
1423
1425 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
1426 order->SetConditionValue(0);
1427 break;
1428
1430 case OCV_RELIABILITY:
1431 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1432 [[fallthrough]];
1433
1434 default:
1435 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
1436 break;
1437 }
1438 break;
1439 }
1440
1443 break;
1444
1445 case MOF_COND_VALUE:
1446 order->SetConditionValue(data);
1447 break;
1448
1450 order->SetConditionSkipToOrder(data);
1451 break;
1452
1453 default: NOT_REACHED();
1454 }
1455
1456 /* Update the windows and full load flags, also for vehicles that share the same order list */
1457 Vehicle *u = v->FirstShared();
1459 for (; u != nullptr; u = u->NextShared()) {
1460 /* Toggle u->current_order "Full load" flag if it changed.
1461 * However, as the same flag is used for depot orders, check
1462 * whether we are not going to a depot as there are three
1463 * cases where the full load flag can be active and only
1464 * one case where the flag is used for depot orders. In the
1465 * other cases for the OrderType the flags are not used,
1466 * so do not care and those orders should not be active
1467 * when this function is called.
1468 */
1469 if (sel_ord == u->cur_real_order_index &&
1470 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1471 u->current_order.GetLoadType() != order->GetLoadType()) {
1473 }
1474
1475 /* Unbunching data is no longer valid. */
1477
1479 }
1480 }
1481
1482 return CommandCost();
1483}
1484
1492static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first)
1493{
1494 if (first == nullptr || v_new->acache.cached_max_range == 0) return true;
1495
1496 /* Iterate over all orders to check the distance between all
1497 * 'goto' orders and their respective next order (of any type). */
1498 for (const Order *o = first; o != nullptr; o = o->next) {
1499 switch (o->GetType()) {
1500 case OT_GOTO_STATION:
1501 case OT_GOTO_DEPOT:
1502 case OT_GOTO_WAYPOINT:
1503 /* If we don't have a next order, we've reached the end and must check the first order instead. */
1504 if (GetOrderDistance(o, o->next != nullptr ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false;
1505 break;
1506
1507 default: break;
1508 }
1509 }
1510
1511 return true;
1512}
1513
1523{
1524 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1525 if (dst == nullptr || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1526
1527 CommandCost ret = CheckOwnership(dst->owner);
1528 if (ret.Failed()) return ret;
1529
1530 switch (action) {
1531 case CO_SHARE: {
1532 Vehicle *src = Vehicle::GetIfValid(veh_src);
1533
1534 /* Sanity checks */
1535 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1536
1537 ret = CheckOwnership(src->owner);
1538 if (ret.Failed()) return ret;
1539
1540 /* Trucks can't share orders with busses (and visa versa) */
1541 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1542 return CMD_ERROR;
1543 }
1544
1545 /* Is the vehicle already in the shared list? */
1546 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1547
1548 for (const Order *order : src->Orders()) {
1549 if (!OrderGoesToStation(dst, order)) continue;
1550
1551 /* Allow copying unreachable destinations if they were already unreachable for the source.
1552 * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1553 * are temporarily invalid due to reconstruction. */
1554 const Station *st = Station::Get(order->GetDestination());
1555 if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1556 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1557 }
1558 }
1559
1560 /* Check for aircraft range limits. */
1561 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1562 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1563 }
1564
1565 if (src->orders == nullptr && !OrderList::CanAllocateItem()) {
1566 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1567 }
1568
1569 if (flags & DC_EXEC) {
1570 /* If the destination vehicle had a OrderList, destroy it.
1571 * We only reset the order indices, if the new orders are obviously different.
1572 * (We mainly do this to keep the order indices valid and in range.) */
1573 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1574
1575 dst->orders = src->orders;
1576
1577 /* Link this vehicle in the shared-list */
1578 dst->AddToShared(src);
1579
1582
1584 }
1585 break;
1586 }
1587
1588 case CO_COPY: {
1589 Vehicle *src = Vehicle::GetIfValid(veh_src);
1590
1591 /* Sanity checks */
1592 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1593
1594 ret = CheckOwnership(src->owner);
1595 if (ret.Failed()) return ret;
1596
1597 /* Trucks can't copy all the orders from busses (and visa versa),
1598 * and neither can helicopters and aircraft. */
1599 for (const Order *order : src->Orders()) {
1600 if (!OrderGoesToStation(dst, order)) continue;
1601 Station *st = Station::Get(order->GetDestination());
1602 if (!CanVehicleUseStation(dst, st)) {
1603 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1604 }
1605 }
1606
1607 /* Check for aircraft range limits. */
1608 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1609 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1610 }
1611
1612 /* make sure there are orders available */
1614 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1615 }
1616
1617 if (flags & DC_EXEC) {
1618 Order *first = nullptr;
1619 Order **order_dst;
1620
1621 /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1622 * We only reset the order indices, if the new orders are obviously different.
1623 * (We mainly do this to keep the order indices valid and in range.) */
1624 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1625
1626 order_dst = &first;
1627 for (const Order *order : src->Orders()) {
1628 *order_dst = new Order();
1629 (*order_dst)->AssignOrder(*order);
1630 order_dst = &(*order_dst)->next;
1631 }
1632 if (dst->orders == nullptr) {
1633 dst->orders = new OrderList(first, dst);
1634 } else {
1635 assert(dst->orders->GetFirstOrder() == nullptr);
1636 assert(!dst->orders->IsShared());
1637 delete dst->orders;
1639 dst->orders = new OrderList(first, dst);
1640 }
1641
1643
1645 }
1646 break;
1647 }
1648
1649 case CO_UNSHARE: return DecloneOrder(dst, flags);
1650 default: return CMD_ERROR;
1651 }
1652
1653 return CommandCost();
1654}
1655
1665{
1666 if (cargo >= NUM_CARGO && cargo != CARGO_NO_REFIT && cargo != CARGO_AUTO_REFIT) return CMD_ERROR;
1667
1668 const Vehicle *v = Vehicle::GetIfValid(veh);
1669 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1670
1672 if (ret.Failed()) return ret;
1673
1674 Order *order = v->GetOrder(order_number);
1675 if (order == nullptr) return CMD_ERROR;
1676
1677 /* Automatic refit cargo is only supported for goto station orders. */
1678 if (cargo == CARGO_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1679
1680 if (order->GetLoadType() & OLFB_NO_LOAD) return CMD_ERROR;
1681
1682 if (flags & DC_EXEC) {
1683 order->SetRefit(cargo);
1684
1685 /* Make the depot order an 'always go' order. */
1686 if (cargo != CARGO_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1689 }
1690
1691 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1692 /* Update any possible open window of the vehicle */
1694
1695 /* If the vehicle already got the current depot set as current order, then update current order as well */
1696 if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
1697 u->current_order.SetRefit(cargo);
1698 }
1699 }
1700 }
1701
1702 return CommandCost();
1703}
1704
1705
1711void CheckOrders(const Vehicle *v)
1712{
1713 /* Does the user wants us to check things? */
1714 if (_settings_client.gui.order_review_system == 0) return;
1715
1716 /* Do nothing for crashed vehicles */
1717 if (v->vehstatus & VS_CRASHED) return;
1718
1719 /* Do nothing for stopped vehicles if setting is '1' */
1720 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
1721
1722 /* do nothing we we're not the first vehicle in a share-chain */
1723 if (v->FirstShared() != v) return;
1724
1725 /* Only check every 20 days, so that we don't flood the message log */
1726 if (v->owner == _local_company && v->day_counter % 20 == 0) {
1727 StringID message = INVALID_STRING_ID;
1728
1729 /* Check the order list */
1730 int n_st = 0;
1731
1732 for (const Order *order : v->Orders()) {
1733 /* Dummy order? */
1734 if (order->IsType(OT_DUMMY)) {
1735 message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1736 break;
1737 }
1738 /* Does station have a load-bay for this vehicle? */
1739 if (order->IsType(OT_GOTO_STATION)) {
1740 const Station *st = Station::Get(order->GetDestination());
1741
1742 n_st++;
1743 if (!CanVehicleUseStation(v, st)) {
1744 message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1745 } else if (v->type == VEH_AIRCRAFT &&
1746 (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1749 message == INVALID_STRING_ID) {
1750 message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1751 }
1752 }
1753 }
1754
1755 /* Check if the last and the first order are the same */
1756 if (v->GetNumOrders() > 1) {
1757 const Order *last = v->GetLastOrder();
1758
1759 if (v->orders->GetFirstOrder()->Equals(*last)) {
1760 message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1761 }
1762 }
1763
1764 /* Do we only have 1 station in our order list? */
1765 if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1766
1767#ifdef WITH_ASSERT
1768 if (v->orders != nullptr) v->orders->DebugCheckSanity();
1769#endif
1770
1771 /* We don't have a problem */
1772 if (message == INVALID_STRING_ID) return;
1773
1774 SetDParam(0, v->index);
1775 AddVehicleAdviceNewsItem(message, v->index);
1776 }
1777}
1778
1787void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1788{
1789 /* Aircraft have StationIDs for depot orders and never use DepotIDs
1790 * This fact is handled specially below
1791 */
1792
1793 /* Go through all vehicles */
1794 for (Vehicle *v : Vehicle::Iterate()) {
1795 if ((v->type == VEH_AIRCRAFT && v->current_order.IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : v->current_order.GetType()) == type &&
1796 (!hangar || v->type == VEH_AIRCRAFT) && v->current_order.GetDestination() == destination) {
1797 v->current_order.MakeDummy();
1799 }
1800
1801 /* Clear the order from the order-list */
1802 int id = -1;
1803 for (Order *order : v->Orders()) {
1804 id++;
1805restart:
1806
1807 OrderType ot = order->GetType();
1808 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
1809 if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) continue; // Not an aircraft? Can't have a hangar order.
1810 if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1811 if (ot == type && order->GetDestination() == destination) {
1812 /* We want to clear implicit orders, but we don't want to make them
1813 * dummy orders. They should just vanish. Also check the actual order
1814 * type as ot is currently OT_GOTO_STATION. */
1815 if (order->IsType(OT_IMPLICIT)) {
1816 order = order->next; // DeleteOrder() invalidates current order
1817 DeleteOrder(v, id);
1818 if (order != nullptr) goto restart;
1819 break;
1820 }
1821
1822 /* Clear wait time */
1823 v->orders->UpdateTotalDuration(-order->GetWaitTime());
1824 if (order->IsWaitTimetabled()) {
1825 v->orders->UpdateTimetableDuration(-order->GetTimetabledWait());
1826 order->SetWaitTimetabled(false);
1827 }
1828 order->SetWaitTime(0);
1829
1830 /* Clear order, preserving travel time */
1831 bool travel_timetabled = order->IsTravelTimetabled();
1832 order->MakeDummy();
1833 order->SetTravelTimetabled(travel_timetabled);
1834
1835 for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1836 /* In GUI, simulate by removing the order and adding it back */
1839 }
1840 }
1841 }
1842 }
1843
1844 OrderBackup::RemoveOrder(type, destination, hangar);
1845}
1846
1852{
1853 for (const Order *order : this->Orders()) {
1854 if (order->IsType(OT_GOTO_DEPOT)) return true;
1855 }
1856
1857 return false;
1858}
1859
1869void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1870{
1872
1873 if (v->IsOrderListShared()) {
1874 /* Remove ourself from the shared order list. */
1875 v->RemoveFromShared();
1876 v->orders = nullptr;
1877 } else if (v->orders != nullptr) {
1878 /* Remove the orders */
1879 v->orders->FreeChain(keep_orderlist);
1880 if (!keep_orderlist) v->orders = nullptr;
1881 }
1882
1883 /* Unbunching data is no longer valid. */
1885
1886 if (reset_order_indices) {
1888 if (v->current_order.IsType(OT_LOADING)) {
1890 }
1891 }
1892}
1893
1901uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
1902{
1903 /* Service intervals are in percents. */
1904 if (ispercent) return Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT);
1905
1906 /* Service intervals are in minutes. */
1907 if (TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU)) return Clamp(interval, MIN_SERVINT_MINUTES, MAX_SERVINT_MINUTES);
1908
1909 /* Service intervals are in days. */
1910 return Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1911}
1912
1921static bool CheckForValidOrders(const Vehicle *v)
1922{
1923 for (const Order *order : v->Orders()) {
1924 switch (order->GetType()) {
1925 case OT_GOTO_STATION:
1926 case OT_GOTO_DEPOT:
1927 case OT_GOTO_WAYPOINT:
1928 return true;
1929
1930 default:
1931 break;
1932 }
1933 }
1934
1935 return false;
1936}
1937
1941static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1942{
1943 switch (occ) {
1944 case OCC_EQUALS: return variable == value;
1945 case OCC_NOT_EQUALS: return variable != value;
1946 case OCC_LESS_THAN: return variable < value;
1947 case OCC_LESS_EQUALS: return variable <= value;
1948 case OCC_MORE_THAN: return variable > value;
1949 case OCC_MORE_EQUALS: return variable >= value;
1950 case OCC_IS_TRUE: return variable != 0;
1951 case OCC_IS_FALSE: return variable == 0;
1952 default: NOT_REACHED();
1953 }
1954}
1955
1956template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
1957static bool OrderConditionCompare(OrderConditionComparator occ, T variable, int value)
1958{
1959 return OrderConditionCompare(occ, variable.base(), value);
1960}
1961
1969{
1970 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1971
1972 bool skip_order = false;
1974 uint16_t value = order->GetConditionValue();
1975
1976 switch (order->GetConditionVariable()) {
1977 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1978 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
1979 case OCV_MAX_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability), value); break;
1980 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1981 case OCV_AGE: skip_order = OrderConditionCompare(occ, TimerGameCalendar::DateToYear(v->age), value); break;
1982 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
1983 case OCV_UNCONDITIONALLY: skip_order = true; break;
1985 default: NOT_REACHED();
1986 }
1987
1988 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1989}
1990
1998bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
1999{
2000 if (conditional_depth > v->GetNumOrders()) {
2001 v->current_order.Free();
2002 v->SetDestTile(0);
2003 return false;
2004 }
2005
2006 switch (order->GetType()) {
2007 case OT_GOTO_STATION:
2008 v->SetDestTile(v->GetOrderStationLocation(order->GetDestination()));
2009 return true;
2010
2011 case OT_GOTO_DEPOT:
2012 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
2013 assert(!pbs_look_ahead);
2014 UpdateVehicleTimetable(v, true);
2016 break;
2017 }
2018
2020 /* If the vehicle can't find its destination, delay its next search.
2021 * In case many vehicles are in this state, use the vehicle index to spread out pathfinder calls. */
2022 if (v->dest_tile == 0 && TimerGameEconomy::date_fract != (v->index % Ticks::DAY_TICKS)) break;
2023
2024 /* We need to search for the nearest depot (hangar). */
2025 ClosestDepot closestDepot = v->FindClosestDepot();
2026
2027 if (closestDepot.found) {
2028 /* PBS reservations cannot reverse */
2029 if (pbs_look_ahead && closestDepot.reverse) return false;
2030
2031 v->SetDestTile(closestDepot.location);
2032 v->current_order.SetDestination(closestDepot.destination);
2033
2034 /* If there is no depot in front, reverse automatically (trains only) */
2035 if (v->type == VEH_TRAIN && closestDepot.reverse) Command<CMD_REVERSE_TRAIN_DIRECTION>::Do(DC_EXEC, v->index, false);
2036
2037 if (v->type == VEH_AIRCRAFT) {
2038 Aircraft *a = Aircraft::From(v);
2039 if (a->state == FLYING && a->targetairport != closestDepot.destination) {
2040 /* The aircraft is now heading for a different hangar than the next in the orders */
2042 }
2043 }
2044 return true;
2045 }
2046
2047 /* If there is no depot, we cannot help PBS either. */
2048 if (pbs_look_ahead) return false;
2049
2050 UpdateVehicleTimetable(v, true);
2052 } else {
2053 if (v->type != VEH_AIRCRAFT) {
2054 v->SetDestTile(Depot::Get(order->GetDestination())->xy);
2055 } else {
2056 Aircraft *a = Aircraft::From(v);
2057 DestinationID destination = a->current_order.GetDestination();
2058 if (a->targetairport != destination) {
2059 /* The aircraft is now heading for a different hangar than the next in the orders */
2060 a->SetDestTile(a->GetOrderStationLocation(destination));
2061 }
2062 }
2063 return true;
2064 }
2065 break;
2066
2067 case OT_GOTO_WAYPOINT:
2068 v->SetDestTile(Waypoint::Get(order->GetDestination())->xy);
2069 return true;
2070
2071 case OT_CONDITIONAL: {
2072 assert(!pbs_look_ahead);
2073 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2074 if (next_order != INVALID_VEH_ORDER_ID) {
2075 /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2076 * cur_real_order_index might come after next_order. */
2077 UpdateVehicleTimetable(v, false);
2081
2082 /* Disable creation of implicit orders.
2083 * When inserting them we do not know that we would have to make the conditional orders point to them. */
2084 if (v->IsGroundVehicle()) {
2085 uint16_t &gv_flags = v->GetGroundVehicleFlags();
2087 }
2088 } else {
2089 UpdateVehicleTimetable(v, true);
2091 }
2092 break;
2093 }
2094
2095 default:
2096 v->SetDestTile(0);
2097 return false;
2098 }
2099
2100 assert(v->cur_implicit_order_index < v->GetNumOrders());
2101 assert(v->cur_real_order_index < v->GetNumOrders());
2102
2103 /* Get the current order */
2104 order = v->GetOrder(v->cur_real_order_index);
2105 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2106 assert(v->GetNumManualOrders() == 0);
2107 order = nullptr;
2108 }
2109
2110 if (order == nullptr) {
2111 v->current_order.Free();
2112 v->SetDestTile(0);
2113 return false;
2114 }
2115
2116 v->current_order = *order;
2117 return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2118}
2119
2128{
2129 switch (v->current_order.GetType()) {
2130 case OT_GOTO_DEPOT:
2131 /* Let a depot order in the orderlist interrupt. */
2132 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
2133 break;
2134
2135 case OT_LOADING:
2136 return false;
2137
2138 case OT_LEAVESTATION:
2139 if (v->type != VEH_AIRCRAFT) return false;
2140 break;
2141
2142 default: break;
2143 }
2144
2152 bool may_reverse = v->current_order.IsType(OT_NOTHING);
2153
2154 /* Check if we've reached a 'via' destination. */
2155 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)) &&
2156 IsTileType(v->tile, MP_STATION) &&
2159 /* We set the last visited station here because we do not want
2160 * the train to stop at this 'via' station if the next order
2161 * is a no-non-stop order; in that case not setting the last
2162 * visited station will cause the vehicle to still stop. */
2164 UpdateVehicleTimetable(v, true);
2166 }
2167
2168 /* Get the current order */
2171
2172 const Order *order = v->GetOrder(v->cur_real_order_index);
2173 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2174 assert(v->GetNumManualOrders() == 0);
2175 order = nullptr;
2176 }
2177
2178 /* If no order, do nothing. */
2179 if (order == nullptr || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
2180 if (v->type == VEH_AIRCRAFT) {
2181 /* Aircraft do something vastly different here, so handle separately */
2182 HandleMissingAircraftOrders(Aircraft::From(v));
2183 return false;
2184 }
2185
2186 v->current_order.Free();
2187 v->SetDestTile(0);
2188 return false;
2189 }
2190
2191 /* If it is unchanged, keep it. */
2192 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
2193 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->ship_station.tile != INVALID_TILE)) {
2194 return false;
2195 }
2196
2197 /* Otherwise set it, and determine the destination tile. */
2198 v->current_order = *order;
2199
2201 switch (v->type) {
2202 default:
2203 NOT_REACHED();
2204
2205 case VEH_ROAD:
2206 case VEH_TRAIN:
2207 break;
2208
2209 case VEH_AIRCRAFT:
2210 case VEH_SHIP:
2212 break;
2213 }
2214
2215 return UpdateOrderDest(v, order) && may_reverse;
2216}
2217
2225bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2226{
2227 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2228
2229 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
2230 v->last_station_visited != station && // Do stop only when we've not just been there
2231 /* Finally do stop when there is no non-stop flag set for this type of station. */
2233}
2234
2235bool Order::CanLoadOrUnload() const
2236{
2237 return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2239 ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
2240 (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
2241}
2242
2249bool Order::CanLeaveWithCargo(bool has_cargo) const
2250{
2251 return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
2252 (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
2253}
Base for aircraft.
void AircraftNextAirportPos_and_Order(Aircraft *v)
set the right pos when heading to other airports after takeoff
@ FLYING
Vehicle is flying in the air.
Definition airport.h:75
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
static const CargoID CARGO_NO_REFIT
Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-renew).
Definition cargo_type.h:78
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
static const CargoID CARGO_AUTO_REFIT
Automatically choose cargo type when doing auto refitting.
Definition cargo_type.h:77
Cheats _cheats
All the cheats.
Definition cheat.cpp:16
Types related to cheating.
Common return value for all commands.
bool Failed() const
Did this command fail?
Minimal stack that uses a pool to avoid pointers.
Titem Pop()
Pop an item from the stack.
bool IsEmpty() const
Check if the stack is empty.
void Push(const Titem &item)
Pushes a new item onto the stack if there is still space in the underlying pool.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static DateFract date_fract
Fractional part of the day.
int32_t Ticks
The type to store ticks in.
static constexpr Year DateToYear(Date date)
Calculate the year of a given date.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
DoCommandFlag
List of flags for a command.
@ DC_EXEC
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Functions related to companies.
@ OWNER_NONE
The tile has no ownership.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
Base for all depots (except hangars)
uint16_t DepotID
Type for the unique identifier of depots.
Definition depot_type.h:13
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:163
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:146
constexpr uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
Functions related to news.
void DeleteVehicleNews(VehicleID vid, StringID news)
Delete a news item type about a vehicle.
Definition news_gui.cpp:998
void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition news_func.h:40
Functions related to order backups.
CommandCost CmdMoveOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID moving_order, VehicleOrderID target_order)
Move an order inside the orderlist.
static bool OrderGoesToStation(const Vehicle *v, const Order *o)
Checks whether the order goes to a station or not, i.e.
static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first)
Check if an aircraft has enough range for an order list.
uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
Clamp the service interval to the correct min/max.
static bool CheckForValidOrders(const Vehicle *v)
Check if a vehicle has any valid orders.
CommandCost CmdOrderRefit(DoCommandFlag flags, VehicleID veh, VehicleOrderID order_number, CargoID cargo)
Add/remove refit orders from an order.
CommandCost CmdCloneOrder(DoCommandFlag flags, CloneOptions action, VehicleID veh_dst, VehicleID veh_src)
Clone/share/copy an order-list of another vehicle.
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
Compare the variable and value based on the given comparator.
static void CancelLoadingDueToDeletedOrder(Vehicle *v)
Cancel the current loading order of the vehicle as the order was deleted.
CommandCost CmdInsertOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID sel_ord, const Order &new_order)
Add an order to the orderlist of a vehicle.
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
Update the vehicle's destination tile from an order.
void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
Insert a new order but skip the validation.
void InvalidateVehicleOrder(const Vehicle *v, int data)
Updates the widgets of a vehicle which contains the order-data.
CommandCost CmdModifyOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID sel_ord, ModifyOrderFlags mof, uint16_t data)
Modify an order in the orderlist of a vehicle.
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
CommandCost CmdDeleteOrder(DoCommandFlag flags, VehicleID veh_id, VehicleOrderID sel_ord)
Delete an order from the orderlist of a vehicle.
CommandCost CmdSkipToOrder(DoCommandFlag flags, VehicleID veh_id, VehicleOrderID sel_ord)
Goto order of order-list.
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
static void DeleteOrderWarnings(const Vehicle *v)
Delete all news items regarding defective orders about a vehicle This could kill still valid warnings...
void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
Delete an order but skip the parameter validation.
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
Process a conditional order and determine the next order.
static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
Declone an order-list.
uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
Get the distance between two orders of a vehicle.
void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
Command definitions related to orders.
OrderDepotActionFlags
Actions that can be performed when the vehicle enters the depot.
Definition order_type.h:102
@ ODATFB_UNBUNCH
Service the vehicle and then unbunch it.
Definition order_type.h:106
@ ODATFB_NEAREST_DEPOT
Send the vehicle to the nearest depot.
Definition order_type.h:105
@ ODATFB_HALT
Service the vehicle and then halt it.
Definition order_type.h:104
OrderConditionComparator
Comparator for the skip reasoning.
Definition order_type.h:128
@ OCC_LESS_EQUALS
Skip if the value is less or equal to the limit.
Definition order_type.h:132
@ OCC_EQUALS
Skip if both values are equal.
Definition order_type.h:129
@ OCC_NOT_EQUALS
Skip if both values are not equal.
Definition order_type.h:130
@ OCC_MORE_THAN
Skip if the value is more than the limit.
Definition order_type.h:133
@ OCC_IS_TRUE
Skip if the variable is true.
Definition order_type.h:135
@ OCC_LESS_THAN
Skip if the value is less than the limit.
Definition order_type.h:131
@ OCC_MORE_EQUALS
Skip if the value is more or equal to the limit.
Definition order_type.h:134
@ OCC_IS_FALSE
Skip if the variable is false.
Definition order_type.h:136
ModifyOrderFlags
Enumeration for the data to set in CmdModifyOrder.
Definition order_type.h:144
@ MOF_COND_VARIABLE
A conditional variable changes.
Definition order_type.h:150
@ MOF_LOAD
Passes an OrderLoadType.
Definition order_type.h:148
@ MOF_UNLOAD
Passes an OrderUnloadType.
Definition order_type.h:147
@ MOF_STOP_LOCATION
Passes an OrderStopLocation.
Definition order_type.h:146
@ MOF_COND_DESTINATION
Change the destination of a conditional order.
Definition order_type.h:153
@ MOF_COND_COMPARATOR
A comparator changes.
Definition order_type.h:151
@ MOF_COND_VALUE
The value to set the condition to.
Definition order_type.h:152
@ MOF_DEPOT_ACTION
Selects the OrderDepotAction.
Definition order_type.h:149
@ MOF_NON_STOP
Passes an OrderNonStopFlags.
Definition order_type.h:145
OrderLoadFlags
Flags related to the loading order.
Definition order_type.h:62
@ OLFB_FULL_LOAD
Full load all cargoes of the consist.
Definition order_type.h:64
@ OLFB_NO_LOAD
Do not load anything.
Definition order_type.h:66
@ OLF_LOAD_IF_POSSIBLE
Load as long as there is cargo that fits in the train.
Definition order_type.h:63
@ OLF_FULL_LOAD_ANY
Full load a single cargo of the consist.
Definition order_type.h:65
OrderStopLocation
Where to stop the trains.
Definition order_type.h:83
@ OSL_PLATFORM_MIDDLE
Stop at the middle of the platform.
Definition order_type.h:85
@ OSL_PLATFORM_FAR_END
Stop at the far end of the platform.
Definition order_type.h:86
@ OSL_PLATFORM_NEAR_END
Stop at the near end of the platform.
Definition order_type.h:84
OrderConditionVariable
Variables (of a vehicle) to 'cause' skipping on.
Definition order_type.h:113
@ OCV_AGE
Skip based on the age.
Definition order_type.h:117
@ OCV_UNCONDITIONALLY
Always skip.
Definition order_type.h:119
@ OCV_MAX_SPEED
Skip based on the maximum speed.
Definition order_type.h:116
@ OCV_LOAD_PERCENTAGE
Skip based on the amount of load.
Definition order_type.h:114
@ OCV_REQUIRES_SERVICE
Skip when the vehicle requires service.
Definition order_type.h:118
@ OCV_RELIABILITY
Skip based on the reliability.
Definition order_type.h:115
@ OCV_REMAINING_LIFETIME
Skip based on the remaining lifetime.
Definition order_type.h:120
@ OCV_MAX_RELIABILITY
Skip based on the maximum reliability.
Definition order_type.h:121
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition order_type.h:15
OrderUnloadFlags
Flags related to the unloading order.
Definition order_type.h:52
@ OUFB_TRANSFER
Transfer all cargo onto the platform.
Definition order_type.h:55
@ OUFB_NO_UNLOAD
Totally no unloading will be done.
Definition order_type.h:56
@ OUF_UNLOAD_IF_POSSIBLE
Unload all cargo that the station accepts.
Definition order_type.h:53
@ OUFB_UNLOAD
Force unloading all cargo onto the platform, possibly not getting paid.
Definition order_type.h:54
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition order_type.h:23
OrderNonStopFlags
Non-stop order flags.
Definition order_type.h:72
@ ONSF_NO_STOP_AT_DESTINATION_STATION
The vehicle will stop at any station it passes except the destination.
Definition order_type.h:75
@ ONSF_STOP_EVERYWHERE
The vehicle will stop at any station it passes and the destination.
Definition order_type.h:73
@ ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
The vehicle will not stop at any stations it passes except the destination.
Definition order_type.h:74
OrderDepotTypeFlags
Reasons that could cause us to go to the depot.
Definition order_type.h:93
@ ODTFB_PART_OF_ORDERS
This depot order is because of a regular order.
Definition order_type.h:96
@ ODTFB_SERVICE
This depot order is because of the servicing limit.
Definition order_type.h:95
@ DA_SERVICE
Service only if needed.
Definition order_type.h:162
@ DA_STOP
Go to the depot and stop there.
Definition order_type.h:163
@ DA_ALWAYS_GO
Always go to the depot.
Definition order_type.h:161
@ DA_UNBUNCH
Go to the depot and unbunch.
Definition order_type.h:164
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition order_type.h:21
CloneOptions
Clone actions.
Definition order_type.h:179
OrderType
Order types.
Definition order_type.h:35
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
static debug_inline bool IsRailDepotTile(Tile t)
Is this tile rail tile and a rail depot?
Definition rail_map.h:105
Pseudo random number generator.
static debug_inline bool IsRoadDepotTile(Tile t)
Return whether a tile is a road depot tile.
Definition road_map.h:116
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
Base classes/functions for stations.
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
@ FACIL_DOCK
Station with a dock.
@ FACIL_BUS_STOP
Station with bus stops.
@ FACIL_TRUCK_STOP
Station with truck stops.
@ FACIL_TRAIN
Station with train station.
Definition of base types and functions in a cross-platform compatible way.
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
uint32_t cached_max_range_sqr
Cached squared maximum range.
Definition aircraft.h:65
uint16_t cached_max_range
Cached maximum range.
Definition aircraft.h:66
uint8_t subtype
Type of aircraft.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:72
uint8_t state
State of the airport.
Definition aircraft.h:77
TileIndex GetOrderStationLocation(StationID station) override
Determine the location for the station where the vehicle goes to next.
StationID targetairport
Airport to go to next.
Definition aircraft.h:76
Flags flags
Flags for this airport type.
Definition airport.h:180
@ SHORT_STRIP
This airport has a short landing strip, dangerous for fast aircraft.
Definition airport.h:150
bool HasHangar() const
Check if this airport has at least one hangar.
const AirportFTAClass * GetFTA() const
Get the finite-state machine for this airport or the finite-state machine for the dummy airport in ca...
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
VehicleOrderID cur_implicit_order_index
The index to the current implicit order.
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
Base class for all station-ish types.
StationFacility facilities
The facilities that this station has.
TileIndex xy
Base tile of the station.
Owner owner
The owner of this station.
VehicleType type
Type of vehicle.
bool value
tells if the bool cheat is active or not
Definition cheat_type.h:18
Cheat no_jetcrash
no jet will crash on small airports anymore
Definition cheat_type.h:31
GUISettings gui
settings related to the GUI
Structure to return information about the closest depot location, and whether it could be found.
DestinationID destination
The DestinationID as used for orders.
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:47
uint8_t order_review_system
perform order reviews on vehicles
static void RemoveOrder(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition order_base.h:259
Order * GetLastOrder() const
Get the last order of the order chain.
Definition order_base.h:305
void DeleteOrderAt(int index)
Remove an order from the order list and delete it.
StationIDStack GetNextStoppingStation(const Vehicle *v, const Order *first=nullptr, uint hops=0) const
Recursively determine the next deterministic station to stop at.
bool IsCompleteTimetable() const
Checks whether all orders of the list have a filled timetable.
const Order * GetNextDecisionNode(const Order *next, uint hops) const
Get the next order which will make the given vehicle stop at a station or refit at a depot or evaluat...
void Initialize(Order *chain, Vehicle *v)
Recomputes everything.
void RemoveVehicle(Vehicle *v)
Removes the vehicle from the shared order list.
uint num_vehicles
NOSAVE: Number of vehicles that share this order list.
Definition order_base.h:266
VehicleOrderID num_orders
NOSAVE: How many orders there are in the list.
Definition order_base.h:264
void InsertOrderAt(Order *new_order, int index)
Insert a new order into the order chain.
Order * GetOrderAt(int index) const
Get a certain order of the order chain.
const Order * GetNext(const Order *curr) const
Get the order after the given one or the first one, if the given one is the last one.
Definition order_base.h:313
void MoveOrder(int from, int to)
Move an order to another position within the order list.
TimerGameTick::Ticks timetable_duration
NOSAVE: Total timetabled duration of the order list.
Definition order_base.h:270
Order * first
First order of the order list.
Definition order_base.h:268
Vehicle * first_shared
NOSAVE: pointer to the first vehicle in the shared order chain.
Definition order_base.h:267
Order * GetFirstOrder() const
Get the first order of the order chain.
Definition order_base.h:297
VehicleOrderID num_manual_orders
NOSAVE: How many manually added orders are there in the list.
Definition order_base.h:265
VehicleOrderID GetNumOrders() const
Get number of orders in the order list.
Definition order_base.h:319
void RecalculateTimetableDuration()
Recomputes Timetable duration.
void FreeChain(bool keep_orderlist=false)
Free a complete order chain.
bool IsShared() const
Is this a shared order list?
Definition order_base.h:338
TimerGameTick::Ticks total_duration
NOSAVE: Total (timetabled or not) duration of the order list.
Definition order_base.h:271
TileIndex GetLocation(const Vehicle *v, bool airport=false) const
Returns a tile somewhat representing the order destination (not suitable for pathfinding).
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition order_base.h:144
CargoID GetRefitCargo() const
Get the cargo to to refit to.
Definition order_base.h:131
uint16_t GetTimetabledTravel() const
Get the time in ticks a vehicle should take to reach the destination or 0 if it's not timetabled.
Definition order_base.h:190
OrderConditionVariable GetConditionVariable() const
What variable do we have to compare?
Definition order_base.h:148
bool Equals(const Order &other) const
Does this order have the same type, flags and destination?
uint16_t MapOldOrder() const
Pack this order into a 16 bits integer as close to the TTD representation as possible.
uint16_t GetMaxSpeed() const
Get the maxmimum speed in km-ish/h a vehicle is allowed to reach on the way to the destination.
Definition order_base.h:201
void SetUnloadType(OrderUnloadFlags unload_type)
Set how the consist must be unloaded.
Definition order_base.h:159
void SetLoadType(OrderLoadFlags load_type)
Set how the consist must be loaded.
Definition order_base.h:157
uint16_t max_speed
How fast the vehicle may go on the way to the destination.
Definition order_base.h:56
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:70
void SetNonStopType(OrderNonStopFlags non_stop_type)
Set whether we must stop at stations or not.
Definition order_base.h:161
VehicleOrderID GetConditionSkipToOrder() const
Get the order to skip to.
Definition order_base.h:152
OrderStopLocation GetStopLocation() const
Where must we stop at the platform?
Definition order_base.h:142
uint16_t GetWaitTime() const
Get the time in ticks a vehicle will probably wait at the destination (timetabled or not).
Definition order_base.h:192
OrderType GetType() const
Get the type of order of this order.
Definition order_base.h:76
void MakeGoToStation(StationID destination)
Makes this order a Go To Station order.
Definition order_cmd.cpp:75
uint8_t type
The type of order + non-stop flags.
Definition order_base.h:48
uint16_t wait_time
How long in ticks to wait at the destination.
Definition order_base.h:54
void SetDepotOrderType(OrderDepotTypeFlags depot_order_type)
Set the cause to go to the depot.
Definition order_base.h:165
OrderLoadFlags GetLoadType() const
How must the consist be loaded?
Definition order_base.h:136
void SetStopLocation(OrderStopLocation stop_location)
Set where we must stop at the platform.
Definition order_base.h:163
void MakeDummy()
Makes this order a Dummy order.
void MakeGoToWaypoint(StationID destination)
Makes this order a Go To Waypoint order.
void SetConditionVariable(OrderConditionVariable condition_variable)
Set variable we have to compare.
Definition order_base.h:169
uint8_t flags
Load/unload types, depot order/action types.
Definition order_base.h:49
void MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoID cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition order_cmd.cpp:90
Order * next
Pointer to next order. If nullptr, end of list.
Definition order_base.h:59
DestinationID dest
The destination of the order.
Definition order_base.h:50
void SetDestination(DestinationID destination)
Sets the destination of this order.
Definition order_base.h:110
void SetRefit(CargoID cargo)
Make this depot/station order also a refit order.
uint32_t Pack() const
Pack this order into a 32 bits integer, or actually only the type, flags and destination.
void SetConditionComparator(OrderConditionComparator condition_comparator)
Set the comparator to use.
Definition order_base.h:171
void MakeConditional(VehicleOrderID order)
Makes this order an conditional order.
void SetDepotActionType(OrderDepotActionFlags depot_service_type)
Set what we are going to do in the depot.
Definition order_base.h:167
void SetConditionSkipToOrder(VehicleOrderID order_id)
Get the order to skip to.
Definition order_base.h:173
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition order_base.h:146
void MakeLeaveStation()
Makes this order a Leave Station order.
bool CanLeaveWithCargo(bool has_cargo) const
A vehicle can leave the current station with cargo if:
void SetConditionValue(uint16_t value)
Set the value to base the skip on.
Definition order_base.h:175
void Free()
'Free' the order
Definition order_cmd.cpp:63
CargoID refit_cargo
Refit CargoID.
Definition order_base.h:52
uint16_t GetTimetabledWait() const
Get the time in ticks a vehicle should wait at the destination or 0 if it's not timetabled.
Definition order_base.h:188
bool ShouldStopAtStation(const Vehicle *v, StationID station) const
Check whether the given vehicle should stop at the given station based on this order and the non-stop...
uint16_t GetTravelTime() const
Get the time in ticks a vehicle will probably take to reach the destination (timetabled or not).
Definition order_base.h:194
void MakeImplicit(StationID destination)
Makes this order an implicit order.
OrderUnloadFlags GetUnloadType() const
How must the consist be unloaded?
Definition order_base.h:138
void AssignOrder(const Order &other)
Assign data to an order (from another order) This function makes sure that the index is maintained co...
OrderConditionComparator GetConditionComparator() const
What is the comparator to use?
Definition order_base.h:150
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition order_base.h:140
bool IsRefit() const
Is this order a refit order.
Definition order_base.h:117
void MakeLoading(bool ordered)
Makes this order a Loading order.
uint16_t GetConditionValue() const
Get the value to base the skip on.
Definition order_base.h:154
uint16_t travel_time
How long in ticks the journey to this destination should take.
Definition order_base.h:55
TileIndex tile
The base tile of the area.
Tindex index
Index of this pool item.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * Get(size_t index)
Returns Titem with given index.
Base class for all pools.
Definition pool_type.hpp:80
static Station * Get(size_t index)
Gets station with given index.
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Station data structure.
TileArea ship_station
Tile area the ship 'station' part covers.
Airport airport
Tile area the airport covers.
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
uint16_t & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition vehicle.cpp:3185
bool IsOrderListShared() const
Check if we share our orders with another vehicle.
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition vehicle.cpp:747
void IncrementRealOrderIndex()
Advanced cur_real_order_index to the next real order, keeps care of the wrap-around and invalidates t...
Order * GetOrder(int index) const
Returns order 'index' of a vehicle or nullptr when it doesn't exists.
bool HasDepotOrder() const
Checks if a vehicle has a depot in its order list.
void LeaveStation()
Perform all actions when leaving a station.
Definition vehicle.cpp:2350
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:2966
bool HasUnbunchingOrder() const
Check if the current vehicle has an unbunching order.
Definition vehicle.cpp:2489
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
uint8_t day_counter
Increased by one for each day.
virtual int GetDisplayMaxSpeed() const
Gets the maximum speed in km-ish/h that can be sent into SetDParam for string processing.
void IncrementImplicitOrderIndex()
Increments cur_implicit_order_index, keeps care of the wrap-around and invalidates the GUI.
Order * GetFirstOrder() const
Get the first order of the vehicles order list.
VehicleOrderID GetNumManualOrders() const
Get the number of manually added orders this vehicle has.
virtual TileIndex GetOrderStationLocation(StationID station)
Determine the location for the station where the vehicle goes to next.
Order current_order
The current order (+ status, like: loading)
OrderList * orders
Pointer to the order list for this vehicle.
virtual ClosestDepot FindClosestDepot()
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
uint8_t vehstatus
Status.
Vehicle * NextShared() const
Get the next vehicle of the shared vehicle chain.
bool HasFullLoadOrder() const
Check if the current vehicle has a full load order.
Definition vehicle.cpp:2465
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
Order * GetLastOrder() const
Returns the last order of a vehicle, or nullptr if it doesn't exists.
TimerGameCalendar::Date age
Age in calendar days.
IterateWrapper Orders() const
Returns an iterable ensemble of orders of a vehicle.
TimerGameCalendar::Date max_age
Maximum age.
uint16_t reliability
Reliability.
Vehicle * PreviousShared() const
Get the previous vehicle of the shared vehicle chain.
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition vehicle.cpp:2989
debug_inline bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
TileIndex tile
Current tile index.
TileIndex dest_tile
Heading for this tile.
bool NeedsServicing() const
Check if the vehicle needs to go to a depot in near future (if a opportunity presents itself) for ser...
Definition vehicle.cpp:190
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition vehicle.cpp:2477
StationID last_station_visited
The last station we stopped at.
Owner owner
Which company owns the vehicle?
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition vehicle.cpp:2164
void UpdateRealOrderIndex()
Skip implicit orders until cur_real_order_index is a non-implicit order.
Representation of a waypoint.
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
Functions related to time tabling.
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
Update the timetable for the vehicle.
Command definitions related to trains.
StringID GetVehicleCannotUseStationReason(const Vehicle *v, const Station *st)
Get reason string why this station can't be used by the given vehicle.
Definition vehicle.cpp:3104
uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1493
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3058
@ VS_STOPPED
Vehicle is stopped by the player.
@ VS_CRASHED
Vehicle is crashed.
Functions related to vehicles.
@ VIWD_MODIFY_ORDERS
Other order modifications.
Definition vehicle_gui.h:36
@ VIWD_REMOVE_ALL_ORDERS
Removed / replaced all orders (after deleting / sharing).
Definition vehicle_gui.h:35
WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition vehicle_gui.h:97
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
uint32_t VehicleID
The type all our vehicle IDs have.
bool IsShipDepotTile(Tile t)
Is it a ship depot tile?
Definition water_map.h:232
Base of waypoints.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3127
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3219
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3101
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition window.cpp:3236
@ WC_STATION_LIST
Station list; Window numbers:
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
@ WC_SHIPS_LIST
Ships list; Window numbers:
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
@ WC_VEHICLE_TIMETABLE
Vehicle timetable; Window numbers:
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers: