OpenTTD Source 20260731-master-g77ba2b244a
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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 "aircraft.h"
21#include "roadveh.h"
22#include "station_base.h"
23#include "waypoint_base.h"
24#include "company_base.h"
25#include "order_backup.h"
26#include "cheat_type.h"
27#include "order_cmd.h"
28#include "train_cmd.h"
29#include "train.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
41OrderListPool _orderlist_pool("OrderList");
43
44
48void Order::Free()
49{
50 this->type = OT_NOTHING;
51 this->flags = 0;
52 this->dest = 0;
53}
54
59void Order::MakeGoToStation(StationID destination)
60{
61 this->type = OT_GOTO_STATION;
62 this->flags = 0;
63 this->dest = destination;
64}
65
75{
76 this->type = OT_GOTO_DEPOT;
77 this->SetDepotOrderType(order);
78 this->SetDepotActionType(action);
79 this->SetNonStopType(non_stop_type);
80 this->dest = destination;
81 this->SetRefit(cargo);
82}
83
88void Order::MakeGoToWaypoint(StationID destination)
89{
90 this->type = OT_GOTO_WAYPOINT;
91 this->flags = 0;
92 this->dest = destination;
93}
94
99void Order::MakeLoading(bool ordered)
100{
101 this->type = OT_LOADING;
102 if (!ordered) this->flags = 0;
103}
104
109{
110 this->type = OT_LEAVESTATION;
111 this->flags = 0;
112}
113
118{
119 this->type = OT_DUMMY;
120 this->flags = 0;
121}
122
128{
129 this->type = OT_CONDITIONAL;
130 this->flags = order;
131 this->dest = 0;
132}
133
138void Order::MakeImplicit(StationID destination)
139{
140 this->type = OT_IMPLICIT;
141 this->dest = destination;
142}
143
150{
151 this->refit_cargo = cargo;
152}
153
159bool Order::Equals(const Order &other) const
160{
161 /* In case of go to nearest depot orders we need "only" compare the flags
162 * with the other and not the nearest depot order bit or the actual
163 * destination because those get clear/filled in during the order
164 * evaluation. If we do not do this the order will continuously be seen as
165 * a different order and it will try to find a "nearest depot" every tick. */
166 if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
167 (this->GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot) ||
169 return this->GetDepotOrderType() == other.GetDepotOrderType() &&
171 }
172
173 return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
174}
175
181uint16_t Order::MapOldOrder() const
182{
183 uint16_t order = this->GetType();
184 switch (this->GetType()) {
185 case OT_GOTO_STATION:
186 if (this->GetUnloadType() == OrderUnloadType::Unload) SetBit(order, 5);
187 if (this->IsFullLoadOrder()) SetBit(order, 6);
188 if (this->GetNonStopType().Test(OrderNonStopFlag::NonStop)) SetBit(order, 7);
189 order |= GB(this->GetDestination().value, 0, 8) << 8;
190 break;
191 case OT_GOTO_DEPOT:
192 if (!this->GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) SetBit(order, 6);
193 SetBit(order, 7);
194 order |= GB(this->GetDestination().value, 0, 8) << 8;
195 break;
196 case OT_LOADING:
197 if (this->IsFullLoadOrder()) SetBit(order, 6);
198 /* If both "no load" and "no unload" are set, return nothing order instead */
200 order = OT_NOTHING;
201 }
202 break;
203 default:
204 break;
205 }
206 return order;
207}
208
214void InvalidateVehicleOrder(const Vehicle *v, int data)
215{
216 InvalidateWindowData(WindowClass::VehicleView, v->index);
217
218 if (data != 0) {
219 /* Calls SetDirty() too */
220 InvalidateWindowData(WindowClass::VehicleOrders, v->index, data);
221 InvalidateWindowData(WindowClass::VehicleTimetable, v->index, data);
222 return;
223 }
224
225 SetWindowDirty(WindowClass::VehicleOrders, v->index);
226 SetWindowDirty(WindowClass::VehicleTimetable, v->index);
227}
228
236void Order::AssignOrder(const Order &other)
237{
238 this->type = other.type;
239 this->flags = other.flags;
240 this->dest = other.dest;
241
242 this->refit_cargo = other.refit_cargo;
243
244 this->wait_time = other.wait_time;
245 this->travel_time = other.travel_time;
246 this->max_speed = other.max_speed;
247}
248
254{
255 this->first_shared = v;
256
257 this->num_manual_orders = 0;
258 this->num_vehicles = 1;
259 this->timetable_duration = 0;
260
261 for (const Order &o : this->orders) {
262 if (!o.IsType(OT_IMPLICIT)) ++this->num_manual_orders;
263 this->total_duration += o.GetWaitTime() + o.GetTravelTime();
264 }
265
267
268 for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
269 ++this->num_vehicles;
270 this->first_shared = u;
271 }
272
273 for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
274}
275
281{
282 this->timetable_duration = 0;
283 for (const Order &o : this->orders) {
284 this->timetable_duration += o.GetTimetabledWait() + o.GetTimetabledTravel();
285 }
286}
287
293void OrderList::FreeChain(bool keep_orderlist)
294{
295 /* We can visit oil rigs and buoys that are not our own. They will be shown in
296 * the list of stations. So, we need to invalidate that window if needed. */
297 for (Order &order: this->orders) {
298 if (order.IsType(OT_GOTO_STATION) || order.IsType(OT_GOTO_WAYPOINT)) {
299 BaseStation *bs = BaseStation::GetIfValid(order.GetDestination().ToStationID());
300 if (bs != nullptr && bs->owner == OWNER_NONE) {
301 InvalidateWindowClassesData(WindowClass::StationList, 0);
302 break;
303 }
304 }
305 }
306
307 if (keep_orderlist) {
308 this->orders.clear();
309 this->num_manual_orders = 0;
310 this->timetable_duration = 0;
311 } else {
312 delete this;
313 }
314}
315
328{
329 if (hops > this->GetNumOrders() || next >= this->GetNumOrders()) return INVALID_VEH_ORDER_ID;
330
331 const Order &order_next = this->orders[next];
332 if (order_next.IsType(OT_CONDITIONAL)) {
333 if (order_next.GetConditionVariable() != OrderConditionVariable::Unconditionally) return next;
334
335 /* We can evaluate trivial conditions right away. They're conceptually
336 * the same as regular order progression. */
337 return this->GetNextDecisionNode(
338 order_next.GetConditionSkipToOrder(),
339 hops + 1);
340 }
341
342 if (order_next.IsType(OT_GOTO_DEPOT)) {
344 if (order_next.IsRefit()) return next;
345 }
346
347 if (!order_next.CanLoadOrUnload()) {
348 return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
349 }
350
351 return next;
352}
353
363void OrderList::GetNextStoppingStation(std::vector<StationID> &next_station, const Vehicle *v, VehicleOrderID first, uint hops) const
364{
365 VehicleOrderID next = first;
366 if (first == INVALID_VEH_ORDER_ID) {
367 next = v->cur_implicit_order_index;
368 if (next >= this->GetNumOrders()) {
369 next = this->GetFirstOrder();
370 if (next == INVALID_VEH_ORDER_ID) return;
371 } else {
372 /* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list.
373 * As the given "next" is already valid and a station in the list, we
374 * don't have to check for INVALID_VEH_ORDER_ID here. */
375 next = this->GetNext(next);
376 assert(next != INVALID_VEH_ORDER_ID);
377 }
378 }
379
380 auto orders = v->Orders();
381 do {
382 next = this->GetNextDecisionNode(next, ++hops);
383
384 /* Resolve possibly nested conditionals by estimation. */
385 while (next != INVALID_VEH_ORDER_ID && orders[next].IsType(OT_CONDITIONAL)) {
386 /* We return both options of conditional orders. */
387 VehicleOrderID skip_to = this->GetNextDecisionNode(orders[next].GetConditionSkipToOrder(), hops);
388 VehicleOrderID advance = this->GetNextDecisionNode(this->GetNext(next), hops);
389 if (advance == INVALID_VEH_ORDER_ID || advance == first || skip_to == advance) {
390 next = (skip_to == first) ? INVALID_VEH_ORDER_ID : skip_to;
391 } else if (skip_to == INVALID_VEH_ORDER_ID || skip_to == first) {
392 next = (advance == first) ? INVALID_VEH_ORDER_ID : advance;
393 } else {
394 this->GetNextStoppingStation(next_station, v, skip_to, hops);
395 this->GetNextStoppingStation(next_station, v, advance, hops);
396 return;
397 }
398 ++hops;
399 }
400
401 /* Don't return a next stop if the vehicle has to unload everything. */
402 if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) &&
403 orders[next].GetDestination() == v->last_station_visited &&
404 (orders[next].GetUnloadType() == OrderUnloadType::Transfer || orders[next].GetUnloadType() == OrderUnloadType::Unload))) {
405 return;
406 }
407 } while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited);
408
409 next_station.push_back(orders[next].GetDestination().ToStationID());
410}
411
418{
419 auto it = std::ranges::next(std::begin(this->orders), index, std::end(this->orders));
420 auto new_order = this->orders.emplace(it, std::move(order));
421
422 if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
423 this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
424 this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
425
426 /* We can visit oil rigs and buoys that are not our own. They will be shown in
427 * the list of stations. So, we need to invalidate that window if needed. */
428 if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
429 BaseStation *bs = BaseStation::Get(new_order->GetDestination().ToStationID());
430 if (bs->owner == OWNER_NONE) InvalidateWindowClassesData(WindowClass::StationList, 0);
431 }
432}
433
434
440{
441 auto to_remove = std::ranges::next(std::begin(this->orders), index, std::end(this->orders));
442 if (to_remove == std::end(this->orders)) return;
443
444 if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
445
446 this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
447 this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
448
449 this->orders.erase(to_remove);
450}
451
458{
459 if (from == to) return;
460 if (from >= this->GetNumOrders()) return;
461 if (to >= this->GetNumOrders()) return;
462
463 auto it = std::begin(this->orders);
464 if (from < to) {
465 std::rotate(it + from, it + from + 1, it + to + 1);
466 } else {
467 std::rotate(it + to, it + from, it + from + 1);
468 }
469}
470
477{
478 --this->num_vehicles;
479 if (v == this->first_shared) this->first_shared = v->NextShared();
480}
481
487{
488 for (const Order &o : this->orders) {
489 /* Implicit orders are, by definition, not timetabled. */
490 if (o.IsType(OT_IMPLICIT)) continue;
491 if (!o.IsCompletelyTimetabled()) return false;
492 }
493 return true;
494}
495
496#ifdef WITH_ASSERT
500void OrderList::DebugCheckSanity() const
501{
502 VehicleOrderID check_num_orders = 0;
503 VehicleOrderID check_num_manual_orders = 0;
504 uint check_num_vehicles = 0;
505 TimerGameTick::Ticks check_timetable_duration = 0;
506 TimerGameTick::Ticks check_total_duration = 0;
507
508 Debug(misc, 6, "Checking OrderList {} for sanity...", this->index);
509
510 for (const Order &o : this->orders) {
511 ++check_num_orders;
512 if (!o.IsType(OT_IMPLICIT)) ++check_num_manual_orders;
513 check_timetable_duration += o.GetTimetabledWait() + o.GetTimetabledTravel();
514 check_total_duration += o.GetWaitTime() + o.GetTravelTime();
515 }
516 assert(this->GetNumOrders() == check_num_orders);
517 assert(this->num_manual_orders == check_num_manual_orders);
518 assert(this->timetable_duration == check_timetable_duration);
519 assert(this->total_duration == check_total_duration);
520
521 for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
522 ++check_num_vehicles;
523 assert(v->orders == this);
524 }
525 assert(this->num_vehicles == check_num_vehicles);
526 Debug(misc, 6, "... detected {} orders ({} manual), {} vehicles, {} timetabled, {} total",
527 (uint)this->GetNumOrders(), (uint)this->num_manual_orders,
529}
530#endif
531
539static inline bool OrderGoesToStation(const Vehicle *v, const Order &o)
540{
541 return o.IsType(OT_GOTO_STATION) ||
542 (v->type == VehicleType::Aircraft && o.IsType(OT_GOTO_DEPOT) && o.GetDestination() != StationID::Invalid());
543}
544
552static void DeleteOrderWarnings(const Vehicle *v)
553{
555}
556
563TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
564{
565 switch (this->GetType()) {
566 case OT_GOTO_WAYPOINT:
567 case OT_GOTO_STATION:
568 case OT_IMPLICIT:
569 if (airport && v->type == VehicleType::Aircraft) return Station::Get(this->GetDestination().ToStationID())->airport.tile;
570 return BaseStation::Get(this->GetDestination().ToStationID())->xy;
571
572 case OT_GOTO_DEPOT:
573 if (this->GetDestination() == DepotID::Invalid()) return INVALID_TILE;
574 return (v->type == VehicleType::Aircraft) ? Station::Get(this->GetDestination().ToStationID())->xy : Depot::Get(this->GetDestination().ToDepotID())->xy;
575
576 default:
577 return INVALID_TILE;
578 }
579}
580
590uint GetOrderDistance(VehicleOrderID prev, VehicleOrderID cur, const Vehicle *v, int conditional_depth)
591{
592 assert(v->orders != nullptr);
593 const OrderList &orderlist = *v->orders;
594 auto orders = orderlist.GetOrders();
595
596 if (orders[cur].IsType(OT_CONDITIONAL)) {
597 if (conditional_depth > v->GetNumOrders()) return 0;
598
599 conditional_depth++;
600
601 int dist1 = GetOrderDistance(prev, orders[cur].GetConditionSkipToOrder(), v, conditional_depth);
602 int dist2 = GetOrderDistance(prev, orderlist.GetNext(cur), v, conditional_depth);
603 return std::max(dist1, dist2);
604 }
605
606 TileIndex prev_tile = orders[prev].GetLocation(v, true);
607 TileIndex cur_tile = orders[cur].GetLocation(v, true);
608 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
609 return v->type == VehicleType::Aircraft ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
610}
611
623{
625 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
626
628 if (ret.Failed()) return ret;
629
630 /* Validate properties we don't want to have different from default as they are set by other commands. */
631 if (new_order.GetRefitCargo() != CARGO_NO_REFIT || new_order.GetWaitTime() != 0 || new_order.GetTravelTime() != 0 || new_order.GetMaxSpeed() != UINT16_MAX) return CMD_ERROR;
632
633 /* Check if the inserted order is to the correct destination (owner, type),
634 * and has the correct flags if any */
635 switch (new_order.GetType()) {
636 case OT_GOTO_STATION: {
637 const Station *st = Station::GetIfValid(new_order.GetDestination().ToStationID());
638 if (st == nullptr) return CMD_ERROR;
639
640 if (st->owner != OWNER_NONE) {
641 ret = CheckOwnership(st->owner);
642 if (ret.Failed()) return ret;
643 }
644
645 if (!CanVehicleUseStation(v, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, GetVehicleCannotUseStationReason(v, st));
646 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
647 if (!CanVehicleUseStation(u, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER_SHARED, GetVehicleCannotUseStationReason(u, st));
648 }
649
650 /* Non stop only allowed for ground vehicles. */
651 if (new_order.GetNonStopType().Any() && !v->IsGroundVehicle()) return CMD_ERROR;
652
653 /* Filter invalid load/unload types. */
654 switch (new_order.GetLoadType()) {
657 break;
658
661 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
662 break;
663
664 default:
665 return CMD_ERROR;
666 }
667 switch (new_order.GetUnloadType()) {
672 break;
673
674 default:
675 return CMD_ERROR;
676 }
677
678 /* Filter invalid stop locations */
679 switch (new_order.GetStopLocation()) {
682 if (v->type != VehicleType::Train) return CMD_ERROR;
683 [[fallthrough]];
684
686 break;
687
688 default:
689 return CMD_ERROR;
690 }
691
692 break;
693 }
694
695 case OT_GOTO_DEPOT: {
697 if (v->type == VehicleType::Aircraft) {
698 const Station *st = Station::GetIfValid(new_order.GetDestination().ToStationID());
699
700 if (st == nullptr) return CMD_ERROR;
701
702 ret = CheckOwnership(st->owner);
703 if (ret.Failed()) return ret;
704
705 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
706 return CMD_ERROR;
707 }
708 } else {
709 const Depot *dp = Depot::GetIfValid(new_order.GetDestination().ToDepotID());
710
711 if (dp == nullptr) return CMD_ERROR;
712
713 ret = CheckOwnership(GetTileOwner(dp->xy));
714 if (ret.Failed()) return ret;
715
716 switch (v->type) {
718 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
719 break;
720
722 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
723 break;
724
726 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
727 break;
728
729 default: return CMD_ERROR;
730 }
731 }
732 }
733
734 if (new_order.GetNonStopType().Any() && !v->IsGroundVehicle()) return CMD_ERROR;
735
736 /* Check depot order type is valid. */
737 OrderDepotTypeFlags depot_order_type = new_order.GetDepotOrderType();
738 if (depot_order_type.Test(OrderDepotTypeFlag::PartOfOrders)) depot_order_type.Reset(OrderDepotTypeFlag::Service);
739 depot_order_type.Reset(OrderDepotTypeFlag::PartOfOrders);
740 if (depot_order_type.Any()) return CMD_ERROR;
741
742 /* Check depot action type is valid. */
743 if (new_order.GetDepotActionType().Reset({OrderDepotActionFlag::Halt, OrderDepotActionFlag::NearestDepot, OrderDepotActionFlag::Unbunch}).Any()) return CMD_ERROR;
744
745 /* Vehicles cannot have a "service if needed" order that also has a depot action. */
746 if (new_order.GetDepotOrderType().Test(OrderDepotTypeFlag::Service) && new_order.GetDepotActionType().Any({OrderDepotActionFlag::Halt, OrderDepotActionFlag::Unbunch})) return CMD_ERROR;
747
748 /* Check if we're allowed to have a new unbunching order. */
750 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
751 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
752 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
753 }
754 break;
755 }
756
757 case OT_GOTO_WAYPOINT: {
758 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination().ToStationID());
759 if (wp == nullptr) return CMD_ERROR;
760
761 switch (v->type) {
762 default: return CMD_ERROR;
763
764 case VehicleType::Train: {
765 if (!wp->facilities.Test(StationFacility::Train)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_RAIL_WAYPOINT);
766
767 ret = CheckOwnership(wp->owner);
768 if (ret.Failed()) return ret;
769 break;
770 }
771
772 case VehicleType::Road: {
773 if (!wp->facilities.Test(StationFacility::BusStop) && !wp->facilities.Test(StationFacility::TruckStop)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_ROAD_WAYPOINT);
774
775 ret = CheckOwnership(wp->owner);
776 if (ret.Failed()) return ret;
777 break;
778 }
779
781 if (!wp->facilities.Test(StationFacility::Dock)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_BUOY);
782 if (wp->owner != OWNER_NONE) {
783 ret = CheckOwnership(wp->owner);
784 if (ret.Failed()) return ret;
785 }
786 break;
787 }
788
789 /* Order flags can be any of the following for waypoints:
790 * [non-stop]
791 * non-stop orders (if any) are only valid for trains and road vehicles */
792 if (new_order.GetNonStopType().Any() && !v->IsGroundVehicle()) return CMD_ERROR;
793 break;
794 }
795
796 case OT_CONDITIONAL: {
797 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
798 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
800 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_CONDITIONAL);
801
803 if (occ >= OrderConditionComparator::End) return CMD_ERROR;
804 switch (new_order.GetConditionVariable()) {
806 if (v->type != VehicleType::Train) return CMD_ERROR;
807 [[fallthrough]];
808
811 break;
812
815 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
816 break;
817
821 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
822 [[fallthrough]];
823
824 default:
826 break;
827 }
828 break;
829 }
830
831 default: return CMD_ERROR;
832 }
833
834 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
835
836 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return CommandCost(STR_ERROR_TOO_MANY_ORDERS);
837 if (v->orders == nullptr && !OrderList::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
838
839 if (flags.Test(DoCommandFlag::Execute)) {
840 InsertOrder(v, Order(new_order), sel_ord);
841 }
842
843 return CommandCost();
844}
845
852void InsertOrder(Vehicle *v, Order &&new_o, VehicleOrderID sel_ord)
853{
854 /* Create new order and link in list */
855 if (v->orders == nullptr) {
856 v->orders = OrderList::Create(std::move(new_o), v);
857 } else {
858 v->orders->InsertOrderAt(std::move(new_o), sel_ord);
859 }
860
861 Vehicle *u = v->FirstShared();
863 for (; u != nullptr; u = u->NextShared()) {
864 assert(v->orders == u->orders);
865
866 /* If there is added an order before the current one, we need
867 * to update the selected order. We do not change implicit/real order indices though.
868 * If the new order is between the current implicit order and real order, the implicit order will
869 * later skip the inserted order. */
870 if (sel_ord <= u->cur_real_order_index) {
871 uint cur = u->cur_real_order_index + 1;
872 /* Check if we don't go out of bound */
873 if (cur < u->GetNumOrders()) {
874 u->cur_real_order_index = cur;
875 }
876 }
877 if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
878 /* We are inserting an order just before the current implicit order.
879 * We do not know whether we will reach current implicit or the newly inserted order first.
880 * So, disable creation of implicit orders until we are on track again. */
882 }
883 if (sel_ord <= u->cur_implicit_order_index) {
884 uint cur = u->cur_implicit_order_index + 1;
885 /* Check if we don't go out of bound */
886 if (cur < u->GetNumOrders()) {
888 }
889 }
890 /* Unbunching data is no longer valid. */
892
893 /* Update any possible open window of the vehicle */
894 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
895 }
896
897 /* As we insert an order, the order to skip to will be 'wrong'. */
898 VehicleOrderID cur_order_id = 0;
899 for (Order &order : v->Orders()) {
900 if (order.IsType(OT_CONDITIONAL)) {
901 VehicleOrderID order_id = order.GetConditionSkipToOrder();
902 if (order_id >= sel_ord) {
903 order.SetConditionSkipToOrder(order_id + 1);
904 }
905 if (order_id == cur_order_id) {
906 order.SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
907 }
908 }
909 cur_order_id++;
910 }
911
912 /* Make sure to rebuild the whole list */
914}
915
931
940{
941 Vehicle *v = Vehicle::GetIfValid(veh_id);
942
943 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
944
946 if (ret.Failed()) return ret;
947
948 /* If we did not select an order, we maybe want to de-clone the orders */
949 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
950
951 if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
952
953 if (flags.Test(DoCommandFlag::Execute)) DeleteOrder(v, sel_ord);
954 return CommandCost();
955}
956
962{
963 assert(v->current_order.IsType(OT_LOADING));
964 /* NON-stop flag is misused to see if a train is in a station that is
965 * on its order list or not */
967 /* When full loading, "cancel" that order so the vehicle doesn't
968 * stay indefinitely at this station anymore. */
970}
971
978{
979 v->orders->DeleteOrderAt(sel_ord);
980
981 Vehicle *u = v->FirstShared();
983 for (; u != nullptr; u = u->NextShared()) {
984 assert(v->orders == u->orders);
985
986 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
988 }
989
990 if (sel_ord < u->cur_real_order_index) {
992 } else if (sel_ord == u->cur_real_order_index) {
994 }
995
996 if (sel_ord < u->cur_implicit_order_index) {
998 } else if (sel_ord == u->cur_implicit_order_index) {
999 /* Make sure the index is valid */
1001
1002 /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
1006 }
1007 }
1008 /* Unbunching data is no longer valid. */
1010
1011 /* Update any possible open window of the vehicle */
1012 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1013 }
1014
1015 /* As we delete an order, the order to skip to will be 'wrong'. */
1016 VehicleOrderID cur_order_id = 0;
1017 for (Order &order : v->Orders()) {
1018 if (order.IsType(OT_CONDITIONAL)) {
1019 VehicleOrderID order_id = order.GetConditionSkipToOrder();
1020 if (order_id >= sel_ord) {
1021 order_id = std::max(order_id - 1, 0);
1022 }
1023 if (order_id == cur_order_id) {
1024 order_id = (order_id + 1) % v->GetNumOrders();
1025 }
1026 order.SetConditionSkipToOrder(order_id);
1027 }
1028 cur_order_id++;
1029 }
1030
1032}
1033
1042{
1043 Vehicle *v = Vehicle::GetIfValid(veh_id);
1044
1045 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1046
1048 if (ret.Failed()) return ret;
1049
1050 if (flags.Test(DoCommandFlag::Execute)) {
1051 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1052
1055
1056 /* Unbunching data is no longer valid. */
1058
1060
1061 /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1062 if (v->type == VehicleType::Aircraft) SetWindowClassesDirty(WindowClass::AircraftList);
1063 if (v->type == VehicleType::Ship) SetWindowClassesDirty(WindowClass::ShipList);
1064 }
1065
1066 return CommandCost();
1067}
1068
1080{
1081 Vehicle *v = Vehicle::GetIfValid(veh);
1082 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
1083
1085 if (ret.Failed()) return ret;
1086
1087 /* Don't make senseless movements */
1088 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1089 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1090
1091 Order *moving_one = v->GetOrder(moving_order);
1092 /* Don't move an empty order */
1093 if (moving_one == nullptr) return CMD_ERROR;
1094
1095 if (flags.Test(DoCommandFlag::Execute)) {
1096 v->orders->MoveOrder(moving_order, target_order);
1097
1098 /* Update shared list */
1099 Vehicle *u = v->FirstShared();
1100
1102
1103 for (; u != nullptr; u = u->NextShared()) {
1104 /* Update the current order.
1105 * There are multiple ways to move orders, which result in cur_implicit_order_index
1106 * and cur_real_order_index to not longer make any sense. E.g. moving another
1107 * real order between them.
1108 *
1109 * Basically one could choose to preserve either of them, but not both.
1110 * While both ways are suitable in this or that case from a human point of view, neither
1111 * of them makes really sense.
1112 * However, from an AI point of view, preserving cur_real_order_index is the most
1113 * predictable and transparent behaviour.
1114 *
1115 * With that decision it basically does not matter what we do to cur_implicit_order_index.
1116 * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1117 * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1118 * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1119 */
1120 if (u->cur_real_order_index == moving_order) {
1121 u->cur_real_order_index = target_order;
1122 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1124 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1126 }
1127
1128 if (u->cur_implicit_order_index == moving_order) {
1129 u->cur_implicit_order_index = target_order;
1130 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1132 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1134 }
1135 /* Unbunching data is no longer valid. */
1137
1138
1139 assert(v->orders == u->orders);
1140 /* Update any possible open window of the vehicle */
1141 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1142 }
1143
1144 /* As we move an order, the order to skip to will be 'wrong'. */
1145 for (Order &order : v->Orders()) {
1146 if (order.IsType(OT_CONDITIONAL)) {
1147 VehicleOrderID order_id = order.GetConditionSkipToOrder();
1148 if (order_id == moving_order) {
1149 order_id = target_order;
1150 } else if (order_id > moving_order && order_id <= target_order) {
1151 order_id--;
1152 } else if (order_id < moving_order && order_id >= target_order) {
1153 order_id++;
1154 }
1155 order.SetConditionSkipToOrder(order_id);
1156 }
1157 }
1158
1159 /* Make sure to rebuild the whole list */
1161 }
1162
1163 return CommandCost();
1164}
1165
1178{
1179 if (mof >= MOF_END) return CMD_ERROR;
1180
1181 Vehicle *v = Vehicle::GetIfValid(veh);
1182 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
1183
1185 if (ret.Failed()) return ret;
1186
1187 /* Is it a valid order? */
1188 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1189
1190 Order *order = v->GetOrder(sel_ord);
1191 assert(order != nullptr);
1192 switch (order->GetType()) {
1193 case OT_GOTO_STATION:
1194 if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1195 break;
1196
1197 case OT_GOTO_DEPOT:
1198 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1199 break;
1200
1201 case OT_GOTO_WAYPOINT:
1202 if (mof != MOF_NON_STOP) return CMD_ERROR;
1203 break;
1204
1205 case OT_CONDITIONAL:
1206 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1207 break;
1208
1209 default:
1210 return CMD_ERROR;
1211 }
1212
1213 switch (mof) {
1214 default: NOT_REACHED();
1215
1216 case MOF_NON_STOP: {
1217 if (!v->IsGroundVehicle()) return CMD_ERROR;
1218
1219 OrderNonStopFlags nonstop_flags = static_cast<OrderNonStopFlags>(data);
1220 if (nonstop_flags == order->GetNonStopType()) return CMD_ERROR;
1221
1222 /* Test for invalid flags. */
1224 if (nonstop_flags.Any()) return CMD_ERROR;
1225 break;
1226 }
1227
1228 case MOF_STOP_LOCATION:
1229 if (v->type != VehicleType::Train) return CMD_ERROR;
1230 if (data >= to_underlying(OrderStopLocation::End)) return CMD_ERROR;
1231 break;
1232
1233 case MOF_UNLOAD: {
1235
1236 OrderUnloadType unload_type = static_cast<OrderUnloadType>(data);
1237 if (unload_type == order->GetUnloadType()) return CMD_ERROR;
1238
1239 /* Test for invalid types. */
1240 switch (unload_type) {
1245 break;
1246
1247 default: return CMD_ERROR;
1248 }
1249 break;
1250 }
1251
1252 case MOF_LOAD: {
1254
1255 OrderLoadType load_type = static_cast<OrderLoadType>(data);
1256 if (load_type == order->GetLoadType()) return CMD_ERROR;
1257
1258 /* Test for invalid types. */
1259 switch (load_type) {
1262 break;
1263
1266 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
1267 break;
1268
1269 default: return CMD_ERROR;
1270 }
1271 break;
1272 }
1273
1274 case MOF_DEPOT_ACTION: {
1275 OrderDepotAction depot_action = static_cast<OrderDepotAction>(data);
1276 if (depot_action >= OrderDepotAction::End) return CMD_ERROR;
1277 /* Check if we are allowed to add unbunching. We are always allowed to remove it. */
1278 if (depot_action == OrderDepotAction::Unbunch) {
1279 /* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */
1280 if (v->HasUnbunchingOrder() && !order->GetDepotActionType().Test(OrderDepotActionFlag::Unbunch)) return CommandCost(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
1281 /* We don't allow unbunching if the vehicle has a conditional order. */
1282 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
1283 /* We don't allow unbunching if the vehicle has a full load order. */
1284 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
1285 }
1286 break;
1287 }
1288
1289 case MOF_COND_VARIABLE: {
1290 OrderConditionVariable cond_variable = static_cast<OrderConditionVariable>(data);
1291 if (cond_variable >= OrderConditionVariable::End) return CMD_ERROR;
1292 if (cond_variable == OrderConditionVariable::DrivingBackwards && v->type != VehicleType::Train) return CMD_ERROR;
1293 break;
1294 }
1295
1296 case MOF_COND_COMPARATOR: {
1297 OrderConditionComparator cond_comparator = static_cast<OrderConditionComparator>(data);
1298 if (cond_comparator >= OrderConditionComparator::End) return CMD_ERROR;
1299 switch (order->GetConditionVariable()) {
1301
1304 if (cond_comparator != OrderConditionComparator::IsTrue && cond_comparator != OrderConditionComparator::IsFalse) return CMD_ERROR;
1305 break;
1306
1307 default:
1308 if (cond_comparator == OrderConditionComparator::IsTrue || cond_comparator == OrderConditionComparator::IsFalse) return CMD_ERROR;
1309 break;
1310 }
1311 break;
1312 }
1313
1314 case MOF_COND_VALUE:
1315 switch (order->GetConditionVariable()) {
1319 return CMD_ERROR;
1320
1324 if (data > 100) return CMD_ERROR;
1325 break;
1326
1327 default:
1328 if (data > 2047) return CMD_ERROR;
1329 break;
1330 }
1331 break;
1332
1334 if (data >= v->GetNumOrders()) return CMD_ERROR;
1335 break;
1336 }
1337
1338 if (flags.Test(DoCommandFlag::Execute)) {
1339 switch (mof) {
1340 case MOF_NON_STOP:
1341 order->SetNonStopType(static_cast<OrderNonStopFlags>(data));
1343 order->SetRefit(CARGO_NO_REFIT);
1346 }
1347 break;
1348
1349 case MOF_STOP_LOCATION:
1350 order->SetStopLocation(static_cast<OrderStopLocation>(data));
1351 break;
1352
1353 case MOF_UNLOAD:
1354 order->SetUnloadType(static_cast<OrderUnloadType>(data));
1355 break;
1356
1357 case MOF_LOAD:
1358 order->SetLoadType(static_cast<OrderLoadType>(data));
1360 break;
1361
1362 case MOF_DEPOT_ACTION: {
1363 switch (static_cast<OrderDepotAction>(data)) {
1366 order->SetDepotActionType(order->GetDepotActionType().Reset({OrderDepotActionFlag::Halt, OrderDepotActionFlag::Unbunch}));
1367 break;
1368
1371 order->SetDepotActionType(order->GetDepotActionType().Reset({OrderDepotActionFlag::Halt, OrderDepotActionFlag::Unbunch}));
1372 order->SetRefit(CARGO_NO_REFIT);
1373 break;
1374
1378 order->SetRefit(CARGO_NO_REFIT);
1379 break;
1380
1384 break;
1385
1386 default:
1387 NOT_REACHED();
1388 }
1389 break;
1390 }
1391
1392 case MOF_COND_VARIABLE: {
1394
1396 switch (order->GetConditionVariable()) {
1399 order->SetConditionValue(0);
1400 break;
1401
1405 order->SetConditionValue(0);
1406 break;
1407
1411 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1412 [[fallthrough]];
1413
1414 default:
1416 break;
1417 }
1418 break;
1419 }
1420
1423 break;
1424
1425 case MOF_COND_VALUE:
1426 order->SetConditionValue(data);
1427 break;
1428
1430 order->SetConditionSkipToOrder(data);
1431 break;
1432
1433 default: NOT_REACHED();
1434 }
1435
1436 /* Update the windows and full load flags, also for vehicles that share the same order list */
1437 Vehicle *u = v->FirstShared();
1439 for (; u != nullptr; u = u->NextShared()) {
1440 /* Toggle u->current_order "Full load" flag if it changed.
1441 * However, as the same flag is used for depot orders, check
1442 * whether we are not going to a depot as there are three
1443 * cases where the full load flag can be active and only
1444 * one case where the flag is used for depot orders. In the
1445 * other cases for the OrderType the flags are not used,
1446 * so do not care and those orders should not be active
1447 * when this function is called.
1448 */
1449 if (sel_ord == u->cur_real_order_index &&
1450 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1451 u->current_order.GetLoadType() != order->GetLoadType()) {
1453 }
1454
1455 /* Unbunching data is no longer valid. */
1457
1459 }
1460 }
1461
1462 return CommandCost();
1463}
1464
1471static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order)
1472{
1473 if (v_new->acache.cached_max_range == 0) return true;
1474 if (v_order->GetNumOrders() == 0) return true;
1475
1476 const OrderList &orderlist = *v_order->orders;
1477 auto orders = orderlist.GetOrders();
1478
1479 /* Iterate over all orders to check the distance between all
1480 * 'goto' orders and their respective next order (of any type). */
1481 for (VehicleOrderID cur = 0; cur < orderlist.GetNumOrders(); ++cur) {
1482 switch (orders[cur].GetType()) {
1483 case OT_GOTO_STATION:
1484 case OT_GOTO_DEPOT:
1485 case OT_GOTO_WAYPOINT:
1486 /* If we don't have a next order, we've reached the end and must check the first order instead. */
1487 if (GetOrderDistance(cur, orderlist.GetNext(cur), v_order) > v_new->acache.cached_max_range_sqr) return false;
1488 break;
1489
1490 default: break;
1491 }
1492 }
1493
1494 return true;
1495}
1496
1506{
1507 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1508 if (dst == nullptr || !IsCompanyBuildableVehicleType(dst) || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1509
1510 CommandCost ret = CheckOwnership(dst->owner);
1511 if (ret.Failed()) return ret;
1512
1513 switch (action) {
1514 case CO_SHARE: {
1515 Vehicle *src = Vehicle::GetIfValid(veh_src);
1516
1517 /* Sanity checks */
1518 if (src == nullptr || !IsCompanyBuildableVehicleType(src) || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1519
1520 ret = CheckOwnership(src->owner);
1521 if (ret.Failed()) return ret;
1522
1523 /* Trucks can't share orders with busses (and visa versa) */
1524 if (src->type == VehicleType::Road && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1525 return CMD_ERROR;
1526 }
1527
1528 /* Is the vehicle already in the shared list? */
1529 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1530
1531 for (const Order &order : src->Orders()) {
1532 if (!OrderGoesToStation(dst, order)) continue;
1533
1534 /* Allow copying unreachable destinations if they were already unreachable for the source.
1535 * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1536 * are temporarily invalid due to reconstruction. */
1537 const Station *st = Station::Get(order.GetDestination().ToStationID());
1538 if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1539 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1540 }
1541 }
1542
1543 /* Check for aircraft range limits. */
1545 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1546 }
1547
1548 if (src->orders == nullptr && !OrderList::CanAllocateItem()) {
1549 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1550 }
1551
1552 if (flags.Test(DoCommandFlag::Execute)) {
1553 /* If the destination vehicle had a OrderList, destroy it.
1554 * We only reset the order indices, if the new orders are obviously different.
1555 * (We mainly do this to keep the order indices valid and in range.) */
1556 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1557
1558 dst->orders = src->orders;
1559
1560 /* Link this vehicle in the shared-list */
1561 dst->AddToShared(src);
1562
1565
1567 }
1568 break;
1569 }
1570
1571 case CO_COPY: {
1572 Vehicle *src = Vehicle::GetIfValid(veh_src);
1573
1574 /* Sanity checks */
1575 if (src == nullptr || !IsCompanyBuildableVehicleType(src) || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1576
1577 ret = CheckOwnership(src->owner);
1578 if (ret.Failed()) return ret;
1579
1580 /* Trucks can't copy all the orders from busses (and visa versa),
1581 * and neither can helicopters and aircraft. */
1582 for (const Order &order : src->Orders()) {
1583 if (!OrderGoesToStation(dst, order)) continue;
1584 Station *st = Station::Get(order.GetDestination().ToStationID());
1585 if (!CanVehicleUseStation(dst, st)) {
1586 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1587 }
1588 }
1589
1590 /* Check for aircraft range limits. */
1592 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1593 }
1594
1595 /* make sure there are orders available */
1597 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1598 }
1599
1600 if (flags.Test(DoCommandFlag::Execute)) {
1601 /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1602 * We only reset the order indices, if the new orders are obviously different.
1603 * (We mainly do this to keep the order indices valid and in range.) */
1604 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1605
1606 std::vector<Order> dst_orders;
1607 for (const Order &order : src->Orders()) {
1608 dst_orders.emplace_back(order);
1609 }
1610
1611 if (dst->orders != nullptr) {
1612 assert(dst->orders->GetNumOrders() == 0);
1613 assert(!dst->orders->IsShared());
1614 delete dst->orders;
1615 }
1616
1618 dst->orders = OrderList::Create(std::move(dst_orders), dst);
1619
1621
1623 }
1624 break;
1625 }
1626
1627 case CO_UNSHARE: return DecloneOrder(dst, flags);
1628 default: return CMD_ERROR;
1629 }
1630
1631 return CommandCost();
1632}
1633
1643{
1644 if (cargo >= NUM_CARGO && cargo != CARGO_NO_REFIT && cargo != CARGO_AUTO_REFIT) return CMD_ERROR;
1645
1646 const Vehicle *v = Vehicle::GetIfValid(veh);
1647 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
1648
1650 if (ret.Failed()) return ret;
1651
1652 Order *order = v->GetOrder(order_number);
1653 if (order == nullptr) return CMD_ERROR;
1654
1655 if (!order->IsType(OT_GOTO_DEPOT) && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1656
1657 /* Automatic refit cargo is only supported for goto station orders. */
1658 if (cargo == CARGO_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1659
1660 if (order->GetLoadType() == OrderLoadType::NoLoad) return CMD_ERROR;
1661
1662 if (flags.Test(DoCommandFlag::Execute)) {
1663 order->SetRefit(cargo);
1664
1665 /* Make the depot order an 'always go' order. */
1666 if (cargo != CARGO_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1669 }
1670
1671 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1672 /* Update any possible open window of the vehicle */
1674
1675 /* If the vehicle has already got the order to modify as the current order, then update the current order as well */
1676 if (u->cur_real_order_index == order_number && (!order->IsType(OT_GOTO_DEPOT) || u->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders))) {
1677 u->current_order.SetRefit(cargo);
1678 }
1679 }
1680 }
1681
1682 return CommandCost();
1683}
1684
1685
1690void CheckOrders(const Vehicle *v)
1691{
1692 /* Does the user want us to check things? */
1693 if (_settings_client.gui.order_review_system == OrderReviewSystem::Off) return;
1694
1695 /* Ignore crashed vehicles. */
1696 if (v->vehstatus.Test(VehState::Crashed)) return;
1697
1698 /* Maybe ignore stopped vehicles. */
1699 if (_settings_client.gui.order_review_system == OrderReviewSystem::ExcludeStopped && v->vehstatus.Test(VehState::Stopped)) return;
1700
1701 /* Do nothing if we're not the first vehicle in a share-chain. */
1702 if (v->FirstShared() != v) return;
1703
1704 /* Only check every 20 days, so that we don't flood the message log */
1705 if (v->owner == _local_company && v->day_counter % 20 == 0) {
1706 StringID message = INVALID_STRING_ID;
1707
1708 /* Check the order list */
1709 int n_st = 0;
1710
1711 for (const Order &order : v->Orders()) {
1712 /* Dummy order? */
1713 if (order.IsType(OT_DUMMY)) {
1714 message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1715 break;
1716 }
1717 /* Does station have a load-bay for this vehicle? */
1718 if (order.IsType(OT_GOTO_STATION)) {
1719 const Station *st = Station::Get(order.GetDestination().ToStationID());
1720
1721 n_st++;
1722 if (!CanVehicleUseStation(v, st)) {
1723 message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1724 } else if (v->type == VehicleType::Aircraft &&
1725 (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1727 !_cheats.no_jetcrash.value &&
1728 message == INVALID_STRING_ID) {
1729 message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1730 }
1731 }
1732 }
1733
1734 /* Check if the last and the first order are the same */
1735 if (v->GetNumOrders() > 1) {
1736 auto orders = v->Orders();
1737
1738 if (orders.front().Equals(orders.back())) {
1739 message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1740 }
1741 }
1742
1743 /* Do we only have 1 station in our order list? */
1744 if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1745
1746#ifdef WITH_ASSERT
1747 if (v->orders != nullptr) v->orders->DebugCheckSanity();
1748#endif
1749
1750 /* We don't have a problem */
1751 if (message == INVALID_STRING_ID) return;
1752
1753 AddVehicleAdviceNewsItem(AdviceType::Order, GetEncodedString(message, v->index), v->index);
1754 }
1755}
1756
1765void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1766{
1767 /* Aircraft have StationIDs for depot orders and never use DepotIDs
1768 * This fact is handled specially below
1769 */
1770
1771 /* Go through all vehicles */
1772 for (Vehicle *v : Vehicle::Iterate()) {
1773 if ((v->type == VehicleType::Aircraft && v->current_order.IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : v->current_order.GetType()) == type &&
1774 (!hangar || v->type == VehicleType::Aircraft) && v->current_order.GetDestination() == destination) {
1775 v->current_order.MakeDummy();
1776 InvalidateWindowData(WindowClass::VehicleView, v->index);
1777 }
1778
1779 if (v->orders == nullptr) continue;
1780
1781 /* Clear the order from the order-list */
1782 for (VehicleOrderID id = 0, next_id = 0; id < v->GetNumOrders(); id = next_id) {
1783 next_id = id + 1;
1784 Order *order = v->orders->GetOrderAt(id);
1785 OrderType ot = order->GetType();
1786 if (ot == OT_GOTO_DEPOT && order->GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot)) continue;
1787 if (ot == OT_GOTO_DEPOT && hangar && v->type != VehicleType::Aircraft) continue; // Not an aircraft? Can't have a hangar order.
1788 if (ot == OT_IMPLICIT || (v->type == VehicleType::Aircraft && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1789 if (ot == type && order->GetDestination() == destination) {
1790 /* We want to clear implicit orders, but we don't want to make them
1791 * dummy orders. They should just vanish. Also check the actual order
1792 * type as ot is currently OT_GOTO_STATION. */
1793 if (order->IsType(OT_IMPLICIT)) {
1794 DeleteOrder(v, id);
1795 next_id = id;
1796 continue;
1797 }
1798
1799 /* Clear wait time */
1800 v->orders->UpdateTotalDuration(-order->GetWaitTime());
1801 if (order->IsWaitTimetabled()) {
1802 v->orders->UpdateTimetableDuration(-order->GetTimetabledWait());
1803 order->SetWaitTimetabled(false);
1804 }
1805 order->SetWaitTime(0);
1806
1807 /* Clear order, preserving travel time */
1808 bool travel_timetabled = order->IsTravelTimetabled();
1809 order->MakeDummy();
1810 order->SetTravelTimetabled(travel_timetabled);
1811
1812 for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1813 /* In GUI, simulate by removing the order and adding it back */
1816 }
1817 }
1818 }
1819 }
1820
1821 OrderBackup::RemoveOrder(type, destination, hangar);
1822}
1823
1829{
1830 return std::ranges::any_of(this->Orders(), [](const Order &order) { return order.IsType(OT_GOTO_DEPOT); });
1831}
1832
1842void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1843{
1845
1846 if (v->IsOrderListShared()) {
1847 /* Remove ourself from the shared order list. */
1848 v->RemoveFromShared();
1849 v->orders = nullptr;
1850 } else if (v->orders != nullptr) {
1851 /* Remove the orders */
1852 v->orders->FreeChain(keep_orderlist);
1853 if (!keep_orderlist) v->orders = nullptr;
1854 }
1855
1856 /* Unbunching data is no longer valid. */
1858
1859 if (reset_order_indices) {
1861 if (v->current_order.IsType(OT_LOADING)) {
1863 }
1864 }
1865}
1866
1874uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
1875{
1876 /* Service intervals are in percents. */
1877 if (ispercent) return Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT);
1878
1879 /* Service intervals are in minutes. */
1880 if (TimerGameEconomy::UsingWallclockUnits(_game_mode == GameMode::Menu)) return Clamp(interval, MIN_SERVINT_MINUTES, MAX_SERVINT_MINUTES);
1881
1882 /* Service intervals are in days. */
1883 return Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1884}
1885
1893static bool CheckForValidOrders(const Vehicle *v)
1894{
1895 /* Check if vehicle has any valid orders.
1896 * Function is only called for aircraft, no type check needed. */
1897 return std::ranges::any_of(v->Orders(), [](const Order &order) {
1898 return order.IsGotoOrder() && (!order.IsType(OT_GOTO_DEPOT) || !order.GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot));
1899 });
1900}
1901
1909static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1910{
1911 switch (occ) {
1912 case OrderConditionComparator::Equal: return variable == value;
1913 case OrderConditionComparator::NotEqual: return variable != value;
1914 case OrderConditionComparator::LessThan: return variable < value;
1915 case OrderConditionComparator::LessThanOrEqual: return variable <= value;
1916 case OrderConditionComparator::MoreThan: return variable > value;
1917 case OrderConditionComparator::MoreThanOrEqual: return variable >= value;
1918 case OrderConditionComparator::IsTrue: return variable != 0;
1919 case OrderConditionComparator::IsFalse: return variable == 0;
1920 default: NOT_REACHED();
1921 }
1922}
1923
1924static bool OrderConditionCompare(OrderConditionComparator occ, ConvertibleThroughBase auto variable, int value)
1925{
1926 return OrderConditionCompare(occ, variable.base(), value);
1927}
1928
1936{
1937 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1938
1939 bool skip_order = false;
1941 uint16_t value = order->GetConditionValue();
1942
1943 switch (order->GetConditionVariable()) {
1944 case OrderConditionVariable::LoadPercentage: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1945 case OrderConditionVariable::Reliability: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
1947 case OrderConditionVariable::MaxSpeed: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1949 case OrderConditionVariable::RequiresService: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
1950 case OrderConditionVariable::Unconditionally: skip_order = true; break;
1952 case OrderConditionVariable::DrivingBackwards: skip_order = OrderConditionCompare(occ, v->IsDrivingBackwards() && !Train::From(v)->GetMovingFront()->CanLeadTrain(), value); break;
1953 default: NOT_REACHED();
1954 }
1955
1956 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1957}
1958
1967bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
1968{
1969 if (conditional_depth > v->GetNumOrders()) {
1970 v->current_order.Free();
1972 return false;
1973 }
1974
1975 switch (order->GetType()) {
1976 case OT_GOTO_STATION:
1977 v->SetDestTile(v->GetOrderStationLocation(order->GetDestination().ToStationID()));
1978 return true;
1979
1980 case OT_GOTO_DEPOT:
1982 assert(!pbs_look_ahead);
1983 UpdateVehicleTimetable(v, true);
1985 break;
1986 }
1987
1989 /* If the vehicle can't find its destination, delay its next search.
1990 * In case many vehicles are in this state, use the vehicle index to spread out pathfinder calls. */
1991 if (v->dest_tile == INVALID_TILE && TimerGameEconomy::date_fract != (v->index % Ticks::DAY_TICKS)) break;
1992
1993 /* We need to search for the nearest depot (hangar). */
1994 ClosestDepot closest_depot = v->FindClosestDepot();
1995
1996 if (closest_depot.found) {
1997 /* PBS reservations cannot reverse */
1998 if (pbs_look_ahead && closest_depot.reverse) return false;
1999
2000 v->SetDestTile(closest_depot.location);
2001 v->current_order.SetDestination(closest_depot.destination);
2002
2003 /* If there is no depot in front, reverse automatically (trains only) */
2004 if (v->type == VehicleType::Train && closest_depot.reverse) Command<Commands::ReverseTrainDirection>::Do(DoCommandFlag::Execute, v->index, false);
2005
2006 if (v->type == VehicleType::Aircraft) {
2007 Aircraft *a = Aircraft::From(v);
2008 if (a->state == FLYING && a->targetairport != closest_depot.destination) {
2009 /* The aircraft is now heading for a different hangar than the next in the orders */
2011 }
2012 }
2013 return true;
2014 }
2015
2016 /* If there is no depot, we cannot help PBS either. */
2017 if (pbs_look_ahead) return false;
2018
2019 UpdateVehicleTimetable(v, true);
2021 } else {
2022 if (v->type != VehicleType::Aircraft) {
2023 v->SetDestTile(Depot::Get(order->GetDestination().ToStationID())->xy);
2024 } else {
2025 Aircraft *a = Aircraft::From(v);
2026 DestinationID destination = a->current_order.GetDestination();
2027 if (a->targetairport != destination) {
2028 /* The aircraft is now heading for a different hangar than the next in the orders */
2029 a->SetDestTile(a->GetOrderStationLocation(destination.ToStationID()));
2030 }
2031 }
2032 return true;
2033 }
2034 break;
2035
2036 case OT_GOTO_WAYPOINT:
2037 v->SetDestTile(Waypoint::Get(order->GetDestination().ToStationID())->xy);
2038 return true;
2039
2040 case OT_CONDITIONAL: {
2041 assert(!pbs_look_ahead);
2042 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2043 if (next_order != INVALID_VEH_ORDER_ID) {
2044 /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2045 * cur_real_order_index might come after next_order. */
2046 UpdateVehicleTimetable(v, false);
2050
2051 /* Disable creation of implicit orders.
2052 * When inserting them we do not know that we would have to make the conditional orders point to them. */
2053 if (v->IsGroundVehicle()) {
2055 }
2056 } else {
2057 UpdateVehicleTimetable(v, true);
2059 }
2060 break;
2061 }
2062
2063 default:
2065 return false;
2066 }
2067
2068 assert(v->cur_implicit_order_index < v->GetNumOrders());
2069 assert(v->cur_real_order_index < v->GetNumOrders());
2070
2071 /* Get the current order */
2072 order = v->GetOrder(v->cur_real_order_index);
2073 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2074 assert(v->GetNumManualOrders() == 0);
2075 order = nullptr;
2076 }
2077
2078 if (order == nullptr) {
2079 v->current_order.Free();
2081 return false;
2082 }
2083
2084 v->current_order = *order;
2085 return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2086}
2087
2096{
2097 switch (v->current_order.GetType()) {
2098 case OT_GOTO_DEPOT:
2099 /* Let a depot order in the orderlist interrupt. */
2101 break;
2102
2103 case OT_LOADING:
2104 return false;
2105
2106 case OT_LEAVESTATION:
2107 if (v->type != VehicleType::Aircraft) return false;
2108 break;
2109
2110 default: break;
2111 }
2112
2120 bool may_reverse = v->current_order.IsType(OT_NOTHING);
2121 Vehicle *moving_front = v->GetMovingFront();
2122
2123 /* Check if we've reached a 'via' destination. */
2124 if (((v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetNonStopType().Test(OrderNonStopFlag::GoVia)) || v->current_order.IsType(OT_GOTO_WAYPOINT)) &&
2125 IsTileType(moving_front->tile, TileType::Station) &&
2126 v->current_order.GetDestination() == GetStationIndex(moving_front->tile)) {
2128 /* We set the last visited station here because we do not want
2129 * the train to stop at this 'via' station if the next order
2130 * is a no-non-stop order; in that case not setting the last
2131 * visited station will cause the vehicle to still stop. */
2132 v->last_station_visited = v->current_order.GetDestination().ToStationID();
2133 UpdateVehicleTimetable(v, true);
2135 }
2136
2137 /* Get the current order */
2140
2141 const Order *order = v->GetOrder(v->cur_real_order_index);
2142 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2143 assert(v->GetNumManualOrders() == 0);
2144 order = nullptr;
2145 }
2146
2147 /* If no order, do nothing. */
2148 if (order == nullptr || (v->type == VehicleType::Aircraft && !CheckForValidOrders(v))) {
2149 if (v->type == VehicleType::Aircraft) {
2150 /* Aircraft do something vastly different here, so handle separately */
2151 HandleMissingAircraftOrders(Aircraft::From(v));
2152 return false;
2153 }
2154
2155 v->current_order.Free();
2157 return false;
2158 }
2159
2160 /* If it is unchanged, keep it. */
2161 if (order->Equals(v->current_order) && (v->type == VehicleType::Aircraft || v->dest_tile != INVALID_TILE) &&
2162 (v->type != VehicleType::Ship || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination().ToStationID())->ship_station.tile != INVALID_TILE)) {
2163 return false;
2164 }
2165
2166 /* Otherwise set it, and determine the destination tile. */
2167 v->current_order = *order;
2168
2170 switch (v->type) {
2171 default:
2172 NOT_REACHED();
2173
2174 case VehicleType::Road:
2175 case VehicleType::Train:
2176 break;
2177
2179 case VehicleType::Ship:
2181 break;
2182 }
2183
2184 return UpdateOrderDest(v, order) && may_reverse;
2185}
2186
2194bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2195{
2196 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2197
2198 return (!this->IsType(OT_GOTO_DEPOT) || this->GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) &&
2199 v->last_station_visited != station && // Do stop only when we've not just been there
2200 /* Finally do stop when there is no non-stop flag set for this type of station. */
2202}
2203
2204bool Order::CanLoadOrUnload() const
2205{
2206 return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2208 (this->GetLoadType() != OrderLoadType::NoLoad ||
2210}
2211
2220bool Order::CanLeaveWithCargo(bool has_cargo) const
2221{
2222 return this->GetLoadType() != OrderLoadType::NoLoad || (has_cargo &&
2225}
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:78
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
static constexpr CargoType CARGO_AUTO_REFIT
Automatically choose cargo type when doing auto refitting.
Definition cargo_type.h:78
static constexpr CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:75
static constexpr 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
CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
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.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Common return value for all commands.
bool Failed() const
Did this command fail?
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:51
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
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)
StrongType::Typedef< int32_t, struct YearTag< struct Calendar >, StrongType::Compare, StrongType::Integer > Year
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
EnumBitSet< DoCommandFlag, uint16_t > DoCommandFlags
Bitset of DoCommandFlag elements.
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).
PoolID< uint16_t, struct DepotIDTag, 64000, 0xFFFF > DepotID
Type for the unique identifier of depots.
Definition depot_type.h:15
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:186
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:169
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:43
void DeleteVehicleNews(VehicleID vid, AdviceType advice_type=AdviceType::Invalid)
Delete news with a given advice type about a vehicle.
@ Vehicle
Vehicle news item. (new engine available).
Definition news_type.h:81
@ Order
Something wrong with the order, e.g. invalid or duplicate entries, too few entries.
Definition news_type.h:54
@ Menu
In the main menu.
Definition openttd.h:19
Functions related to order backups.
CommandCost CmdSkipToOrder(DoCommandFlags flags, VehicleID veh_id, VehicleOrderID sel_ord)
Goto order of 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.
uint GetOrderDistance(VehicleOrderID prev, VehicleOrderID cur, const Vehicle *v, int conditional_depth)
Get the distance between two orders 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.
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.
static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order)
Check if an aircraft has enough range for an order list.
static bool OrderGoesToStation(const Vehicle *v, const Order &o)
Checks whether the order goes to a station or not, i.e.
Command definitions related to orders.
OrderUnloadType
Unloading order types.
Definition order_type.h:67
@ Transfer
Transfer all cargo onto the platform.
Definition order_type.h:70
@ UnloadIfPossible
Unload all cargo that the station accepts.
Definition order_type.h:68
@ NoUnload
Totally no unloading will be done.
Definition order_type.h:71
@ Unload
Force unloading all cargo onto the platform, possibly not getting paid.
Definition order_type.h:69
OrderConditionVariable
Variables (of a vehicle) to 'cause' skipping on.
Definition order_type.h:131
@ Unconditionally
Always skip.
Definition order_type.h:137
@ MaxSpeed
Skip based on the maximum speed.
Definition order_type.h:134
@ Reliability
Skip based on the reliability.
Definition order_type.h:133
@ MaxReliability
Skip based on the maximum reliability.
Definition order_type.h:139
@ RequiresService
Skip when the vehicle requires service.
Definition order_type.h:136
@ LoadPercentage
Skip based on the amount of load.
Definition order_type.h:132
@ Age
Skip based on the age.
Definition order_type.h:135
@ DrivingBackwards
Skip when the train is driving backwards.
Definition order_type.h:140
@ RemainingLifetime
Skip based on the remaining lifetime.
Definition order_type.h:138
OrderStopLocation
Where to stop the trains.
Definition order_type.h:98
@ NearEnd
Stop at the near end of the platform.
Definition order_type.h:99
@ End
End marker.
Definition order_type.h:102
@ FarEnd
Stop at the far end of the platform.
Definition order_type.h:101
@ Middle
Stop at the middle of the platform.
Definition order_type.h:100
ModifyOrderFlags
Enumeration for the data to set in CmdModifyOrder.
Definition order_type.h:163
@ MOF_COND_VARIABLE
A conditional variable changes.
Definition order_type.h:169
@ MOF_LOAD
Passes an OrderLoadType.
Definition order_type.h:167
@ MOF_UNLOAD
Passes an OrderUnloadType.
Definition order_type.h:166
@ MOF_STOP_LOCATION
Passes an OrderStopLocation.
Definition order_type.h:165
@ MOF_COND_DESTINATION
Change the destination of a conditional order.
Definition order_type.h:172
@ MOF_COND_COMPARATOR
A comparator changes.
Definition order_type.h:170
@ MOF_COND_VALUE
The value to set the condition to.
Definition order_type.h:171
@ MOF_DEPOT_ACTION
Selects the OrderDepotAction.
Definition order_type.h:168
@ MOF_NON_STOP
Passes an OrderNonStopFlags.
Definition order_type.h:164
OrderDepotAction
Depot action to switch to when doing a MOF_DEPOT_ACTION.
Definition order_type.h:179
@ Stop
Go to the depot and stop there.
Definition order_type.h:182
@ AlwaysGo
Always go to the depot.
Definition order_type.h:180
@ End
End marker.
Definition order_type.h:184
@ Service
Service only if needed.
Definition order_type.h:181
@ Unbunch
Go to the depot and unbunch.
Definition order_type.h:183
EnumBitSet< OrderNonStopFlag, uint8_t > OrderNonStopFlags
Bitset of OrderNonStopFlag elements.
Definition order_type.h:93
@ NonStop
The vehicle will not stop at any stations it passes except the destination, aka non-stop.
Definition order_type.h:88
@ GoVia
The vehicle will stop at any station it passes except the destination, aka via.
Definition order_type.h:89
EnumBitSet< OrderDepotActionFlag, uint8_t > OrderDepotActionFlags
Bitset of OrderDepotActionFlag elements.
Definition order_type.h:126
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related).
Definition order_type.h:18
EnumBitSet< OrderDepotTypeFlag, uint8_t > OrderDepotTypeFlags
Bitset of OrderDepotTypeFlag elements.
Definition order_type.h:114
OrderLoadType
Loading order types.
Definition order_type.h:77
@ FullLoad
Full load all cargoes of the consist.
Definition order_type.h:79
@ NoLoad
Do not load anything.
Definition order_type.h:81
@ FullLoadAny
Full load a single cargo of the consist.
Definition order_type.h:80
@ LoadIfPossible
Load as long as there is cargo that fits in the train.
Definition order_type.h:78
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition order_type.h:41
@ Halt
Service the vehicle and then halt it.
Definition order_type.h:120
@ NearestDepot
Send the vehicle to the nearest depot.
Definition order_type.h:121
@ Unbunch
Service the vehicle and then unbunch it.
Definition order_type.h:122
@ PartOfOrders
This depot order is because of a regular order.
Definition order_type.h:110
@ Service
This depot order is because of the servicing limit.
Definition order_type.h:109
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel).
Definition order_type.h:39
OrderConditionComparator
Comparator for the skip reasoning.
Definition order_type.h:147
@ IsTrue
Skip if the variable is true.
Definition order_type.h:154
@ NotEqual
Skip if both values are not equal.
Definition order_type.h:149
@ IsFalse
Skip if the variable is false.
Definition order_type.h:155
@ LessThanOrEqual
Skip if the value is less or equal to the limit.
Definition order_type.h:151
@ MoreThan
Skip if the value is more than the limit.
Definition order_type.h:152
@ MoreThanOrEqual
Skip if the value is more or equal to the limit.
Definition order_type.h:153
@ LessThan
Skip if the value is less than the limit.
Definition order_type.h:150
@ Equal
Skip if both values are equal.
Definition order_type.h:148
CloneOptions
Clone actions.
Definition order_type.h:198
OrderType
Order types.
Definition order_type.h:50
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 bool IsRailDepotTile(Tile t)
Is this tile rail tile and a rail depot?
Definition rail_map.h:105
static 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:60
@ ExcludeStopped
Review orders of vehicles which are not stopped in a depot, or manually by the player.
@ Off
Do not review orders.
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:90
Functions related to OTTD's strings.
StrongType::Typedef< uint32_t, struct StringIDTag, StrongType::Compare, StrongType::Integer > StringID
Numeric value that represents a string, independent of the selected language.
static constexpr 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:68
uint16_t cached_max_range
Cached maximum range.
Definition aircraft.h:69
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:75
uint8_t state
State of the airport.
Definition aircraft.h:80
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:79
@ ShortStrip
This airport has a short landing strip, dangerous for fast aircraft.
Definition airport.h:167
Flags flags
Flags for this airport type.
Definition airport.h:198
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.
Structure to return information about the closest depot location, and whether it could be found.
DestinationID destination
The DestinationID as used for orders.
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:384
void DeleteOrderAt(VehicleOrderID index)
Remove an order from the order list and delete it.
std::vector< Order > orders
Orders of the order list.
Definition order_base.h:395
bool IsCompleteTimetable() const
Checks whether all orders of the list have a filled timetable.
void InsertOrderAt(Order &&order, VehicleOrderID index)
Insert a new order into the order chain.
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:393
void Initialize(Vehicle *v)
Recomputes everything.
TimerGameTick::Ticks timetable_duration
NOSAVE: Total timetabled duration of the order list.
Definition order_base.h:398
Vehicle * first_shared
NOSAVE: pointer to the first vehicle in the shared order chain.
Definition order_base.h:394
VehicleOrderID GetFirstOrder() const
Get the first order of the order chain.
Definition order_base.h:442
VehicleOrderID num_manual_orders
NOSAVE: How many manually added orders are there in the list.
Definition order_base.h:392
void MoveOrder(VehicleOrderID from, VehicleOrderID to)
Move an order to another position within the order list.
void GetNextStoppingStation(std::vector< StationID > &next_station, const Vehicle *v, VehicleOrderID first=INVALID_VEH_ORDER_ID, uint hops=0) const
Recursively determine the next deterministic station to stop at.
VehicleOrderID GetNext(VehicleOrderID cur) const
Get the order after the given one or the first one, if the given one is the last one.
Definition order_base.h:476
VehicleOrderID GetNumOrders() const
Get number of orders in the order list.
Definition order_base.h:486
void RecalculateTimetableDuration()
Recomputes Timetable duration.
void FreeChain(bool keep_orderlist=false)
Free a complete order chain.
VehicleOrderID GetNextDecisionNode(VehicleOrderID 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...
bool IsShared() const
Is this a shared order list?
Definition order_base.h:505
TimerGameTick::Ticks total_duration
NOSAVE: Total (timetabled or not) duration of the order list.
Definition order_base.h:399
If you change this, keep in mind that it is also saved in 2 other places:
Definition order_base.h:34
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:170
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:288
OrderConditionVariable GetConditionVariable() const
What variable do we have to compare?
Definition order_base.h:182
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 maximum speed in km-ish/h a vehicle is allowed to reach on the way to the destination.
Definition order_base.h:307
uint16_t max_speed
How fast the vehicle may go on the way to the destination.
Definition order_base.h:56
void SetTravelTimetabled(bool timetabled)
Set if the travel time is explicitly timetabled (unless the order is conditional).
Definition order_base.h:319
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:100
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:67
void SetNonStopType(OrderNonStopFlags non_stop_type)
Set whether we must stop at stations or not.
Definition order_base.h:218
VehicleOrderID GetConditionSkipToOrder() const
Get the order to skip to.
Definition order_base.h:194
OrderStopLocation GetStopLocation() const
Where must we stop at the platform?
Definition order_base.h:164
uint16_t GetWaitTime() const
Get the time in ticks a vehicle will probably wait at the destination (timetabled or not).
Definition order_base.h:294
CargoType GetRefitCargo() const
Get the cargo to to refit to.
Definition order_base.h:128
OrderType GetType() const
Get the type of order of this order.
Definition order_base.h:73
bool IsFullLoadOrder() const
Is this order a OrderLoadType::FullLoad or OrderLoadType::FullLoadAny?
Definition order_base.h:136
void MakeGoToStation(StationID destination)
Makes this order a Go To Station order.
Definition order_cmd.cpp:59
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:230
void SetWaitTime(uint16_t time)
Set the time in ticks to wait at the destination.
Definition order_base.h:325
void SetStopLocation(OrderStopLocation stop_location)
Set where we must stop at the platform.
Definition order_base.h:224
void MakeDummy()
Makes this order a Dummy order.
void MakeGoToWaypoint(StationID destination)
Makes this order a Go To Waypoint order.
Definition order_cmd.cpp:88
void SetConditionVariable(OrderConditionVariable condition_variable)
Set variable we have to compare.
Definition order_base.h:242
OrderUnloadType GetUnloadType() const
How must the consist be unloaded?
Definition order_base.h:152
uint8_t flags
Load/unload types, depot order/action types.
Definition order_base.h:49
bool IsWaitTimetabled() const
Does this order have an explicit wait time set?
Definition order_base.h:271
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:107
void SetWaitTimetabled(bool timetabled)
Set if the wait time is explicitly timetabled (unless the order is conditional).
Definition order_base.h:313
bool IsTravelTimetabled() const
Does this order have an explicit travel time set?
Definition order_base.h:277
void SetConditionComparator(OrderConditionComparator condition_comparator)
Set the comparator to use.
Definition order_base.h:248
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:236
void SetConditionSkipToOrder(VehicleOrderID order_id)
Get the order to skip to.
Definition order_base.h:254
OrderLoadType GetLoadType() const
How must the consist be loaded?
Definition order_base.h:146
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition order_base.h:176
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:260
void SetUnloadType(OrderUnloadType unload_type)
Set how the consist must be unloaded.
Definition order_base.h:212
void Free()
'Free' the order
Definition order_cmd.cpp:48
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:283
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:300
void MakeImplicit(StationID destination)
Makes this order an implicit order.
void SetLoadType(OrderLoadType load_type)
Set how the consist must be loaded.
Definition order_base.h:206
void MakeGoToDepot(DestinationID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=OrderNonStopFlag::NonStop, OrderDepotActionFlags action={}, CargoType cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition order_cmd.cpp:74
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:188
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition order_base.h:158
bool IsRefit() const
Is this order a refit order.
Definition order_base.h:114
void MakeLoading(bool ordered)
Makes this order a Loading order.
Definition order_cmd.cpp:99
uint16_t GetConditionValue() const
Get the value to base the skip on.
Definition order_base.h:200
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.
static Pool::IterateWrapper< Vehicle > Iterate(size_t from=0)
static BaseStation * Get(auto index)
static BaseStation * GetIfValid(auto index)
static Station * Get(auto index)
static Station * GetIfValid(auto index)
static RoadVehicle * From(Vehicle *v)
Station data structure.
Airport airport
Tile area the airport covers.
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
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:749
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:2372
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:3021
bool HasUnbunchingOrder() const
Check if the current vehicle has an unbunching order.
Definition vehicle.cpp:2508
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
virtual void SetDestTile(TileIndex tile)
Set the destination of this vehicle.
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.
bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
VehStates vehstatus
Status.
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.
Vehicle * GetMovingFront() const
Get the moving front of the vehicle chain.
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:2488
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
TimerGameCalendar::Date age
Age in calendar days.
TimerGameCalendar::Date max_age
Maximum age.
uint16_t reliability
Reliability.
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition vehicle.cpp:3044
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:211
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition vehicle.cpp:2499
GroundVehicleFlags & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition vehicle.cpp:3239
StationID last_station_visited
The last station we stopped at.
bool IsDrivingBackwards() const
Is this vehicle moving backwards?
Owner owner
Which company owns the vehicle?
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition vehicle.cpp:2190
void UpdateRealOrderIndex()
Skip implicit orders until cur_real_order_index is a non-implicit order.
Representation of a waypoint.
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
@ Station
A tile of a station or airport.
Definition tile_type.h:54
Functions related to time tabling.
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
Update the timetable for the vehicle.
Base for the train class.
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:3158
uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1504
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3112
@ Crashed
Vehicle is crashed.
@ Stopped
Vehicle is stopped by the player.
Functions related to vehicles.
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
@ 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
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
@ Ship
Ship vehicle type.
@ Aircraft
Aircraft vehicle type.
@ Road
Road vehicle type.
@ Train
Train vehicle type.
@ SuppressImplicitOrders
Disable insertion and removal of automatic orders until the vehicle completes the real order.
bool IsShipDepotTile(Tile t)
Is it a ship depot tile?
Definition water_map.h:234
Base of waypoints.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3226
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:3318
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3196
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:3336