OpenTTD Source 20260711-master-g3fb3006dff
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
30#include "table/strings.h"
31
32#include "safeguards.h"
33
34/* DestinationID must be at least as large as every these below, because it can
35 * be any of them
36 */
37static_assert(sizeof(DestinationID) >= sizeof(DepotID));
38static_assert(sizeof(DestinationID) >= sizeof(StationID));
39
40OrderListPool _orderlist_pool("OrderList");
42
43
47void Order::Free()
48{
49 this->type = OT_NOTHING;
50 this->flags = 0;
51 this->dest = 0;
52}
53
58void Order::MakeGoToStation(StationID destination)
59{
60 this->type = OT_GOTO_STATION;
61 this->flags = 0;
62 this->dest = destination;
63}
64
74{
75 this->type = OT_GOTO_DEPOT;
76 this->SetDepotOrderType(order);
77 this->SetDepotActionType(action);
78 this->SetNonStopType(non_stop_type);
79 this->dest = destination;
80 this->SetRefit(cargo);
81}
82
87void Order::MakeGoToWaypoint(StationID destination)
88{
89 this->type = OT_GOTO_WAYPOINT;
90 this->flags = 0;
91 this->dest = destination;
92}
93
98void Order::MakeLoading(bool ordered)
99{
100 this->type = OT_LOADING;
101 if (!ordered) this->flags = 0;
102}
103
108{
109 this->type = OT_LEAVESTATION;
110 this->flags = 0;
111}
112
117{
118 this->type = OT_DUMMY;
119 this->flags = 0;
120}
121
127{
128 this->type = OT_CONDITIONAL;
129 this->flags = order;
130 this->dest = 0;
131}
132
137void Order::MakeImplicit(StationID destination)
138{
139 this->type = OT_IMPLICIT;
140 this->dest = destination;
141}
142
149{
150 this->refit_cargo = cargo;
151}
152
158bool Order::Equals(const Order &other) const
159{
160 /* In case of go to nearest depot orders we need "only" compare the flags
161 * with the other and not the nearest depot order bit or the actual
162 * destination because those get clear/filled in during the order
163 * evaluation. If we do not do this the order will continuously be seen as
164 * a different order and it will try to find a "nearest depot" every tick. */
165 if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
166 (this->GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot) ||
168 return this->GetDepotOrderType() == other.GetDepotOrderType() &&
170 }
171
172 return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
173}
174
180uint16_t Order::MapOldOrder() const
181{
182 uint16_t order = this->GetType();
183 switch (this->GetType()) {
184 case OT_GOTO_STATION:
185 if (this->GetUnloadType() == OrderUnloadType::Unload) SetBit(order, 5);
186 if (this->IsFullLoadOrder()) SetBit(order, 6);
187 if (this->GetNonStopType().Test(OrderNonStopFlag::NonStop)) SetBit(order, 7);
188 order |= GB(this->GetDestination().value, 0, 8) << 8;
189 break;
190 case OT_GOTO_DEPOT:
191 if (!this->GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) SetBit(order, 6);
192 SetBit(order, 7);
193 order |= GB(this->GetDestination().value, 0, 8) << 8;
194 break;
195 case OT_LOADING:
196 if (this->IsFullLoadOrder()) SetBit(order, 6);
197 /* If both "no load" and "no unload" are set, return nothing order instead */
199 order = OT_NOTHING;
200 }
201 break;
202 default:
203 break;
204 }
205 return order;
206}
207
213void InvalidateVehicleOrder(const Vehicle *v, int data)
214{
215 InvalidateWindowData(WindowClass::VehicleView, v->index);
216
217 if (data != 0) {
218 /* Calls SetDirty() too */
219 InvalidateWindowData(WindowClass::VehicleOrders, v->index, data);
220 InvalidateWindowData(WindowClass::VehicleTimetable, v->index, data);
221 return;
222 }
223
224 SetWindowDirty(WindowClass::VehicleOrders, v->index);
225 SetWindowDirty(WindowClass::VehicleTimetable, v->index);
226}
227
235void Order::AssignOrder(const Order &other)
236{
237 this->type = other.type;
238 this->flags = other.flags;
239 this->dest = other.dest;
240
241 this->refit_cargo = other.refit_cargo;
242
243 this->wait_time = other.wait_time;
244 this->travel_time = other.travel_time;
245 this->max_speed = other.max_speed;
246}
247
253{
254 this->first_shared = v;
255
256 this->num_manual_orders = 0;
257 this->num_vehicles = 1;
258 this->timetable_duration = 0;
259
260 for (const Order &o : this->orders) {
261 if (!o.IsType(OT_IMPLICIT)) ++this->num_manual_orders;
262 this->total_duration += o.GetWaitTime() + o.GetTravelTime();
263 }
264
266
267 for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
268 ++this->num_vehicles;
269 this->first_shared = u;
270 }
271
272 for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
273}
274
280{
281 this->timetable_duration = 0;
282 for (const Order &o : this->orders) {
283 this->timetable_duration += o.GetTimetabledWait() + o.GetTimetabledTravel();
284 }
285}
286
292void OrderList::FreeChain(bool keep_orderlist)
293{
294 /* We can visit oil rigs and buoys that are not our own. They will be shown in
295 * the list of stations. So, we need to invalidate that window if needed. */
296 for (Order &order: this->orders) {
297 if (order.IsType(OT_GOTO_STATION) || order.IsType(OT_GOTO_WAYPOINT)) {
298 BaseStation *bs = BaseStation::GetIfValid(order.GetDestination().ToStationID());
299 if (bs != nullptr && bs->owner == OWNER_NONE) {
300 InvalidateWindowClassesData(WindowClass::StationList, 0);
301 break;
302 }
303 }
304 }
305
306 if (keep_orderlist) {
307 this->orders.clear();
308 this->num_manual_orders = 0;
309 this->timetable_duration = 0;
310 } else {
311 delete this;
312 }
313}
314
327{
328 if (hops > this->GetNumOrders() || next >= this->GetNumOrders()) return INVALID_VEH_ORDER_ID;
329
330 const Order &order_next = this->orders[next];
331 if (order_next.IsType(OT_CONDITIONAL)) {
332 if (order_next.GetConditionVariable() != OrderConditionVariable::Unconditionally) return next;
333
334 /* We can evaluate trivial conditions right away. They're conceptually
335 * the same as regular order progression. */
336 return this->GetNextDecisionNode(
337 order_next.GetConditionSkipToOrder(),
338 hops + 1);
339 }
340
341 if (order_next.IsType(OT_GOTO_DEPOT)) {
343 if (order_next.IsRefit()) return next;
344 }
345
346 if (!order_next.CanLoadOrUnload()) {
347 return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
348 }
349
350 return next;
351}
352
362void OrderList::GetNextStoppingStation(std::vector<StationID> &next_station, const Vehicle *v, VehicleOrderID first, uint hops) const
363{
364 VehicleOrderID next = first;
365 if (first == INVALID_VEH_ORDER_ID) {
366 next = v->cur_implicit_order_index;
367 if (next >= this->GetNumOrders()) {
368 next = this->GetFirstOrder();
369 if (next == INVALID_VEH_ORDER_ID) return;
370 } else {
371 /* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list.
372 * As the given "next" is already valid and a station in the list, we
373 * don't have to check for INVALID_VEH_ORDER_ID here. */
374 next = this->GetNext(next);
375 assert(next != INVALID_VEH_ORDER_ID);
376 }
377 }
378
379 auto orders = v->Orders();
380 do {
381 next = this->GetNextDecisionNode(next, ++hops);
382
383 /* Resolve possibly nested conditionals by estimation. */
384 while (next != INVALID_VEH_ORDER_ID && orders[next].IsType(OT_CONDITIONAL)) {
385 /* We return both options of conditional orders. */
386 VehicleOrderID skip_to = this->GetNextDecisionNode(orders[next].GetConditionSkipToOrder(), hops);
387 VehicleOrderID advance = this->GetNextDecisionNode(this->GetNext(next), hops);
388 if (advance == INVALID_VEH_ORDER_ID || advance == first || skip_to == advance) {
389 next = (skip_to == first) ? INVALID_VEH_ORDER_ID : skip_to;
390 } else if (skip_to == INVALID_VEH_ORDER_ID || skip_to == first) {
391 next = (advance == first) ? INVALID_VEH_ORDER_ID : advance;
392 } else {
393 this->GetNextStoppingStation(next_station, v, skip_to, hops);
394 this->GetNextStoppingStation(next_station, v, advance, hops);
395 return;
396 }
397 ++hops;
398 }
399
400 /* Don't return a next stop if the vehicle has to unload everything. */
401 if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) &&
402 orders[next].GetDestination() == v->last_station_visited &&
403 (orders[next].GetUnloadType() == OrderUnloadType::Transfer || orders[next].GetUnloadType() == OrderUnloadType::Unload))) {
404 return;
405 }
406 } while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited);
407
408 next_station.push_back(orders[next].GetDestination().ToStationID());
409}
410
417{
418 auto it = std::ranges::next(std::begin(this->orders), index, std::end(this->orders));
419 auto new_order = this->orders.emplace(it, std::move(order));
420
421 if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
422 this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
423 this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
424
425 /* We can visit oil rigs and buoys that are not our own. They will be shown in
426 * the list of stations. So, we need to invalidate that window if needed. */
427 if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
428 BaseStation *bs = BaseStation::Get(new_order->GetDestination().ToStationID());
429 if (bs->owner == OWNER_NONE) InvalidateWindowClassesData(WindowClass::StationList, 0);
430 }
431}
432
433
439{
440 auto to_remove = std::ranges::next(std::begin(this->orders), index, std::end(this->orders));
441 if (to_remove == std::end(this->orders)) return;
442
443 if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
444
445 this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
446 this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
447
448 this->orders.erase(to_remove);
449}
450
457{
458 if (from == to) return;
459 if (from >= this->GetNumOrders()) return;
460 if (to >= this->GetNumOrders()) return;
461
462 auto it = std::begin(this->orders);
463 if (from < to) {
464 std::rotate(it + from, it + from + 1, it + to + 1);
465 } else {
466 std::rotate(it + to, it + from, it + from + 1);
467 }
468}
469
476{
477 --this->num_vehicles;
478 if (v == this->first_shared) this->first_shared = v->NextShared();
479}
480
486{
487 for (const Order &o : this->orders) {
488 /* Implicit orders are, by definition, not timetabled. */
489 if (o.IsType(OT_IMPLICIT)) continue;
490 if (!o.IsCompletelyTimetabled()) return false;
491 }
492 return true;
493}
494
495#ifdef WITH_ASSERT
499void OrderList::DebugCheckSanity() const
500{
501 VehicleOrderID check_num_orders = 0;
502 VehicleOrderID check_num_manual_orders = 0;
503 uint check_num_vehicles = 0;
504 TimerGameTick::Ticks check_timetable_duration = 0;
505 TimerGameTick::Ticks check_total_duration = 0;
506
507 Debug(misc, 6, "Checking OrderList {} for sanity...", this->index);
508
509 for (const Order &o : this->orders) {
510 ++check_num_orders;
511 if (!o.IsType(OT_IMPLICIT)) ++check_num_manual_orders;
512 check_timetable_duration += o.GetTimetabledWait() + o.GetTimetabledTravel();
513 check_total_duration += o.GetWaitTime() + o.GetTravelTime();
514 }
515 assert(this->GetNumOrders() == check_num_orders);
516 assert(this->num_manual_orders == check_num_manual_orders);
517 assert(this->timetable_duration == check_timetable_duration);
518 assert(this->total_duration == check_total_duration);
519
520 for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
521 ++check_num_vehicles;
522 assert(v->orders == this);
523 }
524 assert(this->num_vehicles == check_num_vehicles);
525 Debug(misc, 6, "... detected {} orders ({} manual), {} vehicles, {} timetabled, {} total",
526 (uint)this->GetNumOrders(), (uint)this->num_manual_orders,
528}
529#endif
530
538static inline bool OrderGoesToStation(const Vehicle *v, const Order &o)
539{
540 return o.IsType(OT_GOTO_STATION) ||
541 (v->type == VehicleType::Aircraft && o.IsType(OT_GOTO_DEPOT) && o.GetDestination() != StationID::Invalid());
542}
543
551static void DeleteOrderWarnings(const Vehicle *v)
552{
554}
555
562TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
563{
564 switch (this->GetType()) {
565 case OT_GOTO_WAYPOINT:
566 case OT_GOTO_STATION:
567 case OT_IMPLICIT:
568 if (airport && v->type == VehicleType::Aircraft) return Station::Get(this->GetDestination().ToStationID())->airport.tile;
569 return BaseStation::Get(this->GetDestination().ToStationID())->xy;
570
571 case OT_GOTO_DEPOT:
572 if (this->GetDestination() == DepotID::Invalid()) return INVALID_TILE;
573 return (v->type == VehicleType::Aircraft) ? Station::Get(this->GetDestination().ToStationID())->xy : Depot::Get(this->GetDestination().ToDepotID())->xy;
574
575 default:
576 return INVALID_TILE;
577 }
578}
579
589uint GetOrderDistance(VehicleOrderID prev, VehicleOrderID cur, const Vehicle *v, int conditional_depth)
590{
591 assert(v->orders != nullptr);
592 const OrderList &orderlist = *v->orders;
593 auto orders = orderlist.GetOrders();
594
595 if (orders[cur].IsType(OT_CONDITIONAL)) {
596 if (conditional_depth > v->GetNumOrders()) return 0;
597
598 conditional_depth++;
599
600 int dist1 = GetOrderDistance(prev, orders[cur].GetConditionSkipToOrder(), v, conditional_depth);
601 int dist2 = GetOrderDistance(prev, orderlist.GetNext(cur), v, conditional_depth);
602 return std::max(dist1, dist2);
603 }
604
605 TileIndex prev_tile = orders[prev].GetLocation(v, true);
606 TileIndex cur_tile = orders[cur].GetLocation(v, true);
607 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
608 return v->type == VehicleType::Aircraft ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
609}
610
622{
624 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
625
627 if (ret.Failed()) return ret;
628
629 /* Validate properties we don't want to have different from default as they are set by other commands. */
630 if (new_order.GetRefitCargo() != CARGO_NO_REFIT || new_order.GetWaitTime() != 0 || new_order.GetTravelTime() != 0 || new_order.GetMaxSpeed() != UINT16_MAX) return CMD_ERROR;
631
632 /* Check if the inserted order is to the correct destination (owner, type),
633 * and has the correct flags if any */
634 switch (new_order.GetType()) {
635 case OT_GOTO_STATION: {
636 const Station *st = Station::GetIfValid(new_order.GetDestination().ToStationID());
637 if (st == nullptr) return CMD_ERROR;
638
639 if (st->owner != OWNER_NONE) {
640 ret = CheckOwnership(st->owner);
641 if (ret.Failed()) return ret;
642 }
643
644 if (!CanVehicleUseStation(v, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, GetVehicleCannotUseStationReason(v, st));
645 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
646 if (!CanVehicleUseStation(u, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER_SHARED, GetVehicleCannotUseStationReason(u, st));
647 }
648
649 /* Non stop only allowed for ground vehicles. */
650 if (new_order.GetNonStopType().Any() && !v->IsGroundVehicle()) return CMD_ERROR;
651
652 /* Filter invalid load/unload types. */
653 switch (new_order.GetLoadType()) {
656 break;
657
660 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
661 break;
662
663 default:
664 return CMD_ERROR;
665 }
666 switch (new_order.GetUnloadType()) {
671 break;
672
673 default:
674 return CMD_ERROR;
675 }
676
677 /* Filter invalid stop locations */
678 switch (new_order.GetStopLocation()) {
681 if (v->type != VehicleType::Train) return CMD_ERROR;
682 [[fallthrough]];
683
685 break;
686
687 default:
688 return CMD_ERROR;
689 }
690
691 break;
692 }
693
694 case OT_GOTO_DEPOT: {
696 if (v->type == VehicleType::Aircraft) {
697 const Station *st = Station::GetIfValid(new_order.GetDestination().ToStationID());
698
699 if (st == nullptr) return CMD_ERROR;
700
701 ret = CheckOwnership(st->owner);
702 if (ret.Failed()) return ret;
703
704 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
705 return CMD_ERROR;
706 }
707 } else {
708 const Depot *dp = Depot::GetIfValid(new_order.GetDestination().ToDepotID());
709
710 if (dp == nullptr) return CMD_ERROR;
711
712 ret = CheckOwnership(GetTileOwner(dp->xy));
713 if (ret.Failed()) return ret;
714
715 switch (v->type) {
717 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
718 break;
719
721 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
722 break;
723
725 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
726 break;
727
728 default: return CMD_ERROR;
729 }
730 }
731 }
732
733 if (new_order.GetNonStopType().Any() && !v->IsGroundVehicle()) return CMD_ERROR;
734
735 /* Check depot order type is valid. */
736 OrderDepotTypeFlags depot_order_type = new_order.GetDepotOrderType();
737 if (depot_order_type.Test(OrderDepotTypeFlag::PartOfOrders)) depot_order_type.Reset(OrderDepotTypeFlag::Service);
738 depot_order_type.Reset(OrderDepotTypeFlag::PartOfOrders);
739 if (depot_order_type.Any()) return CMD_ERROR;
740
741 /* Check depot action type is valid. */
742 if (new_order.GetDepotActionType().Reset({OrderDepotActionFlag::Halt, OrderDepotActionFlag::NearestDepot, OrderDepotActionFlag::Unbunch}).Any()) return CMD_ERROR;
743
744 /* Vehicles cannot have a "service if needed" order that also has a depot action. */
745 if (new_order.GetDepotOrderType().Test(OrderDepotTypeFlag::Service) && new_order.GetDepotActionType().Any({OrderDepotActionFlag::Halt, OrderDepotActionFlag::Unbunch})) return CMD_ERROR;
746
747 /* Check if we're allowed to have a new unbunching order. */
749 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
750 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
751 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
752 }
753 break;
754 }
755
756 case OT_GOTO_WAYPOINT: {
757 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination().ToStationID());
758 if (wp == nullptr) return CMD_ERROR;
759
760 switch (v->type) {
761 default: return CMD_ERROR;
762
763 case VehicleType::Train: {
764 if (!wp->facilities.Test(StationFacility::Train)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_RAIL_WAYPOINT);
765
766 ret = CheckOwnership(wp->owner);
767 if (ret.Failed()) return ret;
768 break;
769 }
770
771 case VehicleType::Road: {
772 if (!wp->facilities.Test(StationFacility::BusStop) && !wp->facilities.Test(StationFacility::TruckStop)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_ROAD_WAYPOINT);
773
774 ret = CheckOwnership(wp->owner);
775 if (ret.Failed()) return ret;
776 break;
777 }
778
780 if (!wp->facilities.Test(StationFacility::Dock)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_BUOY);
781 if (wp->owner != OWNER_NONE) {
782 ret = CheckOwnership(wp->owner);
783 if (ret.Failed()) return ret;
784 }
785 break;
786 }
787
788 /* Order flags can be any of the following for waypoints:
789 * [non-stop]
790 * non-stop orders (if any) are only valid for trains and road vehicles */
791 if (new_order.GetNonStopType().Any() && !v->IsGroundVehicle()) return CMD_ERROR;
792 break;
793 }
794
795 case OT_CONDITIONAL: {
796 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
797 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
799 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_CONDITIONAL);
800
802 if (occ >= OrderConditionComparator::End) return CMD_ERROR;
803 switch (new_order.GetConditionVariable()) {
805 if (v->type != VehicleType::Train) return CMD_ERROR;
806 [[fallthrough]];
807
810 break;
811
814 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
815 break;
816
820 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
821 [[fallthrough]];
822
823 default:
825 break;
826 }
827 break;
828 }
829
830 default: return CMD_ERROR;
831 }
832
833 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
834
835 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return CommandCost(STR_ERROR_TOO_MANY_ORDERS);
836 if (v->orders == nullptr && !OrderList::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
837
838 if (flags.Test(DoCommandFlag::Execute)) {
839 InsertOrder(v, Order(new_order), sel_ord);
840 }
841
842 return CommandCost();
843}
844
851void InsertOrder(Vehicle *v, Order &&new_o, VehicleOrderID sel_ord)
852{
853 /* Create new order and link in list */
854 if (v->orders == nullptr) {
855 v->orders = OrderList::Create(std::move(new_o), v);
856 } else {
857 v->orders->InsertOrderAt(std::move(new_o), sel_ord);
858 }
859
860 Vehicle *u = v->FirstShared();
862 for (; u != nullptr; u = u->NextShared()) {
863 assert(v->orders == u->orders);
864
865 /* If there is added an order before the current one, we need
866 * to update the selected order. We do not change implicit/real order indices though.
867 * If the new order is between the current implicit order and real order, the implicit order will
868 * later skip the inserted order. */
869 if (sel_ord <= u->cur_real_order_index) {
870 uint cur = u->cur_real_order_index + 1;
871 /* Check if we don't go out of bound */
872 if (cur < u->GetNumOrders()) {
873 u->cur_real_order_index = cur;
874 }
875 }
876 if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
877 /* We are inserting an order just before the current implicit order.
878 * We do not know whether we will reach current implicit or the newly inserted order first.
879 * So, disable creation of implicit orders until we are on track again. */
881 }
882 if (sel_ord <= u->cur_implicit_order_index) {
883 uint cur = u->cur_implicit_order_index + 1;
884 /* Check if we don't go out of bound */
885 if (cur < u->GetNumOrders()) {
887 }
888 }
889 /* Unbunching data is no longer valid. */
891
892 /* Update any possible open window of the vehicle */
893 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
894 }
895
896 /* As we insert an order, the order to skip to will be 'wrong'. */
897 VehicleOrderID cur_order_id = 0;
898 for (Order &order : v->Orders()) {
899 if (order.IsType(OT_CONDITIONAL)) {
900 VehicleOrderID order_id = order.GetConditionSkipToOrder();
901 if (order_id >= sel_ord) {
902 order.SetConditionSkipToOrder(order_id + 1);
903 }
904 if (order_id == cur_order_id) {
905 order.SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
906 }
907 }
908 cur_order_id++;
909 }
910
911 /* Make sure to rebuild the whole list */
913}
914
930
939{
940 Vehicle *v = Vehicle::GetIfValid(veh_id);
941
942 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
943
945 if (ret.Failed()) return ret;
946
947 /* If we did not select an order, we maybe want to de-clone the orders */
948 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
949
950 if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
951
952 if (flags.Test(DoCommandFlag::Execute)) DeleteOrder(v, sel_ord);
953 return CommandCost();
954}
955
961{
962 assert(v->current_order.IsType(OT_LOADING));
963 /* NON-stop flag is misused to see if a train is in a station that is
964 * on its order list or not */
966 /* When full loading, "cancel" that order so the vehicle doesn't
967 * stay indefinitely at this station anymore. */
969}
970
977{
978 v->orders->DeleteOrderAt(sel_ord);
979
980 Vehicle *u = v->FirstShared();
982 for (; u != nullptr; u = u->NextShared()) {
983 assert(v->orders == u->orders);
984
985 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
987 }
988
989 if (sel_ord < u->cur_real_order_index) {
991 } else if (sel_ord == u->cur_real_order_index) {
993 }
994
995 if (sel_ord < u->cur_implicit_order_index) {
997 } else if (sel_ord == u->cur_implicit_order_index) {
998 /* Make sure the index is valid */
1000
1001 /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
1005 }
1006 }
1007 /* Unbunching data is no longer valid. */
1009
1010 /* Update any possible open window of the vehicle */
1011 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1012 }
1013
1014 /* As we delete an order, the order to skip to will be 'wrong'. */
1015 VehicleOrderID cur_order_id = 0;
1016 for (Order &order : v->Orders()) {
1017 if (order.IsType(OT_CONDITIONAL)) {
1018 VehicleOrderID order_id = order.GetConditionSkipToOrder();
1019 if (order_id >= sel_ord) {
1020 order_id = std::max(order_id - 1, 0);
1021 }
1022 if (order_id == cur_order_id) {
1023 order_id = (order_id + 1) % v->GetNumOrders();
1024 }
1025 order.SetConditionSkipToOrder(order_id);
1026 }
1027 cur_order_id++;
1028 }
1029
1031}
1032
1041{
1042 Vehicle *v = Vehicle::GetIfValid(veh_id);
1043
1044 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1045
1047 if (ret.Failed()) return ret;
1048
1049 if (flags.Test(DoCommandFlag::Execute)) {
1050 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1051
1054
1055 /* Unbunching data is no longer valid. */
1057
1059
1060 /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1061 if (v->type == VehicleType::Aircraft) SetWindowClassesDirty(WindowClass::AircraftList);
1062 if (v->type == VehicleType::Ship) SetWindowClassesDirty(WindowClass::ShipList);
1063 }
1064
1065 return CommandCost();
1066}
1067
1079{
1080 Vehicle *v = Vehicle::GetIfValid(veh);
1081 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
1082
1084 if (ret.Failed()) return ret;
1085
1086 /* Don't make senseless movements */
1087 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1088 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1089
1090 Order *moving_one = v->GetOrder(moving_order);
1091 /* Don't move an empty order */
1092 if (moving_one == nullptr) return CMD_ERROR;
1093
1094 if (flags.Test(DoCommandFlag::Execute)) {
1095 v->orders->MoveOrder(moving_order, target_order);
1096
1097 /* Update shared list */
1098 Vehicle *u = v->FirstShared();
1099
1101
1102 for (; u != nullptr; u = u->NextShared()) {
1103 /* Update the current order.
1104 * There are multiple ways to move orders, which result in cur_implicit_order_index
1105 * and cur_real_order_index to not longer make any sense. E.g. moving another
1106 * real order between them.
1107 *
1108 * Basically one could choose to preserve either of them, but not both.
1109 * While both ways are suitable in this or that case from a human point of view, neither
1110 * of them makes really sense.
1111 * However, from an AI point of view, preserving cur_real_order_index is the most
1112 * predictable and transparent behaviour.
1113 *
1114 * With that decision it basically does not matter what we do to cur_implicit_order_index.
1115 * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1116 * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1117 * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1118 */
1119 if (u->cur_real_order_index == moving_order) {
1120 u->cur_real_order_index = target_order;
1121 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1123 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1125 }
1126
1127 if (u->cur_implicit_order_index == moving_order) {
1128 u->cur_implicit_order_index = target_order;
1129 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1131 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1133 }
1134 /* Unbunching data is no longer valid. */
1136
1137
1138 assert(v->orders == u->orders);
1139 /* Update any possible open window of the vehicle */
1140 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1141 }
1142
1143 /* As we move an order, the order to skip to will be 'wrong'. */
1144 for (Order &order : v->Orders()) {
1145 if (order.IsType(OT_CONDITIONAL)) {
1146 VehicleOrderID order_id = order.GetConditionSkipToOrder();
1147 if (order_id == moving_order) {
1148 order_id = target_order;
1149 } else if (order_id > moving_order && order_id <= target_order) {
1150 order_id--;
1151 } else if (order_id < moving_order && order_id >= target_order) {
1152 order_id++;
1153 }
1154 order.SetConditionSkipToOrder(order_id);
1155 }
1156 }
1157
1158 /* Make sure to rebuild the whole list */
1160 }
1161
1162 return CommandCost();
1163}
1164
1177{
1178 if (mof >= MOF_END) return CMD_ERROR;
1179
1180 Vehicle *v = Vehicle::GetIfValid(veh);
1181 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
1182
1184 if (ret.Failed()) return ret;
1185
1186 /* Is it a valid order? */
1187 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1188
1189 Order *order = v->GetOrder(sel_ord);
1190 assert(order != nullptr);
1191 switch (order->GetType()) {
1192 case OT_GOTO_STATION:
1193 if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1194 break;
1195
1196 case OT_GOTO_DEPOT:
1197 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1198 break;
1199
1200 case OT_GOTO_WAYPOINT:
1201 if (mof != MOF_NON_STOP) return CMD_ERROR;
1202 break;
1203
1204 case OT_CONDITIONAL:
1205 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1206 break;
1207
1208 default:
1209 return CMD_ERROR;
1210 }
1211
1212 switch (mof) {
1213 default: NOT_REACHED();
1214
1215 case MOF_NON_STOP: {
1216 if (!v->IsGroundVehicle()) return CMD_ERROR;
1217
1218 OrderNonStopFlags nonstop_flags = static_cast<OrderNonStopFlags>(data);
1219 if (nonstop_flags == order->GetNonStopType()) return CMD_ERROR;
1220
1221 /* Test for invalid flags. */
1223 if (nonstop_flags.Any()) return CMD_ERROR;
1224 break;
1225 }
1226
1227 case MOF_STOP_LOCATION:
1228 if (v->type != VehicleType::Train) return CMD_ERROR;
1229 if (data >= to_underlying(OrderStopLocation::End)) return CMD_ERROR;
1230 break;
1231
1232 case MOF_UNLOAD: {
1234
1235 OrderUnloadType unload_type = static_cast<OrderUnloadType>(data);
1236 if (unload_type == order->GetUnloadType()) return CMD_ERROR;
1237
1238 /* Test for invalid types. */
1239 switch (unload_type) {
1244 break;
1245
1246 default: return CMD_ERROR;
1247 }
1248 break;
1249 }
1250
1251 case MOF_LOAD: {
1253
1254 OrderLoadType load_type = static_cast<OrderLoadType>(data);
1255 if (load_type == order->GetLoadType()) return CMD_ERROR;
1256
1257 /* Test for invalid types. */
1258 switch (load_type) {
1261 break;
1262
1265 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
1266 break;
1267
1268 default: return CMD_ERROR;
1269 }
1270 break;
1271 }
1272
1273 case MOF_DEPOT_ACTION: {
1274 OrderDepotAction depot_action = static_cast<OrderDepotAction>(data);
1275 if (depot_action >= OrderDepotAction::End) return CMD_ERROR;
1276 /* Check if we are allowed to add unbunching. We are always allowed to remove it. */
1277 if (depot_action == OrderDepotAction::Unbunch) {
1278 /* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */
1279 if (v->HasUnbunchingOrder() && !order->GetDepotActionType().Test(OrderDepotActionFlag::Unbunch)) return CommandCost(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
1280 /* We don't allow unbunching if the vehicle has a conditional order. */
1281 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
1282 /* We don't allow unbunching if the vehicle has a full load order. */
1283 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
1284 }
1285 break;
1286 }
1287
1288 case MOF_COND_VARIABLE: {
1289 OrderConditionVariable cond_variable = static_cast<OrderConditionVariable>(data);
1290 if (cond_variable >= OrderConditionVariable::End) return CMD_ERROR;
1291 if (cond_variable == OrderConditionVariable::DrivingBackwards && v->type != VehicleType::Train) return CMD_ERROR;
1292 break;
1293 }
1294
1295 case MOF_COND_COMPARATOR: {
1296 OrderConditionComparator cond_comparator = static_cast<OrderConditionComparator>(data);
1297 if (cond_comparator >= OrderConditionComparator::End) return CMD_ERROR;
1298 switch (order->GetConditionVariable()) {
1300
1303 if (cond_comparator != OrderConditionComparator::IsTrue && cond_comparator != OrderConditionComparator::IsFalse) return CMD_ERROR;
1304 break;
1305
1306 default:
1307 if (cond_comparator == OrderConditionComparator::IsTrue || cond_comparator == OrderConditionComparator::IsFalse) return CMD_ERROR;
1308 break;
1309 }
1310 break;
1311 }
1312
1313 case MOF_COND_VALUE:
1314 switch (order->GetConditionVariable()) {
1318 return CMD_ERROR;
1319
1323 if (data > 100) return CMD_ERROR;
1324 break;
1325
1326 default:
1327 if (data > 2047) return CMD_ERROR;
1328 break;
1329 }
1330 break;
1331
1333 if (data >= v->GetNumOrders()) return CMD_ERROR;
1334 break;
1335 }
1336
1337 if (flags.Test(DoCommandFlag::Execute)) {
1338 switch (mof) {
1339 case MOF_NON_STOP:
1340 order->SetNonStopType(static_cast<OrderNonStopFlags>(data));
1342 order->SetRefit(CARGO_NO_REFIT);
1345 }
1346 break;
1347
1348 case MOF_STOP_LOCATION:
1349 order->SetStopLocation(static_cast<OrderStopLocation>(data));
1350 break;
1351
1352 case MOF_UNLOAD:
1353 order->SetUnloadType(static_cast<OrderUnloadType>(data));
1354 break;
1355
1356 case MOF_LOAD:
1357 order->SetLoadType(static_cast<OrderLoadType>(data));
1359 break;
1360
1361 case MOF_DEPOT_ACTION: {
1362 switch (static_cast<OrderDepotAction>(data)) {
1365 order->SetDepotActionType(order->GetDepotActionType().Reset({OrderDepotActionFlag::Halt, OrderDepotActionFlag::Unbunch}));
1366 break;
1367
1370 order->SetDepotActionType(order->GetDepotActionType().Reset({OrderDepotActionFlag::Halt, OrderDepotActionFlag::Unbunch}));
1371 order->SetRefit(CARGO_NO_REFIT);
1372 break;
1373
1377 order->SetRefit(CARGO_NO_REFIT);
1378 break;
1379
1383 break;
1384
1385 default:
1386 NOT_REACHED();
1387 }
1388 break;
1389 }
1390
1391 case MOF_COND_VARIABLE: {
1393
1395 switch (order->GetConditionVariable()) {
1398 order->SetConditionValue(0);
1399 break;
1400
1404 order->SetConditionValue(0);
1405 break;
1406
1410 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1411 [[fallthrough]];
1412
1413 default:
1415 break;
1416 }
1417 break;
1418 }
1419
1422 break;
1423
1424 case MOF_COND_VALUE:
1425 order->SetConditionValue(data);
1426 break;
1427
1429 order->SetConditionSkipToOrder(data);
1430 break;
1431
1432 default: NOT_REACHED();
1433 }
1434
1435 /* Update the windows and full load flags, also for vehicles that share the same order list */
1436 Vehicle *u = v->FirstShared();
1438 for (; u != nullptr; u = u->NextShared()) {
1439 /* Toggle u->current_order "Full load" flag if it changed.
1440 * However, as the same flag is used for depot orders, check
1441 * whether we are not going to a depot as there are three
1442 * cases where the full load flag can be active and only
1443 * one case where the flag is used for depot orders. In the
1444 * other cases for the OrderType the flags are not used,
1445 * so do not care and those orders should not be active
1446 * when this function is called.
1447 */
1448 if (sel_ord == u->cur_real_order_index &&
1449 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1450 u->current_order.GetLoadType() != order->GetLoadType()) {
1452 }
1453
1454 /* Unbunching data is no longer valid. */
1456
1458 }
1459 }
1460
1461 return CommandCost();
1462}
1463
1470static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order)
1471{
1472 if (v_new->acache.cached_max_range == 0) return true;
1473 if (v_order->GetNumOrders() == 0) return true;
1474
1475 const OrderList &orderlist = *v_order->orders;
1476 auto orders = orderlist.GetOrders();
1477
1478 /* Iterate over all orders to check the distance between all
1479 * 'goto' orders and their respective next order (of any type). */
1480 for (VehicleOrderID cur = 0; cur < orderlist.GetNumOrders(); ++cur) {
1481 switch (orders[cur].GetType()) {
1482 case OT_GOTO_STATION:
1483 case OT_GOTO_DEPOT:
1484 case OT_GOTO_WAYPOINT:
1485 /* If we don't have a next order, we've reached the end and must check the first order instead. */
1486 if (GetOrderDistance(cur, orderlist.GetNext(cur), v_order) > v_new->acache.cached_max_range_sqr) return false;
1487 break;
1488
1489 default: break;
1490 }
1491 }
1492
1493 return true;
1494}
1495
1505{
1506 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1507 if (dst == nullptr || !IsCompanyBuildableVehicleType(dst) || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1508
1509 CommandCost ret = CheckOwnership(dst->owner);
1510 if (ret.Failed()) return ret;
1511
1512 switch (action) {
1513 case CO_SHARE: {
1514 Vehicle *src = Vehicle::GetIfValid(veh_src);
1515
1516 /* Sanity checks */
1517 if (src == nullptr || !IsCompanyBuildableVehicleType(src) || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1518
1519 ret = CheckOwnership(src->owner);
1520 if (ret.Failed()) return ret;
1521
1522 /* Trucks can't share orders with busses (and visa versa) */
1523 if (src->type == VehicleType::Road && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1524 return CMD_ERROR;
1525 }
1526
1527 /* Is the vehicle already in the shared list? */
1528 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1529
1530 for (const Order &order : src->Orders()) {
1531 if (!OrderGoesToStation(dst, order)) continue;
1532
1533 /* Allow copying unreachable destinations if they were already unreachable for the source.
1534 * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1535 * are temporarily invalid due to reconstruction. */
1536 const Station *st = Station::Get(order.GetDestination().ToStationID());
1537 if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1538 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1539 }
1540 }
1541
1542 /* Check for aircraft range limits. */
1544 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1545 }
1546
1547 if (src->orders == nullptr && !OrderList::CanAllocateItem()) {
1548 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1549 }
1550
1551 if (flags.Test(DoCommandFlag::Execute)) {
1552 /* If the destination vehicle had a OrderList, destroy it.
1553 * We only reset the order indices, if the new orders are obviously different.
1554 * (We mainly do this to keep the order indices valid and in range.) */
1555 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1556
1557 dst->orders = src->orders;
1558
1559 /* Link this vehicle in the shared-list */
1560 dst->AddToShared(src);
1561
1564
1566 }
1567 break;
1568 }
1569
1570 case CO_COPY: {
1571 Vehicle *src = Vehicle::GetIfValid(veh_src);
1572
1573 /* Sanity checks */
1574 if (src == nullptr || !IsCompanyBuildableVehicleType(src) || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1575
1576 ret = CheckOwnership(src->owner);
1577 if (ret.Failed()) return ret;
1578
1579 /* Trucks can't copy all the orders from busses (and visa versa),
1580 * and neither can helicopters and aircraft. */
1581 for (const Order &order : src->Orders()) {
1582 if (!OrderGoesToStation(dst, order)) continue;
1583 Station *st = Station::Get(order.GetDestination().ToStationID());
1584 if (!CanVehicleUseStation(dst, st)) {
1585 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1586 }
1587 }
1588
1589 /* Check for aircraft range limits. */
1591 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1592 }
1593
1594 /* make sure there are orders available */
1596 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1597 }
1598
1599 if (flags.Test(DoCommandFlag::Execute)) {
1600 /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1601 * We only reset the order indices, if the new orders are obviously different.
1602 * (We mainly do this to keep the order indices valid and in range.) */
1603 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1604
1605 std::vector<Order> dst_orders;
1606 for (const Order &order : src->Orders()) {
1607 dst_orders.emplace_back(order);
1608 }
1609
1610 if (dst->orders != nullptr) {
1611 assert(dst->orders->GetNumOrders() == 0);
1612 assert(!dst->orders->IsShared());
1613 delete dst->orders;
1614 }
1615
1617 dst->orders = OrderList::Create(std::move(dst_orders), dst);
1618
1620
1622 }
1623 break;
1624 }
1625
1626 case CO_UNSHARE: return DecloneOrder(dst, flags);
1627 default: return CMD_ERROR;
1628 }
1629
1630 return CommandCost();
1631}
1632
1642{
1643 if (cargo >= NUM_CARGO && cargo != CARGO_NO_REFIT && cargo != CARGO_AUTO_REFIT) return CMD_ERROR;
1644
1645 const Vehicle *v = Vehicle::GetIfValid(veh);
1646 if (v == nullptr || !IsCompanyBuildableVehicleType(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
1647
1649 if (ret.Failed()) return ret;
1650
1651 Order *order = v->GetOrder(order_number);
1652 if (order == nullptr) return CMD_ERROR;
1653
1654 if (!order->IsType(OT_GOTO_DEPOT) && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1655
1656 /* Automatic refit cargo is only supported for goto station orders. */
1657 if (cargo == CARGO_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1658
1659 if (order->GetLoadType() == OrderLoadType::NoLoad) return CMD_ERROR;
1660
1661 if (flags.Test(DoCommandFlag::Execute)) {
1662 order->SetRefit(cargo);
1663
1664 /* Make the depot order an 'always go' order. */
1665 if (cargo != CARGO_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1668 }
1669
1670 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1671 /* Update any possible open window of the vehicle */
1673
1674 /* If the vehicle has already got the order to modify as the current order, then update the current order as well */
1675 if (u->cur_real_order_index == order_number && (!order->IsType(OT_GOTO_DEPOT) || u->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders))) {
1676 u->current_order.SetRefit(cargo);
1677 }
1678 }
1679 }
1680
1681 return CommandCost();
1682}
1683
1684
1689void CheckOrders(const Vehicle *v)
1690{
1691 /* Does the user want us to check things? */
1692 if (_settings_client.gui.order_review_system == OrderReviewSystem::Off) return;
1693
1694 /* Ignore crashed vehicles. */
1695 if (v->vehstatus.Test(VehState::Crashed)) return;
1696
1697 /* Maybe ignore stopped vehicles. */
1698 if (_settings_client.gui.order_review_system == OrderReviewSystem::ExcludeStopped && v->vehstatus.Test(VehState::Stopped)) return;
1699
1700 /* Do nothing if we're not the first vehicle in a share-chain. */
1701 if (v->FirstShared() != v) return;
1702
1703 /* Only check every 20 days, so that we don't flood the message log */
1704 if (v->owner == _local_company && v->day_counter % 20 == 0) {
1705 StringID message = INVALID_STRING_ID;
1706
1707 /* Check the order list */
1708 int n_st = 0;
1709
1710 for (const Order &order : v->Orders()) {
1711 /* Dummy order? */
1712 if (order.IsType(OT_DUMMY)) {
1713 message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1714 break;
1715 }
1716 /* Does station have a load-bay for this vehicle? */
1717 if (order.IsType(OT_GOTO_STATION)) {
1718 const Station *st = Station::Get(order.GetDestination().ToStationID());
1719
1720 n_st++;
1721 if (!CanVehicleUseStation(v, st)) {
1722 message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1723 } else if (v->type == VehicleType::Aircraft &&
1724 (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1726 !_cheats.no_jetcrash.value &&
1727 message == INVALID_STRING_ID) {
1728 message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1729 }
1730 }
1731 }
1732
1733 /* Check if the last and the first order are the same */
1734 if (v->GetNumOrders() > 1) {
1735 auto orders = v->Orders();
1736
1737 if (orders.front().Equals(orders.back())) {
1738 message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1739 }
1740 }
1741
1742 /* Do we only have 1 station in our order list? */
1743 if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1744
1745#ifdef WITH_ASSERT
1746 if (v->orders != nullptr) v->orders->DebugCheckSanity();
1747#endif
1748
1749 /* We don't have a problem */
1750 if (message == INVALID_STRING_ID) return;
1751
1752 AddVehicleAdviceNewsItem(AdviceType::Order, GetEncodedString(message, v->index), v->index);
1753 }
1754}
1755
1764void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1765{
1766 /* Aircraft have StationIDs for depot orders and never use DepotIDs
1767 * This fact is handled specially below
1768 */
1769
1770 /* Go through all vehicles */
1771 for (Vehicle *v : Vehicle::Iterate()) {
1772 if ((v->type == VehicleType::Aircraft && v->current_order.IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : v->current_order.GetType()) == type &&
1773 (!hangar || v->type == VehicleType::Aircraft) && v->current_order.GetDestination() == destination) {
1774 v->current_order.MakeDummy();
1775 InvalidateWindowData(WindowClass::VehicleView, v->index);
1776 }
1777
1778 if (v->orders == nullptr) continue;
1779
1780 /* Clear the order from the order-list */
1781 for (VehicleOrderID id = 0, next_id = 0; id < v->GetNumOrders(); id = next_id) {
1782 next_id = id + 1;
1783 Order *order = v->orders->GetOrderAt(id);
1784 OrderType ot = order->GetType();
1785 if (ot == OT_GOTO_DEPOT && order->GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot)) continue;
1786 if (ot == OT_GOTO_DEPOT && hangar && v->type != VehicleType::Aircraft) continue; // Not an aircraft? Can't have a hangar order.
1787 if (ot == OT_IMPLICIT || (v->type == VehicleType::Aircraft && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1788 if (ot == type && order->GetDestination() == destination) {
1789 /* We want to clear implicit orders, but we don't want to make them
1790 * dummy orders. They should just vanish. Also check the actual order
1791 * type as ot is currently OT_GOTO_STATION. */
1792 if (order->IsType(OT_IMPLICIT)) {
1793 DeleteOrder(v, id);
1794 next_id = id;
1795 continue;
1796 }
1797
1798 /* Clear wait time */
1799 v->orders->UpdateTotalDuration(-order->GetWaitTime());
1800 if (order->IsWaitTimetabled()) {
1801 v->orders->UpdateTimetableDuration(-order->GetTimetabledWait());
1802 order->SetWaitTimetabled(false);
1803 }
1804 order->SetWaitTime(0);
1805
1806 /* Clear order, preserving travel time */
1807 bool travel_timetabled = order->IsTravelTimetabled();
1808 order->MakeDummy();
1809 order->SetTravelTimetabled(travel_timetabled);
1810
1811 for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1812 /* In GUI, simulate by removing the order and adding it back */
1815 }
1816 }
1817 }
1818 }
1819
1820 OrderBackup::RemoveOrder(type, destination, hangar);
1821}
1822
1828{
1829 return std::ranges::any_of(this->Orders(), [](const Order &order) { return order.IsType(OT_GOTO_DEPOT); });
1830}
1831
1841void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1842{
1844
1845 if (v->IsOrderListShared()) {
1846 /* Remove ourself from the shared order list. */
1847 v->RemoveFromShared();
1848 v->orders = nullptr;
1849 } else if (v->orders != nullptr) {
1850 /* Remove the orders */
1851 v->orders->FreeChain(keep_orderlist);
1852 if (!keep_orderlist) v->orders = nullptr;
1853 }
1854
1855 /* Unbunching data is no longer valid. */
1857
1858 if (reset_order_indices) {
1860 if (v->current_order.IsType(OT_LOADING)) {
1862 }
1863 }
1864}
1865
1873uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
1874{
1875 /* Service intervals are in percents. */
1876 if (ispercent) return Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT);
1877
1878 /* Service intervals are in minutes. */
1879 if (TimerGameEconomy::UsingWallclockUnits(_game_mode == GameMode::Menu)) return Clamp(interval, MIN_SERVINT_MINUTES, MAX_SERVINT_MINUTES);
1880
1881 /* Service intervals are in days. */
1882 return Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1883}
1884
1892static bool CheckForValidOrders(const Vehicle *v)
1893{
1894 /* Check if vehicle has any valid orders.
1895 * Function is only called for aircraft, no type check needed. */
1896 return std::ranges::any_of(v->Orders(), [](const Order &order) {
1897 return order.IsGotoOrder() && (!order.IsType(OT_GOTO_DEPOT) || !order.GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot));
1898 });
1899}
1900
1908static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1909{
1910 switch (occ) {
1911 case OrderConditionComparator::Equal: return variable == value;
1912 case OrderConditionComparator::NotEqual: return variable != value;
1913 case OrderConditionComparator::LessThan: return variable < value;
1914 case OrderConditionComparator::LessThanOrEqual: return variable <= value;
1915 case OrderConditionComparator::MoreThan: return variable > value;
1916 case OrderConditionComparator::MoreThanOrEqual: return variable >= value;
1917 case OrderConditionComparator::IsTrue: return variable != 0;
1918 case OrderConditionComparator::IsFalse: return variable == 0;
1919 default: NOT_REACHED();
1920 }
1921}
1922
1923static bool OrderConditionCompare(OrderConditionComparator occ, ConvertibleThroughBase auto variable, int value)
1924{
1925 return OrderConditionCompare(occ, variable.base(), value);
1926}
1927
1935{
1936 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1937
1938 bool skip_order = false;
1940 uint16_t value = order->GetConditionValue();
1941
1942 switch (order->GetConditionVariable()) {
1943 case OrderConditionVariable::LoadPercentage: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1944 case OrderConditionVariable::Reliability: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
1946 case OrderConditionVariable::MaxSpeed: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1948 case OrderConditionVariable::RequiresService: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
1949 case OrderConditionVariable::Unconditionally: skip_order = true; break;
1951 case OrderConditionVariable::DrivingBackwards: skip_order = OrderConditionCompare(occ, v->IsDrivingBackwards(), value); break;
1952 default: NOT_REACHED();
1953 }
1954
1955 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1956}
1957
1966bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
1967{
1968 if (conditional_depth > v->GetNumOrders()) {
1969 v->current_order.Free();
1971 return false;
1972 }
1973
1974 switch (order->GetType()) {
1975 case OT_GOTO_STATION:
1976 v->SetDestTile(v->GetOrderStationLocation(order->GetDestination().ToStationID()));
1977 return true;
1978
1979 case OT_GOTO_DEPOT:
1981 assert(!pbs_look_ahead);
1982 UpdateVehicleTimetable(v, true);
1984 break;
1985 }
1986
1988 /* If the vehicle can't find its destination, delay its next search.
1989 * In case many vehicles are in this state, use the vehicle index to spread out pathfinder calls. */
1990 if (v->dest_tile == INVALID_TILE && TimerGameEconomy::date_fract != (v->index % Ticks::DAY_TICKS)) break;
1991
1992 /* We need to search for the nearest depot (hangar). */
1993 ClosestDepot closest_depot = v->FindClosestDepot();
1994
1995 if (closest_depot.found) {
1996 /* PBS reservations cannot reverse */
1997 if (pbs_look_ahead && closest_depot.reverse) return false;
1998
1999 v->SetDestTile(closest_depot.location);
2000 v->current_order.SetDestination(closest_depot.destination);
2001
2002 /* If there is no depot in front, reverse automatically (trains only) */
2003 if (v->type == VehicleType::Train && closest_depot.reverse) Command<Commands::ReverseTrainDirection>::Do(DoCommandFlag::Execute, v->index, false);
2004
2005 if (v->type == VehicleType::Aircraft) {
2006 Aircraft *a = Aircraft::From(v);
2007 if (a->state == FLYING && a->targetairport != closest_depot.destination) {
2008 /* The aircraft is now heading for a different hangar than the next in the orders */
2010 }
2011 }
2012 return true;
2013 }
2014
2015 /* If there is no depot, we cannot help PBS either. */
2016 if (pbs_look_ahead) return false;
2017
2018 UpdateVehicleTimetable(v, true);
2020 } else {
2021 if (v->type != VehicleType::Aircraft) {
2022 v->SetDestTile(Depot::Get(order->GetDestination().ToStationID())->xy);
2023 } else {
2024 Aircraft *a = Aircraft::From(v);
2025 DestinationID destination = a->current_order.GetDestination();
2026 if (a->targetairport != destination) {
2027 /* The aircraft is now heading for a different hangar than the next in the orders */
2028 a->SetDestTile(a->GetOrderStationLocation(destination.ToStationID()));
2029 }
2030 }
2031 return true;
2032 }
2033 break;
2034
2035 case OT_GOTO_WAYPOINT:
2036 v->SetDestTile(Waypoint::Get(order->GetDestination().ToStationID())->xy);
2037 return true;
2038
2039 case OT_CONDITIONAL: {
2040 assert(!pbs_look_ahead);
2041 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2042 if (next_order != INVALID_VEH_ORDER_ID) {
2043 /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2044 * cur_real_order_index might come after next_order. */
2045 UpdateVehicleTimetable(v, false);
2049
2050 /* Disable creation of implicit orders.
2051 * When inserting them we do not know that we would have to make the conditional orders point to them. */
2052 if (v->IsGroundVehicle()) {
2054 }
2055 } else {
2056 UpdateVehicleTimetable(v, true);
2058 }
2059 break;
2060 }
2061
2062 default:
2064 return false;
2065 }
2066
2067 assert(v->cur_implicit_order_index < v->GetNumOrders());
2068 assert(v->cur_real_order_index < v->GetNumOrders());
2069
2070 /* Get the current order */
2071 order = v->GetOrder(v->cur_real_order_index);
2072 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2073 assert(v->GetNumManualOrders() == 0);
2074 order = nullptr;
2075 }
2076
2077 if (order == nullptr) {
2078 v->current_order.Free();
2080 return false;
2081 }
2082
2083 v->current_order = *order;
2084 return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2085}
2086
2095{
2096 switch (v->current_order.GetType()) {
2097 case OT_GOTO_DEPOT:
2098 /* Let a depot order in the orderlist interrupt. */
2100 break;
2101
2102 case OT_LOADING:
2103 return false;
2104
2105 case OT_LEAVESTATION:
2106 if (v->type != VehicleType::Aircraft) return false;
2107 break;
2108
2109 default: break;
2110 }
2111
2119 bool may_reverse = v->current_order.IsType(OT_NOTHING);
2120 Vehicle *moving_front = v->GetMovingFront();
2121
2122 /* Check if we've reached a 'via' destination. */
2123 if (((v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetNonStopType().Test(OrderNonStopFlag::GoVia)) || v->current_order.IsType(OT_GOTO_WAYPOINT)) &&
2124 IsTileType(moving_front->tile, TileType::Station) &&
2125 v->current_order.GetDestination() == GetStationIndex(moving_front->tile)) {
2127 /* We set the last visited station here because we do not want
2128 * the train to stop at this 'via' station if the next order
2129 * is a no-non-stop order; in that case not setting the last
2130 * visited station will cause the vehicle to still stop. */
2131 v->last_station_visited = v->current_order.GetDestination().ToStationID();
2132 UpdateVehicleTimetable(v, true);
2134 }
2135
2136 /* Get the current order */
2139
2140 const Order *order = v->GetOrder(v->cur_real_order_index);
2141 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2142 assert(v->GetNumManualOrders() == 0);
2143 order = nullptr;
2144 }
2145
2146 /* If no order, do nothing. */
2147 if (order == nullptr || (v->type == VehicleType::Aircraft && !CheckForValidOrders(v))) {
2148 if (v->type == VehicleType::Aircraft) {
2149 /* Aircraft do something vastly different here, so handle separately */
2150 HandleMissingAircraftOrders(Aircraft::From(v));
2151 return false;
2152 }
2153
2154 v->current_order.Free();
2156 return false;
2157 }
2158
2159 /* If it is unchanged, keep it. */
2160 if (order->Equals(v->current_order) && (v->type == VehicleType::Aircraft || v->dest_tile != INVALID_TILE) &&
2161 (v->type != VehicleType::Ship || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination().ToStationID())->ship_station.tile != INVALID_TILE)) {
2162 return false;
2163 }
2164
2165 /* Otherwise set it, and determine the destination tile. */
2166 v->current_order = *order;
2167
2169 switch (v->type) {
2170 default:
2171 NOT_REACHED();
2172
2173 case VehicleType::Road:
2174 case VehicleType::Train:
2175 break;
2176
2178 case VehicleType::Ship:
2180 break;
2181 }
2182
2183 return UpdateOrderDest(v, order) && may_reverse;
2184}
2185
2193bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2194{
2195 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2196
2197 return (!this->IsType(OT_GOTO_DEPOT) || this->GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) &&
2198 v->last_station_visited != station && // Do stop only when we've not just been there
2199 /* Finally do stop when there is no non-stop flag set for this type of station. */
2201}
2202
2203bool Order::CanLoadOrUnload() const
2204{
2205 return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2207 (this->GetLoadType() != OrderLoadType::NoLoad ||
2209}
2210
2219bool Order::CanLeaveWithCargo(bool has_cargo) const
2220{
2221 return this->GetLoadType() != OrderLoadType::NoLoad || (has_cargo &&
2224}
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:50
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.
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: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:58
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:87
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:47
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:73
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:98
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:748
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:2371
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:3020
bool HasUnbunchingOrder() const
Check if the current vehicle has an unbunching order.
Definition vehicle.cpp:2507
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:2487
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:3043
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:210
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition vehicle.cpp:2498
GroundVehicleFlags & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition vehicle.cpp:3238
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:2189
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.
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:3157
uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1503
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3111
@ 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:3223
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:3315
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3193
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:3333