OpenTTD Source 20250527-master-g808af15975
order_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "debug.h"
12#include "command_func.h"
13#include "company_func.h"
14#include "news_func.h"
15#include "strings_func.h"
16#include "timetable.h"
17#include "vehicle_func.h"
18#include "depot_base.h"
19#include "core/pool_func.hpp"
20#include "core/random_func.hpp"
21#include "aircraft.h"
22#include "roadveh.h"
23#include "station_base.h"
24#include "waypoint_base.h"
25#include "company_base.h"
26#include "order_backup.h"
27#include "cheat_type.h"
28#include "order_cmd.h"
29#include "train_cmd.h"
30
31#include "table/strings.h"
32
33#include "safeguards.h"
34
35/* DestinationID must be at least as large as every these below, because it can
36 * be any of them
37 */
38static_assert(sizeof(DestinationID) >= sizeof(DepotID));
39static_assert(sizeof(DestinationID) >= sizeof(StationID));
40
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
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
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
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() & ODATFB_NEAREST_DEPOT) != 0 ||
168 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
169 return this->GetDepotOrderType() == other.GetDepotOrderType() &&
170 (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
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() & OUFB_UNLOAD) SetBit(order, 5);
187 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
189 order |= GB(this->GetDestination().value, 0, 8) << 8;
190 break;
191 case OT_GOTO_DEPOT:
192 if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) 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->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
198 /* If both "no load" and "no unload" are set, return nothing order instead */
199 if ((this->GetLoadType() & OLFB_NO_LOAD) && (this->GetUnloadType() & OUFB_NO_UNLOAD)) {
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{
217
218 if (data != 0) {
219 /* Calls SetDirty() too */
222 return;
223 }
224
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
255{
256 this->first_shared = v;
257
258 this->num_manual_orders = 0;
259 this->num_vehicles = 1;
260 this->timetable_duration = 0;
261
262 for (const Order &o : this->orders) {
263 if (!o.IsType(OT_IMPLICIT)) ++this->num_manual_orders;
264 this->total_duration += o.GetWaitTime() + o.GetTravelTime();
265 }
266
268
269 for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
270 ++this->num_vehicles;
271 this->first_shared = u;
272 }
273
274 for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
275}
276
282{
283 this->timetable_duration = 0;
284 for (const Order &o : this->orders) {
285 this->timetable_duration += o.GetTimetabledWait() + o.GetTimetabledTravel();
286 }
287}
288
294void OrderList::FreeChain(bool keep_orderlist)
295{
296 /* We can visit oil rigs and buoys that are not our own. They will be shown in
297 * the list of stations. So, we need to invalidate that window if needed. */
298 for (Order &order: this->orders) {
299 if (order.IsType(OT_GOTO_STATION) || order.IsType(OT_GOTO_WAYPOINT)) {
300 BaseStation *bs = BaseStation::GetIfValid(order.GetDestination().ToStationID());
301 if (bs != nullptr && bs->owner == OWNER_NONE) {
303 break;
304 }
305 }
306 }
307
308 if (keep_orderlist) {
309 this->orders.clear();
310 this->num_manual_orders = 0;
311 this->timetable_duration = 0;
312 } else {
313 delete this;
314 }
315}
316
329{
330 if (hops > this->GetNumOrders() || next >= this->GetNumOrders()) return INVALID_VEH_ORDER_ID;
331
332 const Order &order_next = this->orders[next];
333 if (order_next.IsType(OT_CONDITIONAL)) {
334 if (order_next.GetConditionVariable() != OCV_UNCONDITIONALLY) return next;
335
336 /* We can evaluate trivial conditions right away. They're conceptually
337 * the same as regular order progression. */
338 return this->GetNextDecisionNode(
339 order_next.GetConditionSkipToOrder(),
340 hops + 1);
341 }
342
343 if (order_next.IsType(OT_GOTO_DEPOT)) {
344 if ((order_next.GetDepotActionType() & ODATFB_HALT) != 0) return INVALID_VEH_ORDER_ID;
345 if (order_next.IsRefit()) return next;
346 }
347
348 if (!order_next.CanLoadOrUnload()) {
349 return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
350 }
351
352 return next;
353}
354
365{
366 VehicleOrderID next = first;
367 if (first == INVALID_VEH_ORDER_ID) {
368 next = v->cur_implicit_order_index;
369 if (next >= this->GetNumOrders()) {
370 next = this->GetFirstOrder();
371 if (next == INVALID_VEH_ORDER_ID) return StationID::Invalid().base();
372 } else {
373 /* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list.
374 * As the given "next" is already valid and a station in the list, we
375 * don't have to check for INVALID_VEH_ORDER_ID here. */
376 next = this->GetNext(next);
377 assert(next != INVALID_VEH_ORDER_ID);
378 }
379 }
380
381 auto orders = v->Orders();
382 do {
383 next = this->GetNextDecisionNode(next, ++hops);
384
385 /* Resolve possibly nested conditionals by estimation. */
386 while (next != INVALID_VEH_ORDER_ID && orders[next].IsType(OT_CONDITIONAL)) {
387 /* We return both options of conditional orders. */
388 VehicleOrderID skip_to = this->GetNextDecisionNode(orders[next].GetConditionSkipToOrder(), hops);
389 VehicleOrderID advance = this->GetNextDecisionNode(this->GetNext(next), hops);
390 if (advance == INVALID_VEH_ORDER_ID || advance == first || skip_to == advance) {
391 next = (skip_to == first) ? INVALID_VEH_ORDER_ID : skip_to;
392 } else if (skip_to == INVALID_VEH_ORDER_ID || skip_to == first) {
393 next = (advance == first) ? INVALID_VEH_ORDER_ID : advance;
394 } else {
395 StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
396 StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
397 while (!st2.IsEmpty()) st1.Push(st2.Pop());
398 return st1;
399 }
400 ++hops;
401 }
402
403 /* Don't return a next stop if the vehicle has to unload everything. */
404 if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) &&
405 orders[next].GetDestination() == v->last_station_visited &&
406 (orders[next].GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
407 return StationID::Invalid().base();
408 }
409 } while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited);
410
411 return orders[next].GetDestination().ToStationID().base();
412}
413
420{
421 auto it = std::ranges::next(std::begin(this->orders), index, std::end(this->orders));
422 auto new_order = this->orders.emplace(it, std::move(order));
423
424 if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
425 this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
426 this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
427
428 /* We can visit oil rigs and buoys that are not our own. They will be shown in
429 * the list of stations. So, we need to invalidate that window if needed. */
430 if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
431 BaseStation *bs = BaseStation::Get(new_order->GetDestination().ToStationID());
433 }
434}
435
436
442{
443 auto to_remove = std::ranges::next(std::begin(this->orders), index, std::end(this->orders));
444 if (to_remove == std::end(this->orders)) return;
445
446 if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
447
448 this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
449 this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
450
451 this->orders.erase(to_remove);
452}
453
460{
461 if (from == to) return;
462 if (from >= this->GetNumOrders()) return;
463 if (to >= this->GetNumOrders()) return;
464
465 auto it = std::begin(this->orders);
466 if (from < to) {
467 std::rotate(it + from, it + from + 1, it + to + 1);
468 } else {
469 std::rotate(it + to, it + from, it + from + 1);
470 }
471}
472
479{
480 --this->num_vehicles;
481 if (v == this->first_shared) this->first_shared = v->NextShared();
482}
483
489{
490 for (const Order &o : this->orders) {
491 /* Implicit orders are, by definition, not timetabled. */
492 if (o.IsType(OT_IMPLICIT)) continue;
493 if (!o.IsCompletelyTimetabled()) return false;
494 }
495 return true;
496}
497
498#ifdef WITH_ASSERT
502void OrderList::DebugCheckSanity() const
503{
504 VehicleOrderID check_num_orders = 0;
505 VehicleOrderID check_num_manual_orders = 0;
506 uint check_num_vehicles = 0;
507 TimerGameTick::Ticks check_timetable_duration = 0;
508 TimerGameTick::Ticks check_total_duration = 0;
509
510 Debug(misc, 6, "Checking OrderList {} for sanity...", this->index);
511
512 for (const Order &o : this->orders) {
513 ++check_num_orders;
514 if (!o.IsType(OT_IMPLICIT)) ++check_num_manual_orders;
515 check_timetable_duration += o.GetTimetabledWait() + o.GetTimetabledTravel();
516 check_total_duration += o.GetWaitTime() + o.GetTravelTime();
517 }
518 assert(this->GetNumOrders() == check_num_orders);
519 assert(this->num_manual_orders == check_num_manual_orders);
520 assert(this->timetable_duration == check_timetable_duration);
521 assert(this->total_duration == check_total_duration);
522
523 for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
524 ++check_num_vehicles;
525 assert(v->orders == this);
526 }
527 assert(this->num_vehicles == check_num_vehicles);
528 Debug(misc, 6, "... detected {} orders ({} manual), {} vehicles, {} timetabled, {} total",
529 (uint)this->GetNumOrders(), (uint)this->num_manual_orders,
531}
532#endif
533
541static inline bool OrderGoesToStation(const Vehicle *v, const Order &o)
542{
543 return o.IsType(OT_GOTO_STATION) ||
544 (v->type == VEH_AIRCRAFT && o.IsType(OT_GOTO_DEPOT) && o.GetDestination() != StationID::Invalid());
545}
546
553static void DeleteOrderWarnings(const Vehicle *v)
554{
556}
557
564TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
565{
566 switch (this->GetType()) {
567 case OT_GOTO_WAYPOINT:
568 case OT_GOTO_STATION:
569 case OT_IMPLICIT:
570 if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination().ToStationID())->airport.tile;
571 return BaseStation::Get(this->GetDestination().ToStationID())->xy;
572
573 case OT_GOTO_DEPOT:
574 if (this->GetDestination() == DepotID::Invalid()) return INVALID_TILE;
575 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination().ToStationID())->xy : Depot::Get(this->GetDestination().ToDepotID())->xy;
576
577 default:
578 return INVALID_TILE;
579 }
580}
581
591uint GetOrderDistance(VehicleOrderID prev, VehicleOrderID cur, const Vehicle *v, int conditional_depth)
592{
593 assert(v->orders != nullptr);
594 const OrderList &orderlist = *v->orders;
595 auto orders = orderlist.GetOrders();
596
597 if (orders[cur].IsType(OT_CONDITIONAL)) {
598 if (conditional_depth > v->GetNumOrders()) return 0;
599
600 conditional_depth++;
601
602 int dist1 = GetOrderDistance(prev, orders[cur].GetConditionSkipToOrder(), v, conditional_depth);
603 int dist2 = GetOrderDistance(prev, orderlist.GetNext(cur), v, conditional_depth);
604 return std::max(dist1, dist2);
605 }
606
607 TileIndex prev_tile = orders[prev].GetLocation(v, true);
608 TileIndex cur_tile = orders[cur].GetLocation(v, true);
609 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
610 return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
611}
612
624{
626 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
627
629 if (ret.Failed()) return ret;
630
631 /* Validate properties we don't want to have different from default as they are set by other commands. */
632 if (new_order.GetRefitCargo() != CARGO_NO_REFIT || new_order.GetWaitTime() != 0 || new_order.GetTravelTime() != 0 || new_order.GetMaxSpeed() != UINT16_MAX) return CMD_ERROR;
633
634 /* Check if the inserted order is to the correct destination (owner, type),
635 * and has the correct flags if any */
636 switch (new_order.GetType()) {
637 case OT_GOTO_STATION: {
638 const Station *st = Station::GetIfValid(new_order.GetDestination().ToStationID());
639 if (st == nullptr) return CMD_ERROR;
640
641 if (st->owner != OWNER_NONE) {
642 ret = CheckOwnership(st->owner);
643 if (ret.Failed()) return ret;
644 }
645
646 if (!CanVehicleUseStation(v, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, GetVehicleCannotUseStationReason(v, st));
647 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
648 if (!CanVehicleUseStation(u, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER_SHARED, GetVehicleCannotUseStationReason(u, st));
649 }
650
651 /* Non stop only allowed for ground vehicles. */
652 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
653
654 /* Filter invalid load/unload types. */
655 switch (new_order.GetLoadType()) {
657 case OLFB_NO_LOAD:
658 break;
659
660 case OLFB_FULL_LOAD:
662 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
663 break;
664
665 default:
666 return CMD_ERROR;
667 }
668 switch (new_order.GetUnloadType()) {
670 default: return CMD_ERROR;
671 }
672
673 /* Filter invalid stop locations */
674 switch (new_order.GetStopLocation()) {
677 if (v->type != VEH_TRAIN) return CMD_ERROR;
678 [[fallthrough]];
679
681 break;
682
683 default:
684 return CMD_ERROR;
685 }
686
687 break;
688 }
689
690 case OT_GOTO_DEPOT: {
691 if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
692 if (v->type == VEH_AIRCRAFT) {
693 const Station *st = Station::GetIfValid(new_order.GetDestination().ToStationID());
694
695 if (st == nullptr) return CMD_ERROR;
696
697 ret = CheckOwnership(st->owner);
698 if (ret.Failed()) return ret;
699
700 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
701 return CMD_ERROR;
702 }
703 } else {
704 const Depot *dp = Depot::GetIfValid(new_order.GetDestination().ToDepotID());
705
706 if (dp == nullptr) return CMD_ERROR;
707
708 ret = CheckOwnership(GetTileOwner(dp->xy));
709 if (ret.Failed()) return ret;
710
711 switch (v->type) {
712 case VEH_TRAIN:
713 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
714 break;
715
716 case VEH_ROAD:
717 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
718 break;
719
720 case VEH_SHIP:
721 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
722 break;
723
724 default: return CMD_ERROR;
725 }
726 }
727 }
728
729 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
730 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
732
733 /* Vehicles cannot have a "service if needed" order that also has a depot action. */
734 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & (ODATFB_HALT | ODATFB_UNBUNCH))) return CMD_ERROR;
735
736 /* Check if we're allowed to have a new unbunching order. */
737 if ((new_order.GetDepotActionType() & ODATFB_UNBUNCH)) {
738 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
739 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
740 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
741 }
742 break;
743 }
744
745 case OT_GOTO_WAYPOINT: {
746 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination().ToStationID());
747 if (wp == nullptr) return CMD_ERROR;
748
749 switch (v->type) {
750 default: return CMD_ERROR;
751
752 case VEH_TRAIN: {
753 if (!wp->facilities.Test(StationFacility::Train)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_RAIL_WAYPOINT);
754
755 ret = CheckOwnership(wp->owner);
756 if (ret.Failed()) return ret;
757 break;
758 }
759
760 case VEH_ROAD: {
761 if (!wp->facilities.Test(StationFacility::BusStop) && !wp->facilities.Test(StationFacility::TruckStop)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_ROAD_WAYPOINT);
762
763 ret = CheckOwnership(wp->owner);
764 if (ret.Failed()) return ret;
765 break;
766 }
767
768 case VEH_SHIP:
769 if (!wp->facilities.Test(StationFacility::Dock)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_BUOY);
770 if (wp->owner != OWNER_NONE) {
771 ret = CheckOwnership(wp->owner);
772 if (ret.Failed()) return ret;
773 }
774 break;
775 }
776
777 /* Order flags can be any of the following for waypoints:
778 * [non-stop]
779 * non-stop orders (if any) are only valid for trains and road vehicles */
780 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
781 break;
782 }
783
784 case OT_CONDITIONAL: {
785 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
786 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
787 if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
788 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_CONDITIONAL);
789
791 if (occ >= OCC_END) return CMD_ERROR;
792 switch (new_order.GetConditionVariable()) {
794 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
795 break;
796
798 if (occ != OCC_EQUALS) return CMD_ERROR;
799 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
800 break;
801
803 case OCV_RELIABILITY:
804 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
805 [[fallthrough]];
806
807 default:
808 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
809 break;
810 }
811 break;
812 }
813
814 default: return CMD_ERROR;
815 }
816
817 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
818
819 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return CommandCost(STR_ERROR_TOO_MANY_ORDERS);
820 if (v->orders == nullptr && !OrderList::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
821
822 if (flags.Test(DoCommandFlag::Execute)) {
823 InsertOrder(v, Order(new_order), sel_ord);
824 }
825
826 return CommandCost();
827}
828
835void InsertOrder(Vehicle *v, Order &&new_o, VehicleOrderID sel_ord)
836{
837 /* Create new order and link in list */
838 if (v->orders == nullptr) {
839 v->orders = new OrderList(std::move(new_o), v);
840 } else {
841 v->orders->InsertOrderAt(std::move(new_o), sel_ord);
842 }
843
844 Vehicle *u = v->FirstShared();
846 for (; u != nullptr; u = u->NextShared()) {
847 assert(v->orders == u->orders);
848
849 /* If there is added an order before the current one, we need
850 * to update the selected order. We do not change implicit/real order indices though.
851 * If the new order is between the current implicit order and real order, the implicit order will
852 * later skip the inserted order. */
853 if (sel_ord <= u->cur_real_order_index) {
854 uint cur = u->cur_real_order_index + 1;
855 /* Check if we don't go out of bound */
856 if (cur < u->GetNumOrders()) {
857 u->cur_real_order_index = cur;
858 }
859 }
860 if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
861 /* We are inserting an order just before the current implicit order.
862 * We do not know whether we will reach current implicit or the newly inserted order first.
863 * So, disable creation of implicit orders until we are on track again. */
864 uint16_t &gv_flags = u->GetGroundVehicleFlags();
866 }
867 if (sel_ord <= u->cur_implicit_order_index) {
868 uint cur = u->cur_implicit_order_index + 1;
869 /* Check if we don't go out of bound */
870 if (cur < u->GetNumOrders()) {
872 }
873 }
874 /* Unbunching data is no longer valid. */
876
877 /* Update any possible open window of the vehicle */
878 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
879 }
880
881 /* As we insert an order, the order to skip to will be 'wrong'. */
882 VehicleOrderID cur_order_id = 0;
883 for (Order &order : v->Orders()) {
884 if (order.IsType(OT_CONDITIONAL)) {
885 VehicleOrderID order_id = order.GetConditionSkipToOrder();
886 if (order_id >= sel_ord) {
887 order.SetConditionSkipToOrder(order_id + 1);
888 }
889 if (order_id == cur_order_id) {
890 order.SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
891 }
892 }
893 cur_order_id++;
894 }
895
896 /* Make sure to rebuild the whole list */
898}
899
914
923{
924 Vehicle *v = Vehicle::GetIfValid(veh_id);
925
926 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
927
929 if (ret.Failed()) return ret;
930
931 /* If we did not select an order, we maybe want to de-clone the orders */
932 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
933
934 if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
935
936 if (flags.Test(DoCommandFlag::Execute)) DeleteOrder(v, sel_ord);
937 return CommandCost();
938}
939
945{
946 assert(v->current_order.IsType(OT_LOADING));
947 /* NON-stop flag is misused to see if a train is in a station that is
948 * on its order list or not */
950 /* When full loading, "cancel" that order so the vehicle doesn't
951 * stay indefinitely at this station anymore. */
953}
954
961{
962 v->orders->DeleteOrderAt(sel_ord);
963
964 Vehicle *u = v->FirstShared();
966 for (; u != nullptr; u = u->NextShared()) {
967 assert(v->orders == u->orders);
968
969 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
971 }
972
973 if (sel_ord < u->cur_real_order_index) {
975 } else if (sel_ord == u->cur_real_order_index) {
977 }
978
979 if (sel_ord < u->cur_implicit_order_index) {
981 } else if (sel_ord == u->cur_implicit_order_index) {
982 /* Make sure the index is valid */
984
985 /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
989 }
990 }
991 /* Unbunching data is no longer valid. */
993
994 /* Update any possible open window of the vehicle */
995 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
996 }
997
998 /* As we delete an order, the order to skip to will be 'wrong'. */
999 VehicleOrderID cur_order_id = 0;
1000 for (Order &order : v->Orders()) {
1001 if (order.IsType(OT_CONDITIONAL)) {
1002 VehicleOrderID order_id = order.GetConditionSkipToOrder();
1003 if (order_id >= sel_ord) {
1004 order_id = std::max(order_id - 1, 0);
1005 }
1006 if (order_id == cur_order_id) {
1007 order_id = (order_id + 1) % v->GetNumOrders();
1008 }
1009 order.SetConditionSkipToOrder(order_id);
1010 }
1011 cur_order_id++;
1012 }
1013
1015}
1016
1025{
1026 Vehicle *v = Vehicle::GetIfValid(veh_id);
1027
1028 if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1029
1031 if (ret.Failed()) return ret;
1032
1033 if (flags.Test(DoCommandFlag::Execute)) {
1034 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1035
1038
1039 /* Unbunching data is no longer valid. */
1041
1043
1044 /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1047 }
1048
1049 return CommandCost();
1050}
1051
1063{
1064 Vehicle *v = Vehicle::GetIfValid(veh);
1065 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1066
1068 if (ret.Failed()) return ret;
1069
1070 /* Don't make senseless movements */
1071 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1072 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1073
1074 Order *moving_one = v->GetOrder(moving_order);
1075 /* Don't move an empty order */
1076 if (moving_one == nullptr) return CMD_ERROR;
1077
1078 if (flags.Test(DoCommandFlag::Execute)) {
1079 v->orders->MoveOrder(moving_order, target_order);
1080
1081 /* Update shared list */
1082 Vehicle *u = v->FirstShared();
1083
1085
1086 for (; u != nullptr; u = u->NextShared()) {
1087 /* Update the current order.
1088 * There are multiple ways to move orders, which result in cur_implicit_order_index
1089 * and cur_real_order_index to not longer make any sense. E.g. moving another
1090 * real order between them.
1091 *
1092 * Basically one could choose to preserve either of them, but not both.
1093 * While both ways are suitable in this or that case from a human point of view, neither
1094 * of them makes really sense.
1095 * However, from an AI point of view, preserving cur_real_order_index is the most
1096 * predictable and transparent behaviour.
1097 *
1098 * With that decision it basically does not matter what we do to cur_implicit_order_index.
1099 * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1100 * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1101 * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1102 */
1103 if (u->cur_real_order_index == moving_order) {
1104 u->cur_real_order_index = target_order;
1105 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1107 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1109 }
1110
1111 if (u->cur_implicit_order_index == moving_order) {
1112 u->cur_implicit_order_index = target_order;
1113 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1115 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1117 }
1118 /* Unbunching data is no longer valid. */
1120
1121
1122 assert(v->orders == u->orders);
1123 /* Update any possible open window of the vehicle */
1124 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1125 }
1126
1127 /* As we move an order, the order to skip to will be 'wrong'. */
1128 for (Order &order : v->Orders()) {
1129 if (order.IsType(OT_CONDITIONAL)) {
1130 VehicleOrderID order_id = order.GetConditionSkipToOrder();
1131 if (order_id == moving_order) {
1132 order_id = target_order;
1133 } else if (order_id > moving_order && order_id <= target_order) {
1134 order_id--;
1135 } else if (order_id < moving_order && order_id >= target_order) {
1136 order_id++;
1137 }
1138 order.SetConditionSkipToOrder(order_id);
1139 }
1140 }
1141
1142 /* Make sure to rebuild the whole list */
1144 }
1145
1146 return CommandCost();
1147}
1148
1161{
1162 if (mof >= MOF_END) return CMD_ERROR;
1163
1164 Vehicle *v = Vehicle::GetIfValid(veh);
1165 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1166
1168 if (ret.Failed()) return ret;
1169
1170 /* Is it a valid order? */
1171 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1172
1173 Order *order = v->GetOrder(sel_ord);
1174 assert(order != nullptr);
1175 switch (order->GetType()) {
1176 case OT_GOTO_STATION:
1177 if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1178 break;
1179
1180 case OT_GOTO_DEPOT:
1181 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1182 break;
1183
1184 case OT_GOTO_WAYPOINT:
1185 if (mof != MOF_NON_STOP) return CMD_ERROR;
1186 break;
1187
1188 case OT_CONDITIONAL:
1189 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1190 break;
1191
1192 default:
1193 return CMD_ERROR;
1194 }
1195
1196 switch (mof) {
1197 default: NOT_REACHED();
1198
1199 case MOF_NON_STOP:
1200 if (!v->IsGroundVehicle()) return CMD_ERROR;
1201 if (data >= ONSF_END) return CMD_ERROR;
1202 if (data == order->GetNonStopType()) return CMD_ERROR;
1203 break;
1204
1205 case MOF_STOP_LOCATION:
1206 if (v->type != VEH_TRAIN) return CMD_ERROR;
1207 if (data >= OSL_END) return CMD_ERROR;
1208 break;
1209
1210 case MOF_UNLOAD:
1212 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
1213 /* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
1214 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
1215 if (data == order->GetUnloadType()) return CMD_ERROR;
1216 break;
1217
1218 case MOF_LOAD:
1220 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
1221 if (data == order->GetLoadType()) return CMD_ERROR;
1222 if ((data & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) && v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
1223 break;
1224
1225 case MOF_DEPOT_ACTION:
1226 if (data >= DA_END) return CMD_ERROR;
1227 /* Check if we are allowed to add unbunching. We are always allowed to remove it. */
1228 if (data == DA_UNBUNCH) {
1229 /* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */
1230 if (v->HasUnbunchingOrder() && !(order->GetDepotActionType() & ODATFB_UNBUNCH)) return CommandCost(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
1231 /* We don't allow unbunching if the vehicle has a conditional order. */
1232 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
1233 /* We don't allow unbunching if the vehicle has a full load order. */
1234 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
1235 }
1236 break;
1237
1238 case MOF_COND_VARIABLE:
1239 if (data >= OCV_END) return CMD_ERROR;
1240 break;
1241
1243 if (data >= OCC_END) return CMD_ERROR;
1244 switch (order->GetConditionVariable()) {
1245 case OCV_UNCONDITIONALLY: return CMD_ERROR;
1246
1248 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
1249 break;
1250
1251 default:
1252 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
1253 break;
1254 }
1255 break;
1256
1257 case MOF_COND_VALUE:
1258 switch (order->GetConditionVariable()) {
1261 return CMD_ERROR;
1262
1264 case OCV_RELIABILITY:
1265 if (data > 100) return CMD_ERROR;
1266 break;
1267
1268 default:
1269 if (data > 2047) return CMD_ERROR;
1270 break;
1271 }
1272 break;
1273
1275 if (data >= v->GetNumOrders()) return CMD_ERROR;
1276 break;
1277 }
1278
1279 if (flags.Test(DoCommandFlag::Execute)) {
1280 switch (mof) {
1281 case MOF_NON_STOP:
1282 order->SetNonStopType((OrderNonStopFlags)data);
1284 order->SetRefit(CARGO_NO_REFIT);
1287 }
1288 break;
1289
1290 case MOF_STOP_LOCATION:
1291 order->SetStopLocation((OrderStopLocation)data);
1292 break;
1293
1294 case MOF_UNLOAD:
1295 order->SetUnloadType((OrderUnloadFlags)data);
1296 break;
1297
1298 case MOF_LOAD:
1299 order->SetLoadType((OrderLoadFlags)data);
1300 if (data & OLFB_NO_LOAD) order->SetRefit(CARGO_NO_REFIT);
1301 break;
1302
1303 case MOF_DEPOT_ACTION: {
1304 switch (data) {
1305 case DA_ALWAYS_GO:
1309 break;
1310
1311 case DA_SERVICE:
1315 order->SetRefit(CARGO_NO_REFIT);
1316 break;
1317
1318 case DA_STOP:
1322 order->SetRefit(CARGO_NO_REFIT);
1323 break;
1324
1325 case DA_UNBUNCH:
1329 break;
1330
1331 default:
1332 NOT_REACHED();
1333 }
1334 break;
1335 }
1336
1337 case MOF_COND_VARIABLE: {
1339
1341 switch (order->GetConditionVariable()) {
1344 order->SetConditionValue(0);
1345 break;
1346
1348 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
1349 order->SetConditionValue(0);
1350 break;
1351
1353 case OCV_RELIABILITY:
1354 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1355 [[fallthrough]];
1356
1357 default:
1358 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
1359 break;
1360 }
1361 break;
1362 }
1363
1366 break;
1367
1368 case MOF_COND_VALUE:
1369 order->SetConditionValue(data);
1370 break;
1371
1373 order->SetConditionSkipToOrder(data);
1374 break;
1375
1376 default: NOT_REACHED();
1377 }
1378
1379 /* Update the windows and full load flags, also for vehicles that share the same order list */
1380 Vehicle *u = v->FirstShared();
1382 for (; u != nullptr; u = u->NextShared()) {
1383 /* Toggle u->current_order "Full load" flag if it changed.
1384 * However, as the same flag is used for depot orders, check
1385 * whether we are not going to a depot as there are three
1386 * cases where the full load flag can be active and only
1387 * one case where the flag is used for depot orders. In the
1388 * other cases for the OrderType the flags are not used,
1389 * so do not care and those orders should not be active
1390 * when this function is called.
1391 */
1392 if (sel_ord == u->cur_real_order_index &&
1393 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1394 u->current_order.GetLoadType() != order->GetLoadType()) {
1396 }
1397
1398 /* Unbunching data is no longer valid. */
1400
1402 }
1403 }
1404
1405 return CommandCost();
1406}
1407
1415static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order)
1416{
1417 assert(v_order->orders != nullptr);
1418 const OrderList &orderlist = *v_order->orders;
1419 if (v_new->acache.cached_max_range == 0) return true;
1420 if (orderlist.GetNumOrders() == 0) return true;
1421
1422 auto orders = orderlist.GetOrders();
1423
1424 /* Iterate over all orders to check the distance between all
1425 * 'goto' orders and their respective next order (of any type). */
1426 for (VehicleOrderID cur = 0; cur < orderlist.GetNumOrders(); ++cur) {
1427 switch (orders[cur].GetType()) {
1428 case OT_GOTO_STATION:
1429 case OT_GOTO_DEPOT:
1430 case OT_GOTO_WAYPOINT:
1431 /* If we don't have a next order, we've reached the end and must check the first order instead. */
1432 if (GetOrderDistance(cur, orderlist.GetNext(cur), v_order) > v_new->acache.cached_max_range_sqr) return false;
1433 break;
1434
1435 default: break;
1436 }
1437 }
1438
1439 return true;
1440}
1441
1451{
1452 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1453 if (dst == nullptr || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1454
1455 CommandCost ret = CheckOwnership(dst->owner);
1456 if (ret.Failed()) return ret;
1457
1458 switch (action) {
1459 case CO_SHARE: {
1460 Vehicle *src = Vehicle::GetIfValid(veh_src);
1461
1462 /* Sanity checks */
1463 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1464
1465 ret = CheckOwnership(src->owner);
1466 if (ret.Failed()) return ret;
1467
1468 /* Trucks can't share orders with busses (and visa versa) */
1469 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1470 return CMD_ERROR;
1471 }
1472
1473 /* Is the vehicle already in the shared list? */
1474 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1475
1476 for (const Order &order : src->Orders()) {
1477 if (!OrderGoesToStation(dst, order)) continue;
1478
1479 /* Allow copying unreachable destinations if they were already unreachable for the source.
1480 * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1481 * are temporarily invalid due to reconstruction. */
1482 const Station *st = Station::Get(order.GetDestination().ToStationID());
1483 if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1484 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1485 }
1486 }
1487
1488 /* Check for aircraft range limits. */
1489 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src)) {
1490 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1491 }
1492
1493 if (src->orders == nullptr && !OrderList::CanAllocateItem()) {
1494 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1495 }
1496
1497 if (flags.Test(DoCommandFlag::Execute)) {
1498 /* If the destination vehicle had a OrderList, destroy it.
1499 * We only reset the order indices, if the new orders are obviously different.
1500 * (We mainly do this to keep the order indices valid and in range.) */
1501 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1502
1503 dst->orders = src->orders;
1504
1505 /* Link this vehicle in the shared-list */
1506 dst->AddToShared(src);
1507
1510
1512 }
1513 break;
1514 }
1515
1516 case CO_COPY: {
1517 Vehicle *src = Vehicle::GetIfValid(veh_src);
1518
1519 /* Sanity checks */
1520 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1521
1522 ret = CheckOwnership(src->owner);
1523 if (ret.Failed()) return ret;
1524
1525 /* Trucks can't copy all the orders from busses (and visa versa),
1526 * and neither can helicopters and aircraft. */
1527 for (const Order &order : src->Orders()) {
1528 if (!OrderGoesToStation(dst, order)) continue;
1529 Station *st = Station::Get(order.GetDestination().ToStationID());
1530 if (!CanVehicleUseStation(dst, st)) {
1531 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1532 }
1533 }
1534
1535 /* Check for aircraft range limits. */
1536 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src)) {
1537 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1538 }
1539
1540 /* make sure there are orders available */
1542 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1543 }
1544
1545 if (flags.Test(DoCommandFlag::Execute)) {
1546 /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1547 * We only reset the order indices, if the new orders are obviously different.
1548 * (We mainly do this to keep the order indices valid and in range.) */
1549 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1550
1551 std::vector<Order> dst_orders;
1552 for (const Order &order : src->Orders()) {
1553 dst_orders.emplace_back(order);
1554 }
1555
1556 if (dst->orders != nullptr) {
1557 assert(dst->orders->GetNumOrders() == 0);
1558 assert(!dst->orders->IsShared());
1559 delete dst->orders;
1560 }
1561
1563 dst->orders = new OrderList(std::move(dst_orders), dst);
1564
1566
1568 }
1569 break;
1570 }
1571
1572 case CO_UNSHARE: return DecloneOrder(dst, flags);
1573 default: return CMD_ERROR;
1574 }
1575
1576 return CommandCost();
1577}
1578
1588{
1589 if (cargo >= NUM_CARGO && cargo != CARGO_NO_REFIT && cargo != CARGO_AUTO_REFIT) return CMD_ERROR;
1590
1591 const Vehicle *v = Vehicle::GetIfValid(veh);
1592 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1593
1595 if (ret.Failed()) return ret;
1596
1597 Order *order = v->GetOrder(order_number);
1598 if (order == nullptr) return CMD_ERROR;
1599
1600 /* Automatic refit cargo is only supported for goto station orders. */
1601 if (cargo == CARGO_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1602
1603 if (order->GetLoadType() & OLFB_NO_LOAD) return CMD_ERROR;
1604
1605 if (flags.Test(DoCommandFlag::Execute)) {
1606 order->SetRefit(cargo);
1607
1608 /* Make the depot order an 'always go' order. */
1609 if (cargo != CARGO_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1612 }
1613
1614 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1615 /* Update any possible open window of the vehicle */
1617
1618 /* If the vehicle already got the current depot set as current order, then update current order as well */
1619 if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
1620 u->current_order.SetRefit(cargo);
1621 }
1622 }
1623 }
1624
1625 return CommandCost();
1626}
1627
1628
1634void CheckOrders(const Vehicle *v)
1635{
1636 /* Does the user wants us to check things? */
1637 if (_settings_client.gui.order_review_system == 0) return;
1638
1639 /* Do nothing for crashed vehicles */
1640 if (v->vehstatus.Test(VehState::Crashed)) return;
1641
1642 /* Do nothing for stopped vehicles if setting is '1' */
1644
1645 /* do nothing we we're not the first vehicle in a share-chain */
1646 if (v->FirstShared() != v) return;
1647
1648 /* Only check every 20 days, so that we don't flood the message log */
1649 if (v->owner == _local_company && v->day_counter % 20 == 0) {
1650 StringID message = INVALID_STRING_ID;
1651
1652 /* Check the order list */
1653 int n_st = 0;
1654
1655 for (const Order &order : v->Orders()) {
1656 /* Dummy order? */
1657 if (order.IsType(OT_DUMMY)) {
1658 message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1659 break;
1660 }
1661 /* Does station have a load-bay for this vehicle? */
1662 if (order.IsType(OT_GOTO_STATION)) {
1663 const Station *st = Station::Get(order.GetDestination().ToStationID());
1664
1665 n_st++;
1666 if (!CanVehicleUseStation(v, st)) {
1667 message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1668 } else if (v->type == VEH_AIRCRAFT &&
1669 (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1672 message == INVALID_STRING_ID) {
1673 message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1674 }
1675 }
1676 }
1677
1678 /* Check if the last and the first order are the same */
1679 if (v->GetNumOrders() > 1) {
1680 auto orders = v->Orders();
1681
1682 if (orders.front().Equals(orders.back())) {
1683 message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1684 }
1685 }
1686
1687 /* Do we only have 1 station in our order list? */
1688 if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1689
1690#ifdef WITH_ASSERT
1691 if (v->orders != nullptr) v->orders->DebugCheckSanity();
1692#endif
1693
1694 /* We don't have a problem */
1695 if (message == INVALID_STRING_ID) return;
1696
1698 }
1699}
1700
1709void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1710{
1711 /* Aircraft have StationIDs for depot orders and never use DepotIDs
1712 * This fact is handled specially below
1713 */
1714
1715 /* Go through all vehicles */
1716 for (Vehicle *v : Vehicle::Iterate()) {
1717 if ((v->type == VEH_AIRCRAFT && v->current_order.IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : v->current_order.GetType()) == type &&
1718 (!hangar || v->type == VEH_AIRCRAFT) && v->current_order.GetDestination() == destination) {
1719 v->current_order.MakeDummy();
1721 }
1722
1723 if (v->orders == nullptr) continue;
1724
1725 /* Clear the order from the order-list */
1726 for (VehicleOrderID id = 0, next_id = 0; id < v->GetNumOrders(); id = next_id) {
1727 next_id = id + 1;
1728 Order *order = v->orders->GetOrderAt(id);
1729 OrderType ot = order->GetType();
1730 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
1731 if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) continue; // Not an aircraft? Can't have a hangar order.
1732 if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1733 if (ot == type && order->GetDestination() == destination) {
1734 /* We want to clear implicit orders, but we don't want to make them
1735 * dummy orders. They should just vanish. Also check the actual order
1736 * type as ot is currently OT_GOTO_STATION. */
1737 if (order->IsType(OT_IMPLICIT)) {
1738 DeleteOrder(v, id);
1739 next_id = id;
1740 continue;
1741 }
1742
1743 /* Clear wait time */
1744 v->orders->UpdateTotalDuration(-order->GetWaitTime());
1745 if (order->IsWaitTimetabled()) {
1746 v->orders->UpdateTimetableDuration(-order->GetTimetabledWait());
1747 order->SetWaitTimetabled(false);
1748 }
1749 order->SetWaitTime(0);
1750
1751 /* Clear order, preserving travel time */
1752 bool travel_timetabled = order->IsTravelTimetabled();
1753 order->MakeDummy();
1754 order->SetTravelTimetabled(travel_timetabled);
1755
1756 for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1757 /* In GUI, simulate by removing the order and adding it back */
1760 }
1761 }
1762 }
1763 }
1764
1765 OrderBackup::RemoveOrder(type, destination, hangar);
1766}
1767
1773{
1774 return std::ranges::any_of(this->Orders(), [](const Order &order) { return order.IsType(OT_GOTO_DEPOT); });
1775}
1776
1786void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1787{
1789
1790 if (v->IsOrderListShared()) {
1791 /* Remove ourself from the shared order list. */
1792 v->RemoveFromShared();
1793 v->orders = nullptr;
1794 } else if (v->orders != nullptr) {
1795 /* Remove the orders */
1796 v->orders->FreeChain(keep_orderlist);
1797 if (!keep_orderlist) v->orders = nullptr;
1798 }
1799
1800 /* Unbunching data is no longer valid. */
1802
1803 if (reset_order_indices) {
1805 if (v->current_order.IsType(OT_LOADING)) {
1807 }
1808 }
1809}
1810
1818uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
1819{
1820 /* Service intervals are in percents. */
1821 if (ispercent) return Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT);
1822
1823 /* Service intervals are in minutes. */
1824 if (TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU)) return Clamp(interval, MIN_SERVINT_MINUTES, MAX_SERVINT_MINUTES);
1825
1826 /* Service intervals are in days. */
1827 return Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1828}
1829
1838static bool CheckForValidOrders(const Vehicle *v)
1839{
1840 return std::ranges::any_of(v->Orders(), [](const Order &order) { return order.IsGotoOrder(); });
1841}
1842
1846static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1847{
1848 switch (occ) {
1849 case OCC_EQUALS: return variable == value;
1850 case OCC_NOT_EQUALS: return variable != value;
1851 case OCC_LESS_THAN: return variable < value;
1852 case OCC_LESS_EQUALS: return variable <= value;
1853 case OCC_MORE_THAN: return variable > value;
1854 case OCC_MORE_EQUALS: return variable >= value;
1855 case OCC_IS_TRUE: return variable != 0;
1856 case OCC_IS_FALSE: return variable == 0;
1857 default: NOT_REACHED();
1858 }
1859}
1860
1861static bool OrderConditionCompare(OrderConditionComparator occ, ConvertibleThroughBase auto variable, int value)
1862{
1863 return OrderConditionCompare(occ, variable.base(), value);
1864}
1865
1873{
1874 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1875
1876 bool skip_order = false;
1878 uint16_t value = order->GetConditionValue();
1879
1880 switch (order->GetConditionVariable()) {
1881 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1882 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
1883 case OCV_MAX_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability), value); break;
1884 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1885 case OCV_AGE: skip_order = OrderConditionCompare(occ, TimerGameCalendar::DateToYear(v->age), value); break;
1886 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
1887 case OCV_UNCONDITIONALLY: skip_order = true; break;
1889 default: NOT_REACHED();
1890 }
1891
1892 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1893}
1894
1902bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
1903{
1904 if (conditional_depth > v->GetNumOrders()) {
1905 v->current_order.Free();
1906 v->SetDestTile(TileIndex{});
1907 return false;
1908 }
1909
1910 switch (order->GetType()) {
1911 case OT_GOTO_STATION:
1912 v->SetDestTile(v->GetOrderStationLocation(order->GetDestination().ToStationID()));
1913 return true;
1914
1915 case OT_GOTO_DEPOT:
1916 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
1917 assert(!pbs_look_ahead);
1918 UpdateVehicleTimetable(v, true);
1920 break;
1921 }
1922
1924 /* If the vehicle can't find its destination, delay its next search.
1925 * In case many vehicles are in this state, use the vehicle index to spread out pathfinder calls. */
1926 if (v->dest_tile == 0 && TimerGameEconomy::date_fract != (v->index % Ticks::DAY_TICKS)) break;
1927
1928 /* We need to search for the nearest depot (hangar). */
1929 ClosestDepot closest_depot = v->FindClosestDepot();
1930
1931 if (closest_depot.found) {
1932 /* PBS reservations cannot reverse */
1933 if (pbs_look_ahead && closest_depot.reverse) return false;
1934
1935 v->SetDestTile(closest_depot.location);
1936 v->current_order.SetDestination(closest_depot.destination);
1937
1938 /* If there is no depot in front, reverse automatically (trains only) */
1939 if (v->type == VEH_TRAIN && closest_depot.reverse) Command<CMD_REVERSE_TRAIN_DIRECTION>::Do(DoCommandFlag::Execute, v->index, false);
1940
1941 if (v->type == VEH_AIRCRAFT) {
1942 Aircraft *a = Aircraft::From(v);
1943 if (a->state == FLYING && a->targetairport != closest_depot.destination) {
1944 /* The aircraft is now heading for a different hangar than the next in the orders */
1946 }
1947 }
1948 return true;
1949 }
1950
1951 /* If there is no depot, we cannot help PBS either. */
1952 if (pbs_look_ahead) return false;
1953
1954 UpdateVehicleTimetable(v, true);
1956 } else {
1957 if (v->type != VEH_AIRCRAFT) {
1958 v->SetDestTile(Depot::Get(order->GetDestination().ToStationID())->xy);
1959 } else {
1960 Aircraft *a = Aircraft::From(v);
1961 DestinationID destination = a->current_order.GetDestination();
1962 if (a->targetairport != destination) {
1963 /* The aircraft is now heading for a different hangar than the next in the orders */
1964 a->SetDestTile(a->GetOrderStationLocation(destination.ToStationID()));
1965 }
1966 }
1967 return true;
1968 }
1969 break;
1970
1971 case OT_GOTO_WAYPOINT:
1972 v->SetDestTile(Waypoint::Get(order->GetDestination().ToStationID())->xy);
1973 return true;
1974
1975 case OT_CONDITIONAL: {
1976 assert(!pbs_look_ahead);
1977 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
1978 if (next_order != INVALID_VEH_ORDER_ID) {
1979 /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
1980 * cur_real_order_index might come after next_order. */
1981 UpdateVehicleTimetable(v, false);
1985
1986 /* Disable creation of implicit orders.
1987 * When inserting them we do not know that we would have to make the conditional orders point to them. */
1988 if (v->IsGroundVehicle()) {
1989 uint16_t &gv_flags = v->GetGroundVehicleFlags();
1991 }
1992 } else {
1993 UpdateVehicleTimetable(v, true);
1995 }
1996 break;
1997 }
1998
1999 default:
2000 v->SetDestTile(TileIndex{});
2001 return false;
2002 }
2003
2004 assert(v->cur_implicit_order_index < v->GetNumOrders());
2005 assert(v->cur_real_order_index < v->GetNumOrders());
2006
2007 /* Get the current order */
2008 order = v->GetOrder(v->cur_real_order_index);
2009 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2010 assert(v->GetNumManualOrders() == 0);
2011 order = nullptr;
2012 }
2013
2014 if (order == nullptr) {
2015 v->current_order.Free();
2016 v->SetDestTile(TileIndex{});
2017 return false;
2018 }
2019
2020 v->current_order = *order;
2021 return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2022}
2023
2032{
2033 switch (v->current_order.GetType()) {
2034 case OT_GOTO_DEPOT:
2035 /* Let a depot order in the orderlist interrupt. */
2036 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
2037 break;
2038
2039 case OT_LOADING:
2040 return false;
2041
2042 case OT_LEAVESTATION:
2043 if (v->type != VEH_AIRCRAFT) return false;
2044 break;
2045
2046 default: break;
2047 }
2048
2056 bool may_reverse = v->current_order.IsType(OT_NOTHING);
2057
2058 /* Check if we've reached a 'via' destination. */
2059 if (((v->current_order.IsType(OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) || v->current_order.IsType(OT_GOTO_WAYPOINT)) &&
2060 IsTileType(v->tile, MP_STATION) &&
2063 /* We set the last visited station here because we do not want
2064 * the train to stop at this 'via' station if the next order
2065 * is a no-non-stop order; in that case not setting the last
2066 * visited station will cause the vehicle to still stop. */
2067 v->last_station_visited = v->current_order.GetDestination().ToStationID();
2068 UpdateVehicleTimetable(v, true);
2070 }
2071
2072 /* Get the current order */
2075
2076 const Order *order = v->GetOrder(v->cur_real_order_index);
2077 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2078 assert(v->GetNumManualOrders() == 0);
2079 order = nullptr;
2080 }
2081
2082 /* If no order, do nothing. */
2083 if (order == nullptr || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
2084 if (v->type == VEH_AIRCRAFT) {
2085 /* Aircraft do something vastly different here, so handle separately */
2086 HandleMissingAircraftOrders(Aircraft::From(v));
2087 return false;
2088 }
2089
2090 v->current_order.Free();
2091 v->SetDestTile(TileIndex{});
2092 return false;
2093 }
2094
2095 /* If it is unchanged, keep it. */
2096 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
2097 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination().ToStationID())->ship_station.tile != INVALID_TILE)) {
2098 return false;
2099 }
2100
2101 /* Otherwise set it, and determine the destination tile. */
2102 v->current_order = *order;
2103
2105 switch (v->type) {
2106 default:
2107 NOT_REACHED();
2108
2109 case VEH_ROAD:
2110 case VEH_TRAIN:
2111 break;
2112
2113 case VEH_AIRCRAFT:
2114 case VEH_SHIP:
2116 break;
2117 }
2118
2119 return UpdateOrderDest(v, order) && may_reverse;
2120}
2121
2129bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2130{
2131 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2132
2133 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
2134 v->last_station_visited != station && // Do stop only when we've not just been there
2135 /* Finally do stop when there is no non-stop flag set for this type of station. */
2137}
2138
2139bool Order::CanLoadOrUnload() const
2140{
2141 return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2143 ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
2144 (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
2145}
2146
2153bool Order::CanLeaveWithCargo(bool has_cargo) const
2154{
2155 return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
2156 (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
2157}
Base for aircraft.
void AircraftNextAirportPos_and_Order(Aircraft *v)
set the right pos when heading to other airports after takeoff
@ FLYING
Vehicle is flying in the air.
Definition airport.h:77
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
static const CargoType CARGO_AUTO_REFIT
Automatically choose cargo type when doing auto refitting.
Definition cargo_type.h:78
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:75
static const CargoType CARGO_NO_REFIT
Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-renew).
Definition cargo_type.h:79
Cheats _cheats
All the cheats.
Definition cheat.cpp:16
Types related to cheating.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Common return value for all commands.
bool Failed() const
Did this command fail?
Enum-as-bit-set wrapper.
Minimal stack that uses a pool to avoid pointers.
Titem Pop()
Pop an item from the stack.
bool IsEmpty() const
Check if the stack is empty.
void Push(const Titem &item)
Pushes a new item onto the stack if there is still space in the underlying pool.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static DateFract date_fract
Fractional part of the day.
int32_t Ticks
The type to store ticks in.
static constexpr Year DateToYear(Date date)
Calculate the year of a given date.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Functions related to companies.
static constexpr Owner OWNER_NONE
The tile has no ownership.
A type is considered 'convertible through base()' when it has a 'base()' function that returns someth...
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Base for all depots (except hangars)
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:159
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:142
constexpr uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
Functions related to news.
void AddVehicleAdviceNewsItem(AdviceType advice_type, EncodedString &&headline, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition news_func.h:40
void DeleteVehicleNews(VehicleID vid, AdviceType advice_type=AdviceType::Invalid)
Delete news with a given advice type about a vehicle.
@ Order
Something wrong with the order, e.g. invalid or duplicate entries, too few entries.
Functions related to order backups.
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.
OrderConditionVariable
Variables (of a vehicle) to 'cause' skipping on.
Definition order_type.h:128
@ OCV_AGE
Skip based on the age.
Definition order_type.h:132
@ OCV_UNCONDITIONALLY
Always skip.
Definition order_type.h:134
@ OCV_MAX_SPEED
Skip based on the maximum speed.
Definition order_type.h:131
@ OCV_LOAD_PERCENTAGE
Skip based on the amount of load.
Definition order_type.h:129
@ OCV_REQUIRES_SERVICE
Skip when the vehicle requires service.
Definition order_type.h:133
@ OCV_RELIABILITY
Skip based on the reliability.
Definition order_type.h:130
@ OCV_REMAINING_LIFETIME
Skip based on the remaining lifetime.
Definition order_type.h:135
@ OCV_MAX_RELIABILITY
Skip based on the maximum reliability.
Definition order_type.h:136
OrderStopLocation
Where to stop the trains.
Definition order_type.h:98
@ OSL_PLATFORM_MIDDLE
Stop at the middle of the platform.
Definition order_type.h:100
@ OSL_PLATFORM_FAR_END
Stop at the far end of the platform.
Definition order_type.h:101
@ OSL_PLATFORM_NEAR_END
Stop at the near end of the platform.
Definition order_type.h:99
ModifyOrderFlags
Enumeration for the data to set in CmdModifyOrder.
Definition order_type.h:159
@ MOF_COND_VARIABLE
A conditional variable changes.
Definition order_type.h:165
@ MOF_LOAD
Passes an OrderLoadType.
Definition order_type.h:163
@ MOF_UNLOAD
Passes an OrderUnloadType.
Definition order_type.h:162
@ MOF_STOP_LOCATION
Passes an OrderStopLocation.
Definition order_type.h:161
@ MOF_COND_DESTINATION
Change the destination of a conditional order.
Definition order_type.h:168
@ MOF_COND_COMPARATOR
A comparator changes.
Definition order_type.h:166
@ MOF_COND_VALUE
The value to set the condition to.
Definition order_type.h:167
@ MOF_DEPOT_ACTION
Selects the OrderDepotAction.
Definition order_type.h:164
@ MOF_NON_STOP
Passes an OrderNonStopFlags.
Definition order_type.h:160
OrderUnloadFlags
Flags related to the unloading order.
Definition order_type.h:67
@ OUFB_TRANSFER
Transfer all cargo onto the platform.
Definition order_type.h:70
@ OUFB_NO_UNLOAD
Totally no unloading will be done.
Definition order_type.h:71
@ OUF_UNLOAD_IF_POSSIBLE
Unload all cargo that the station accepts.
Definition order_type.h:68
@ OUFB_UNLOAD
Force unloading all cargo onto the platform, possibly not getting paid.
Definition order_type.h:69
@ DA_SERVICE
Service only if needed.
Definition order_type.h:177
@ DA_STOP
Go to the depot and stop there.
Definition order_type.h:178
@ DA_ALWAYS_GO
Always go to the depot.
Definition order_type.h:176
@ DA_UNBUNCH
Go to the depot and unbunch.
Definition order_type.h:179
OrderDepotTypeFlags
Reasons that could cause us to go to the depot.
Definition order_type.h:108
@ ODTFB_PART_OF_ORDERS
This depot order is because of a regular order.
Definition order_type.h:111
@ ODTFB_SERVICE
This depot order is because of the servicing limit.
Definition order_type.h:110
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition order_type.h:18
OrderDepotActionFlags
Actions that can be performed when the vehicle enters the depot.
Definition order_type.h:117
@ ODATFB_UNBUNCH
Service the vehicle and then unbunch it.
Definition order_type.h:121
@ ODATFB_NEAREST_DEPOT
Send the vehicle to the nearest depot.
Definition order_type.h:120
@ ODATFB_HALT
Service the vehicle and then halt it.
Definition order_type.h:119
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition order_type.h:41
OrderLoadFlags
Flags related to the loading order.
Definition order_type.h:77
@ OLFB_FULL_LOAD
Full load all cargoes of the consist.
Definition order_type.h:79
@ OLFB_NO_LOAD
Do not load anything.
Definition order_type.h:81
@ OLF_LOAD_IF_POSSIBLE
Load as long as there is cargo that fits in the train.
Definition order_type.h:78
@ OLF_FULL_LOAD_ANY
Full load a single cargo of the consist.
Definition order_type.h:80
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:143
@ OCC_LESS_EQUALS
Skip if the value is less or equal to the limit.
Definition order_type.h:147
@ OCC_EQUALS
Skip if both values are equal.
Definition order_type.h:144
@ OCC_NOT_EQUALS
Skip if both values are not equal.
Definition order_type.h:145
@ OCC_MORE_THAN
Skip if the value is more than the limit.
Definition order_type.h:148
@ OCC_IS_TRUE
Skip if the variable is true.
Definition order_type.h:150
@ OCC_LESS_THAN
Skip if the value is less than the limit.
Definition order_type.h:146
@ OCC_MORE_EQUALS
Skip if the value is more or equal to the limit.
Definition order_type.h:149
@ OCC_IS_FALSE
Skip if the variable is false.
Definition order_type.h:151
OrderNonStopFlags
Non-stop order flags.
Definition order_type.h:87
@ ONSF_NO_STOP_AT_DESTINATION_STATION
The vehicle will stop at any station it passes except the destination.
Definition order_type.h:90
@ ONSF_STOP_EVERYWHERE
The vehicle will stop at any station it passes and the destination.
Definition order_type.h:88
@ ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
The vehicle will not stop at any stations it passes except the destination.
Definition order_type.h:89
CloneOptions
Clone actions.
Definition order_type.h:194
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 debug_inline bool IsRailDepotTile(Tile t)
Is this tile rail tile and a rail depot?
Definition rail_map.h:105
Pseudo random number generator.
static debug_inline bool IsRoadDepotTile(Tile t)
Return whether a tile is a road depot tile.
Definition road_map.h:100
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Base classes/functions for stations.
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
@ Dock
Station with a dock.
@ TruckStop
Station with truck stops.
@ Train
Station with train station.
@ BusStop
Station with bus stops.
Definition of base types and functions in a cross-platform compatible way.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:91
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
uint32_t cached_max_range_sqr
Cached squared maximum range.
Definition aircraft.h:65
uint16_t cached_max_range
Cached maximum range.
Definition aircraft.h:66
uint8_t subtype
Type of aircraft.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:72
uint8_t state
State of the airport.
Definition aircraft.h:77
TileIndex GetOrderStationLocation(StationID station) override
Determine the location for the station where the vehicle goes to next.
StationID targetairport
Airport to go to next.
Definition aircraft.h:76
@ ShortStrip
This airport has a short landing strip, dangerous for fast aircraft.
Flags flags
Flags for this airport type.
Definition airport.h:193
bool HasHangar() const
Check if this airport has at least one hangar.
const AirportFTAClass * GetFTA() const
Get the finite-state machine for this airport or the finite-state machine for the dummy airport in ca...
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
VehicleOrderID cur_implicit_order_index
The index to the current implicit order.
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
Base class for all station-ish types.
TileIndex xy
Base tile of the station.
StationFacilities facilities
The facilities that this station has.
Owner owner
The owner of this station.
VehicleType type
Type of vehicle.
bool value
tells if the bool cheat is active or not
Definition cheat_type.h:18
Cheat no_jetcrash
no jet will crash on small airports anymore
Definition cheat_type.h:31
GUISettings gui
settings related to the GUI
Structure to return information about the closest depot location, and whether it could be found.
DestinationID destination
The DestinationID as used for orders.
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:48
uint8_t order_review_system
perform order reviews on vehicles
static void RemoveOrder(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition order_base.h:264
StationIDStack GetNextStoppingStation(const Vehicle *v, VehicleOrderID first=INVALID_VEH_ORDER_ID, uint hops=0) const
Recursively determine the next deterministic station to stop at.
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:275
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:273
void Initialize(Vehicle *v)
Recomputes everything.
TimerGameTick::Ticks timetable_duration
NOSAVE: Total timetabled duration of the order list.
Definition order_base.h:278
Vehicle * first_shared
NOSAVE: pointer to the first vehicle in the shared order chain.
Definition order_base.h:274
VehicleOrderID GetFirstOrder() const
Get the first order of the order chain.
Definition order_base.h:318
VehicleOrderID num_manual_orders
NOSAVE: How many manually added orders are there in the list.
Definition order_base.h:272
void MoveOrder(VehicleOrderID from, VehicleOrderID to)
Move an order to another position within the order list.
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:352
VehicleOrderID GetNumOrders() const
Get number of orders in the order list.
Definition order_base.h:362
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:381
TimerGameTick::Ticks total_duration
NOSAVE: Total (timetabled or not) duration of the order list.
Definition order_base.h:279
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:140
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:186
OrderConditionVariable GetConditionVariable() const
What variable do we have to compare?
Definition order_base.h:144
bool Equals(const Order &other) const
Does this order have the same type, flags and destination?
uint16_t MapOldOrder() const
Pack this order into a 16 bits integer as close to the TTD representation as possible.
uint16_t GetMaxSpeed() const
Get the maxmimum speed in km-ish/h a vehicle is allowed to reach on the way to the destination.
Definition order_base.h:197
void SetUnloadType(OrderUnloadFlags unload_type)
Set how the consist must be unloaded.
Definition order_base.h:155
void SetLoadType(OrderLoadFlags load_type)
Set how the consist must be loaded.
Definition order_base.h:153
uint16_t max_speed
How fast the vehicle may go on the way to the destination.
Definition order_base.h:55
void SetTravelTimetabled(bool timetabled)
Set if the travel time is explicitly timetabled (unless the order is conditional).
Definition order_base.h:202
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:99
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:66
void SetNonStopType(OrderNonStopFlags non_stop_type)
Set whether we must stop at stations or not.
Definition order_base.h:157
VehicleOrderID GetConditionSkipToOrder() const
Get the order to skip to.
Definition order_base.h:148
OrderStopLocation GetStopLocation() const
Where must we stop at the platform?
Definition order_base.h:138
uint16_t GetWaitTime() const
Get the time in ticks a vehicle will probably wait at the destination (timetabled or not).
Definition order_base.h:188
CargoType GetRefitCargo() const
Get the cargo to to refit to.
Definition order_base.h:127
OrderType GetType() const
Get the type of order of this order.
Definition order_base.h:72
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:47
uint16_t wait_time
How long in ticks to wait at the destination.
Definition order_base.h:53
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:161
OrderLoadFlags GetLoadType() const
How must the consist be loaded?
Definition order_base.h:132
void SetWaitTime(uint16_t time)
Set the time in ticks to wait at the destination.
Definition order_base.h:208
void SetStopLocation(OrderStopLocation stop_location)
Set where we must stop at the platform.
Definition order_base.h:159
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:165
uint8_t flags
Load/unload types, depot order/action types.
Definition order_base.h:48
bool IsWaitTimetabled() const
Does this order have an explicit wait time set?
Definition order_base.h:179
DestinationID dest
The destination of the order.
Definition order_base.h:49
void SetDestination(DestinationID destination)
Sets the destination of this order.
Definition order_base.h:106
void SetWaitTimetabled(bool timetabled)
Set if the wait time is explicitly timetabled (unless the order is conditional).
Definition order_base.h:200
bool IsTravelTimetabled() const
Does this order have an explicit travel time set?
Definition order_base.h:181
void SetConditionComparator(OrderConditionComparator condition_comparator)
Set the comparator to use.
Definition order_base.h:167
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:163
void SetConditionSkipToOrder(VehicleOrderID order_id)
Get the order to skip to.
Definition order_base.h:169
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition order_base.h:142
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:171
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:184
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:51
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:190
void MakeImplicit(StationID destination)
Makes this order an implicit order.
OrderUnloadFlags GetUnloadType() const
How must the consist be unloaded?
Definition order_base.h:134
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:146
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition order_base.h:136
bool IsRefit() const
Is this order a refit order.
Definition order_base.h:113
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:150
void MakeGoToDepot(DestinationID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoType cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition order_cmd.cpp:74
uint16_t travel_time
How long in ticks the journey to this destination should take.
Definition order_base.h:54
TileIndex tile
The base tile of the area.
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:43
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Base class for all pools.
static Station * Get(auto index)
Gets station with given index.
static Station * GetIfValid(auto index)
Returns station if the index is a valid index for this station type.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Station data structure.
TileArea ship_station
Tile area the ship 'station' part covers.
Airport airport
Tile area the airport covers.
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
uint16_t & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition vehicle.cpp:3146
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:718
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:2316
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:2929
bool HasUnbunchingOrder() const
Check if the current vehicle has an unbunching order.
Definition vehicle.cpp:2451
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
uint8_t day_counter
Increased by one for each day.
virtual int GetDisplayMaxSpeed() const
Gets the maximum speed in km-ish/h that can be sent into string parameters for string processing.
void IncrementImplicitOrderIndex()
Increments cur_implicit_order_index, keeps care of the wrap-around and invalidates the GUI.
VehStates vehstatus
Status.
VehicleOrderID GetNumManualOrders() const
Get the number of manually added orders this vehicle has.
virtual TileIndex GetOrderStationLocation(StationID station)
Determine the location for the station where the vehicle goes to next.
Order current_order
The current order (+ status, like: loading)
OrderList * orders
Pointer to the order list for this vehicle.
virtual ClosestDepot FindClosestDepot()
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
Vehicle * NextShared() const
Get the next vehicle of the shared vehicle chain.
bool HasFullLoadOrder() const
Check if the current vehicle has a full load order.
Definition vehicle.cpp:2431
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 * PreviousShared() const
Get the previous vehicle of the shared vehicle chain.
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition vehicle.cpp:2952
debug_inline bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
TileIndex tile
Current tile index.
TileIndex dest_tile
Heading for this tile.
bool NeedsServicing() const
Check if the vehicle needs to go to a depot in near future (if a opportunity presents itself) for ser...
Definition vehicle.cpp:201
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition vehicle.cpp:2442
StationID last_station_visited
The last station we stopped at.
Owner owner
Which company owns the vehicle?
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition vehicle.cpp:2134
void UpdateRealOrderIndex()
Skip implicit orders until cur_real_order_index is a non-implicit order.
Representation of a waypoint.
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
Functions related to time tabling.
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
Update the timetable for the vehicle.
Command definitions related to trains.
StringID GetVehicleCannotUseStationReason(const Vehicle *v, const Station *st)
Get reason string why this station can't be used by the given vehicle.
Definition vehicle.cpp:3065
uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1462
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3019
@ Crashed
Vehicle is crashed.
@ Stopped
Vehicle is stopped by the player.
Functions related to vehicles.
@ VIWD_MODIFY_ORDERS
Other order modifications.
Definition vehicle_gui.h:36
@ VIWD_REMOVE_ALL_ORDERS
Removed / replaced all orders (after deleting / sharing).
Definition vehicle_gui.h:35
WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition vehicle_gui.h:97
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
bool IsShipDepotTile(Tile t)
Is it a ship depot tile?
Definition water_map.h:232
Base of waypoints.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3173
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:3265
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3147
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:3282
@ WC_STATION_LIST
Station list; Window numbers:
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
@ WC_SHIPS_LIST
Ships list; Window numbers:
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
@ WC_VEHICLE_TIMETABLE
Vehicle timetable; Window numbers:
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers: