OpenTTD Source 20250205-master-gfd85ab1e2c
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
197uint16_t Order::MapOldOrder() const
198{
199 uint16_t order = this->GetType();
200 switch (this->type) {
201 case OT_GOTO_STATION:
202 if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
203 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
205 order |= GB(this->GetDestination(), 0, 8) << 8;
206 break;
207 case OT_GOTO_DEPOT:
208 if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
209 SetBit(order, 7);
210 order |= GB(this->GetDestination(), 0, 8) << 8;
211 break;
212 case OT_LOADING:
213 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
214 break;
215 }
216 return order;
217}
218
224void InvalidateVehicleOrder(const Vehicle *v, int data)
225{
227
228 if (data != 0) {
229 /* Calls SetDirty() too */
232 return;
233 }
234
237}
238
246void Order::AssignOrder(const Order &other)
247{
248 this->type = other.type;
249 this->flags = other.flags;
250 this->dest = other.dest;
251
252 this->refit_cargo = other.refit_cargo;
253
254 this->wait_time = other.wait_time;
255 this->travel_time = other.travel_time;
256 this->max_speed = other.max_speed;
257}
258
265{
266 this->first = chain;
267 this->first_shared = v;
268
269 this->num_orders = 0;
270 this->num_manual_orders = 0;
271 this->num_vehicles = 1;
272 this->timetable_duration = 0;
273
274 for (Order *o = this->first; o != nullptr; o = o->next) {
275 ++this->num_orders;
276 if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
277 this->total_duration += o->GetWaitTime() + o->GetTravelTime();
278 }
279
281
282 for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
283 ++this->num_vehicles;
284 this->first_shared = u;
285 }
286
287 for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
288}
289
295{
296 this->timetable_duration = 0;
297 for (Order *o = this->first; o != nullptr; o = o->next) {
298 this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
299 }
300}
301
307void OrderList::FreeChain(bool keep_orderlist)
308{
309 Order *next;
310 for (Order *o = this->first; o != nullptr; o = next) {
311 next = o->next;
312 delete o;
313 }
314
315 if (keep_orderlist) {
316 this->first = nullptr;
317 this->num_orders = 0;
318 this->num_manual_orders = 0;
319 this->timetable_duration = 0;
320 } else {
321 delete this;
322 }
323}
324
331{
332 if (index < 0) return nullptr;
333
334 Order *order = this->first;
335
336 while (order != nullptr && index-- > 0) {
337 order = order->next;
338 }
339 return order;
340}
341
353const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
354{
355 if (hops > this->GetNumOrders() || next == nullptr) return nullptr;
356
357 if (next->IsType(OT_CONDITIONAL)) {
358 if (next->GetConditionVariable() != OCV_UNCONDITIONALLY) return next;
359
360 /* We can evaluate trivial conditions right away. They're conceptually
361 * the same as regular order progression. */
362 return this->GetNextDecisionNode(
363 this->GetOrderAt(next->GetConditionSkipToOrder()),
364 hops + 1);
365 }
366
367 if (next->IsType(OT_GOTO_DEPOT)) {
368 if ((next->GetDepotActionType() & ODATFB_HALT) != 0) return nullptr;
369 if (next->IsRefit()) return next;
370 }
371
372 if (!next->CanLoadOrUnload()) {
373 return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
374 }
375
376 return next;
377}
378
388StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first, uint hops) const
389{
390
391 const Order *next = first;
392 if (first == nullptr) {
393 next = this->GetOrderAt(v->cur_implicit_order_index);
394 if (next == nullptr) {
395 next = this->GetFirstOrder();
396 if (next == nullptr) return INVALID_STATION;
397 } else {
398 /* GetNext never returns nullptr if there is a valid station in the list.
399 * As the given "next" is already valid and a station in the list, we
400 * don't have to check for nullptr here. */
401 next = this->GetNext(next);
402 assert(next != nullptr);
403 }
404 }
405
406 do {
407 next = this->GetNextDecisionNode(next, ++hops);
408
409 /* Resolve possibly nested conditionals by estimation. */
410 while (next != nullptr && next->IsType(OT_CONDITIONAL)) {
411 /* We return both options of conditional orders. */
412 const Order *skip_to = this->GetNextDecisionNode(
413 this->GetOrderAt(next->GetConditionSkipToOrder()), hops);
414 const Order *advance = this->GetNextDecisionNode(
415 this->GetNext(next), hops);
416 if (advance == nullptr || advance == first || skip_to == advance) {
417 next = (skip_to == first) ? nullptr : skip_to;
418 } else if (skip_to == nullptr || skip_to == first) {
419 next = (advance == first) ? nullptr : advance;
420 } else {
421 StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
422 StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
423 while (!st2.IsEmpty()) st1.Push(st2.Pop());
424 return st1;
425 }
426 ++hops;
427 }
428
429 /* Don't return a next stop if the vehicle has to unload everything. */
430 if (next == nullptr || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) &&
431 next->GetDestination() == v->last_station_visited &&
432 (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
433 return INVALID_STATION;
434 }
435 } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
436
437 return next->GetDestination();
438}
439
445void OrderList::InsertOrderAt(Order *new_order, int index)
446{
447 if (this->first == nullptr) {
448 this->first = new_order;
449 } else {
450 if (index == 0) {
451 /* Insert as first or only order */
452 new_order->next = this->first;
453 this->first = new_order;
454 } else if (index >= this->num_orders) {
455 /* index is after the last order, add it to the end */
456 this->GetLastOrder()->next = new_order;
457 } else {
458 /* Put the new order in between */
459 Order *order = this->GetOrderAt(index - 1);
460 new_order->next = order->next;
461 order->next = new_order;
462 }
463 }
464 ++this->num_orders;
465 if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
466 this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
467 this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
468
469 /* We can visit oil rigs and buoys that are not our own. They will be shown in
470 * the list of stations. So, we need to invalidate that window if needed. */
471 if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
472 BaseStation *bs = BaseStation::Get(new_order->GetDestination());
474 }
475
476}
477
478
484{
485 if (index >= this->num_orders) return;
486
487 Order *to_remove;
488
489 if (index == 0) {
490 to_remove = this->first;
491 this->first = to_remove->next;
492 } else {
493 Order *prev = GetOrderAt(index - 1);
494 to_remove = prev->next;
495 prev->next = to_remove->next;
496 }
497 --this->num_orders;
498 if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
499 this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
500 this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
501 delete to_remove;
502}
503
509void OrderList::MoveOrder(int from, int to)
510{
511 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
512
513 Order *moving_one;
514
515 /* Take the moving order out of the pointer-chain */
516 if (from == 0) {
517 moving_one = this->first;
518 this->first = moving_one->next;
519 } else {
520 Order *one_before = GetOrderAt(from - 1);
521 moving_one = one_before->next;
522 one_before->next = moving_one->next;
523 }
524
525 /* Insert the moving_order again in the pointer-chain */
526 if (to == 0) {
527 moving_one->next = this->first;
528 this->first = moving_one;
529 } else {
530 Order *one_before = GetOrderAt(to - 1);
531 moving_one->next = one_before->next;
532 one_before->next = moving_one;
533 }
534}
535
542{
543 --this->num_vehicles;
544 if (v == this->first_shared) this->first_shared = v->NextShared();
545}
546
552{
553 for (Order *o = this->first; o != nullptr; o = o->next) {
554 /* Implicit orders are, by definition, not timetabled. */
555 if (o->IsType(OT_IMPLICIT)) continue;
556 if (!o->IsCompletelyTimetabled()) return false;
557 }
558 return true;
559}
560
561#ifdef WITH_ASSERT
565void OrderList::DebugCheckSanity() const
566{
567 VehicleOrderID check_num_orders = 0;
568 VehicleOrderID check_num_manual_orders = 0;
569 uint check_num_vehicles = 0;
570 TimerGameTick::Ticks check_timetable_duration = 0;
571 TimerGameTick::Ticks check_total_duration = 0;
572
573 Debug(misc, 6, "Checking OrderList {} for sanity...", this->index);
574
575 for (const Order *o = this->first; o != nullptr; o = o->next) {
576 ++check_num_orders;
577 if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
578 check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
579 check_total_duration += o->GetWaitTime() + o->GetTravelTime();
580 }
581 assert(this->num_orders == check_num_orders);
582 assert(this->num_manual_orders == check_num_manual_orders);
583 assert(this->timetable_duration == check_timetable_duration);
584 assert(this->total_duration == check_total_duration);
585
586 for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
587 ++check_num_vehicles;
588 assert(v->orders == this);
589 }
590 assert(this->num_vehicles == check_num_vehicles);
591 Debug(misc, 6, "... detected {} orders ({} manual), {} vehicles, {} timetabled, {} total",
592 (uint)this->num_orders, (uint)this->num_manual_orders,
594}
595#endif
596
604static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
605{
606 return o->IsType(OT_GOTO_STATION) ||
607 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && o->GetDestination() != INVALID_STATION);
608}
609
616static void DeleteOrderWarnings(const Vehicle *v)
617{
619}
620
627TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
628{
629 switch (this->GetType()) {
630 case OT_GOTO_WAYPOINT:
631 case OT_GOTO_STATION:
632 case OT_IMPLICIT:
633 if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile;
634 return BaseStation::Get(this->GetDestination())->xy;
635
636 case OT_GOTO_DEPOT:
637 if (this->GetDestination() == INVALID_DEPOT) return INVALID_TILE;
638 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
639
640 default:
641 return INVALID_TILE;
642 }
643}
644
654uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
655{
656 if (cur->IsType(OT_CONDITIONAL)) {
657 if (conditional_depth > v->GetNumOrders()) return 0;
658
659 conditional_depth++;
660
661 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
662 int dist2 = GetOrderDistance(prev, cur->next == nullptr ? v->orders->GetFirstOrder() : cur->next, v, conditional_depth);
663 return std::max(dist1, dist2);
664 }
665
666 TileIndex prev_tile = prev->GetLocation(v, true);
667 TileIndex cur_tile = cur->GetLocation(v, true);
668 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
669 return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
670}
671
683{
685 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
686
688 if (ret.Failed()) return ret;
689
690 /* Validate properties we don't want to have different from default as they are set by other commands. */
691 if (new_order.GetRefitCargo() != CARGO_NO_REFIT || new_order.GetWaitTime() != 0 || new_order.GetTravelTime() != 0 || new_order.GetMaxSpeed() != UINT16_MAX) return CMD_ERROR;
692
693 /* Check if the inserted order is to the correct destination (owner, type),
694 * and has the correct flags if any */
695 switch (new_order.GetType()) {
696 case OT_GOTO_STATION: {
697 const Station *st = Station::GetIfValid(new_order.GetDestination());
698 if (st == nullptr) return CMD_ERROR;
699
700 if (st->owner != OWNER_NONE) {
701 ret = CheckOwnership(st->owner);
702 if (ret.Failed()) return ret;
703 }
704
705 if (!CanVehicleUseStation(v, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, GetVehicleCannotUseStationReason(v, st));
706 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
707 if (!CanVehicleUseStation(u, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER_SHARED, GetVehicleCannotUseStationReason(u, st));
708 }
709
710 /* Non stop only allowed for ground vehicles. */
711 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
712
713 /* Filter invalid load/unload types. */
714 switch (new_order.GetLoadType()) {
716 case OLFB_NO_LOAD:
717 break;
718
719 case OLFB_FULL_LOAD:
721 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
722 break;
723
724 default:
725 return CMD_ERROR;
726 }
727 switch (new_order.GetUnloadType()) {
729 default: return CMD_ERROR;
730 }
731
732 /* Filter invalid stop locations */
733 switch (new_order.GetStopLocation()) {
736 if (v->type != VEH_TRAIN) return CMD_ERROR;
737 [[fallthrough]];
738
740 break;
741
742 default:
743 return CMD_ERROR;
744 }
745
746 break;
747 }
748
749 case OT_GOTO_DEPOT: {
750 if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
751 if (v->type == VEH_AIRCRAFT) {
752 const Station *st = Station::GetIfValid(new_order.GetDestination());
753
754 if (st == nullptr) return CMD_ERROR;
755
756 ret = CheckOwnership(st->owner);
757 if (ret.Failed()) return ret;
758
759 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
760 return CMD_ERROR;
761 }
762 } else {
763 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
764
765 if (dp == nullptr) return CMD_ERROR;
766
767 ret = CheckOwnership(GetTileOwner(dp->xy));
768 if (ret.Failed()) return ret;
769
770 switch (v->type) {
771 case VEH_TRAIN:
772 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
773 break;
774
775 case VEH_ROAD:
776 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
777 break;
778
779 case VEH_SHIP:
780 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
781 break;
782
783 default: return CMD_ERROR;
784 }
785 }
786 }
787
788 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
789 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
791
792 /* Vehicles cannot have a "service if needed" order that also has a depot action. */
793 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & (ODATFB_HALT | ODATFB_UNBUNCH))) return CMD_ERROR;
794
795 /* Check if we're allowed to have a new unbunching order. */
796 if ((new_order.GetDepotActionType() & ODATFB_UNBUNCH)) {
797 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
798 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
799 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
800 }
801 break;
802 }
803
804 case OT_GOTO_WAYPOINT: {
805 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
806 if (wp == nullptr) return CMD_ERROR;
807
808 switch (v->type) {
809 default: return CMD_ERROR;
810
811 case VEH_TRAIN: {
812 if (!(wp->facilities & FACIL_TRAIN)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_RAIL_WAYPOINT);
813
814 ret = CheckOwnership(wp->owner);
815 if (ret.Failed()) return ret;
816 break;
817 }
818
819 case VEH_ROAD: {
820 if (!(wp->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP))) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_ROAD_WAYPOINT);
821
822 ret = CheckOwnership(wp->owner);
823 if (ret.Failed()) return ret;
824 break;
825 }
826
827 case VEH_SHIP:
828 if (!(wp->facilities & FACIL_DOCK)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_BUOY);
829 if (wp->owner != OWNER_NONE) {
830 ret = CheckOwnership(wp->owner);
831 if (ret.Failed()) return ret;
832 }
833 break;
834 }
835
836 /* Order flags can be any of the following for waypoints:
837 * [non-stop]
838 * non-stop orders (if any) are only valid for trains and road vehicles */
839 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
840 break;
841 }
842
843 case OT_CONDITIONAL: {
844 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
845 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
846 if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
847 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_CONDITIONAL);
848
850 if (occ >= OCC_END) return CMD_ERROR;
851 switch (new_order.GetConditionVariable()) {
853 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
854 break;
855
857 if (occ != OCC_EQUALS) return CMD_ERROR;
858 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
859 break;
860
862 case OCV_RELIABILITY:
863 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
864 [[fallthrough]];
865
866 default:
867 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
868 break;
869 }
870 break;
871 }
872
873 default: return CMD_ERROR;
874 }
875
876 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
877
878 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return CommandCost(STR_ERROR_TOO_MANY_ORDERS);
879 if (!Order::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
880 if (v->orders == nullptr && !OrderList::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
881
882 if (flags & DC_EXEC) {
883 Order *new_o = new Order();
884 new_o->AssignOrder(new_order);
885 InsertOrder(v, new_o, sel_ord);
886 }
887
888 return CommandCost();
889}
890
897void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
898{
899 /* Create new order and link in list */
900 if (v->orders == nullptr) {
901 v->orders = new OrderList(new_o, v);
902 } else {
903 v->orders->InsertOrderAt(new_o, sel_ord);
904 }
905
906 Vehicle *u = v->FirstShared();
908 for (; u != nullptr; u = u->NextShared()) {
909 assert(v->orders == u->orders);
910
911 /* If there is added an order before the current one, we need
912 * to update the selected order. We do not change implicit/real order indices though.
913 * If the new order is between the current implicit order and real order, the implicit order will
914 * later skip the inserted order. */
915 if (sel_ord <= u->cur_real_order_index) {
916 uint cur = u->cur_real_order_index + 1;
917 /* Check if we don't go out of bound */
918 if (cur < u->GetNumOrders()) {
919 u->cur_real_order_index = cur;
920 }
921 }
922 if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
923 /* We are inserting an order just before the current implicit order.
924 * We do not know whether we will reach current implicit or the newly inserted order first.
925 * So, disable creation of implicit orders until we are on track again. */
926 uint16_t &gv_flags = u->GetGroundVehicleFlags();
928 }
929 if (sel_ord <= u->cur_implicit_order_index) {
930 uint cur = u->cur_implicit_order_index + 1;
931 /* Check if we don't go out of bound */
932 if (cur < u->GetNumOrders()) {
934 }
935 }
936 /* Unbunching data is no longer valid. */
938
939 /* Update any possible open window of the vehicle */
940 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
941 }
942
943 /* As we insert an order, the order to skip to will be 'wrong'. */
944 VehicleOrderID cur_order_id = 0;
945 for (Order *order : v->Orders()) {
946 if (order->IsType(OT_CONDITIONAL)) {
947 VehicleOrderID order_id = order->GetConditionSkipToOrder();
948 if (order_id >= sel_ord) {
949 order->SetConditionSkipToOrder(order_id + 1);
950 }
951 if (order_id == cur_order_id) {
952 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
953 }
954 }
955 cur_order_id++;
956 }
957
958 /* Make sure to rebuild the whole list */
960}
961
976
985{
986 Vehicle *v = Vehicle::GetIfValid(veh_id);
987
988 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
989
991 if (ret.Failed()) return ret;
992
993 /* If we did not select an order, we maybe want to de-clone the orders */
994 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
995
996 if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
997
998 if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
999 return CommandCost();
1000}
1001
1007{
1008 assert(v->current_order.IsType(OT_LOADING));
1009 /* NON-stop flag is misused to see if a train is in a station that is
1010 * on its order list or not */
1012 /* When full loading, "cancel" that order so the vehicle doesn't
1013 * stay indefinitely at this station anymore. */
1015}
1016
1023{
1024 v->orders->DeleteOrderAt(sel_ord);
1025
1026 Vehicle *u = v->FirstShared();
1028 for (; u != nullptr; u = u->NextShared()) {
1029 assert(v->orders == u->orders);
1030
1031 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
1033 }
1034
1035 if (sel_ord < u->cur_real_order_index) {
1037 } else if (sel_ord == u->cur_real_order_index) {
1039 }
1040
1041 if (sel_ord < u->cur_implicit_order_index) {
1043 } else if (sel_ord == u->cur_implicit_order_index) {
1044 /* Make sure the index is valid */
1046
1047 /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
1051 }
1052 }
1053 /* Unbunching data is no longer valid. */
1055
1056 /* Update any possible open window of the vehicle */
1057 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1058 }
1059
1060 /* As we delete an order, the order to skip to will be 'wrong'. */
1061 VehicleOrderID cur_order_id = 0;
1062 for (Order *order : v->Orders()) {
1063 if (order->IsType(OT_CONDITIONAL)) {
1064 VehicleOrderID order_id = order->GetConditionSkipToOrder();
1065 if (order_id >= sel_ord) {
1066 order_id = std::max(order_id - 1, 0);
1067 }
1068 if (order_id == cur_order_id) {
1069 order_id = (order_id + 1) % v->GetNumOrders();
1070 }
1071 order->SetConditionSkipToOrder(order_id);
1072 }
1073 cur_order_id++;
1074 }
1075
1077}
1078
1087{
1088 Vehicle *v = Vehicle::GetIfValid(veh_id);
1089
1090 if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1091
1093 if (ret.Failed()) return ret;
1094
1095 if (flags & DC_EXEC) {
1096 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1097
1100
1101 /* Unbunching data is no longer valid. */
1103
1105
1106 /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1109 }
1110
1111 return CommandCost();
1112}
1113
1125{
1126 Vehicle *v = Vehicle::GetIfValid(veh);
1127 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1128
1130 if (ret.Failed()) return ret;
1131
1132 /* Don't make senseless movements */
1133 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1134 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1135
1136 Order *moving_one = v->GetOrder(moving_order);
1137 /* Don't move an empty order */
1138 if (moving_one == nullptr) return CMD_ERROR;
1139
1140 if (flags & DC_EXEC) {
1141 v->orders->MoveOrder(moving_order, target_order);
1142
1143 /* Update shared list */
1144 Vehicle *u = v->FirstShared();
1145
1147
1148 for (; u != nullptr; u = u->NextShared()) {
1149 /* Update the current order.
1150 * There are multiple ways to move orders, which result in cur_implicit_order_index
1151 * and cur_real_order_index to not longer make any sense. E.g. moving another
1152 * real order between them.
1153 *
1154 * Basically one could choose to preserve either of them, but not both.
1155 * While both ways are suitable in this or that case from a human point of view, neither
1156 * of them makes really sense.
1157 * However, from an AI point of view, preserving cur_real_order_index is the most
1158 * predictable and transparent behaviour.
1159 *
1160 * With that decision it basically does not matter what we do to cur_implicit_order_index.
1161 * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1162 * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1163 * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1164 */
1165 if (u->cur_real_order_index == moving_order) {
1166 u->cur_real_order_index = target_order;
1167 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1169 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1171 }
1172
1173 if (u->cur_implicit_order_index == moving_order) {
1174 u->cur_implicit_order_index = target_order;
1175 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1177 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1179 }
1180 /* Unbunching data is no longer valid. */
1182
1183
1184 assert(v->orders == u->orders);
1185 /* Update any possible open window of the vehicle */
1186 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1187 }
1188
1189 /* As we move an order, the order to skip to will be 'wrong'. */
1190 for (Order *order : v->Orders()) {
1191 if (order->IsType(OT_CONDITIONAL)) {
1192 VehicleOrderID order_id = order->GetConditionSkipToOrder();
1193 if (order_id == moving_order) {
1194 order_id = target_order;
1195 } else if (order_id > moving_order && order_id <= target_order) {
1196 order_id--;
1197 } else if (order_id < moving_order && order_id >= target_order) {
1198 order_id++;
1199 }
1200 order->SetConditionSkipToOrder(order_id);
1201 }
1202 }
1203
1204 /* Make sure to rebuild the whole list */
1206 }
1207
1208 return CommandCost();
1209}
1210
1223{
1224 if (mof >= MOF_END) return CMD_ERROR;
1225
1226 Vehicle *v = Vehicle::GetIfValid(veh);
1227 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1228
1230 if (ret.Failed()) return ret;
1231
1232 /* Is it a valid order? */
1233 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1234
1235 Order *order = v->GetOrder(sel_ord);
1236 assert(order != nullptr);
1237 switch (order->GetType()) {
1238 case OT_GOTO_STATION:
1239 if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1240 break;
1241
1242 case OT_GOTO_DEPOT:
1243 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1244 break;
1245
1246 case OT_GOTO_WAYPOINT:
1247 if (mof != MOF_NON_STOP) return CMD_ERROR;
1248 break;
1249
1250 case OT_CONDITIONAL:
1251 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1252 break;
1253
1254 default:
1255 return CMD_ERROR;
1256 }
1257
1258 switch (mof) {
1259 default: NOT_REACHED();
1260
1261 case MOF_NON_STOP:
1262 if (!v->IsGroundVehicle()) return CMD_ERROR;
1263 if (data >= ONSF_END) return CMD_ERROR;
1264 if (data == order->GetNonStopType()) return CMD_ERROR;
1265 break;
1266
1267 case MOF_STOP_LOCATION:
1268 if (v->type != VEH_TRAIN) return CMD_ERROR;
1269 if (data >= OSL_END) return CMD_ERROR;
1270 break;
1271
1272 case MOF_UNLOAD:
1274 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
1275 /* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
1276 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
1277 if (data == order->GetUnloadType()) return CMD_ERROR;
1278 break;
1279
1280 case MOF_LOAD:
1282 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
1283 if (data == order->GetLoadType()) return CMD_ERROR;
1284 if ((data & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) && v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
1285 break;
1286
1287 case MOF_DEPOT_ACTION:
1288 if (data >= DA_END) return CMD_ERROR;
1289 /* Check if we are allowed to add unbunching. We are always allowed to remove it. */
1290 if (data == DA_UNBUNCH) {
1291 /* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */
1292 if (v->HasUnbunchingOrder() && !(order->GetDepotActionType() & ODATFB_UNBUNCH)) return CommandCost(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
1293 /* We don't allow unbunching if the vehicle has a conditional order. */
1294 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
1295 /* We don't allow unbunching if the vehicle has a full load order. */
1296 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
1297 }
1298 break;
1299
1300 case MOF_COND_VARIABLE:
1301 if (data >= OCV_END) return CMD_ERROR;
1302 break;
1303
1305 if (data >= OCC_END) return CMD_ERROR;
1306 switch (order->GetConditionVariable()) {
1307 case OCV_UNCONDITIONALLY: return CMD_ERROR;
1308
1310 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
1311 break;
1312
1313 default:
1314 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
1315 break;
1316 }
1317 break;
1318
1319 case MOF_COND_VALUE:
1320 switch (order->GetConditionVariable()) {
1323 return CMD_ERROR;
1324
1326 case OCV_RELIABILITY:
1327 if (data > 100) return CMD_ERROR;
1328 break;
1329
1330 default:
1331 if (data > 2047) return CMD_ERROR;
1332 break;
1333 }
1334 break;
1335
1337 if (data >= v->GetNumOrders()) return CMD_ERROR;
1338 break;
1339 }
1340
1341 if (flags & DC_EXEC) {
1342 switch (mof) {
1343 case MOF_NON_STOP:
1344 order->SetNonStopType((OrderNonStopFlags)data);
1346 order->SetRefit(CARGO_NO_REFIT);
1349 }
1350 break;
1351
1352 case MOF_STOP_LOCATION:
1353 order->SetStopLocation((OrderStopLocation)data);
1354 break;
1355
1356 case MOF_UNLOAD:
1357 order->SetUnloadType((OrderUnloadFlags)data);
1358 break;
1359
1360 case MOF_LOAD:
1361 order->SetLoadType((OrderLoadFlags)data);
1362 if (data & OLFB_NO_LOAD) order->SetRefit(CARGO_NO_REFIT);
1363 break;
1364
1365 case MOF_DEPOT_ACTION: {
1366 switch (data) {
1367 case DA_ALWAYS_GO:
1371 break;
1372
1373 case DA_SERVICE:
1377 order->SetRefit(CARGO_NO_REFIT);
1378 break;
1379
1380 case DA_STOP:
1384 order->SetRefit(CARGO_NO_REFIT);
1385 break;
1386
1387 case DA_UNBUNCH:
1391 break;
1392
1393 default:
1394 NOT_REACHED();
1395 }
1396 break;
1397 }
1398
1399 case MOF_COND_VARIABLE: {
1401
1403 switch (order->GetConditionVariable()) {
1406 order->SetConditionValue(0);
1407 break;
1408
1410 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
1411 order->SetConditionValue(0);
1412 break;
1413
1415 case OCV_RELIABILITY:
1416 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1417 [[fallthrough]];
1418
1419 default:
1420 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
1421 break;
1422 }
1423 break;
1424 }
1425
1428 break;
1429
1430 case MOF_COND_VALUE:
1431 order->SetConditionValue(data);
1432 break;
1433
1435 order->SetConditionSkipToOrder(data);
1436 break;
1437
1438 default: NOT_REACHED();
1439 }
1440
1441 /* Update the windows and full load flags, also for vehicles that share the same order list */
1442 Vehicle *u = v->FirstShared();
1444 for (; u != nullptr; u = u->NextShared()) {
1445 /* Toggle u->current_order "Full load" flag if it changed.
1446 * However, as the same flag is used for depot orders, check
1447 * whether we are not going to a depot as there are three
1448 * cases where the full load flag can be active and only
1449 * one case where the flag is used for depot orders. In the
1450 * other cases for the OrderType the flags are not used,
1451 * so do not care and those orders should not be active
1452 * when this function is called.
1453 */
1454 if (sel_ord == u->cur_real_order_index &&
1455 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1456 u->current_order.GetLoadType() != order->GetLoadType()) {
1458 }
1459
1460 /* Unbunching data is no longer valid. */
1462
1464 }
1465 }
1466
1467 return CommandCost();
1468}
1469
1477static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first)
1478{
1479 if (first == nullptr || v_new->acache.cached_max_range == 0) return true;
1480
1481 /* Iterate over all orders to check the distance between all
1482 * 'goto' orders and their respective next order (of any type). */
1483 for (const Order *o = first; o != nullptr; o = o->next) {
1484 switch (o->GetType()) {
1485 case OT_GOTO_STATION:
1486 case OT_GOTO_DEPOT:
1487 case OT_GOTO_WAYPOINT:
1488 /* If we don't have a next order, we've reached the end and must check the first order instead. */
1489 if (GetOrderDistance(o, o->next != nullptr ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false;
1490 break;
1491
1492 default: break;
1493 }
1494 }
1495
1496 return true;
1497}
1498
1508{
1509 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1510 if (dst == nullptr || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1511
1512 CommandCost ret = CheckOwnership(dst->owner);
1513 if (ret.Failed()) return ret;
1514
1515 switch (action) {
1516 case CO_SHARE: {
1517 Vehicle *src = Vehicle::GetIfValid(veh_src);
1518
1519 /* Sanity checks */
1520 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1521
1522 ret = CheckOwnership(src->owner);
1523 if (ret.Failed()) return ret;
1524
1525 /* Trucks can't share orders with busses (and visa versa) */
1526 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1527 return CMD_ERROR;
1528 }
1529
1530 /* Is the vehicle already in the shared list? */
1531 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1532
1533 for (const Order *order : src->Orders()) {
1534 if (!OrderGoesToStation(dst, order)) continue;
1535
1536 /* Allow copying unreachable destinations if they were already unreachable for the source.
1537 * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1538 * are temporarily invalid due to reconstruction. */
1539 const Station *st = Station::Get(order->GetDestination());
1540 if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1541 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1542 }
1543 }
1544
1545 /* Check for aircraft range limits. */
1546 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1547 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1548 }
1549
1550 if (src->orders == nullptr && !OrderList::CanAllocateItem()) {
1551 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1552 }
1553
1554 if (flags & DC_EXEC) {
1555 /* If the destination vehicle had a OrderList, destroy it.
1556 * We only reset the order indices, if the new orders are obviously different.
1557 * (We mainly do this to keep the order indices valid and in range.) */
1558 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1559
1560 dst->orders = src->orders;
1561
1562 /* Link this vehicle in the shared-list */
1563 dst->AddToShared(src);
1564
1567
1569 }
1570 break;
1571 }
1572
1573 case CO_COPY: {
1574 Vehicle *src = Vehicle::GetIfValid(veh_src);
1575
1576 /* Sanity checks */
1577 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1578
1579 ret = CheckOwnership(src->owner);
1580 if (ret.Failed()) return ret;
1581
1582 /* Trucks can't copy all the orders from busses (and visa versa),
1583 * and neither can helicopters and aircraft. */
1584 for (const Order *order : src->Orders()) {
1585 if (!OrderGoesToStation(dst, order)) continue;
1586 Station *st = Station::Get(order->GetDestination());
1587 if (!CanVehicleUseStation(dst, st)) {
1588 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1589 }
1590 }
1591
1592 /* Check for aircraft range limits. */
1593 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1594 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1595 }
1596
1597 /* make sure there are orders available */
1599 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1600 }
1601
1602 if (flags & DC_EXEC) {
1603 Order *first = nullptr;
1604 Order **order_dst;
1605
1606 /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1607 * We only reset the order indices, if the new orders are obviously different.
1608 * (We mainly do this to keep the order indices valid and in range.) */
1609 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1610
1611 order_dst = &first;
1612 for (const Order *order : src->Orders()) {
1613 *order_dst = new Order();
1614 (*order_dst)->AssignOrder(*order);
1615 order_dst = &(*order_dst)->next;
1616 }
1617 if (dst->orders == nullptr) {
1618 dst->orders = new OrderList(first, dst);
1619 } else {
1620 assert(dst->orders->GetFirstOrder() == nullptr);
1621 assert(!dst->orders->IsShared());
1622 delete dst->orders;
1624 dst->orders = new OrderList(first, dst);
1625 }
1626
1628
1630 }
1631 break;
1632 }
1633
1634 case CO_UNSHARE: return DecloneOrder(dst, flags);
1635 default: return CMD_ERROR;
1636 }
1637
1638 return CommandCost();
1639}
1640
1650{
1651 if (cargo >= NUM_CARGO && cargo != CARGO_NO_REFIT && cargo != CARGO_AUTO_REFIT) return CMD_ERROR;
1652
1653 const Vehicle *v = Vehicle::GetIfValid(veh);
1654 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1655
1657 if (ret.Failed()) return ret;
1658
1659 Order *order = v->GetOrder(order_number);
1660 if (order == nullptr) return CMD_ERROR;
1661
1662 /* Automatic refit cargo is only supported for goto station orders. */
1663 if (cargo == CARGO_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1664
1665 if (order->GetLoadType() & OLFB_NO_LOAD) return CMD_ERROR;
1666
1667 if (flags & DC_EXEC) {
1668 order->SetRefit(cargo);
1669
1670 /* Make the depot order an 'always go' order. */
1671 if (cargo != CARGO_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1674 }
1675
1676 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1677 /* Update any possible open window of the vehicle */
1679
1680 /* If the vehicle already got the current depot set as current order, then update current order as well */
1681 if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
1682 u->current_order.SetRefit(cargo);
1683 }
1684 }
1685 }
1686
1687 return CommandCost();
1688}
1689
1690
1696void CheckOrders(const Vehicle *v)
1697{
1698 /* Does the user wants us to check things? */
1699 if (_settings_client.gui.order_review_system == 0) return;
1700
1701 /* Do nothing for crashed vehicles */
1702 if (v->vehstatus & VS_CRASHED) return;
1703
1704 /* Do nothing for stopped vehicles if setting is '1' */
1705 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
1706
1707 /* do nothing we we're not the first vehicle in a share-chain */
1708 if (v->FirstShared() != v) return;
1709
1710 /* Only check every 20 days, so that we don't flood the message log */
1711 if (v->owner == _local_company && v->day_counter % 20 == 0) {
1712 StringID message = INVALID_STRING_ID;
1713
1714 /* Check the order list */
1715 int n_st = 0;
1716
1717 for (const Order *order : v->Orders()) {
1718 /* Dummy order? */
1719 if (order->IsType(OT_DUMMY)) {
1720 message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1721 break;
1722 }
1723 /* Does station have a load-bay for this vehicle? */
1724 if (order->IsType(OT_GOTO_STATION)) {
1725 const Station *st = Station::Get(order->GetDestination());
1726
1727 n_st++;
1728 if (!CanVehicleUseStation(v, st)) {
1729 message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1730 } else if (v->type == VEH_AIRCRAFT &&
1731 (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1734 message == INVALID_STRING_ID) {
1735 message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1736 }
1737 }
1738 }
1739
1740 /* Check if the last and the first order are the same */
1741 if (v->GetNumOrders() > 1) {
1742 const Order *last = v->GetLastOrder();
1743
1744 if (v->orders->GetFirstOrder()->Equals(*last)) {
1745 message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1746 }
1747 }
1748
1749 /* Do we only have 1 station in our order list? */
1750 if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1751
1752#ifdef WITH_ASSERT
1753 if (v->orders != nullptr) v->orders->DebugCheckSanity();
1754#endif
1755
1756 /* We don't have a problem */
1757 if (message == INVALID_STRING_ID) return;
1758
1759 SetDParam(0, v->index);
1761 }
1762}
1763
1772void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1773{
1774 /* Aircraft have StationIDs for depot orders and never use DepotIDs
1775 * This fact is handled specially below
1776 */
1777
1778 /* Go through all vehicles */
1779 for (Vehicle *v : Vehicle::Iterate()) {
1780 if ((v->type == VEH_AIRCRAFT && v->current_order.IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : v->current_order.GetType()) == type &&
1781 (!hangar || v->type == VEH_AIRCRAFT) && v->current_order.GetDestination() == destination) {
1782 v->current_order.MakeDummy();
1784 }
1785
1786 /* Clear the order from the order-list */
1787 int id = -1;
1788 for (Order *order : v->Orders()) {
1789 id++;
1790restart:
1791
1792 OrderType ot = order->GetType();
1793 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
1794 if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) continue; // Not an aircraft? Can't have a hangar order.
1795 if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1796 if (ot == type && order->GetDestination() == destination) {
1797 /* We want to clear implicit orders, but we don't want to make them
1798 * dummy orders. They should just vanish. Also check the actual order
1799 * type as ot is currently OT_GOTO_STATION. */
1800 if (order->IsType(OT_IMPLICIT)) {
1801 order = order->next; // DeleteOrder() invalidates current order
1802 DeleteOrder(v, id);
1803 if (order != nullptr) goto restart;
1804 break;
1805 }
1806
1807 /* Clear wait time */
1808 v->orders->UpdateTotalDuration(-order->GetWaitTime());
1809 if (order->IsWaitTimetabled()) {
1810 v->orders->UpdateTimetableDuration(-order->GetTimetabledWait());
1811 order->SetWaitTimetabled(false);
1812 }
1813 order->SetWaitTime(0);
1814
1815 /* Clear order, preserving travel time */
1816 bool travel_timetabled = order->IsTravelTimetabled();
1817 order->MakeDummy();
1818 order->SetTravelTimetabled(travel_timetabled);
1819
1820 for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1821 /* In GUI, simulate by removing the order and adding it back */
1824 }
1825 }
1826 }
1827 }
1828
1829 OrderBackup::RemoveOrder(type, destination, hangar);
1830}
1831
1837{
1838 for (const Order *order : this->Orders()) {
1839 if (order->IsType(OT_GOTO_DEPOT)) return true;
1840 }
1841
1842 return false;
1843}
1844
1854void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1855{
1857
1858 if (v->IsOrderListShared()) {
1859 /* Remove ourself from the shared order list. */
1860 v->RemoveFromShared();
1861 v->orders = nullptr;
1862 } else if (v->orders != nullptr) {
1863 /* Remove the orders */
1864 v->orders->FreeChain(keep_orderlist);
1865 if (!keep_orderlist) v->orders = nullptr;
1866 }
1867
1868 /* Unbunching data is no longer valid. */
1870
1871 if (reset_order_indices) {
1873 if (v->current_order.IsType(OT_LOADING)) {
1875 }
1876 }
1877}
1878
1886uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
1887{
1888 /* Service intervals are in percents. */
1889 if (ispercent) return Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT);
1890
1891 /* Service intervals are in minutes. */
1892 if (TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU)) return Clamp(interval, MIN_SERVINT_MINUTES, MAX_SERVINT_MINUTES);
1893
1894 /* Service intervals are in days. */
1895 return Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1896}
1897
1906static bool CheckForValidOrders(const Vehicle *v)
1907{
1908 for (const Order *order : v->Orders()) {
1909 switch (order->GetType()) {
1910 case OT_GOTO_STATION:
1911 case OT_GOTO_DEPOT:
1912 case OT_GOTO_WAYPOINT:
1913 return true;
1914
1915 default:
1916 break;
1917 }
1918 }
1919
1920 return false;
1921}
1922
1926static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1927{
1928 switch (occ) {
1929 case OCC_EQUALS: return variable == value;
1930 case OCC_NOT_EQUALS: return variable != value;
1931 case OCC_LESS_THAN: return variable < value;
1932 case OCC_LESS_EQUALS: return variable <= value;
1933 case OCC_MORE_THAN: return variable > value;
1934 case OCC_MORE_EQUALS: return variable >= value;
1935 case OCC_IS_TRUE: return variable != 0;
1936 case OCC_IS_FALSE: return variable == 0;
1937 default: NOT_REACHED();
1938 }
1939}
1940
1941static bool OrderConditionCompare(OrderConditionComparator occ, ConvertibleThroughBase auto variable, int value)
1942{
1943 return OrderConditionCompare(occ, variable.base(), value);
1944}
1945
1953{
1954 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1955
1956 bool skip_order = false;
1958 uint16_t value = order->GetConditionValue();
1959
1960 switch (order->GetConditionVariable()) {
1961 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1962 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
1963 case OCV_MAX_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability), value); break;
1964 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1965 case OCV_AGE: skip_order = OrderConditionCompare(occ, TimerGameCalendar::DateToYear(v->age), value); break;
1966 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
1967 case OCV_UNCONDITIONALLY: skip_order = true; break;
1969 default: NOT_REACHED();
1970 }
1971
1972 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1973}
1974
1982bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
1983{
1984 if (conditional_depth > v->GetNumOrders()) {
1985 v->current_order.Free();
1986 v->SetDestTile(TileIndex{});
1987 return false;
1988 }
1989
1990 switch (order->GetType()) {
1991 case OT_GOTO_STATION:
1992 v->SetDestTile(v->GetOrderStationLocation(order->GetDestination()));
1993 return true;
1994
1995 case OT_GOTO_DEPOT:
1996 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
1997 assert(!pbs_look_ahead);
1998 UpdateVehicleTimetable(v, true);
2000 break;
2001 }
2002
2004 /* If the vehicle can't find its destination, delay its next search.
2005 * In case many vehicles are in this state, use the vehicle index to spread out pathfinder calls. */
2006 if (v->dest_tile == 0 && TimerGameEconomy::date_fract != (v->index % Ticks::DAY_TICKS)) break;
2007
2008 /* We need to search for the nearest depot (hangar). */
2009 ClosestDepot closestDepot = v->FindClosestDepot();
2010
2011 if (closestDepot.found) {
2012 /* PBS reservations cannot reverse */
2013 if (pbs_look_ahead && closestDepot.reverse) return false;
2014
2015 v->SetDestTile(closestDepot.location);
2016 v->current_order.SetDestination(closestDepot.destination);
2017
2018 /* If there is no depot in front, reverse automatically (trains only) */
2019 if (v->type == VEH_TRAIN && closestDepot.reverse) Command<CMD_REVERSE_TRAIN_DIRECTION>::Do(DC_EXEC, v->index, false);
2020
2021 if (v->type == VEH_AIRCRAFT) {
2022 Aircraft *a = Aircraft::From(v);
2023 if (a->state == FLYING && a->targetairport != closestDepot.destination) {
2024 /* The aircraft is now heading for a different hangar than the next in the orders */
2026 }
2027 }
2028 return true;
2029 }
2030
2031 /* If there is no depot, we cannot help PBS either. */
2032 if (pbs_look_ahead) return false;
2033
2034 UpdateVehicleTimetable(v, true);
2036 } else {
2037 if (v->type != VEH_AIRCRAFT) {
2038 v->SetDestTile(Depot::Get(order->GetDestination())->xy);
2039 } else {
2040 Aircraft *a = Aircraft::From(v);
2041 DestinationID destination = a->current_order.GetDestination();
2042 if (a->targetairport != destination) {
2043 /* The aircraft is now heading for a different hangar than the next in the orders */
2044 a->SetDestTile(a->GetOrderStationLocation(destination));
2045 }
2046 }
2047 return true;
2048 }
2049 break;
2050
2051 case OT_GOTO_WAYPOINT:
2052 v->SetDestTile(Waypoint::Get(order->GetDestination())->xy);
2053 return true;
2054
2055 case OT_CONDITIONAL: {
2056 assert(!pbs_look_ahead);
2057 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2058 if (next_order != INVALID_VEH_ORDER_ID) {
2059 /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2060 * cur_real_order_index might come after next_order. */
2061 UpdateVehicleTimetable(v, false);
2065
2066 /* Disable creation of implicit orders.
2067 * When inserting them we do not know that we would have to make the conditional orders point to them. */
2068 if (v->IsGroundVehicle()) {
2069 uint16_t &gv_flags = v->GetGroundVehicleFlags();
2071 }
2072 } else {
2073 UpdateVehicleTimetable(v, true);
2075 }
2076 break;
2077 }
2078
2079 default:
2080 v->SetDestTile(TileIndex{});
2081 return false;
2082 }
2083
2084 assert(v->cur_implicit_order_index < v->GetNumOrders());
2085 assert(v->cur_real_order_index < v->GetNumOrders());
2086
2087 /* Get the current order */
2088 order = v->GetOrder(v->cur_real_order_index);
2089 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2090 assert(v->GetNumManualOrders() == 0);
2091 order = nullptr;
2092 }
2093
2094 if (order == nullptr) {
2095 v->current_order.Free();
2096 v->SetDestTile(TileIndex{});
2097 return false;
2098 }
2099
2100 v->current_order = *order;
2101 return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2102}
2103
2112{
2113 switch (v->current_order.GetType()) {
2114 case OT_GOTO_DEPOT:
2115 /* Let a depot order in the orderlist interrupt. */
2116 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
2117 break;
2118
2119 case OT_LOADING:
2120 return false;
2121
2122 case OT_LEAVESTATION:
2123 if (v->type != VEH_AIRCRAFT) return false;
2124 break;
2125
2126 default: break;
2127 }
2128
2136 bool may_reverse = v->current_order.IsType(OT_NOTHING);
2137
2138 /* Check if we've reached a 'via' destination. */
2139 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)) &&
2140 IsTileType(v->tile, MP_STATION) &&
2143 /* We set the last visited station here because we do not want
2144 * the train to stop at this 'via' station if the next order
2145 * is a no-non-stop order; in that case not setting the last
2146 * visited station will cause the vehicle to still stop. */
2148 UpdateVehicleTimetable(v, true);
2150 }
2151
2152 /* Get the current order */
2155
2156 const Order *order = v->GetOrder(v->cur_real_order_index);
2157 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2158 assert(v->GetNumManualOrders() == 0);
2159 order = nullptr;
2160 }
2161
2162 /* If no order, do nothing. */
2163 if (order == nullptr || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
2164 if (v->type == VEH_AIRCRAFT) {
2165 /* Aircraft do something vastly different here, so handle separately */
2166 HandleMissingAircraftOrders(Aircraft::From(v));
2167 return false;
2168 }
2169
2170 v->current_order.Free();
2171 v->SetDestTile(TileIndex{});
2172 return false;
2173 }
2174
2175 /* If it is unchanged, keep it. */
2176 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
2177 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->ship_station.tile != INVALID_TILE)) {
2178 return false;
2179 }
2180
2181 /* Otherwise set it, and determine the destination tile. */
2182 v->current_order = *order;
2183
2185 switch (v->type) {
2186 default:
2187 NOT_REACHED();
2188
2189 case VEH_ROAD:
2190 case VEH_TRAIN:
2191 break;
2192
2193 case VEH_AIRCRAFT:
2194 case VEH_SHIP:
2196 break;
2197 }
2198
2199 return UpdateOrderDest(v, order) && may_reverse;
2200}
2201
2209bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2210{
2211 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2212
2213 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
2214 v->last_station_visited != station && // Do stop only when we've not just been there
2215 /* Finally do stop when there is no non-stop flag set for this type of station. */
2217}
2218
2219bool Order::CanLoadOrUnload() const
2220{
2221 return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2223 ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
2224 (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
2225}
2226
2233bool Order::CanLeaveWithCargo(bool has_cargo) const
2234{
2235 return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
2236 (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
2237}
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.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
static const CargoType CARGO_AUTO_REFIT
Automatically choose cargo type when doing auto refitting.
Definition cargo_type.h:77
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
static const CargoType CARGO_NO_REFIT
Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-renew).
Definition cargo_type.h:78
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.
A type is considered 'convertible through base()' when it has a 'base()' function that returns someth...
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:160
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:143
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 AddVehicleAdviceNewsItem(AdviceType advice_type, StringID string, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition news_func.h:40
void DeleteVehicleNews(VehicleID vid, AdviceType advice_type=AdviceType::Invalid)
Delete news with a given advice type about a vehicle.
@ Order
Something wrong with the order, e.g. invalid or duplicate entries, too few entries.
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, CargoType 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.
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
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
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
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
@ 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
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
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition order_type.h:15
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
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition order_type.h:23
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
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition order_type.h:21
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
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
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
@ SHORT_STRIP
This airport has a short landing strip, dangerous for fast aircraft.
Definition airport.h:150
Flags flags
Flags for this airport type.
Definition airport.h:180
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:48
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:258
Order * GetLastOrder() const
Get the last order of the order chain.
Definition order_base.h:304
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:265
VehicleOrderID num_orders
NOSAVE: How many orders there are in the list.
Definition order_base.h:263
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:312
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:269
Order * first
First order of the order list.
Definition order_base.h:267
Vehicle * first_shared
NOSAVE: pointer to the first vehicle in the shared order chain.
Definition order_base.h:266
Order * GetFirstOrder() const
Get the first order of the order chain.
Definition order_base.h:296
VehicleOrderID num_manual_orders
NOSAVE: How many manually added orders are there in the list.
Definition order_base.h:264
VehicleOrderID GetNumOrders() const
Get number of orders in the order list.
Definition order_base.h:318
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:337
TimerGameTick::Ticks total_duration
NOSAVE: Total (timetabled or not) duration of the order list.
Definition order_base.h:270
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
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
CargoType GetRefitCargo() const
Get the cargo to to refit to.
Definition order_base.h:131
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
void MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoType cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition order_cmd.cpp:90
uint16_t wait_time
How long in ticks to wait at the destination.
Definition order_base.h:54
void SetRefit(CargoType cargo)
Make this depot/station order also a refit order.
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
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 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
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...
CargoType refit_cargo
Refit CargoType.
Definition order_base.h:52
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:79
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:3125
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:3217
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3099
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:3234
@ 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: