OpenTTD Source 15.0-beta2
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().ToStationID());
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
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
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
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->GetType()) {
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().value, 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().value, 0, 8) << 8;
211 break;
212 case OT_LOADING:
213 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
214 /* If both "no load" and "no unload" are set, return nothing order instead */
215 if ((this->GetLoadType() & OLFB_NO_LOAD) && (this->GetUnloadType() & OUFB_NO_UNLOAD)) {
216 order = OT_NOTHING;
217 }
218 break;
219 default:
220 break;
221 }
222 return order;
223}
224
230void InvalidateVehicleOrder(const Vehicle *v, int data)
231{
233
234 if (data != 0) {
235 /* Calls SetDirty() too */
238 return;
239 }
240
243}
244
252void Order::AssignOrder(const Order &other)
253{
254 this->type = other.type;
255 this->flags = other.flags;
256 this->dest = other.dest;
257
258 this->refit_cargo = other.refit_cargo;
259
260 this->wait_time = other.wait_time;
261 this->travel_time = other.travel_time;
262 this->max_speed = other.max_speed;
263}
264
271{
272 this->first = chain;
273 this->first_shared = v;
274
275 this->num_orders = 0;
276 this->num_manual_orders = 0;
277 this->num_vehicles = 1;
278 this->timetable_duration = 0;
279
280 for (Order *o = this->first; o != nullptr; o = o->next) {
281 ++this->num_orders;
282 if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
283 this->total_duration += o->GetWaitTime() + o->GetTravelTime();
284 }
285
287
288 for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
289 ++this->num_vehicles;
290 this->first_shared = u;
291 }
292
293 for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
294}
295
301{
302 this->timetable_duration = 0;
303 for (Order *o = this->first; o != nullptr; o = o->next) {
304 this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
305 }
306}
307
313void OrderList::FreeChain(bool keep_orderlist)
314{
315 Order *next;
316 for (Order *o = this->first; o != nullptr; o = next) {
317 next = o->next;
318 delete o;
319 }
320
321 if (keep_orderlist) {
322 this->first = nullptr;
323 this->num_orders = 0;
324 this->num_manual_orders = 0;
325 this->timetable_duration = 0;
326 } else {
327 delete this;
328 }
329}
330
337{
338 if (index < 0) return nullptr;
339
340 Order *order = this->first;
341
342 while (order != nullptr && index-- > 0) {
343 order = order->next;
344 }
345 return order;
346}
347
359const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
360{
361 if (hops > this->GetNumOrders() || next == nullptr) return nullptr;
362
363 if (next->IsType(OT_CONDITIONAL)) {
364 if (next->GetConditionVariable() != OCV_UNCONDITIONALLY) return next;
365
366 /* We can evaluate trivial conditions right away. They're conceptually
367 * the same as regular order progression. */
368 return this->GetNextDecisionNode(
369 this->GetOrderAt(next->GetConditionSkipToOrder()),
370 hops + 1);
371 }
372
373 if (next->IsType(OT_GOTO_DEPOT)) {
374 if ((next->GetDepotActionType() & ODATFB_HALT) != 0) return nullptr;
375 if (next->IsRefit()) return next;
376 }
377
378 if (!next->CanLoadOrUnload()) {
379 return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
380 }
381
382 return next;
383}
384
394StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first, uint hops) const
395{
396
397 const Order *next = first;
398 if (first == nullptr) {
399 next = this->GetOrderAt(v->cur_implicit_order_index);
400 if (next == nullptr) {
401 next = this->GetFirstOrder();
402 if (next == nullptr) return StationID::Invalid().base();
403 } else {
404 /* GetNext never returns nullptr if there is a valid station in the list.
405 * As the given "next" is already valid and a station in the list, we
406 * don't have to check for nullptr here. */
407 next = this->GetNext(next);
408 assert(next != nullptr);
409 }
410 }
411
412 do {
413 next = this->GetNextDecisionNode(next, ++hops);
414
415 /* Resolve possibly nested conditionals by estimation. */
416 while (next != nullptr && next->IsType(OT_CONDITIONAL)) {
417 /* We return both options of conditional orders. */
418 const Order *skip_to = this->GetNextDecisionNode(
419 this->GetOrderAt(next->GetConditionSkipToOrder()), hops);
420 const Order *advance = this->GetNextDecisionNode(
421 this->GetNext(next), hops);
422 if (advance == nullptr || advance == first || skip_to == advance) {
423 next = (skip_to == first) ? nullptr : skip_to;
424 } else if (skip_to == nullptr || skip_to == first) {
425 next = (advance == first) ? nullptr : advance;
426 } else {
427 StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
428 StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
429 while (!st2.IsEmpty()) st1.Push(st2.Pop());
430 return st1;
431 }
432 ++hops;
433 }
434
435 /* Don't return a next stop if the vehicle has to unload everything. */
436 if (next == nullptr || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) &&
437 next->GetDestination() == v->last_station_visited &&
438 (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
439 return StationID::Invalid().base();
440 }
441 } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
442
443 return next->GetDestination().ToStationID().base();
444}
445
451void OrderList::InsertOrderAt(Order *new_order, int index)
452{
453 if (this->first == nullptr) {
454 this->first = new_order;
455 } else {
456 if (index == 0) {
457 /* Insert as first or only order */
458 new_order->next = this->first;
459 this->first = new_order;
460 } else if (index >= this->num_orders) {
461 /* index is after the last order, add it to the end */
462 this->GetLastOrder()->next = new_order;
463 } else {
464 /* Put the new order in between */
465 Order *order = this->GetOrderAt(index - 1);
466 new_order->next = order->next;
467 order->next = new_order;
468 }
469 }
470 ++this->num_orders;
471 if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
472 this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
473 this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
474
475 /* We can visit oil rigs and buoys that are not our own. They will be shown in
476 * the list of stations. So, we need to invalidate that window if needed. */
477 if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
478 BaseStation *bs = BaseStation::Get(new_order->GetDestination().ToStationID());
480 }
481
482}
483
484
490{
491 if (index >= this->num_orders) return;
492
493 Order *to_remove;
494
495 if (index == 0) {
496 to_remove = this->first;
497 this->first = to_remove->next;
498 } else {
499 Order *prev = GetOrderAt(index - 1);
500 to_remove = prev->next;
501 prev->next = to_remove->next;
502 }
503 --this->num_orders;
504 if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
505 this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
506 this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
507 delete to_remove;
508}
509
515void OrderList::MoveOrder(int from, int to)
516{
517 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
518
519 Order *moving_one;
520
521 /* Take the moving order out of the pointer-chain */
522 if (from == 0) {
523 moving_one = this->first;
524 this->first = moving_one->next;
525 } else {
526 Order *one_before = GetOrderAt(from - 1);
527 moving_one = one_before->next;
528 one_before->next = moving_one->next;
529 }
530
531 /* Insert the moving_order again in the pointer-chain */
532 if (to == 0) {
533 moving_one->next = this->first;
534 this->first = moving_one;
535 } else {
536 Order *one_before = GetOrderAt(to - 1);
537 moving_one->next = one_before->next;
538 one_before->next = moving_one;
539 }
540}
541
548{
549 --this->num_vehicles;
550 if (v == this->first_shared) this->first_shared = v->NextShared();
551}
552
558{
559 for (Order *o = this->first; o != nullptr; o = o->next) {
560 /* Implicit orders are, by definition, not timetabled. */
561 if (o->IsType(OT_IMPLICIT)) continue;
562 if (!o->IsCompletelyTimetabled()) return false;
563 }
564 return true;
565}
566
567#ifdef WITH_ASSERT
571void OrderList::DebugCheckSanity() const
572{
573 VehicleOrderID check_num_orders = 0;
574 VehicleOrderID check_num_manual_orders = 0;
575 uint check_num_vehicles = 0;
576 TimerGameTick::Ticks check_timetable_duration = 0;
577 TimerGameTick::Ticks check_total_duration = 0;
578
579 Debug(misc, 6, "Checking OrderList {} for sanity...", this->index);
580
581 for (const Order *o = this->first; o != nullptr; o = o->next) {
582 ++check_num_orders;
583 if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
584 check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
585 check_total_duration += o->GetWaitTime() + o->GetTravelTime();
586 }
587 assert(this->num_orders == check_num_orders);
588 assert(this->num_manual_orders == check_num_manual_orders);
589 assert(this->timetable_duration == check_timetable_duration);
590 assert(this->total_duration == check_total_duration);
591
592 for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
593 ++check_num_vehicles;
594 assert(v->orders == this);
595 }
596 assert(this->num_vehicles == check_num_vehicles);
597 Debug(misc, 6, "... detected {} orders ({} manual), {} vehicles, {} timetabled, {} total",
598 (uint)this->num_orders, (uint)this->num_manual_orders,
600}
601#endif
602
610static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
611{
612 return o->IsType(OT_GOTO_STATION) ||
613 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && o->GetDestination() != StationID::Invalid());
614}
615
622static void DeleteOrderWarnings(const Vehicle *v)
623{
625}
626
633TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
634{
635 switch (this->GetType()) {
636 case OT_GOTO_WAYPOINT:
637 case OT_GOTO_STATION:
638 case OT_IMPLICIT:
639 if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination().ToStationID())->airport.tile;
640 return BaseStation::Get(this->GetDestination().ToStationID())->xy;
641
642 case OT_GOTO_DEPOT:
643 if (this->GetDestination() == DepotID::Invalid()) return INVALID_TILE;
644 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination().ToStationID())->xy : Depot::Get(this->GetDestination().ToDepotID())->xy;
645
646 default:
647 return INVALID_TILE;
648 }
649}
650
660uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
661{
662 if (cur->IsType(OT_CONDITIONAL)) {
663 if (conditional_depth > v->GetNumOrders()) return 0;
664
665 conditional_depth++;
666
667 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
668 int dist2 = GetOrderDistance(prev, cur->next == nullptr ? v->orders->GetFirstOrder() : cur->next, v, conditional_depth);
669 return std::max(dist1, dist2);
670 }
671
672 TileIndex prev_tile = prev->GetLocation(v, true);
673 TileIndex cur_tile = cur->GetLocation(v, true);
674 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
675 return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
676}
677
689{
691 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
692
694 if (ret.Failed()) return ret;
695
696 /* Validate properties we don't want to have different from default as they are set by other commands. */
697 if (new_order.GetRefitCargo() != CARGO_NO_REFIT || new_order.GetWaitTime() != 0 || new_order.GetTravelTime() != 0 || new_order.GetMaxSpeed() != UINT16_MAX) return CMD_ERROR;
698
699 /* Check if the inserted order is to the correct destination (owner, type),
700 * and has the correct flags if any */
701 switch (new_order.GetType()) {
702 case OT_GOTO_STATION: {
703 const Station *st = Station::GetIfValid(new_order.GetDestination().ToStationID());
704 if (st == nullptr) return CMD_ERROR;
705
706 if (st->owner != OWNER_NONE) {
707 ret = CheckOwnership(st->owner);
708 if (ret.Failed()) return ret;
709 }
710
711 if (!CanVehicleUseStation(v, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, GetVehicleCannotUseStationReason(v, st));
712 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
713 if (!CanVehicleUseStation(u, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER_SHARED, GetVehicleCannotUseStationReason(u, st));
714 }
715
716 /* Non stop only allowed for ground vehicles. */
717 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
718
719 /* Filter invalid load/unload types. */
720 switch (new_order.GetLoadType()) {
722 case OLFB_NO_LOAD:
723 break;
724
725 case OLFB_FULL_LOAD:
727 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
728 break;
729
730 default:
731 return CMD_ERROR;
732 }
733 switch (new_order.GetUnloadType()) {
735 default: return CMD_ERROR;
736 }
737
738 /* Filter invalid stop locations */
739 switch (new_order.GetStopLocation()) {
742 if (v->type != VEH_TRAIN) return CMD_ERROR;
743 [[fallthrough]];
744
746 break;
747
748 default:
749 return CMD_ERROR;
750 }
751
752 break;
753 }
754
755 case OT_GOTO_DEPOT: {
756 if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
757 if (v->type == VEH_AIRCRAFT) {
758 const Station *st = Station::GetIfValid(new_order.GetDestination().ToStationID());
759
760 if (st == nullptr) return CMD_ERROR;
761
762 ret = CheckOwnership(st->owner);
763 if (ret.Failed()) return ret;
764
765 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
766 return CMD_ERROR;
767 }
768 } else {
769 const Depot *dp = Depot::GetIfValid(new_order.GetDestination().ToDepotID());
770
771 if (dp == nullptr) return CMD_ERROR;
772
773 ret = CheckOwnership(GetTileOwner(dp->xy));
774 if (ret.Failed()) return ret;
775
776 switch (v->type) {
777 case VEH_TRAIN:
778 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
779 break;
780
781 case VEH_ROAD:
782 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
783 break;
784
785 case VEH_SHIP:
786 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
787 break;
788
789 default: return CMD_ERROR;
790 }
791 }
792 }
793
794 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
795 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
797
798 /* Vehicles cannot have a "service if needed" order that also has a depot action. */
799 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & (ODATFB_HALT | ODATFB_UNBUNCH))) return CMD_ERROR;
800
801 /* Check if we're allowed to have a new unbunching order. */
802 if ((new_order.GetDepotActionType() & ODATFB_UNBUNCH)) {
803 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
804 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
805 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
806 }
807 break;
808 }
809
810 case OT_GOTO_WAYPOINT: {
811 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination().ToStationID());
812 if (wp == nullptr) return CMD_ERROR;
813
814 switch (v->type) {
815 default: return CMD_ERROR;
816
817 case VEH_TRAIN: {
818 if (!wp->facilities.Test(StationFacility::Train)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_RAIL_WAYPOINT);
819
820 ret = CheckOwnership(wp->owner);
821 if (ret.Failed()) return ret;
822 break;
823 }
824
825 case VEH_ROAD: {
826 if (!wp->facilities.Test(StationFacility::BusStop) && !wp->facilities.Test(StationFacility::TruckStop)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_ROAD_WAYPOINT);
827
828 ret = CheckOwnership(wp->owner);
829 if (ret.Failed()) return ret;
830 break;
831 }
832
833 case VEH_SHIP:
834 if (!wp->facilities.Test(StationFacility::Dock)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_BUOY);
835 if (wp->owner != OWNER_NONE) {
836 ret = CheckOwnership(wp->owner);
837 if (ret.Failed()) return ret;
838 }
839 break;
840 }
841
842 /* Order flags can be any of the following for waypoints:
843 * [non-stop]
844 * non-stop orders (if any) are only valid for trains and road vehicles */
845 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
846 break;
847 }
848
849 case OT_CONDITIONAL: {
850 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
851 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
852 if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
853 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_CONDITIONAL);
854
856 if (occ >= OCC_END) return CMD_ERROR;
857 switch (new_order.GetConditionVariable()) {
859 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
860 break;
861
863 if (occ != OCC_EQUALS) return CMD_ERROR;
864 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
865 break;
866
868 case OCV_RELIABILITY:
869 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
870 [[fallthrough]];
871
872 default:
873 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
874 break;
875 }
876 break;
877 }
878
879 default: return CMD_ERROR;
880 }
881
882 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
883
884 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return CommandCost(STR_ERROR_TOO_MANY_ORDERS);
885 if (!Order::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
886 if (v->orders == nullptr && !OrderList::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
887
888 if (flags.Test(DoCommandFlag::Execute)) {
889 Order *new_o = new Order();
890 new_o->AssignOrder(new_order);
891 InsertOrder(v, new_o, sel_ord);
892 }
893
894 return CommandCost();
895}
896
903void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
904{
905 /* Create new order and link in list */
906 if (v->orders == nullptr) {
907 v->orders = new OrderList(new_o, v);
908 } else {
909 v->orders->InsertOrderAt(new_o, sel_ord);
910 }
911
912 Vehicle *u = v->FirstShared();
914 for (; u != nullptr; u = u->NextShared()) {
915 assert(v->orders == u->orders);
916
917 /* If there is added an order before the current one, we need
918 * to update the selected order. We do not change implicit/real order indices though.
919 * If the new order is between the current implicit order and real order, the implicit order will
920 * later skip the inserted order. */
921 if (sel_ord <= u->cur_real_order_index) {
922 uint cur = u->cur_real_order_index + 1;
923 /* Check if we don't go out of bound */
924 if (cur < u->GetNumOrders()) {
925 u->cur_real_order_index = cur;
926 }
927 }
928 if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
929 /* We are inserting an order just before the current implicit order.
930 * We do not know whether we will reach current implicit or the newly inserted order first.
931 * So, disable creation of implicit orders until we are on track again. */
932 uint16_t &gv_flags = u->GetGroundVehicleFlags();
934 }
935 if (sel_ord <= u->cur_implicit_order_index) {
936 uint cur = u->cur_implicit_order_index + 1;
937 /* Check if we don't go out of bound */
938 if (cur < u->GetNumOrders()) {
940 }
941 }
942 /* Unbunching data is no longer valid. */
944
945 /* Update any possible open window of the vehicle */
946 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
947 }
948
949 /* As we insert an order, the order to skip to will be 'wrong'. */
950 VehicleOrderID cur_order_id = 0;
951 for (Order *order : v->Orders()) {
952 if (order->IsType(OT_CONDITIONAL)) {
953 VehicleOrderID order_id = order->GetConditionSkipToOrder();
954 if (order_id >= sel_ord) {
955 order->SetConditionSkipToOrder(order_id + 1);
956 }
957 if (order_id == cur_order_id) {
958 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
959 }
960 }
961 cur_order_id++;
962 }
963
964 /* Make sure to rebuild the whole list */
966}
967
982
991{
992 Vehicle *v = Vehicle::GetIfValid(veh_id);
993
994 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
995
997 if (ret.Failed()) return ret;
998
999 /* If we did not select an order, we maybe want to de-clone the orders */
1000 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
1001
1002 if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
1003
1004 if (flags.Test(DoCommandFlag::Execute)) DeleteOrder(v, sel_ord);
1005 return CommandCost();
1006}
1007
1013{
1014 assert(v->current_order.IsType(OT_LOADING));
1015 /* NON-stop flag is misused to see if a train is in a station that is
1016 * on its order list or not */
1018 /* When full loading, "cancel" that order so the vehicle doesn't
1019 * stay indefinitely at this station anymore. */
1021}
1022
1029{
1030 v->orders->DeleteOrderAt(sel_ord);
1031
1032 Vehicle *u = v->FirstShared();
1034 for (; u != nullptr; u = u->NextShared()) {
1035 assert(v->orders == u->orders);
1036
1037 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
1039 }
1040
1041 if (sel_ord < u->cur_real_order_index) {
1043 } else if (sel_ord == u->cur_real_order_index) {
1045 }
1046
1047 if (sel_ord < u->cur_implicit_order_index) {
1049 } else if (sel_ord == u->cur_implicit_order_index) {
1050 /* Make sure the index is valid */
1052
1053 /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
1057 }
1058 }
1059 /* Unbunching data is no longer valid. */
1061
1062 /* Update any possible open window of the vehicle */
1063 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1064 }
1065
1066 /* As we delete an order, the order to skip to will be 'wrong'. */
1067 VehicleOrderID cur_order_id = 0;
1068 for (Order *order : v->Orders()) {
1069 if (order->IsType(OT_CONDITIONAL)) {
1070 VehicleOrderID order_id = order->GetConditionSkipToOrder();
1071 if (order_id >= sel_ord) {
1072 order_id = std::max(order_id - 1, 0);
1073 }
1074 if (order_id == cur_order_id) {
1075 order_id = (order_id + 1) % v->GetNumOrders();
1076 }
1077 order->SetConditionSkipToOrder(order_id);
1078 }
1079 cur_order_id++;
1080 }
1081
1083}
1084
1093{
1094 Vehicle *v = Vehicle::GetIfValid(veh_id);
1095
1096 if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1097
1099 if (ret.Failed()) return ret;
1100
1101 if (flags.Test(DoCommandFlag::Execute)) {
1102 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1103
1106
1107 /* Unbunching data is no longer valid. */
1109
1111
1112 /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1115 }
1116
1117 return CommandCost();
1118}
1119
1131{
1132 Vehicle *v = Vehicle::GetIfValid(veh);
1133 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1134
1136 if (ret.Failed()) return ret;
1137
1138 /* Don't make senseless movements */
1139 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1140 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1141
1142 Order *moving_one = v->GetOrder(moving_order);
1143 /* Don't move an empty order */
1144 if (moving_one == nullptr) return CMD_ERROR;
1145
1146 if (flags.Test(DoCommandFlag::Execute)) {
1147 v->orders->MoveOrder(moving_order, target_order);
1148
1149 /* Update shared list */
1150 Vehicle *u = v->FirstShared();
1151
1153
1154 for (; u != nullptr; u = u->NextShared()) {
1155 /* Update the current order.
1156 * There are multiple ways to move orders, which result in cur_implicit_order_index
1157 * and cur_real_order_index to not longer make any sense. E.g. moving another
1158 * real order between them.
1159 *
1160 * Basically one could choose to preserve either of them, but not both.
1161 * While both ways are suitable in this or that case from a human point of view, neither
1162 * of them makes really sense.
1163 * However, from an AI point of view, preserving cur_real_order_index is the most
1164 * predictable and transparent behaviour.
1165 *
1166 * With that decision it basically does not matter what we do to cur_implicit_order_index.
1167 * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1168 * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1169 * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1170 */
1171 if (u->cur_real_order_index == moving_order) {
1172 u->cur_real_order_index = target_order;
1173 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1175 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1177 }
1178
1179 if (u->cur_implicit_order_index == moving_order) {
1180 u->cur_implicit_order_index = target_order;
1181 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1183 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1185 }
1186 /* Unbunching data is no longer valid. */
1188
1189
1190 assert(v->orders == u->orders);
1191 /* Update any possible open window of the vehicle */
1192 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1193 }
1194
1195 /* As we move an order, the order to skip to will be 'wrong'. */
1196 for (Order *order : v->Orders()) {
1197 if (order->IsType(OT_CONDITIONAL)) {
1198 VehicleOrderID order_id = order->GetConditionSkipToOrder();
1199 if (order_id == moving_order) {
1200 order_id = target_order;
1201 } else if (order_id > moving_order && order_id <= target_order) {
1202 order_id--;
1203 } else if (order_id < moving_order && order_id >= target_order) {
1204 order_id++;
1205 }
1206 order->SetConditionSkipToOrder(order_id);
1207 }
1208 }
1209
1210 /* Make sure to rebuild the whole list */
1212 }
1213
1214 return CommandCost();
1215}
1216
1229{
1230 if (mof >= MOF_END) return CMD_ERROR;
1231
1232 Vehicle *v = Vehicle::GetIfValid(veh);
1233 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1234
1236 if (ret.Failed()) return ret;
1237
1238 /* Is it a valid order? */
1239 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1240
1241 Order *order = v->GetOrder(sel_ord);
1242 assert(order != nullptr);
1243 switch (order->GetType()) {
1244 case OT_GOTO_STATION:
1245 if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1246 break;
1247
1248 case OT_GOTO_DEPOT:
1249 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1250 break;
1251
1252 case OT_GOTO_WAYPOINT:
1253 if (mof != MOF_NON_STOP) return CMD_ERROR;
1254 break;
1255
1256 case OT_CONDITIONAL:
1257 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1258 break;
1259
1260 default:
1261 return CMD_ERROR;
1262 }
1263
1264 switch (mof) {
1265 default: NOT_REACHED();
1266
1267 case MOF_NON_STOP:
1268 if (!v->IsGroundVehicle()) return CMD_ERROR;
1269 if (data >= ONSF_END) return CMD_ERROR;
1270 if (data == order->GetNonStopType()) return CMD_ERROR;
1271 break;
1272
1273 case MOF_STOP_LOCATION:
1274 if (v->type != VEH_TRAIN) return CMD_ERROR;
1275 if (data >= OSL_END) return CMD_ERROR;
1276 break;
1277
1278 case MOF_UNLOAD:
1280 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
1281 /* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
1282 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
1283 if (data == order->GetUnloadType()) return CMD_ERROR;
1284 break;
1285
1286 case MOF_LOAD:
1288 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
1289 if (data == order->GetLoadType()) return CMD_ERROR;
1290 if ((data & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) && v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
1291 break;
1292
1293 case MOF_DEPOT_ACTION:
1294 if (data >= DA_END) return CMD_ERROR;
1295 /* Check if we are allowed to add unbunching. We are always allowed to remove it. */
1296 if (data == DA_UNBUNCH) {
1297 /* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */
1298 if (v->HasUnbunchingOrder() && !(order->GetDepotActionType() & ODATFB_UNBUNCH)) return CommandCost(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
1299 /* We don't allow unbunching if the vehicle has a conditional order. */
1300 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
1301 /* We don't allow unbunching if the vehicle has a full load order. */
1302 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
1303 }
1304 break;
1305
1306 case MOF_COND_VARIABLE:
1307 if (data >= OCV_END) return CMD_ERROR;
1308 break;
1309
1311 if (data >= OCC_END) return CMD_ERROR;
1312 switch (order->GetConditionVariable()) {
1313 case OCV_UNCONDITIONALLY: return CMD_ERROR;
1314
1316 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
1317 break;
1318
1319 default:
1320 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
1321 break;
1322 }
1323 break;
1324
1325 case MOF_COND_VALUE:
1326 switch (order->GetConditionVariable()) {
1329 return CMD_ERROR;
1330
1332 case OCV_RELIABILITY:
1333 if (data > 100) return CMD_ERROR;
1334 break;
1335
1336 default:
1337 if (data > 2047) return CMD_ERROR;
1338 break;
1339 }
1340 break;
1341
1343 if (data >= v->GetNumOrders()) return CMD_ERROR;
1344 break;
1345 }
1346
1347 if (flags.Test(DoCommandFlag::Execute)) {
1348 switch (mof) {
1349 case MOF_NON_STOP:
1350 order->SetNonStopType((OrderNonStopFlags)data);
1352 order->SetRefit(CARGO_NO_REFIT);
1355 }
1356 break;
1357
1358 case MOF_STOP_LOCATION:
1359 order->SetStopLocation((OrderStopLocation)data);
1360 break;
1361
1362 case MOF_UNLOAD:
1363 order->SetUnloadType((OrderUnloadFlags)data);
1364 break;
1365
1366 case MOF_LOAD:
1367 order->SetLoadType((OrderLoadFlags)data);
1368 if (data & OLFB_NO_LOAD) order->SetRefit(CARGO_NO_REFIT);
1369 break;
1370
1371 case MOF_DEPOT_ACTION: {
1372 switch (data) {
1373 case DA_ALWAYS_GO:
1377 break;
1378
1379 case DA_SERVICE:
1383 order->SetRefit(CARGO_NO_REFIT);
1384 break;
1385
1386 case DA_STOP:
1390 order->SetRefit(CARGO_NO_REFIT);
1391 break;
1392
1393 case DA_UNBUNCH:
1397 break;
1398
1399 default:
1400 NOT_REACHED();
1401 }
1402 break;
1403 }
1404
1405 case MOF_COND_VARIABLE: {
1407
1409 switch (order->GetConditionVariable()) {
1412 order->SetConditionValue(0);
1413 break;
1414
1416 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
1417 order->SetConditionValue(0);
1418 break;
1419
1421 case OCV_RELIABILITY:
1422 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1423 [[fallthrough]];
1424
1425 default:
1426 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
1427 break;
1428 }
1429 break;
1430 }
1431
1434 break;
1435
1436 case MOF_COND_VALUE:
1437 order->SetConditionValue(data);
1438 break;
1439
1441 order->SetConditionSkipToOrder(data);
1442 break;
1443
1444 default: NOT_REACHED();
1445 }
1446
1447 /* Update the windows and full load flags, also for vehicles that share the same order list */
1448 Vehicle *u = v->FirstShared();
1450 for (; u != nullptr; u = u->NextShared()) {
1451 /* Toggle u->current_order "Full load" flag if it changed.
1452 * However, as the same flag is used for depot orders, check
1453 * whether we are not going to a depot as there are three
1454 * cases where the full load flag can be active and only
1455 * one case where the flag is used for depot orders. In the
1456 * other cases for the OrderType the flags are not used,
1457 * so do not care and those orders should not be active
1458 * when this function is called.
1459 */
1460 if (sel_ord == u->cur_real_order_index &&
1461 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1462 u->current_order.GetLoadType() != order->GetLoadType()) {
1464 }
1465
1466 /* Unbunching data is no longer valid. */
1468
1470 }
1471 }
1472
1473 return CommandCost();
1474}
1475
1483static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first)
1484{
1485 if (first == nullptr || v_new->acache.cached_max_range == 0) return true;
1486
1487 /* Iterate over all orders to check the distance between all
1488 * 'goto' orders and their respective next order (of any type). */
1489 for (const Order *o = first; o != nullptr; o = o->next) {
1490 switch (o->GetType()) {
1491 case OT_GOTO_STATION:
1492 case OT_GOTO_DEPOT:
1493 case OT_GOTO_WAYPOINT:
1494 /* If we don't have a next order, we've reached the end and must check the first order instead. */
1495 if (GetOrderDistance(o, o->next != nullptr ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false;
1496 break;
1497
1498 default: break;
1499 }
1500 }
1501
1502 return true;
1503}
1504
1514{
1515 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1516 if (dst == nullptr || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1517
1518 CommandCost ret = CheckOwnership(dst->owner);
1519 if (ret.Failed()) return ret;
1520
1521 switch (action) {
1522 case CO_SHARE: {
1523 Vehicle *src = Vehicle::GetIfValid(veh_src);
1524
1525 /* Sanity checks */
1526 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1527
1528 ret = CheckOwnership(src->owner);
1529 if (ret.Failed()) return ret;
1530
1531 /* Trucks can't share orders with busses (and visa versa) */
1532 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1533 return CMD_ERROR;
1534 }
1535
1536 /* Is the vehicle already in the shared list? */
1537 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1538
1539 for (const Order *order : src->Orders()) {
1540 if (!OrderGoesToStation(dst, order)) continue;
1541
1542 /* Allow copying unreachable destinations if they were already unreachable for the source.
1543 * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1544 * are temporarily invalid due to reconstruction. */
1545 const Station *st = Station::Get(order->GetDestination().ToStationID());
1546 if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1547 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1548 }
1549 }
1550
1551 /* Check for aircraft range limits. */
1552 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1553 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1554 }
1555
1556 if (src->orders == nullptr && !OrderList::CanAllocateItem()) {
1557 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1558 }
1559
1560 if (flags.Test(DoCommandFlag::Execute)) {
1561 /* If the destination vehicle had a OrderList, destroy it.
1562 * We only reset the order indices, if the new orders are obviously different.
1563 * (We mainly do this to keep the order indices valid and in range.) */
1564 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1565
1566 dst->orders = src->orders;
1567
1568 /* Link this vehicle in the shared-list */
1569 dst->AddToShared(src);
1570
1573
1575 }
1576 break;
1577 }
1578
1579 case CO_COPY: {
1580 Vehicle *src = Vehicle::GetIfValid(veh_src);
1581
1582 /* Sanity checks */
1583 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1584
1585 ret = CheckOwnership(src->owner);
1586 if (ret.Failed()) return ret;
1587
1588 /* Trucks can't copy all the orders from busses (and visa versa),
1589 * and neither can helicopters and aircraft. */
1590 for (const Order *order : src->Orders()) {
1591 if (!OrderGoesToStation(dst, order)) continue;
1592 Station *st = Station::Get(order->GetDestination().ToStationID());
1593 if (!CanVehicleUseStation(dst, st)) {
1594 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1595 }
1596 }
1597
1598 /* Check for aircraft range limits. */
1599 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1600 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1601 }
1602
1603 /* make sure there are orders available */
1605 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1606 }
1607
1608 if (flags.Test(DoCommandFlag::Execute)) {
1609 Order *first = nullptr;
1610 Order **order_dst;
1611
1612 /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1613 * We only reset the order indices, if the new orders are obviously different.
1614 * (We mainly do this to keep the order indices valid and in range.) */
1615 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1616
1617 order_dst = &first;
1618 for (const Order *order : src->Orders()) {
1619 *order_dst = new Order();
1620 (*order_dst)->AssignOrder(*order);
1621 order_dst = &(*order_dst)->next;
1622 }
1623 if (dst->orders == nullptr) {
1624 dst->orders = new OrderList(first, dst);
1625 } else {
1626 assert(dst->orders->GetFirstOrder() == nullptr);
1627 assert(!dst->orders->IsShared());
1628 delete dst->orders;
1630 dst->orders = new OrderList(first, dst);
1631 }
1632
1634
1636 }
1637 break;
1638 }
1639
1640 case CO_UNSHARE: return DecloneOrder(dst, flags);
1641 default: return CMD_ERROR;
1642 }
1643
1644 return CommandCost();
1645}
1646
1656{
1657 if (cargo >= NUM_CARGO && cargo != CARGO_NO_REFIT && cargo != CARGO_AUTO_REFIT) return CMD_ERROR;
1658
1659 const Vehicle *v = Vehicle::GetIfValid(veh);
1660 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1661
1663 if (ret.Failed()) return ret;
1664
1665 Order *order = v->GetOrder(order_number);
1666 if (order == nullptr) return CMD_ERROR;
1667
1668 /* Automatic refit cargo is only supported for goto station orders. */
1669 if (cargo == CARGO_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1670
1671 if (order->GetLoadType() & OLFB_NO_LOAD) return CMD_ERROR;
1672
1673 if (flags.Test(DoCommandFlag::Execute)) {
1674 order->SetRefit(cargo);
1675
1676 /* Make the depot order an 'always go' order. */
1677 if (cargo != CARGO_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1680 }
1681
1682 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1683 /* Update any possible open window of the vehicle */
1685
1686 /* If the vehicle already got the current depot set as current order, then update current order as well */
1687 if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
1688 u->current_order.SetRefit(cargo);
1689 }
1690 }
1691 }
1692
1693 return CommandCost();
1694}
1695
1696
1702void CheckOrders(const Vehicle *v)
1703{
1704 /* Does the user wants us to check things? */
1705 if (_settings_client.gui.order_review_system == 0) return;
1706
1707 /* Do nothing for crashed vehicles */
1708 if (v->vehstatus.Test(VehState::Crashed)) return;
1709
1710 /* Do nothing for stopped vehicles if setting is '1' */
1712
1713 /* do nothing we we're not the first vehicle in a share-chain */
1714 if (v->FirstShared() != v) return;
1715
1716 /* Only check every 20 days, so that we don't flood the message log */
1717 if (v->owner == _local_company && v->day_counter % 20 == 0) {
1718 StringID message = INVALID_STRING_ID;
1719
1720 /* Check the order list */
1721 int n_st = 0;
1722
1723 for (const Order *order : v->Orders()) {
1724 /* Dummy order? */
1725 if (order->IsType(OT_DUMMY)) {
1726 message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1727 break;
1728 }
1729 /* Does station have a load-bay for this vehicle? */
1730 if (order->IsType(OT_GOTO_STATION)) {
1731 const Station *st = Station::Get(order->GetDestination().ToStationID());
1732
1733 n_st++;
1734 if (!CanVehicleUseStation(v, st)) {
1735 message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1736 } else if (v->type == VEH_AIRCRAFT &&
1737 (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1740 message == INVALID_STRING_ID) {
1741 message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1742 }
1743 }
1744 }
1745
1746 /* Check if the last and the first order are the same */
1747 if (v->GetNumOrders() > 1) {
1748 const Order *last = v->GetLastOrder();
1749
1750 if (v->orders->GetFirstOrder()->Equals(*last)) {
1751 message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1752 }
1753 }
1754
1755 /* Do we only have 1 station in our order list? */
1756 if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1757
1758#ifdef WITH_ASSERT
1759 if (v->orders != nullptr) v->orders->DebugCheckSanity();
1760#endif
1761
1762 /* We don't have a problem */
1763 if (message == INVALID_STRING_ID) return;
1764
1766 }
1767}
1768
1777void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1778{
1779 /* Aircraft have StationIDs for depot orders and never use DepotIDs
1780 * This fact is handled specially below
1781 */
1782
1783 /* Go through all vehicles */
1784 for (Vehicle *v : Vehicle::Iterate()) {
1785 if ((v->type == VEH_AIRCRAFT && v->current_order.IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : v->current_order.GetType()) == type &&
1786 (!hangar || v->type == VEH_AIRCRAFT) && v->current_order.GetDestination() == destination) {
1787 v->current_order.MakeDummy();
1789 }
1790
1791 /* Clear the order from the order-list */
1792 int id = -1;
1793 for (Order *order : v->Orders()) {
1794 id++;
1795restart:
1796
1797 OrderType ot = order->GetType();
1798 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
1799 if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) continue; // Not an aircraft? Can't have a hangar order.
1800 if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1801 if (ot == type && order->GetDestination() == destination) {
1802 /* We want to clear implicit orders, but we don't want to make them
1803 * dummy orders. They should just vanish. Also check the actual order
1804 * type as ot is currently OT_GOTO_STATION. */
1805 if (order->IsType(OT_IMPLICIT)) {
1806 order = order->next; // DeleteOrder() invalidates current order
1807 DeleteOrder(v, id);
1808 if (order != nullptr) goto restart;
1809 break;
1810 }
1811
1812 /* Clear wait time */
1813 v->orders->UpdateTotalDuration(-order->GetWaitTime());
1814 if (order->IsWaitTimetabled()) {
1815 v->orders->UpdateTimetableDuration(-order->GetTimetabledWait());
1816 order->SetWaitTimetabled(false);
1817 }
1818 order->SetWaitTime(0);
1819
1820 /* Clear order, preserving travel time */
1821 bool travel_timetabled = order->IsTravelTimetabled();
1822 order->MakeDummy();
1823 order->SetTravelTimetabled(travel_timetabled);
1824
1825 for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1826 /* In GUI, simulate by removing the order and adding it back */
1829 }
1830 }
1831 }
1832 }
1833
1834 OrderBackup::RemoveOrder(type, destination, hangar);
1835}
1836
1842{
1843 for (const Order *order : this->Orders()) {
1844 if (order->IsType(OT_GOTO_DEPOT)) return true;
1845 }
1846
1847 return false;
1848}
1849
1859void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1860{
1862
1863 if (v->IsOrderListShared()) {
1864 /* Remove ourself from the shared order list. */
1865 v->RemoveFromShared();
1866 v->orders = nullptr;
1867 } else if (v->orders != nullptr) {
1868 /* Remove the orders */
1869 v->orders->FreeChain(keep_orderlist);
1870 if (!keep_orderlist) v->orders = nullptr;
1871 }
1872
1873 /* Unbunching data is no longer valid. */
1875
1876 if (reset_order_indices) {
1878 if (v->current_order.IsType(OT_LOADING)) {
1880 }
1881 }
1882}
1883
1891uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
1892{
1893 /* Service intervals are in percents. */
1894 if (ispercent) return Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT);
1895
1896 /* Service intervals are in minutes. */
1897 if (TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU)) return Clamp(interval, MIN_SERVINT_MINUTES, MAX_SERVINT_MINUTES);
1898
1899 /* Service intervals are in days. */
1900 return Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1901}
1902
1911static bool CheckForValidOrders(const Vehicle *v)
1912{
1913 for (const Order *order : v->Orders()) {
1914 switch (order->GetType()) {
1915 case OT_GOTO_STATION:
1916 case OT_GOTO_DEPOT:
1917 case OT_GOTO_WAYPOINT:
1918 return true;
1919
1920 default:
1921 break;
1922 }
1923 }
1924
1925 return false;
1926}
1927
1931static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1932{
1933 switch (occ) {
1934 case OCC_EQUALS: return variable == value;
1935 case OCC_NOT_EQUALS: return variable != value;
1936 case OCC_LESS_THAN: return variable < value;
1937 case OCC_LESS_EQUALS: return variable <= value;
1938 case OCC_MORE_THAN: return variable > value;
1939 case OCC_MORE_EQUALS: return variable >= value;
1940 case OCC_IS_TRUE: return variable != 0;
1941 case OCC_IS_FALSE: return variable == 0;
1942 default: NOT_REACHED();
1943 }
1944}
1945
1946static bool OrderConditionCompare(OrderConditionComparator occ, ConvertibleThroughBase auto variable, int value)
1947{
1948 return OrderConditionCompare(occ, variable.base(), value);
1949}
1950
1958{
1959 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1960
1961 bool skip_order = false;
1963 uint16_t value = order->GetConditionValue();
1964
1965 switch (order->GetConditionVariable()) {
1966 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1967 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
1968 case OCV_MAX_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability), value); break;
1969 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1970 case OCV_AGE: skip_order = OrderConditionCompare(occ, TimerGameCalendar::DateToYear(v->age), value); break;
1971 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
1972 case OCV_UNCONDITIONALLY: skip_order = true; break;
1974 default: NOT_REACHED();
1975 }
1976
1977 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1978}
1979
1987bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
1988{
1989 if (conditional_depth > v->GetNumOrders()) {
1990 v->current_order.Free();
1991 v->SetDestTile(TileIndex{});
1992 return false;
1993 }
1994
1995 switch (order->GetType()) {
1996 case OT_GOTO_STATION:
1997 v->SetDestTile(v->GetOrderStationLocation(order->GetDestination().ToStationID()));
1998 return true;
1999
2000 case OT_GOTO_DEPOT:
2001 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
2002 assert(!pbs_look_ahead);
2003 UpdateVehicleTimetable(v, true);
2005 break;
2006 }
2007
2009 /* If the vehicle can't find its destination, delay its next search.
2010 * In case many vehicles are in this state, use the vehicle index to spread out pathfinder calls. */
2011 if (v->dest_tile == 0 && TimerGameEconomy::date_fract != (v->index % Ticks::DAY_TICKS)) break;
2012
2013 /* We need to search for the nearest depot (hangar). */
2014 ClosestDepot closest_depot = v->FindClosestDepot();
2015
2016 if (closest_depot.found) {
2017 /* PBS reservations cannot reverse */
2018 if (pbs_look_ahead && closest_depot.reverse) return false;
2019
2020 v->SetDestTile(closest_depot.location);
2021 v->current_order.SetDestination(closest_depot.destination);
2022
2023 /* If there is no depot in front, reverse automatically (trains only) */
2024 if (v->type == VEH_TRAIN && closest_depot.reverse) Command<CMD_REVERSE_TRAIN_DIRECTION>::Do(DoCommandFlag::Execute, v->index, false);
2025
2026 if (v->type == VEH_AIRCRAFT) {
2027 Aircraft *a = Aircraft::From(v);
2028 if (a->state == FLYING && a->targetairport != closest_depot.destination) {
2029 /* The aircraft is now heading for a different hangar than the next in the orders */
2031 }
2032 }
2033 return true;
2034 }
2035
2036 /* If there is no depot, we cannot help PBS either. */
2037 if (pbs_look_ahead) return false;
2038
2039 UpdateVehicleTimetable(v, true);
2041 } else {
2042 if (v->type != VEH_AIRCRAFT) {
2043 v->SetDestTile(Depot::Get(order->GetDestination().ToStationID())->xy);
2044 } else {
2045 Aircraft *a = Aircraft::From(v);
2046 DestinationID destination = a->current_order.GetDestination();
2047 if (a->targetairport != destination) {
2048 /* The aircraft is now heading for a different hangar than the next in the orders */
2049 a->SetDestTile(a->GetOrderStationLocation(destination.ToStationID()));
2050 }
2051 }
2052 return true;
2053 }
2054 break;
2055
2056 case OT_GOTO_WAYPOINT:
2057 v->SetDestTile(Waypoint::Get(order->GetDestination().ToStationID())->xy);
2058 return true;
2059
2060 case OT_CONDITIONAL: {
2061 assert(!pbs_look_ahead);
2062 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2063 if (next_order != INVALID_VEH_ORDER_ID) {
2064 /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2065 * cur_real_order_index might come after next_order. */
2066 UpdateVehicleTimetable(v, false);
2070
2071 /* Disable creation of implicit orders.
2072 * When inserting them we do not know that we would have to make the conditional orders point to them. */
2073 if (v->IsGroundVehicle()) {
2074 uint16_t &gv_flags = v->GetGroundVehicleFlags();
2076 }
2077 } else {
2078 UpdateVehicleTimetable(v, true);
2080 }
2081 break;
2082 }
2083
2084 default:
2085 v->SetDestTile(TileIndex{});
2086 return false;
2087 }
2088
2089 assert(v->cur_implicit_order_index < v->GetNumOrders());
2090 assert(v->cur_real_order_index < v->GetNumOrders());
2091
2092 /* Get the current order */
2093 order = v->GetOrder(v->cur_real_order_index);
2094 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2095 assert(v->GetNumManualOrders() == 0);
2096 order = nullptr;
2097 }
2098
2099 if (order == nullptr) {
2100 v->current_order.Free();
2101 v->SetDestTile(TileIndex{});
2102 return false;
2103 }
2104
2105 v->current_order = *order;
2106 return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2107}
2108
2117{
2118 switch (v->current_order.GetType()) {
2119 case OT_GOTO_DEPOT:
2120 /* Let a depot order in the orderlist interrupt. */
2121 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
2122 break;
2123
2124 case OT_LOADING:
2125 return false;
2126
2127 case OT_LEAVESTATION:
2128 if (v->type != VEH_AIRCRAFT) return false;
2129 break;
2130
2131 default: break;
2132 }
2133
2141 bool may_reverse = v->current_order.IsType(OT_NOTHING);
2142
2143 /* Check if we've reached a 'via' destination. */
2144 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)) &&
2145 IsTileType(v->tile, MP_STATION) &&
2148 /* We set the last visited station here because we do not want
2149 * the train to stop at this 'via' station if the next order
2150 * is a no-non-stop order; in that case not setting the last
2151 * visited station will cause the vehicle to still stop. */
2152 v->last_station_visited = v->current_order.GetDestination().ToStationID();
2153 UpdateVehicleTimetable(v, true);
2155 }
2156
2157 /* Get the current order */
2160
2161 const Order *order = v->GetOrder(v->cur_real_order_index);
2162 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2163 assert(v->GetNumManualOrders() == 0);
2164 order = nullptr;
2165 }
2166
2167 /* If no order, do nothing. */
2168 if (order == nullptr || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
2169 if (v->type == VEH_AIRCRAFT) {
2170 /* Aircraft do something vastly different here, so handle separately */
2171 HandleMissingAircraftOrders(Aircraft::From(v));
2172 return false;
2173 }
2174
2175 v->current_order.Free();
2176 v->SetDestTile(TileIndex{});
2177 return false;
2178 }
2179
2180 /* If it is unchanged, keep it. */
2181 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
2182 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination().ToStationID())->ship_station.tile != INVALID_TILE)) {
2183 return false;
2184 }
2185
2186 /* Otherwise set it, and determine the destination tile. */
2187 v->current_order = *order;
2188
2190 switch (v->type) {
2191 default:
2192 NOT_REACHED();
2193
2194 case VEH_ROAD:
2195 case VEH_TRAIN:
2196 break;
2197
2198 case VEH_AIRCRAFT:
2199 case VEH_SHIP:
2201 break;
2202 }
2203
2204 return UpdateOrderDest(v, order) && may_reverse;
2205}
2206
2214bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2215{
2216 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2217
2218 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
2219 v->last_station_visited != station && // Do stop only when we've not just been there
2220 /* Finally do stop when there is no non-stop flag set for this type of station. */
2222}
2223
2224bool Order::CanLoadOrUnload() const
2225{
2226 return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2228 ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
2229 (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
2230}
2231
2238bool Order::CanLeaveWithCargo(bool has_cargo) const
2239{
2240 return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
2241 (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
2242}
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:77
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:23
static const CargoType CARGO_AUTO_REFIT
Automatically choose cargo type when doing auto refitting.
Definition cargo_type.h:78
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:75
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:79
Cheats _cheats
All the cheats.
Definition cheat.cpp:16
Types related to cheating.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Common return value for all commands.
bool Failed() const
Did this command fail?
Enum-as-bit-set wrapper.
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.
@ Execute
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.
static constexpr Owner 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,...)
Output a line of debugging information.
Definition debug.h:37
Base for all depots (except hangars)
@ 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:159
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:142
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, EncodedString &&headline, 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.
static bool OrderGoesToStation(const Vehicle *v, const Order *o)
Checks whether the order goes to a station or not, i.e.
CommandCost CmdSkipToOrder(DoCommandFlags flags, VehicleID veh_id, VehicleOrderID sel_ord)
Goto order of order-list.
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.
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.
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
Update the vehicle's destination tile from an order.
CommandCost CmdOrderRefit(DoCommandFlags flags, VehicleID veh, VehicleOrderID order_number, CargoType cargo)
Add/remove refit orders 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.
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
CommandCost CmdInsertOrder(DoCommandFlags flags, VehicleID veh, VehicleOrderID sel_ord, const Order &new_order)
Add an order to the orderlist of a vehicle.
CommandCost CmdModifyOrder(DoCommandFlags flags, VehicleID veh, VehicleOrderID sel_ord, ModifyOrderFlags mof, uint16_t data)
Modify an order in the orderlist of a vehicle.
CommandCost CmdCloneOrder(DoCommandFlags flags, CloneOptions action, VehicleID veh_dst, VehicleID veh_src)
Clone/share/copy an order-list of another vehicle.
static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlags flags)
Declone an order-list.
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
CommandCost CmdDeleteOrder(DoCommandFlags flags, VehicleID veh_id, VehicleOrderID sel_ord)
Delete an order from the orderlist of 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.
uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
Get the distance between two orders of a vehicle.
CommandCost CmdMoveOrder(DoCommandFlags flags, VehicleID veh, VehicleOrderID moving_order, VehicleOrderID target_order)
Move an order inside the orderlist.
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:129
@ OCV_AGE
Skip based on the age.
Definition order_type.h:133
@ OCV_UNCONDITIONALLY
Always skip.
Definition order_type.h:135
@ OCV_MAX_SPEED
Skip based on the maximum speed.
Definition order_type.h:132
@ OCV_LOAD_PERCENTAGE
Skip based on the amount of load.
Definition order_type.h:130
@ OCV_REQUIRES_SERVICE
Skip when the vehicle requires service.
Definition order_type.h:134
@ OCV_RELIABILITY
Skip based on the reliability.
Definition order_type.h:131
@ OCV_REMAINING_LIFETIME
Skip based on the remaining lifetime.
Definition order_type.h:136
@ OCV_MAX_RELIABILITY
Skip based on the maximum reliability.
Definition order_type.h:137
OrderStopLocation
Where to stop the trains.
Definition order_type.h:99
@ OSL_PLATFORM_MIDDLE
Stop at the middle of the platform.
Definition order_type.h:101
@ OSL_PLATFORM_FAR_END
Stop at the far end of the platform.
Definition order_type.h:102
@ OSL_PLATFORM_NEAR_END
Stop at the near end of the platform.
Definition order_type.h:100
ModifyOrderFlags
Enumeration for the data to set in CmdModifyOrder.
Definition order_type.h:160
@ MOF_COND_VARIABLE
A conditional variable changes.
Definition order_type.h:166
@ MOF_LOAD
Passes an OrderLoadType.
Definition order_type.h:164
@ MOF_UNLOAD
Passes an OrderUnloadType.
Definition order_type.h:163
@ MOF_STOP_LOCATION
Passes an OrderStopLocation.
Definition order_type.h:162
@ MOF_COND_DESTINATION
Change the destination of a conditional order.
Definition order_type.h:169
@ MOF_COND_COMPARATOR
A comparator changes.
Definition order_type.h:167
@ MOF_COND_VALUE
The value to set the condition to.
Definition order_type.h:168
@ MOF_DEPOT_ACTION
Selects the OrderDepotAction.
Definition order_type.h:165
@ MOF_NON_STOP
Passes an OrderNonStopFlags.
Definition order_type.h:161
OrderUnloadFlags
Flags related to the unloading order.
Definition order_type.h:68
@ OUFB_TRANSFER
Transfer all cargo onto the platform.
Definition order_type.h:71
@ OUFB_NO_UNLOAD
Totally no unloading will be done.
Definition order_type.h:72
@ OUF_UNLOAD_IF_POSSIBLE
Unload all cargo that the station accepts.
Definition order_type.h:69
@ OUFB_UNLOAD
Force unloading all cargo onto the platform, possibly not getting paid.
Definition order_type.h:70
@ DA_SERVICE
Service only if needed.
Definition order_type.h:178
@ DA_STOP
Go to the depot and stop there.
Definition order_type.h:179
@ DA_ALWAYS_GO
Always go to the depot.
Definition order_type.h:177
@ DA_UNBUNCH
Go to the depot and unbunch.
Definition order_type.h:180
OrderDepotTypeFlags
Reasons that could cause us to go to the depot.
Definition order_type.h:109
@ ODTFB_PART_OF_ORDERS
This depot order is because of a regular order.
Definition order_type.h:112
@ ODTFB_SERVICE
This depot order is because of the servicing limit.
Definition order_type.h:111
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition order_type.h:18
OrderDepotActionFlags
Actions that can be performed when the vehicle enters the depot.
Definition order_type.h:118
@ ODATFB_UNBUNCH
Service the vehicle and then unbunch it.
Definition order_type.h:122
@ ODATFB_NEAREST_DEPOT
Send the vehicle to the nearest depot.
Definition order_type.h:121
@ ODATFB_HALT
Service the vehicle and then halt it.
Definition order_type.h:120
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition order_type.h:42
OrderLoadFlags
Flags related to the loading order.
Definition order_type.h:78
@ OLFB_FULL_LOAD
Full load all cargoes of the consist.
Definition order_type.h:80
@ OLFB_NO_LOAD
Do not load anything.
Definition order_type.h:82
@ OLF_LOAD_IF_POSSIBLE
Load as long as there is cargo that fits in the train.
Definition order_type.h:79
@ OLF_FULL_LOAD_ANY
Full load a single cargo of the consist.
Definition order_type.h:81
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition order_type.h:40
OrderConditionComparator
Comparator for the skip reasoning.
Definition order_type.h:144
@ OCC_LESS_EQUALS
Skip if the value is less or equal to the limit.
Definition order_type.h:148
@ OCC_EQUALS
Skip if both values are equal.
Definition order_type.h:145
@ OCC_NOT_EQUALS
Skip if both values are not equal.
Definition order_type.h:146
@ OCC_MORE_THAN
Skip if the value is more than the limit.
Definition order_type.h:149
@ OCC_IS_TRUE
Skip if the variable is true.
Definition order_type.h:151
@ OCC_LESS_THAN
Skip if the value is less than the limit.
Definition order_type.h:147
@ OCC_MORE_EQUALS
Skip if the value is more or equal to the limit.
Definition order_type.h:150
@ OCC_IS_FALSE
Skip if the variable is false.
Definition order_type.h:152
OrderNonStopFlags
Non-stop order flags.
Definition order_type.h:88
@ ONSF_NO_STOP_AT_DESTINATION_STATION
The vehicle will stop at any station it passes except the destination.
Definition order_type.h:91
@ ONSF_STOP_EVERYWHERE
The vehicle will stop at any station it passes and the destination.
Definition order_type.h:89
@ ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
The vehicle will not stop at any stations it passes except the destination.
Definition order_type.h:90
CloneOptions
Clone actions.
Definition order_type.h:195
OrderType
Order types.
Definition order_type.h:51
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:100
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:58
Base classes/functions for stations.
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
@ Dock
Station with a dock.
@ TruckStop
Station with truck stops.
@ Train
Station with train station.
@ BusStop
Station with bus stops.
Definition of base types and functions in a cross-platform compatible way.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:91
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
@ ShortStrip
This airport has a short landing strip, dangerous for fast aircraft.
Flags flags
Flags for this airport type.
Definition airport.h:193
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.
TileIndex xy
Base tile of the station.
StationFacilities facilities
The facilities that this station has.
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:302
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:310
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:294
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:316
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:335
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
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
void MakeGoToDepot(DestinationID 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 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.
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:43
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Base class for all pools.
static Station * Get(auto index)
Gets station with given index.
static Station * GetIfValid(auto 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:3176
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:744
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:2343
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:2959
bool HasUnbunchingOrder() const
Check if the current vehicle has an unbunching order.
Definition vehicle.cpp:2482
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 string parameters for string processing.
void IncrementImplicitOrderIndex()
Increments cur_implicit_order_index, keeps care of the wrap-around and invalidates the GUI.
VehStates vehstatus
Status.
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...
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:2458
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:2982
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:2470
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:2157
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:3095
uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1488
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3049
@ Crashed
Vehicle is crashed.
@ Stopped
Vehicle is stopped by the player.
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.
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:3132
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:3224
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3106
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:3241
@ 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: