OpenTTD Source: src/order_cmd.cpp Source File

OpenTTD Source 15.3

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
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
40 OrderListPool _orderlist_pool("OrderList");
41 INSTANTIATE_POOL_METHODS(OrderList)
42
43
47void Order::Free()
48{
49 this->type = OT_NOTHING;
50 this->flags = 0;
51 this->dest = 0;
52}
53
58 void Order::MakeGoToStation(StationID destination)
59{
60 this->type = OT_GOTO_STATION;
61 this->flags = 0;
62 this->dest = destination;
63}
64
73 void Order::MakeGoToDepot(DestinationID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoType cargo)
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
87 void Order::MakeGoToWaypoint(StationID destination)
88{
89 this->type = OT_GOTO_WAYPOINT;
90 this->flags = 0;
91 this->dest = destination;
92}
93
98 void Order::MakeLoading(bool ordered)
99{
100 this->type = OT_LOADING;
101 if (!ordered) this->flags = 0;
102}
103
107 void Order::MakeLeaveStation()
108{
109 this->type = OT_LEAVESTATION;
110 this->flags = 0;
111}
112
116 void Order::MakeDummy()
117{
118 this->type = OT_DUMMY;
119 this->flags = 0;
120}
121
126 void Order::MakeConditional(VehicleOrderID order)
127{
128 this->type = OT_CONDITIONAL;
129 this->flags = order;
130 this->dest = 0;
131}
132
137 void Order::MakeImplicit(StationID destination)
138{
139 this->type = OT_IMPLICIT;
140 this->dest = destination;
141}
142
148 void Order::SetRefit(CargoType cargo)
149{
150 this->refit_cargo = cargo;
151}
152
158 bool 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) ||
167 other.GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot))) {
168 return this->GetDepotOrderType() == other.GetDepotOrderType() &&
169 this->GetDepotActionType().Reset(OrderDepotActionFlag::NearestDepot) == other.GetDepotActionType().Reset(OrderDepotActionFlag::NearestDepot);
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::NoIntermediate)) 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 */
198 if (this->GetLoadType() == OrderLoadType::NoLoad && this->GetUnloadType() == OrderUnloadType::NoUnload) {
199 order = OT_NOTHING;
200 }
201 break;
202 default:
203 break;
204 }
205 return order;
206}
207
213 void InvalidateVehicleOrder(const Vehicle *v, int data)
214{
215 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
216
217 if (data != 0) {
218 /* Calls SetDirty() too */
219 InvalidateWindowData(WC_VEHICLE_ORDERS, v->index, data);
220 InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data);
221 return;
222 }
223
224 SetWindowDirty(WC_VEHICLE_ORDERS, v->index);
225 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
226}
227
235 void 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 void OrderList::Initialize(Vehicle *v)
254{
255 this->first_shared = v;
256
257 this->num_manual_orders = 0;
258 this->num_vehicles = 1;
259 this->timetable_duration = 0;
260
261 for (const Order &o : this->orders) {
262 if (!o.IsType(OT_IMPLICIT)) ++this->num_manual_orders;
263 this->total_duration += o.GetWaitTime() + o.GetTravelTime();
264 }
265
266 this->RecalculateTimetableDuration();
267
268 for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
269 ++this->num_vehicles;
270 this->first_shared = u;
271 }
272
273 for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
274}
275
280 void OrderList::RecalculateTimetableDuration()
281{
282 this->timetable_duration = 0;
283 for (const Order &o : this->orders) {
284 this->timetable_duration += o.GetTimetabledWait() + o.GetTimetabledTravel();
285 }
286}
287
293 void OrderList::FreeChain(bool keep_orderlist)
294{
295 /* We can visit oil rigs and buoys that are not our own. They will be shown in
296 * the list of stations. So, we need to invalidate that window if needed. */
297 for (Order &order: this->orders) {
298 if (order.IsType(OT_GOTO_STATION) || order.IsType(OT_GOTO_WAYPOINT)) {
299 BaseStation *bs = BaseStation::GetIfValid(order.GetDestination().ToStationID());
300 if (bs != nullptr && bs->owner == OWNER_NONE) {
301 InvalidateWindowClassesData(WC_STATION_LIST, 0);
302 break;
303 }
304 }
305 }
306
307 if (keep_orderlist) {
308 this->orders.clear();
309 this->num_manual_orders = 0;
310 this->timetable_duration = 0;
311 } else {
312 delete this;
313 }
314}
315
327 VehicleOrderID OrderList::GetNextDecisionNode(VehicleOrderID next, uint hops) const
328{
329 if (hops > this->GetNumOrders() || next >= this->GetNumOrders()) return INVALID_VEH_ORDER_ID;
330
331 const Order &order_next = this->orders[next];
332 if (order_next.IsType(OT_CONDITIONAL)) {
333 if (order_next.GetConditionVariable() != OrderConditionVariable::Unconditionally) return next;
334
335 /* We can evaluate trivial conditions right away. They're conceptually
336 * the same as regular order progression. */
337 return this->GetNextDecisionNode(
338 order_next.GetConditionSkipToOrder(),
339 hops + 1);
340 }
341
342 if (order_next.IsType(OT_GOTO_DEPOT)) {
343 if (order_next.GetDepotActionType().Test(OrderDepotActionFlag::Halt)) return INVALID_VEH_ORDER_ID;
344 if (order_next.IsRefit()) return next;
345 }
346
347 if (!order_next.CanLoadOrUnload()) {
348 return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
349 }
350
351 return next;
352}
353
363 void OrderList::GetNextStoppingStation(std::vector<StationID> &next_station, const Vehicle *v, VehicleOrderID first, uint hops) const
364{
365 VehicleOrderID next = first;
366 if (first == INVALID_VEH_ORDER_ID) {
367 next = v->cur_implicit_order_index;
368 if (next >= this->GetNumOrders()) {
369 next = this->GetFirstOrder();
370 if (next == INVALID_VEH_ORDER_ID) return;
371 } else {
372 /* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list.
373 * As the given "next" is already valid and a station in the list, we
374 * don't have to check for INVALID_VEH_ORDER_ID here. */
375 next = this->GetNext(next);
376 assert(next != INVALID_VEH_ORDER_ID);
377 }
378 }
379
380 auto orders = v->Orders();
381 do {
382 next = this->GetNextDecisionNode(next, ++hops);
383
384 /* Resolve possibly nested conditionals by estimation. */
385 while (next != INVALID_VEH_ORDER_ID && orders[next].IsType(OT_CONDITIONAL)) {
386 /* We return both options of conditional orders. */
387 VehicleOrderID skip_to = this->GetNextDecisionNode(orders[next].GetConditionSkipToOrder(), hops);
388 VehicleOrderID advance = this->GetNextDecisionNode(this->GetNext(next), hops);
389 if (advance == INVALID_VEH_ORDER_ID || advance == first || skip_to == advance) {
390 next = (skip_to == first) ? INVALID_VEH_ORDER_ID : skip_to;
391 } else if (skip_to == INVALID_VEH_ORDER_ID || skip_to == first) {
392 next = (advance == first) ? INVALID_VEH_ORDER_ID : advance;
393 } else {
394 this->GetNextStoppingStation(next_station, v, skip_to, hops);
395 this->GetNextStoppingStation(next_station, v, advance, hops);
396 return;
397 }
398 ++hops;
399 }
400
401 /* Don't return a next stop if the vehicle has to unload everything. */
402 if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) &&
403 orders[next].GetDestination() == v->last_station_visited &&
404 (orders[next].GetUnloadType() == OrderUnloadType::Transfer || orders[next].GetUnloadType() == OrderUnloadType::Unload))) {
405 return;
406 }
407 } while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited);
408
409 next_station.push_back(orders[next].GetDestination().ToStationID());
410}
411
417 void OrderList::InsertOrderAt(Order &&order, VehicleOrderID index)
418{
419 auto it = std::ranges::next(std::begin(this->orders), index, std::end(this->orders));
420 auto new_order = this->orders.emplace(it, std::move(order));
421
422 if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
423 this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
424 this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
425
426 /* We can visit oil rigs and buoys that are not our own. They will be shown in
427 * the list of stations. So, we need to invalidate that window if needed. */
428 if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
429 BaseStation *bs = BaseStation::Get(new_order->GetDestination().ToStationID());
430 if (bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0);
431 }
432}
433
434
439 void OrderList::DeleteOrderAt(VehicleOrderID index)
440{
441 auto to_remove = std::ranges::next(std::begin(this->orders), index, std::end(this->orders));
442 if (to_remove == std::end(this->orders)) return;
443
444 if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
445
446 this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
447 this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
448
449 this->orders.erase(to_remove);
450}
451
457 void OrderList::MoveOrder(VehicleOrderID from, VehicleOrderID to)
458{
459 if (from == to) return;
460 if (from >= this->GetNumOrders()) return;
461 if (to >= this->GetNumOrders()) return;
462
463 auto it = std::begin(this->orders);
464 if (from < to) {
465 std::rotate(it + from, it + from + 1, it + to + 1);
466 } else {
467 std::rotate(it + to, it + from, it + from + 1);
468 }
469}
470
476 void OrderList::RemoveVehicle(Vehicle *v)
477{
478 --this->num_vehicles;
479 if (v == this->first_shared) this->first_shared = v->NextShared();
480}
481
486 bool OrderList::IsCompleteTimetable() const
487{
488 for (const Order &o : this->orders) {
489 /* Implicit orders are, by definition, not timetabled. */
490 if (o.IsType(OT_IMPLICIT)) continue;
491 if (!o.IsCompletelyTimetabled()) return false;
492 }
493 return true;
494}
495
496#ifdef WITH_ASSERT
500void OrderList::DebugCheckSanity() const
501{
502 VehicleOrderID check_num_orders = 0;
503 VehicleOrderID check_num_manual_orders = 0;
504 uint check_num_vehicles = 0;
505 TimerGameTick::Ticks check_timetable_duration = 0;
506 TimerGameTick::Ticks check_total_duration = 0;
507
508 Debug(misc, 6, "Checking OrderList {} for sanity...", this->index);
509
510 for (const Order &o : this->orders) {
511 ++check_num_orders;
512 if (!o.IsType(OT_IMPLICIT)) ++check_num_manual_orders;
513 check_timetable_duration += o.GetTimetabledWait() + o.GetTimetabledTravel();
514 check_total_duration += o.GetWaitTime() + o.GetTravelTime();
515 }
516 assert(this->GetNumOrders() == check_num_orders);
517 assert(this->num_manual_orders == check_num_manual_orders);
518 assert(this->timetable_duration == check_timetable_duration);
519 assert(this->total_duration == check_total_duration);
520
521 for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
522 ++check_num_vehicles;
523 assert(v->orders == this);
524 }
525 assert(this->num_vehicles == check_num_vehicles);
526 Debug(misc, 6, "... detected {} orders ({} manual), {} vehicles, {} timetabled, {} total",
527 (uint)this->GetNumOrders(), (uint)this->num_manual_orders,
528 this->num_vehicles, this->timetable_duration, this->total_duration);
529}
530#endif
531
539 static inline bool OrderGoesToStation(const Vehicle *v, const Order &o)
540{
541 return o.IsType(OT_GOTO_STATION) ||
542 (v->type == VEH_AIRCRAFT && o.IsType(OT_GOTO_DEPOT) && o.GetDestination() != StationID::Invalid());
543}
544
551 static void DeleteOrderWarnings(const Vehicle *v)
552{
553 DeleteVehicleNews(v->index, AdviceType::Order);
554}
555
562 TileIndex 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 == VEH_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 == VEH_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 == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
609}
610
621 CommandCost CmdInsertOrder(DoCommandFlags flags, VehicleID veh, VehicleOrderID sel_ord, const Order &new_order)
622{
623 Vehicle *v = Vehicle::GetIfValid(veh);
624 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
625
626 CommandCost ret = CheckOwnership(v->owner);
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()) {
654 case OrderLoadType::LoadIfPossible:
655 case OrderLoadType::NoLoad:
656 break;
657
658 case OrderLoadType::FullLoad:
659 case OrderLoadType::FullLoadAny:
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()) {
667 case OrderUnloadType::UnloadIfPossible:
668 case OrderUnloadType::Unload:
669 case OrderUnloadType::Transfer:
670 case OrderUnloadType::NoUnload:
671 break;
672
673 default:
674 return CMD_ERROR;
675 }
676
677 /* Filter invalid stop locations */
678 switch (new_order.GetStopLocation()) {
679 case OrderStopLocation::NearEnd:
680 case OrderStopLocation::Middle:
681 if (v->type != VEH_TRAIN) return CMD_ERROR;
682 [[fallthrough]];
683
684 case OrderStopLocation::FarEnd:
685 break;
686
687 default:
688 return CMD_ERROR;
689 }
690
691 break;
692 }
693
694 case OT_GOTO_DEPOT: {
695 if (!new_order.GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot)) {
696 if (v->type == VEH_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) {
716 case VEH_TRAIN:
717 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
718 break;
719
720 case VEH_ROAD:
721 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
722 break;
723
724 case VEH_SHIP:
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. */
748 if (new_order.GetDepotActionType().Test(OrderDepotActionFlag::Unbunch)) {
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 VEH_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 VEH_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
779 case VEH_SHIP:
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).
798 if (new_order.GetConditionVariable() >= OrderConditionVariable::End) return CMD_ERROR;
799 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_CONDITIONAL);
800
801 OrderConditionComparator occ = new_order.GetConditionComparator();
802 if (occ >= OrderConditionComparator::End) return CMD_ERROR;
803 switch (new_order.GetConditionVariable()) {
804 case OrderConditionVariable::RequiresService:
805 if (occ != OrderConditionComparator::IsTrue && occ != OrderConditionComparator::IsFalse) return CMD_ERROR;
806 break;
807
808 case OrderConditionVariable::Unconditionally:
809 if (occ != OrderConditionComparator::Equal) return CMD_ERROR;
810 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
811 break;
812
813 case OrderConditionVariable::LoadPercentage:
814 case OrderConditionVariable::Reliability:
815 case OrderConditionVariable::MaxReliability:
816 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
817 [[fallthrough]];
818
819 default:
820 if (occ == OrderConditionComparator::IsTrue || occ == OrderConditionComparator::IsFalse) return CMD_ERROR;
821 break;
822 }
823 break;
824 }
825
826 default: return CMD_ERROR;
827 }
828
829 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
830
831 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return CommandCost(STR_ERROR_TOO_MANY_ORDERS);
832 if (v->orders == nullptr && !OrderList::CanAllocateItem()) return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
833
834 if (flags.Test(DoCommandFlag::Execute)) {
835 InsertOrder(v, Order(new_order), sel_ord);
836 }
837
838 return CommandCost();
839}
840
847 void InsertOrder(Vehicle *v, Order &&new_o, VehicleOrderID sel_ord)
848{
849 /* Create new order and link in list */
850 if (v->orders == nullptr) {
851 v->orders = new OrderList(std::move(new_o), v);
852 } else {
853 v->orders->InsertOrderAt(std::move(new_o), sel_ord);
854 }
855
856 Vehicle *u = v->FirstShared();
857 DeleteOrderWarnings(u);
858 for (; u != nullptr; u = u->NextShared()) {
859 assert(v->orders == u->orders);
860
861 /* If there is added an order before the current one, we need
862 * to update the selected order. We do not change implicit/real order indices though.
863 * If the new order is between the current implicit order and real order, the implicit order will
864 * later skip the inserted order. */
865 if (sel_ord <= u->cur_real_order_index) {
866 uint cur = u->cur_real_order_index + 1;
867 /* Check if we don't go out of bound */
868 if (cur < u->GetNumOrders()) {
869 u->cur_real_order_index = cur;
870 }
871 }
872 if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
873 /* We are inserting an order just before the current implicit order.
874 * We do not know whether we will reach current implicit or the newly inserted order first.
875 * So, disable creation of implicit orders until we are on track again. */
876 uint16_t &gv_flags = u->GetGroundVehicleFlags();
877 SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
878 }
879 if (sel_ord <= u->cur_implicit_order_index) {
880 uint cur = u->cur_implicit_order_index + 1;
881 /* Check if we don't go out of bound */
882 if (cur < u->GetNumOrders()) {
883 u->cur_implicit_order_index = cur;
884 }
885 }
886 /* Unbunching data is no longer valid. */
887 u->ResetDepotUnbunching();
888
889 /* Update any possible open window of the vehicle */
890 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
891 }
892
893 /* As we insert an order, the order to skip to will be 'wrong'. */
894 VehicleOrderID cur_order_id = 0;
895 for (Order &order : v->Orders()) {
896 if (order.IsType(OT_CONDITIONAL)) {
897 VehicleOrderID order_id = order.GetConditionSkipToOrder();
898 if (order_id >= sel_ord) {
899 order.SetConditionSkipToOrder(order_id + 1);
900 }
901 if (order_id == cur_order_id) {
902 order.SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
903 }
904 }
905 cur_order_id++;
906 }
907
908 /* Make sure to rebuild the whole list */
909 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
910}
911
917 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlags flags)
918{
919 if (flags.Test(DoCommandFlag::Execute)) {
920 DeleteVehicleOrders(dst);
921 InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
922 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
923 }
924 return CommandCost();
925}
926
934 CommandCost CmdDeleteOrder(DoCommandFlags flags, VehicleID veh_id, VehicleOrderID sel_ord)
935{
936 Vehicle *v = Vehicle::GetIfValid(veh_id);
937
938 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
939
940 CommandCost ret = CheckOwnership(v->owner);
941 if (ret.Failed()) return ret;
942
943 /* If we did not select an order, we maybe want to de-clone the orders */
944 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
945
946 if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
947
948 if (flags.Test(DoCommandFlag::Execute)) DeleteOrder(v, sel_ord);
949 return CommandCost();
950}
951
956 static void CancelLoadingDueToDeletedOrder(Vehicle *v)
957{
958 assert(v->current_order.IsType(OT_LOADING));
959 /* NON-stop flag is misused to see if a train is in a station that is
960 * on its order list or not */
961 v->current_order.SetNonStopType({});
962 /* When full loading, "cancel" that order so the vehicle doesn't
963 * stay indefinitely at this station anymore. */
964 if (v->current_order.IsFullLoadOrder()) v->current_order.SetLoadType(OrderLoadType::LoadIfPossible);
965}
966
972 void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
973{
974 v->orders->DeleteOrderAt(sel_ord);
975
976 Vehicle *u = v->FirstShared();
977 DeleteOrderWarnings(u);
978 for (; u != nullptr; u = u->NextShared()) {
979 assert(v->orders == u->orders);
980
981 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
982 CancelLoadingDueToDeletedOrder(u);
983 }
984
985 if (sel_ord < u->cur_real_order_index) {
986 u->cur_real_order_index--;
987 } else if (sel_ord == u->cur_real_order_index) {
988 u->UpdateRealOrderIndex();
989 }
990
991 if (sel_ord < u->cur_implicit_order_index) {
992 u->cur_implicit_order_index--;
993 } else if (sel_ord == u->cur_implicit_order_index) {
994 /* Make sure the index is valid */
995 if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
996
997 /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
998 while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) {
999 u->cur_implicit_order_index++;
1000 if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
1001 }
1002 }
1003 /* Unbunching data is no longer valid. */
1004 u->ResetDepotUnbunching();
1005
1006 /* Update any possible open window of the vehicle */
1007 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1008 }
1009
1010 /* As we delete an order, the order to skip to will be 'wrong'. */
1011 VehicleOrderID cur_order_id = 0;
1012 for (Order &order : v->Orders()) {
1013 if (order.IsType(OT_CONDITIONAL)) {
1014 VehicleOrderID order_id = order.GetConditionSkipToOrder();
1015 if (order_id >= sel_ord) {
1016 order_id = std::max(order_id - 1, 0);
1017 }
1018 if (order_id == cur_order_id) {
1019 order_id = (order_id + 1) % v->GetNumOrders();
1020 }
1021 order.SetConditionSkipToOrder(order_id);
1022 }
1023 cur_order_id++;
1024 }
1025
1026 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
1027}
1028
1036 CommandCost CmdSkipToOrder(DoCommandFlags flags, VehicleID veh_id, VehicleOrderID sel_ord)
1037{
1038 Vehicle *v = Vehicle::GetIfValid(veh_id);
1039
1040 if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1041
1042 CommandCost ret = CheckOwnership(v->owner);
1043 if (ret.Failed()) return ret;
1044
1045 if (flags.Test(DoCommandFlag::Execute)) {
1046 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1047
1048 v->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
1049 v->UpdateRealOrderIndex();
1050
1051 /* Unbunching data is no longer valid. */
1052 v->ResetDepotUnbunching();
1053
1054 InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
1055
1056 /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1057 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
1058 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
1059 }
1060
1061 return CommandCost();
1062}
1063
1074 CommandCost CmdMoveOrder(DoCommandFlags flags, VehicleID veh, VehicleOrderID moving_order, VehicleOrderID target_order)
1075{
1076 Vehicle *v = Vehicle::GetIfValid(veh);
1077 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1078
1079 CommandCost ret = CheckOwnership(v->owner);
1080 if (ret.Failed()) return ret;
1081
1082 /* Don't make senseless movements */
1083 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1084 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1085
1086 Order *moving_one = v->GetOrder(moving_order);
1087 /* Don't move an empty order */
1088 if (moving_one == nullptr) return CMD_ERROR;
1089
1090 if (flags.Test(DoCommandFlag::Execute)) {
1091 v->orders->MoveOrder(moving_order, target_order);
1092
1093 /* Update shared list */
1094 Vehicle *u = v->FirstShared();
1095
1096 DeleteOrderWarnings(u);
1097
1098 for (; u != nullptr; u = u->NextShared()) {
1099 /* Update the current order.
1100 * There are multiple ways to move orders, which result in cur_implicit_order_index
1101 * and cur_real_order_index to not longer make any sense. E.g. moving another
1102 * real order between them.
1103 *
1104 * Basically one could choose to preserve either of them, but not both.
1105 * While both ways are suitable in this or that case from a human point of view, neither
1106 * of them makes really sense.
1107 * However, from an AI point of view, preserving cur_real_order_index is the most
1108 * predictable and transparent behaviour.
1109 *
1110 * With that decision it basically does not matter what we do to cur_implicit_order_index.
1111 * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1112 * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1113 * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1114 */
1115 if (u->cur_real_order_index == moving_order) {
1116 u->cur_real_order_index = target_order;
1117 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1118 u->cur_real_order_index--;
1119 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1120 u->cur_real_order_index++;
1121 }
1122
1123 if (u->cur_implicit_order_index == moving_order) {
1124 u->cur_implicit_order_index = target_order;
1125 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1126 u->cur_implicit_order_index--;
1127 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1128 u->cur_implicit_order_index++;
1129 }
1130 /* Unbunching data is no longer valid. */
1131 u->ResetDepotUnbunching();
1132
1133
1134 assert(v->orders == u->orders);
1135 /* Update any possible open window of the vehicle */
1136 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1137 }
1138
1139 /* As we move an order, the order to skip to will be 'wrong'. */
1140 for (Order &order : v->Orders()) {
1141 if (order.IsType(OT_CONDITIONAL)) {
1142 VehicleOrderID order_id = order.GetConditionSkipToOrder();
1143 if (order_id == moving_order) {
1144 order_id = target_order;
1145 } else if (order_id > moving_order && order_id <= target_order) {
1146 order_id--;
1147 } else if (order_id < moving_order && order_id >= target_order) {
1148 order_id++;
1149 }
1150 order.SetConditionSkipToOrder(order_id);
1151 }
1152 }
1153
1154 /* Make sure to rebuild the whole list */
1155 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
1156 }
1157
1158 return CommandCost();
1159}
1160
1172 CommandCost CmdModifyOrder(DoCommandFlags flags, VehicleID veh, VehicleOrderID sel_ord, ModifyOrderFlags mof, uint16_t data)
1173{
1174 if (mof >= MOF_END) return CMD_ERROR;
1175
1176 Vehicle *v = Vehicle::GetIfValid(veh);
1177 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1178
1179 CommandCost ret = CheckOwnership(v->owner);
1180 if (ret.Failed()) return ret;
1181
1182 /* Is it a valid order? */
1183 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1184
1185 Order *order = v->GetOrder(sel_ord);
1186 assert(order != nullptr);
1187 switch (order->GetType()) {
1188 case OT_GOTO_STATION:
1189 if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1190 break;
1191
1192 case OT_GOTO_DEPOT:
1193 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1194 break;
1195
1196 case OT_GOTO_WAYPOINT:
1197 if (mof != MOF_NON_STOP) return CMD_ERROR;
1198 break;
1199
1200 case OT_CONDITIONAL:
1201 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1202 break;
1203
1204 default:
1205 return CMD_ERROR;
1206 }
1207
1208 switch (mof) {
1209 default: NOT_REACHED();
1210
1211 case MOF_NON_STOP: {
1212 if (!v->IsGroundVehicle()) return CMD_ERROR;
1213
1214 OrderNonStopFlags nonstop_flags = static_cast<OrderNonStopFlags>(data);
1215 if (nonstop_flags == order->GetNonStopType()) return CMD_ERROR;
1216
1217 /* Test for invalid flags. */
1218 nonstop_flags.Reset({OrderNonStopFlag::NoIntermediate, OrderNonStopFlag::NoDestination});
1219 if (nonstop_flags.Any()) return CMD_ERROR;
1220 break;
1221 }
1222
1223 case MOF_STOP_LOCATION:
1224 if (v->type != VEH_TRAIN) return CMD_ERROR;
1225 if (data >= to_underlying(OrderStopLocation::End)) return CMD_ERROR;
1226 break;
1227
1228 case MOF_UNLOAD: {
1229 if (order->GetNonStopType().Test(OrderNonStopFlag::NoDestination)) return CMD_ERROR;
1230
1231 OrderUnloadType unload_type = static_cast<OrderUnloadType>(data);
1232 if (unload_type == order->GetUnloadType()) return CMD_ERROR;
1233
1234 /* Test for invalid types. */
1235 switch (unload_type) {
1236 case OrderUnloadType::UnloadIfPossible:
1237 case OrderUnloadType::Unload:
1238 case OrderUnloadType::Transfer:
1239 case OrderUnloadType::NoUnload:
1240 break;
1241
1242 default: return CMD_ERROR;
1243 }
1244 break;
1245 }
1246
1247 case MOF_LOAD: {
1248 if (order->GetNonStopType().Test(OrderNonStopFlag::NoDestination)) return CMD_ERROR;
1249
1250 OrderLoadType load_type = static_cast<OrderLoadType>(data);
1251 if (load_type == order->GetLoadType()) return CMD_ERROR;
1252
1253 /* Test for invalid types. */
1254 switch (load_type) {
1255 case OrderLoadType::LoadIfPossible:
1256 case OrderLoadType::NoLoad:
1257 break;
1258
1259 case OrderLoadType::FullLoad:
1260 case OrderLoadType::FullLoadAny:
1261 if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
1262 break;
1263
1264 default: return CMD_ERROR;
1265 }
1266 break;
1267 }
1268
1269 case MOF_DEPOT_ACTION: {
1270 OrderDepotAction depot_action = static_cast<OrderDepotAction>(data);
1271 if (depot_action >= OrderDepotAction::End) return CMD_ERROR;
1272 /* Check if we are allowed to add unbunching. We are always allowed to remove it. */
1273 if (depot_action == OrderDepotAction::Unbunch) {
1274 /* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */
1275 if (v->HasUnbunchingOrder() && !order->GetDepotActionType().Test(OrderDepotActionFlag::Unbunch)) return CommandCost(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
1276 /* We don't allow unbunching if the vehicle has a conditional order. */
1277 if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
1278 /* We don't allow unbunching if the vehicle has a full load order. */
1279 if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
1280 }
1281 break;
1282 }
1283
1284 case MOF_COND_VARIABLE: {
1285 OrderConditionVariable cond_variable = static_cast<OrderConditionVariable>(data);
1286 if (cond_variable >= OrderConditionVariable::End) return CMD_ERROR;
1287 break;
1288 }
1289
1290 case MOF_COND_COMPARATOR: {
1291 OrderConditionComparator cond_comparator = static_cast<OrderConditionComparator>(data);
1292 if (cond_comparator >= OrderConditionComparator::End) return CMD_ERROR;
1293 switch (order->GetConditionVariable()) {
1294 case OrderConditionVariable::Unconditionally: return CMD_ERROR;
1295
1296 case OrderConditionVariable::RequiresService:
1297 if (cond_comparator != OrderConditionComparator::IsTrue && cond_comparator != OrderConditionComparator::IsFalse) return CMD_ERROR;
1298 break;
1299
1300 default:
1301 if (cond_comparator == OrderConditionComparator::IsTrue || cond_comparator == OrderConditionComparator::IsFalse) return CMD_ERROR;
1302 break;
1303 }
1304 break;
1305 }
1306
1307 case MOF_COND_VALUE:
1308 switch (order->GetConditionVariable()) {
1309 case OrderConditionVariable::Unconditionally:
1310 case OrderConditionVariable::RequiresService:
1311 return CMD_ERROR;
1312
1313 case OrderConditionVariable::LoadPercentage:
1314 case OrderConditionVariable::Reliability:
1315 case OrderConditionVariable::MaxReliability:
1316 if (data > 100) return CMD_ERROR;
1317 break;
1318
1319 default:
1320 if (data > 2047) return CMD_ERROR;
1321 break;
1322 }
1323 break;
1324
1325 case MOF_COND_DESTINATION:
1326 if (data >= v->GetNumOrders()) return CMD_ERROR;
1327 break;
1328 }
1329
1330 if (flags.Test(DoCommandFlag::Execute)) {
1331 switch (mof) {
1332 case MOF_NON_STOP:
1333 order->SetNonStopType(static_cast<OrderNonStopFlags>(data));
1334 if (order->GetNonStopType().Test(OrderNonStopFlag::NoDestination)) {
1335 order->SetRefit(CARGO_NO_REFIT);
1336 order->SetLoadType(OrderLoadType::LoadIfPossible);
1337 order->SetUnloadType(OrderUnloadType::UnloadIfPossible);
1338 }
1339 break;
1340
1341 case MOF_STOP_LOCATION:
1342 order->SetStopLocation(static_cast<OrderStopLocation>(data));
1343 break;
1344
1345 case MOF_UNLOAD:
1346 order->SetUnloadType(static_cast<OrderUnloadType>(data));
1347 break;
1348
1349 case MOF_LOAD:
1350 order->SetLoadType(static_cast<OrderLoadType>(data));
1351 if (order->GetLoadType() == OrderLoadType::NoLoad) order->SetRefit(CARGO_NO_REFIT);
1352 break;
1353
1354 case MOF_DEPOT_ACTION: {
1355 switch (static_cast<OrderDepotAction>(data)) {
1356 case OrderDepotAction::AlwaysGo:
1357 order->SetDepotOrderType(order->GetDepotOrderType().Reset(OrderDepotTypeFlag::Service));
1358 order->SetDepotActionType(order->GetDepotActionType().Reset({OrderDepotActionFlag::Halt, OrderDepotActionFlag::Unbunch}));
1359 break;
1360
1361 case OrderDepotAction::Service:
1362 order->SetDepotOrderType(order->GetDepotOrderType().Set(OrderDepotTypeFlag::Service));
1363 order->SetDepotActionType(order->GetDepotActionType().Reset({OrderDepotActionFlag::Halt, OrderDepotActionFlag::Unbunch}));
1364 order->SetRefit(CARGO_NO_REFIT);
1365 break;
1366
1367 case OrderDepotAction::Stop:
1368 order->SetDepotOrderType(order->GetDepotOrderType().Reset(OrderDepotTypeFlag::Service));
1369 order->SetDepotActionType(order->GetDepotActionType().Set(OrderDepotActionFlag::Halt).Reset(OrderDepotActionFlag::Unbunch));
1370 order->SetRefit(CARGO_NO_REFIT);
1371 break;
1372
1373 case OrderDepotAction::Unbunch:
1374 order->SetDepotOrderType(order->GetDepotOrderType().Reset(OrderDepotTypeFlag::Service));
1375 order->SetDepotActionType(order->GetDepotActionType().Reset(OrderDepotActionFlag::Halt).Set(OrderDepotActionFlag::Unbunch));
1376 break;
1377
1378 default:
1379 NOT_REACHED();
1380 }
1381 break;
1382 }
1383
1384 case MOF_COND_VARIABLE: {
1385 order->SetConditionVariable((OrderConditionVariable)data);
1386
1387 OrderConditionComparator occ = order->GetConditionComparator();
1388 switch (order->GetConditionVariable()) {
1389 case OrderConditionVariable::Unconditionally:
1390 order->SetConditionComparator(OrderConditionComparator::Equal);
1391 order->SetConditionValue(0);
1392 break;
1393
1394 case OrderConditionVariable::RequiresService:
1395 if (occ != OrderConditionComparator::IsTrue && occ != OrderConditionComparator::IsFalse) order->SetConditionComparator(OrderConditionComparator::IsTrue);
1396 order->SetConditionValue(0);
1397 break;
1398
1399 case OrderConditionVariable::LoadPercentage:
1400 case OrderConditionVariable::Reliability:
1401 case OrderConditionVariable::MaxReliability:
1402 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1403 [[fallthrough]];
1404
1405 default:
1406 if (occ == OrderConditionComparator::IsTrue || occ == OrderConditionComparator::IsFalse) order->SetConditionComparator(OrderConditionComparator::Equal);
1407 break;
1408 }
1409 break;
1410 }
1411
1412 case MOF_COND_COMPARATOR:
1413 order->SetConditionComparator((OrderConditionComparator)data);
1414 break;
1415
1416 case MOF_COND_VALUE:
1417 order->SetConditionValue(data);
1418 break;
1419
1420 case MOF_COND_DESTINATION:
1421 order->SetConditionSkipToOrder(data);
1422 break;
1423
1424 default: NOT_REACHED();
1425 }
1426
1427 /* Update the windows and full load flags, also for vehicles that share the same order list */
1428 Vehicle *u = v->FirstShared();
1429 DeleteOrderWarnings(u);
1430 for (; u != nullptr; u = u->NextShared()) {
1431 /* Toggle u->current_order "Full load" flag if it changed.
1432 * However, as the same flag is used for depot orders, check
1433 * whether we are not going to a depot as there are three
1434 * cases where the full load flag can be active and only
1435 * one case where the flag is used for depot orders. In the
1436 * other cases for the OrderType the flags are not used,
1437 * so do not care and those orders should not be active
1438 * when this function is called.
1439 */
1440 if (sel_ord == u->cur_real_order_index &&
1441 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1442 u->current_order.GetLoadType() != order->GetLoadType()) {
1443 u->current_order.SetLoadType(order->GetLoadType());
1444 }
1445
1446 /* Unbunching data is no longer valid. */
1447 u->ResetDepotUnbunching();
1448
1449 InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS);
1450 }
1451 }
1452
1453 return CommandCost();
1454}
1455
1463 static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order)
1464{
1465 if (v_new->acache.cached_max_range == 0) return true;
1466 if (v_order->GetNumOrders() == 0) return true;
1467
1468 const OrderList &orderlist = *v_order->orders;
1469 auto orders = orderlist.GetOrders();
1470
1471 /* Iterate over all orders to check the distance between all
1472 * 'goto' orders and their respective next order (of any type). */
1473 for (VehicleOrderID cur = 0; cur < orderlist.GetNumOrders(); ++cur) {
1474 switch (orders[cur].GetType()) {
1475 case OT_GOTO_STATION:
1476 case OT_GOTO_DEPOT:
1477 case OT_GOTO_WAYPOINT:
1478 /* If we don't have a next order, we've reached the end and must check the first order instead. */
1479 if (GetOrderDistance(cur, orderlist.GetNext(cur), v_order) > v_new->acache.cached_max_range_sqr) return false;
1480 break;
1481
1482 default: break;
1483 }
1484 }
1485
1486 return true;
1487}
1488
1497 CommandCost CmdCloneOrder(DoCommandFlags flags, CloneOptions action, VehicleID veh_dst, VehicleID veh_src)
1498{
1499 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1500 if (dst == nullptr || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1501
1502 CommandCost ret = CheckOwnership(dst->owner);
1503 if (ret.Failed()) return ret;
1504
1505 switch (action) {
1506 case CO_SHARE: {
1507 Vehicle *src = Vehicle::GetIfValid(veh_src);
1508
1509 /* Sanity checks */
1510 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1511
1512 ret = CheckOwnership(src->owner);
1513 if (ret.Failed()) return ret;
1514
1515 /* Trucks can't share orders with busses (and visa versa) */
1516 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1517 return CMD_ERROR;
1518 }
1519
1520 /* Is the vehicle already in the shared list? */
1521 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1522
1523 for (const Order &order : src->Orders()) {
1524 if (!OrderGoesToStation(dst, order)) continue;
1525
1526 /* Allow copying unreachable destinations if they were already unreachable for the source.
1527 * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1528 * are temporarily invalid due to reconstruction. */
1529 const Station *st = Station::Get(order.GetDestination().ToStationID());
1530 if (CanVehicleUseStation(src, st) && !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 if (src->orders == nullptr && !OrderList::CanAllocateItem()) {
1541 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1542 }
1543
1544 if (flags.Test(DoCommandFlag::Execute)) {
1545 /* If the destination vehicle had a OrderList, destroy it.
1546 * We only reset the order indices, if the new orders are obviously different.
1547 * (We mainly do this to keep the order indices valid and in range.) */
1548 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1549
1550 dst->orders = src->orders;
1551
1552 /* Link this vehicle in the shared-list */
1553 dst->AddToShared(src);
1554
1555 InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
1556 InvalidateVehicleOrder(src, VIWD_MODIFY_ORDERS);
1557
1558 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
1559 }
1560 break;
1561 }
1562
1563 case CO_COPY: {
1564 Vehicle *src = Vehicle::GetIfValid(veh_src);
1565
1566 /* Sanity checks */
1567 if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1568
1569 ret = CheckOwnership(src->owner);
1570 if (ret.Failed()) return ret;
1571
1572 /* Trucks can't copy all the orders from busses (and visa versa),
1573 * and neither can helicopters and aircraft. */
1574 for (const Order &order : src->Orders()) {
1575 if (!OrderGoesToStation(dst, order)) continue;
1576 Station *st = Station::Get(order.GetDestination().ToStationID());
1577 if (!CanVehicleUseStation(dst, st)) {
1578 return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1579 }
1580 }
1581
1582 /* Check for aircraft range limits. */
1583 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src)) {
1584 return CommandCost(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1585 }
1586
1587 /* make sure there are orders available */
1588 if (!OrderList::CanAllocateItem()) {
1589 return CommandCost(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1590 }
1591
1592 if (flags.Test(DoCommandFlag::Execute)) {
1593 /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1594 * We only reset the order indices, if the new orders are obviously different.
1595 * (We mainly do this to keep the order indices valid and in range.) */
1596 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1597
1598 std::vector<Order> dst_orders;
1599 for (const Order &order : src->Orders()) {
1600 dst_orders.emplace_back(order);
1601 }
1602
1603 if (dst->orders != nullptr) {
1604 assert(dst->orders->GetNumOrders() == 0);
1605 assert(!dst->orders->IsShared());
1606 delete dst->orders;
1607 }
1608
1609 assert(OrderList::CanAllocateItem());
1610 dst->orders = new OrderList(std::move(dst_orders), dst);
1611
1612 InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
1613
1614 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
1615 }
1616 break;
1617 }
1618
1619 case CO_UNSHARE: return DecloneOrder(dst, flags);
1620 default: return CMD_ERROR;
1621 }
1622
1623 return CommandCost();
1624}
1625
1634 CommandCost CmdOrderRefit(DoCommandFlags flags, VehicleID veh, VehicleOrderID order_number, CargoType cargo)
1635{
1636 if (cargo >= NUM_CARGO && cargo != CARGO_NO_REFIT && cargo != CARGO_AUTO_REFIT) return CMD_ERROR;
1637
1638 const Vehicle *v = Vehicle::GetIfValid(veh);
1639 if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1640
1641 CommandCost ret = CheckOwnership(v->owner);
1642 if (ret.Failed()) return ret;
1643
1644 Order *order = v->GetOrder(order_number);
1645 if (order == nullptr) return CMD_ERROR;
1646
1647 /* Automatic refit cargo is only supported for goto station orders. */
1648 if (cargo == CARGO_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1649
1650 if (order->GetLoadType() == OrderLoadType::NoLoad) return CMD_ERROR;
1651
1652 if (flags.Test(DoCommandFlag::Execute)) {
1653 order->SetRefit(cargo);
1654
1655 /* Make the depot order an 'always go' order. */
1656 if (cargo != CARGO_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1657 order->SetDepotOrderType(order->GetDepotOrderType().Reset(OrderDepotTypeFlag::Service));
1658 order->SetDepotActionType(order->GetDepotActionType().Reset(OrderDepotActionFlag::Halt));
1659 }
1660
1661 for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1662 /* Update any possible open window of the vehicle */
1663 InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS);
1664
1665 /* If the vehicle already got the current depot set as current order, then update current order as well */
1666 if (u->cur_real_order_index == order_number && u->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) {
1667 u->current_order.SetRefit(cargo);
1668 }
1669 }
1670 }
1671
1672 return CommandCost();
1673}
1674
1675
1681 void CheckOrders(const Vehicle *v)
1682{
1683 /* Does the user wants us to check things? */
1684 if (_settings_client.gui.order_review_system == 0) return;
1685
1686 /* Do nothing for crashed vehicles */
1687 if (v->vehstatus.Test(VehState::Crashed)) return;
1688
1689 /* Do nothing for stopped vehicles if setting is '1' */
1690 if (_settings_client.gui.order_review_system == 1 && v->vehstatus.Test(VehState::Stopped)) return;
1691
1692 /* do nothing we we're not the first vehicle in a share-chain */
1693 if (v->FirstShared() != v) return;
1694
1695 /* Only check every 20 days, so that we don't flood the message log */
1696 if (v->owner == _local_company && v->day_counter % 20 == 0) {
1697 StringID message = INVALID_STRING_ID;
1698
1699 /* Check the order list */
1700 int n_st = 0;
1701
1702 for (const Order &order : v->Orders()) {
1703 /* Dummy order? */
1704 if (order.IsType(OT_DUMMY)) {
1705 message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1706 break;
1707 }
1708 /* Does station have a load-bay for this vehicle? */
1709 if (order.IsType(OT_GOTO_STATION)) {
1710 const Station *st = Station::Get(order.GetDestination().ToStationID());
1711
1712 n_st++;
1713 if (!CanVehicleUseStation(v, st)) {
1714 message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1715 } else if (v->type == VEH_AIRCRAFT &&
1716 (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1717 st->airport.GetFTA()->flags.Test(AirportFTAClass::Flag::ShortStrip) &&
1718 !_cheats.no_jetcrash.value &&
1719 message == INVALID_STRING_ID) {
1720 message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1721 }
1722 }
1723 }
1724
1725 /* Check if the last and the first order are the same */
1726 if (v->GetNumOrders() > 1) {
1727 auto orders = v->Orders();
1728
1729 if (orders.front().Equals(orders.back())) {
1730 message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1731 }
1732 }
1733
1734 /* Do we only have 1 station in our order list? */
1735 if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1736
1737#ifdef WITH_ASSERT
1738 if (v->orders != nullptr) v->orders->DebugCheckSanity();
1739#endif
1740
1741 /* We don't have a problem */
1742 if (message == INVALID_STRING_ID) return;
1743
1744 AddVehicleAdviceNewsItem(AdviceType::Order, GetEncodedString(message, v->index), v->index);
1745 }
1746}
1747
1756 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1757{
1758 /* Aircraft have StationIDs for depot orders and never use DepotIDs
1759 * This fact is handled specially below
1760 */
1761
1762 /* Go through all vehicles */
1763 for (Vehicle *v : Vehicle::Iterate()) {
1764 if ((v->type == VEH_AIRCRAFT && v->current_order.IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : v->current_order.GetType()) == type &&
1765 (!hangar || v->type == VEH_AIRCRAFT) && v->current_order.GetDestination() == destination) {
1766 v->current_order.MakeDummy();
1767 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
1768 }
1769
1770 if (v->orders == nullptr) continue;
1771
1772 /* Clear the order from the order-list */
1773 for (VehicleOrderID id = 0, next_id = 0; id < v->GetNumOrders(); id = next_id) {
1774 next_id = id + 1;
1775 Order *order = v->orders->GetOrderAt(id);
1776 OrderType ot = order->GetType();
1777 if (ot == OT_GOTO_DEPOT && order->GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot)) continue;
1778 if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) continue; // Not an aircraft? Can't have a hangar order.
1779 if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1780 if (ot == type && order->GetDestination() == destination) {
1781 /* We want to clear implicit orders, but we don't want to make them
1782 * dummy orders. They should just vanish. Also check the actual order
1783 * type as ot is currently OT_GOTO_STATION. */
1784 if (order->IsType(OT_IMPLICIT)) {
1785 DeleteOrder(v, id);
1786 next_id = id;
1787 continue;
1788 }
1789
1790 /* Clear wait time */
1791 v->orders->UpdateTotalDuration(-order->GetWaitTime());
1792 if (order->IsWaitTimetabled()) {
1793 v->orders->UpdateTimetableDuration(-order->GetTimetabledWait());
1794 order->SetWaitTimetabled(false);
1795 }
1796 order->SetWaitTime(0);
1797
1798 /* Clear order, preserving travel time */
1799 bool travel_timetabled = order->IsTravelTimetabled();
1800 order->MakeDummy();
1801 order->SetTravelTimetabled(travel_timetabled);
1802
1803 for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1804 /* In GUI, simulate by removing the order and adding it back */
1805 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
1806 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
1807 }
1808 }
1809 }
1810 }
1811
1812 OrderBackup::RemoveOrder(type, destination, hangar);
1813}
1814
1819 bool Vehicle::HasDepotOrder() const
1820{
1821 return std::ranges::any_of(this->Orders(), [](const Order &order) { return order.IsType(OT_GOTO_DEPOT); });
1822}
1823
1833 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1834{
1835 DeleteOrderWarnings(v);
1836
1837 if (v->IsOrderListShared()) {
1838 /* Remove ourself from the shared order list. */
1839 v->RemoveFromShared();
1840 v->orders = nullptr;
1841 } else if (v->orders != nullptr) {
1842 /* Remove the orders */
1843 v->orders->FreeChain(keep_orderlist);
1844 if (!keep_orderlist) v->orders = nullptr;
1845 }
1846
1847 /* Unbunching data is no longer valid. */
1848 v->ResetDepotUnbunching();
1849
1850 if (reset_order_indices) {
1851 v->cur_implicit_order_index = v->cur_real_order_index = 0;
1852 if (v->current_order.IsType(OT_LOADING)) {
1853 CancelLoadingDueToDeletedOrder(v);
1854 }
1855 }
1856}
1857
1865uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
1866{
1867 /* Service intervals are in percents. */
1868 if (ispercent) return Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT);
1869
1870 /* Service intervals are in minutes. */
1871 if (TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU)) return Clamp(interval, MIN_SERVINT_MINUTES, MAX_SERVINT_MINUTES);
1872
1873 /* Service intervals are in days. */
1874 return Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1875}
1876
1885 static bool CheckForValidOrders(const Vehicle *v)
1886{
1887 return std::ranges::any_of(v->Orders(), [](const Order &order) { return order.IsGotoOrder(); });
1888}
1889
1893 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1894{
1895 switch (occ) {
1896 case OrderConditionComparator::Equal: return variable == value;
1897 case OrderConditionComparator::NotEqual: return variable != value;
1898 case OrderConditionComparator::LessThan: return variable < value;
1899 case OrderConditionComparator::LessThanOrEqual: return variable <= value;
1900 case OrderConditionComparator::MoreThan: return variable > value;
1901 case OrderConditionComparator::MoreThanOrEqual: return variable >= value;
1902 case OrderConditionComparator::IsTrue: return variable != 0;
1903 case OrderConditionComparator::IsFalse: return variable == 0;
1904 default: NOT_REACHED();
1905 }
1906}
1907
1908static bool OrderConditionCompare(OrderConditionComparator occ, ConvertibleThroughBase auto variable, int value)
1909{
1910 return OrderConditionCompare(occ, variable.base(), value);
1911}
1912
1919 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
1920{
1921 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1922
1923 bool skip_order = false;
1924 OrderConditionComparator occ = order->GetConditionComparator();
1925 uint16_t value = order->GetConditionValue();
1926
1927 switch (order->GetConditionVariable()) {
1928 case OrderConditionVariable::LoadPercentage: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1929 case OrderConditionVariable::Reliability: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
1930 case OrderConditionVariable::MaxReliability: skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability), value); break;
1931 case OrderConditionVariable::MaxSpeed: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1932 case OrderConditionVariable::Age: skip_order = OrderConditionCompare(occ, TimerGameCalendar::DateToYear(v->age), value); break;
1933 case OrderConditionVariable::RequiresService: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
1934 case OrderConditionVariable::Unconditionally: skip_order = true; break;
1935 case OrderConditionVariable::RemainingLifetime: skip_order = OrderConditionCompare(occ, std::max(TimerGameCalendar::DateToYear(v->max_age - v->age + CalendarTime::DAYS_IN_LEAP_YEAR - 1), TimerGameCalendar::Year(0)), value); break;
1936 default: NOT_REACHED();
1937 }
1938
1939 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1940}
1941
1949 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
1950{
1951 if (conditional_depth > v->GetNumOrders()) {
1952 v->current_order.Free();
1953 v->SetDestTile(TileIndex{});
1954 return false;
1955 }
1956
1957 switch (order->GetType()) {
1958 case OT_GOTO_STATION:
1959 v->SetDestTile(v->GetOrderStationLocation(order->GetDestination().ToStationID()));
1960 return true;
1961
1962 case OT_GOTO_DEPOT:
1963 if (order->GetDepotOrderType().Test(OrderDepotTypeFlag::Service) && !v->NeedsServicing()) {
1964 assert(!pbs_look_ahead);
1965 UpdateVehicleTimetable(v, true);
1966 v->IncrementRealOrderIndex();
1967 break;
1968 }
1969
1970 if (v->current_order.GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot)) {
1971 /* If the vehicle can't find its destination, delay its next search.
1972 * In case many vehicles are in this state, use the vehicle index to spread out pathfinder calls. */
1973 if (v->dest_tile == 0 && TimerGameEconomy::date_fract != (v->index % Ticks::DAY_TICKS)) break;
1974
1975 /* We need to search for the nearest depot (hangar). */
1976 ClosestDepot closest_depot = v->FindClosestDepot();
1977
1978 if (closest_depot.found) {
1979 /* PBS reservations cannot reverse */
1980 if (pbs_look_ahead && closest_depot.reverse) return false;
1981
1982 v->SetDestTile(closest_depot.location);
1983 v->current_order.SetDestination(closest_depot.destination);
1984
1985 /* If there is no depot in front, reverse automatically (trains only) */
1986 if (v->type == VEH_TRAIN && closest_depot.reverse) Command<CMD_REVERSE_TRAIN_DIRECTION>::Do(DoCommandFlag::Execute, v->index, false);
1987
1988 if (v->type == VEH_AIRCRAFT) {
1989 Aircraft *a = Aircraft::From(v);
1990 if (a->state == FLYING && a->targetairport != closest_depot.destination) {
1991 /* The aircraft is now heading for a different hangar than the next in the orders */
1992 AircraftNextAirportPos_and_Order(a);
1993 }
1994 }
1995 return true;
1996 }
1997
1998 /* If there is no depot, we cannot help PBS either. */
1999 if (pbs_look_ahead) return false;
2000
2001 UpdateVehicleTimetable(v, true);
2002 v->IncrementRealOrderIndex();
2003 } else {
2004 if (v->type != VEH_AIRCRAFT) {
2005 v->SetDestTile(Depot::Get(order->GetDestination().ToStationID())->xy);
2006 } else {
2007 Aircraft *a = Aircraft::From(v);
2008 DestinationID destination = a->current_order.GetDestination();
2009 if (a->targetairport != destination) {
2010 /* The aircraft is now heading for a different hangar than the next in the orders */
2011 a->SetDestTile(a->GetOrderStationLocation(destination.ToStationID()));
2012 }
2013 }
2014 return true;
2015 }
2016 break;
2017
2018 case OT_GOTO_WAYPOINT:
2019 v->SetDestTile(Waypoint::Get(order->GetDestination().ToStationID())->xy);
2020 return true;
2021
2022 case OT_CONDITIONAL: {
2023 assert(!pbs_look_ahead);
2024 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2025 if (next_order != INVALID_VEH_ORDER_ID) {
2026 /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2027 * cur_real_order_index might come after next_order. */
2028 UpdateVehicleTimetable(v, false);
2029 v->cur_implicit_order_index = v->cur_real_order_index = next_order;
2030 v->UpdateRealOrderIndex();
2031 v->current_order_time += v->GetOrder(v->cur_real_order_index)->GetTimetabledTravel();
2032
2033 /* Disable creation of implicit orders.
2034 * When inserting them we do not know that we would have to make the conditional orders point to them. */
2035 if (v->IsGroundVehicle()) {
2036 uint16_t &gv_flags = v->GetGroundVehicleFlags();
2037 SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
2038 }
2039 } else {
2040 UpdateVehicleTimetable(v, true);
2041 v->IncrementRealOrderIndex();
2042 }
2043 break;
2044 }
2045
2046 default:
2047 v->SetDestTile(TileIndex{});
2048 return false;
2049 }
2050
2051 assert(v->cur_implicit_order_index < v->GetNumOrders());
2052 assert(v->cur_real_order_index < v->GetNumOrders());
2053
2054 /* Get the current order */
2055 order = v->GetOrder(v->cur_real_order_index);
2056 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2057 assert(v->GetNumManualOrders() == 0);
2058 order = nullptr;
2059 }
2060
2061 if (order == nullptr) {
2062 v->current_order.Free();
2063 v->SetDestTile(TileIndex{});
2064 return false;
2065 }
2066
2067 v->current_order = *order;
2068 return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2069}
2070
2078 bool ProcessOrders(Vehicle *v)
2079{
2080 switch (v->current_order.GetType()) {
2081 case OT_GOTO_DEPOT:
2082 /* Let a depot order in the orderlist interrupt. */
2083 if (!v->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) return false;
2084 break;
2085
2086 case OT_LOADING:
2087 return false;
2088
2089 case OT_LEAVESTATION:
2090 if (v->type != VEH_AIRCRAFT) return false;
2091 break;
2092
2093 default: break;
2094 }
2095
2103 bool may_reverse = v->current_order.IsType(OT_NOTHING);
2104
2105 /* Check if we've reached a 'via' destination. */
2106 if (((v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetNonStopType().Test(OrderNonStopFlag::NoDestination)) || v->current_order.IsType(OT_GOTO_WAYPOINT)) &&
2107 IsTileType(v->tile, MP_STATION) &&
2108 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
2109 v->DeleteUnreachedImplicitOrders();
2110 /* We set the last visited station here because we do not want
2111 * the train to stop at this 'via' station if the next order
2112 * is a no-non-stop order; in that case not setting the last
2113 * visited station will cause the vehicle to still stop. */
2114 v->last_station_visited = v->current_order.GetDestination().ToStationID();
2115 UpdateVehicleTimetable(v, true);
2116 v->IncrementImplicitOrderIndex();
2117 }
2118
2119 /* Get the current order */
2120 assert(v->cur_implicit_order_index == 0 || v->cur_implicit_order_index < v->GetNumOrders());
2121 v->UpdateRealOrderIndex();
2122
2123 const Order *order = v->GetOrder(v->cur_real_order_index);
2124 if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2125 assert(v->GetNumManualOrders() == 0);
2126 order = nullptr;
2127 }
2128
2129 /* If no order, do nothing. */
2130 if (order == nullptr || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
2131 if (v->type == VEH_AIRCRAFT) {
2132 /* Aircraft do something vastly different here, so handle separately */
2133 HandleMissingAircraftOrders(Aircraft::From(v));
2134 return false;
2135 }
2136
2137 v->current_order.Free();
2138 v->SetDestTile(TileIndex{});
2139 return false;
2140 }
2141
2142 /* If it is unchanged, keep it. */
2143 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
2144 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination().ToStationID())->ship_station.tile != INVALID_TILE)) {
2145 return false;
2146 }
2147
2148 /* Otherwise set it, and determine the destination tile. */
2149 v->current_order = *order;
2150
2151 InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
2152 switch (v->type) {
2153 default:
2154 NOT_REACHED();
2155
2156 case VEH_ROAD:
2157 case VEH_TRAIN:
2158 break;
2159
2160 case VEH_AIRCRAFT:
2161 case VEH_SHIP:
2162 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
2163 break;
2164 }
2165
2166 return UpdateOrderDest(v, order) && may_reverse;
2167}
2168
2176 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2177{
2178 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2179
2180 return (!this->IsType(OT_GOTO_DEPOT) || this->GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) &&
2181 v->last_station_visited != station && // Do stop only when we've not just been there
2182 /* Finally do stop when there is no non-stop flag set for this type of station. */
2183 !this->GetNonStopType().Test(is_dest_station ? OrderNonStopFlag::NoDestination : OrderNonStopFlag::NoIntermediate);
2184}
2185
2186bool Order::CanLoadOrUnload() const
2187{
2188 return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2189 !this->GetNonStopType().Test(OrderNonStopFlag::NoDestination) &&
2190 (this->GetLoadType() != OrderLoadType::NoLoad ||
2191 this->GetUnloadType() != OrderUnloadType::NoUnload);
2192}
2193
2200 bool Order::CanLeaveWithCargo(bool has_cargo) const
2201{
2202 return this->GetLoadType() != OrderLoadType::NoLoad || (has_cargo &&
2203 this->GetUnloadType() != OrderUnloadType::Unload &&
2204 this->GetUnloadType() != OrderUnloadType::Transfer);
2205}
aircraft.h
Base for aircraft.
AircraftNextAirportPos_and_Order
void AircraftNextAirportPos_and_Order(Aircraft *v)
set the right pos when heading to other airports after takeoff
Definition aircraft_cmd.cpp:1460
FLYING
@ FLYING
Vehicle is flying in the air.
Definition airport.h:77
GB
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
Definition bitmath_func.hpp:32
SetBit
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
Definition bitmath_func.hpp:121
CargoType
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
CARGO_AUTO_REFIT
static const CargoType CARGO_AUTO_REFIT
Automatically choose cargo type when doing auto refitting.
Definition cargo_type.h:76
NUM_CARGO
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:73
CARGO_NO_REFIT
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:77
_cheats
Cheats _cheats
All the cheats.
Definition cheat.cpp:16
cheat_type.h
Types related to cheating.
BaseBitSet::Test
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Definition base_bitset_type.hpp:141
BaseBitSet::Reset
constexpr Timpl & Reset()
Reset all bits.
Definition base_bitset_type.hpp:83
BaseBitSet::Set
constexpr Timpl & Set()
Set all bits.
Definition base_bitset_type.hpp:40
BaseBitSet::Any
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Definition base_bitset_type.hpp:170
CommandCost
Common return value for all commands.
Definition command_type.h:24
CommandCost::Failed
bool Failed() const
Did this command fail?
Definition command_type.h:177
Engine::reliability
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:49
EnumBitSet
Enum-as-bit-set wrapper.
Definition enum_type.hpp:177
Ticks::DAY_TICKS
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
Definition timer_game_tick.h:75
TimerGameConst< struct Calendar >::DAYS_IN_LEAP_YEAR
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
Definition timer_game_common.h:150
TimerGameEconomy::UsingWallclockUnits
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
Definition timer_game_economy.cpp:98
TimerGameEconomy::date_fract
static DateFract date_fract
Fractional part of the day.
Definition timer_game_economy.h:39
TimerGameTick::Ticks
int32_t Ticks
The type to store ticks in.
Definition timer_game_tick.h:24
TimerGame< struct Calendar >::DateToYear
static constexpr Year DateToYear(Date date)
Calculate the year of a given date.
Definition timer_game_common.h:77
command_func.h
Functions related to commands.
CMD_ERROR
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition command_func.h:28
DoCommandFlag::Execute
@ Execute
execute the given command
company_base.h
Definition of stuff that is very close to a company, like the company struct itself.
CheckOwnership
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
Definition company_cmd.cpp:381
_local_company
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition company_cmd.cpp:55
company_func.h
Functions related to companies.
OWNER_NONE
static constexpr Owner OWNER_NONE
The tile has no ownership.
Definition company_type.h:26
ConvertibleThroughBase
A type is considered 'convertible through base()' when it has a 'base()' function that returns someth...
Definition convertible_through_base.hpp:19
debug.h
Functions related to debugging.
Debug
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
depot_base.h
Base for all depots (except hangars)
to_underlying
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
GVF_SUPPRESS_IMPLICIT_ORDERS
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
Definition ground_vehicle.hpp:57
DistanceSquare
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:186
DistanceManhattan
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:169
ToPercent16
constexpr uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
Definition math_func.hpp:296
Clamp
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
news_func.h
Functions related to news.
AddVehicleAdviceNewsItem
void AddVehicleAdviceNewsItem(AdviceType advice_type, EncodedString &&headline, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition news_func.h:40
DeleteVehicleNews
void DeleteVehicleNews(VehicleID vid, AdviceType advice_type=AdviceType::Invalid)
Delete news with a given advice type about a vehicle.
Definition news_gui.cpp:1015
AdviceType::Order
@ Order
Something wrong with the order, e.g. invalid or duplicate entries, too few entries.
order_backup.h
Functions related to order backups.
CmdSkipToOrder
CommandCost CmdSkipToOrder(DoCommandFlags flags, VehicleID veh_id, VehicleOrderID sel_ord)
Goto order of order-list.
Definition order_cmd.cpp:1036
GetServiceIntervalClamped
uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
Clamp the service interval to the correct min/max.
Definition order_cmd.cpp:1865
CheckForValidOrders
static bool CheckForValidOrders(const Vehicle *v)
Check if a vehicle has any valid orders.
Definition order_cmd.cpp:1885
ProcessOrders
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
Definition order_cmd.cpp:2078
OrderConditionCompare
static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
Compare the variable and value based on the given comparator.
Definition order_cmd.cpp:1893
CancelLoadingDueToDeletedOrder
static void CancelLoadingDueToDeletedOrder(Vehicle *v)
Cancel the current loading order of the vehicle as the order was deleted.
Definition order_cmd.cpp:956
UpdateOrderDest
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
Update the vehicle's destination tile from an order.
Definition order_cmd.cpp:1949
CmdOrderRefit
CommandCost CmdOrderRefit(DoCommandFlags flags, VehicleID veh, VehicleOrderID order_number, CargoType cargo)
Add/remove refit orders from an order.
Definition order_cmd.cpp:1634
InsertOrder
void InsertOrder(Vehicle *v, Order &&new_o, VehicleOrderID sel_ord)
Insert a new order but skip the validation.
Definition order_cmd.cpp:847
InvalidateVehicleOrder
void InvalidateVehicleOrder(const Vehicle *v, int data)
Updates the widgets of a vehicle which contains the order-data.
Definition order_cmd.cpp:213
CheckOrders
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
Definition order_cmd.cpp:1681
CmdInsertOrder
CommandCost CmdInsertOrder(DoCommandFlags flags, VehicleID veh, VehicleOrderID sel_ord, const Order &new_order)
Add an order to the orderlist of a vehicle.
Definition order_cmd.cpp:621
CmdModifyOrder
CommandCost CmdModifyOrder(DoCommandFlags flags, VehicleID veh, VehicleOrderID sel_ord, ModifyOrderFlags mof, uint16_t data)
Modify an order in the orderlist of a vehicle.
Definition order_cmd.cpp:1172
CmdCloneOrder
CommandCost CmdCloneOrder(DoCommandFlags flags, CloneOptions action, VehicleID veh_dst, VehicleID veh_src)
Clone/share/copy an order-list of another vehicle.
Definition order_cmd.cpp:1497
DecloneOrder
static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlags flags)
Declone an order-list.
Definition order_cmd.cpp:917
DeleteVehicleOrders
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
Definition order_cmd.cpp:1833
CmdDeleteOrder
CommandCost CmdDeleteOrder(DoCommandFlags flags, VehicleID veh_id, VehicleOrderID sel_ord)
Delete an order from the orderlist of a vehicle.
Definition order_cmd.cpp:934
GetOrderDistance
uint GetOrderDistance(VehicleOrderID prev, VehicleOrderID cur, const Vehicle *v, int conditional_depth)
Get the distance between two orders of a vehicle.
Definition order_cmd.cpp:589
DeleteOrderWarnings
static void DeleteOrderWarnings(const Vehicle *v)
Delete all news items regarding defective orders about a vehicle This could kill still valid warnings...
Definition order_cmd.cpp:551
DeleteOrder
void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
Delete an order but skip the parameter validation.
Definition order_cmd.cpp:972
ProcessConditionalOrder
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
Process a conditional order and determine the next order.
Definition order_cmd.cpp:1919
CmdMoveOrder
CommandCost CmdMoveOrder(DoCommandFlags flags, VehicleID veh, VehicleOrderID moving_order, VehicleOrderID target_order)
Move an order inside the orderlist.
Definition order_cmd.cpp:1074
RemoveOrderFromAllVehicles
void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
Definition order_cmd.cpp:1756
CheckAircraftOrderDistance
static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order)
Check if an aircraft has enough range for an order list.
Definition order_cmd.cpp:1463
OrderGoesToStation
static bool OrderGoesToStation(const Vehicle *v, const Order &o)
Checks whether the order goes to a station or not, i.e.
Definition order_cmd.cpp:539
order_cmd.h
Command definitions related to orders.
OrderUnloadType
OrderUnloadType
Unloading order types.
Definition order_type.h:67
OrderUnloadType::Transfer
@ Transfer
Transfer all cargo onto the platform.
OrderUnloadType::UnloadIfPossible
@ UnloadIfPossible
Unload all cargo that the station accepts.
OrderUnloadType::NoUnload
@ NoUnload
Totally no unloading will be done.
OrderUnloadType::Unload
@ Unload
Force unloading all cargo onto the platform, possibly not getting paid.
OrderConditionVariable
OrderConditionVariable
Variables (of a vehicle) to 'cause' skipping on.
Definition order_type.h:128
OrderConditionVariable::Unconditionally
@ Unconditionally
Always skip.
OrderConditionVariable::MaxSpeed
@ MaxSpeed
Skip based on the maximum speed.
OrderConditionVariable::Reliability
@ Reliability
Skip based on the reliability.
OrderConditionVariable::MaxReliability
@ MaxReliability
Skip based on the maximum reliability.
OrderConditionVariable::RequiresService
@ RequiresService
Skip when the vehicle requires service.
OrderConditionVariable::LoadPercentage
@ LoadPercentage
Skip based on the amount of load.
OrderConditionVariable::Age
@ Age
Skip based on the age.
OrderConditionVariable::RemainingLifetime
@ RemainingLifetime
Skip based on the remaining lifetime.
OrderStopLocation
OrderStopLocation
Where to stop the trains.
Definition order_type.h:97
OrderStopLocation::NearEnd
@ NearEnd
Stop at the near end of the platform.
OrderStopLocation::FarEnd
@ FarEnd
Stop at the far end of the platform.
OrderStopLocation::Middle
@ Middle
Stop at the middle of the platform.
ModifyOrderFlags
ModifyOrderFlags
Enumeration for the data to set in CmdModifyOrder.
Definition order_type.h:159
MOF_COND_VARIABLE
@ MOF_COND_VARIABLE
A conditional variable changes.
Definition order_type.h:165
MOF_LOAD
@ MOF_LOAD
Passes an OrderLoadType.
Definition order_type.h:163
MOF_UNLOAD
@ MOF_UNLOAD
Passes an OrderUnloadType.
Definition order_type.h:162
MOF_STOP_LOCATION
@ MOF_STOP_LOCATION
Passes an OrderStopLocation.
Definition order_type.h:161
MOF_COND_DESTINATION
@ MOF_COND_DESTINATION
Change the destination of a conditional order.
Definition order_type.h:168
MOF_COND_COMPARATOR
@ MOF_COND_COMPARATOR
A comparator changes.
Definition order_type.h:166
MOF_COND_VALUE
@ MOF_COND_VALUE
The value to set the condition to.
Definition order_type.h:167
MOF_DEPOT_ACTION
@ MOF_DEPOT_ACTION
Selects the OrderDepotAction.
Definition order_type.h:164
MOF_NON_STOP
@ MOF_NON_STOP
Passes an OrderNonStopFlags.
Definition order_type.h:160
OrderDepotAction
OrderDepotAction
Depot action to switch to when doing a MOF_DEPOT_ACTION.
Definition order_type.h:175
OrderDepotAction::Stop
@ Stop
Go to the depot and stop there.
OrderDepotAction::AlwaysGo
@ AlwaysGo
Always go to the depot.
OrderDepotAction::Service
@ Service
Service only if needed.
OrderDepotAction::Unbunch
@ Unbunch
Go to the depot and unbunch.
OrderNonStopFlag::NoDestination
@ NoDestination
The vehicle will stop at any station it passes except the destination, aka via.
OrderNonStopFlag::NoIntermediate
@ NoIntermediate
The vehicle will not stop at any stations it passes except the destination, aka non-stop.
VehicleOrderID
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition order_type.h:18
OrderLoadType
OrderLoadType
Loading order types.
Definition order_type.h:77
OrderLoadType::FullLoad
@ FullLoad
Full load all cargoes of the consist.
OrderLoadType::NoLoad
@ NoLoad
Do not load anything.
OrderLoadType::FullLoadAny
@ FullLoadAny
Full load a single cargo of the consist.
OrderLoadType::LoadIfPossible
@ LoadIfPossible
Load as long as there is cargo that fits in the train.
MAX_VEH_ORDER_ID
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition order_type.h:41
OrderDepotActionFlag::Halt
@ Halt
Service the vehicle and then halt it.
OrderDepotActionFlag::NearestDepot
@ NearestDepot
Send the vehicle to the nearest depot.
OrderDepotActionFlag::Unbunch
@ Unbunch
Service the vehicle and then unbunch it.
OrderDepotTypeFlag::PartOfOrders
@ PartOfOrders
This depot order is because of a regular order.
OrderDepotTypeFlag::Service
@ Service
This depot order is because of the servicing limit.
INVALID_VEH_ORDER_ID
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition order_type.h:39
OrderConditionComparator
OrderConditionComparator
Comparator for the skip reasoning.
Definition order_type.h:143
OrderConditionComparator::IsTrue
@ IsTrue
Skip if the variable is true.
OrderConditionComparator::NotEqual
@ NotEqual
Skip if both values are not equal.
OrderConditionComparator::IsFalse
@ IsFalse
Skip if the variable is false.
OrderConditionComparator::LessThanOrEqual
@ LessThanOrEqual
Skip if the value is less or equal to the limit.
OrderConditionComparator::MoreThan
@ MoreThan
Skip if the value is more than the limit.
OrderConditionComparator::MoreThanOrEqual
@ MoreThanOrEqual
Skip if the value is more or equal to the limit.
OrderConditionComparator::LessThan
@ LessThan
Skip if the value is less than the limit.
OrderConditionComparator::Equal
@ Equal
Skip if both values are equal.
CloneOptions
CloneOptions
Clone actions.
Definition order_type.h:194
OrderType
OrderType
Order types.
Definition order_type.h:50
pool_func.hpp
Some methods of Pool are placed here in order to reduce compilation time and binary size.
INSTANTIATE_POOL_METHODS
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
Definition pool_func.hpp:210
IsRailDepotTile
static bool IsRailDepotTile(Tile t)
Is this tile rail tile and a rail depot?
Definition rail_map.h:105
IsRoadDepotTile
static bool IsRoadDepotTile(Tile t)
Return whether a tile is a road depot tile.
Definition road_map.h:100
roadveh.h
Road vehicle states.
safeguards.h
A number of safeguards to prevent using unsafe methods.
_settings_client
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
station_base.h
Base classes/functions for stations.
GetStationIndex
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
StationFacility::Dock
@ Dock
Station with a dock.
StationFacility::TruckStop
@ TruckStop
Station with truck stops.
StationFacility::Train
@ Train
Station with train station.
StationFacility::BusStop
@ BusStop
Station with bus stops.
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
GetEncodedString
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
strings_func.h
Functions related to OTTD's strings.
StringID
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition strings_type.h:19
INVALID_STRING_ID
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition strings_type.h:20
AircraftCache::cached_max_range_sqr
uint32_t cached_max_range_sqr
Cached squared maximum range.
Definition aircraft.h:65
AircraftCache::cached_max_range
uint16_t cached_max_range
Cached maximum range.
Definition aircraft.h:66
AircraftVehicleInfo::subtype
uint8_t subtype
Type of aircraft.
Definition engine_type.h:136
Aircraft
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:72
Aircraft::state
uint8_t state
State of the airport.
Definition aircraft.h:77
Aircraft::GetOrderStationLocation
TileIndex GetOrderStationLocation(StationID station) override
Determine the location for the station where the vehicle goes to next.
Definition aircraft_cmd.cpp:1315
Aircraft::targetairport
StationID targetairport
Airport to go to next.
Definition aircraft.h:76
AirportFTAClass::Flag::ShortStrip
@ ShortStrip
This airport has a short landing strip, dangerous for fast aircraft.
AirportFTAClass::flags
Flags flags
Flags for this airport type.
Definition airport.h:194
Airport::HasHangar
bool HasHangar() const
Check if this airport has at least one hangar.
Definition station_base.h:404
Airport::GetFTA
const AirportFTAClass * GetFTA() const
Get the finite-state machine for this airport or the finite-state machine for the dummy airport in ca...
Definition station_base.h:398
BaseConsist::current_order_time
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
Definition base_consist.h:37
BaseConsist::cur_real_order_index
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
Definition base_consist.h:47
BaseConsist::cur_implicit_order_index
VehicleOrderID cur_implicit_order_index
The index to the current implicit order.
Definition base_consist.h:48
BaseConsist::ResetDepotUnbunching
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
Definition base_consist.cpp:49
BaseStation
Base class for all station-ish types.
Definition base_station_base.h:58
BaseStation::xy
TileIndex xy
Base tile of the station.
Definition base_station_base.h:59
BaseStation::facilities
StationFacilities facilities
The facilities that this station has.
Definition base_station_base.h:69
BaseStation::owner
Owner owner
The owner of this station.
Definition base_station_base.h:68
BaseVehicle::type
VehicleType type
Type of vehicle.
Definition vehicle_type.h:51
Cheat::value
bool value
tells if the bool cheat is active or not
Definition cheat_type.h:18
Cheats::no_jetcrash
Cheat no_jetcrash
no jet will crash on small airports anymore
Definition cheat_type.h:31
ClientSettings::gui
GUISettings gui
settings related to the GUI
Definition settings_type.h:650
ClosestDepot
Structure to return information about the closest depot location, and whether it could be found.
Definition vehicle_base.h:192
ClosestDepot::destination
DestinationID destination
The DestinationID as used for orders.
Definition vehicle_base.h:194
CommandHelper
Definition command_func.h:84
Depot
Definition depot_base.h:20
DestinationID
Definition order_type.h:21
GUISettings::order_review_system
uint8_t order_review_system
perform order reviews on vehicles
Definition settings_type.h:166
OrderBackup::RemoveOrder
static void RemoveOrder(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
Definition order_backup.cpp:231
OrderList
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition order_base.h:274
OrderList::DeleteOrderAt
void DeleteOrderAt(VehicleOrderID index)
Remove an order from the order list and delete it.
Definition order_cmd.cpp:439
OrderList::orders
std::vector< Order > orders
Orders of the order list.
Definition order_base.h:285
OrderList::IsCompleteTimetable
bool IsCompleteTimetable() const
Checks whether all orders of the list have a filled timetable.
Definition order_cmd.cpp:486
OrderList::InsertOrderAt
void InsertOrderAt(Order &&order, VehicleOrderID index)
Insert a new order into the order chain.
Definition order_cmd.cpp:417
OrderList::RemoveVehicle
void RemoveVehicle(Vehicle *v)
Removes the vehicle from the shared order list.
Definition order_cmd.cpp:476
OrderList::num_vehicles
uint num_vehicles
NOSAVE: Number of vehicles that share this order list.
Definition order_base.h:283
OrderList::Initialize
void Initialize(Vehicle *v)
Recomputes everything.
Definition order_cmd.cpp:253
OrderList::timetable_duration
TimerGameTick::Ticks timetable_duration
NOSAVE: Total timetabled duration of the order list.
Definition order_base.h:288
OrderList::first_shared
Vehicle * first_shared
NOSAVE: pointer to the first vehicle in the shared order chain.
Definition order_base.h:284
OrderList::GetFirstOrder
VehicleOrderID GetFirstOrder() const
Get the first order of the order chain.
Definition order_base.h:328
OrderList::num_manual_orders
VehicleOrderID num_manual_orders
NOSAVE: How many manually added orders are there in the list.
Definition order_base.h:282
OrderList::MoveOrder
void MoveOrder(VehicleOrderID from, VehicleOrderID to)
Move an order to another position within the order list.
Definition order_cmd.cpp:457
OrderList::GetNextStoppingStation
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.
Definition order_cmd.cpp:363
OrderList::GetNext
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:362
OrderList::GetNumOrders
VehicleOrderID GetNumOrders() const
Get number of orders in the order list.
Definition order_base.h:372
OrderList::RecalculateTimetableDuration
void RecalculateTimetableDuration()
Recomputes Timetable duration.
Definition order_cmd.cpp:280
OrderList::FreeChain
void FreeChain(bool keep_orderlist=false)
Free a complete order chain.
Definition order_cmd.cpp:293
OrderList::GetNextDecisionNode
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...
Definition order_cmd.cpp:327
OrderList::IsShared
bool IsShared() const
Is this a shared order list?
Definition order_base.h:391
OrderList::total_duration
TimerGameTick::Ticks total_duration
NOSAVE: Total (timetabled or not) duration of the order list.
Definition order_base.h:289
Order
Definition order_base.h:33
Order::GetLocation
TileIndex GetLocation(const Vehicle *v, bool airport=false) const
Returns a tile somewhat representing the order destination (not suitable for pathfinding).
Definition order_cmd.cpp:562
Order::GetDepotOrderType
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition order_base.h:150
Order::GetTimetabledTravel
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:196
Order::GetConditionVariable
OrderConditionVariable GetConditionVariable() const
What variable do we have to compare?
Definition order_base.h:154
Order::Equals
bool Equals(const Order &other) const
Does this order have the same type, flags and destination?
Definition order_cmd.cpp:158
Order::MapOldOrder
uint16_t MapOldOrder() const
Pack this order into a 16 bits integer as close to the TTD representation as possible.
Definition order_cmd.cpp:180
Order::GetMaxSpeed
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:207
Order::max_speed
uint16_t max_speed
How fast the vehicle may go on the way to the destination.
Definition order_base.h:55
Order::SetTravelTimetabled
void SetTravelTimetabled(bool timetabled)
Set if the travel time is explicitly timetabled (unless the order is conditional).
Definition order_base.h:212
Order::GetDestination
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:99
Order::IsType
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:66
Order::SetNonStopType
void SetNonStopType(OrderNonStopFlags non_stop_type)
Set whether we must stop at stations or not.
Definition order_base.h:167
Order::GetConditionSkipToOrder
VehicleOrderID GetConditionSkipToOrder() const
Get the order to skip to.
Definition order_base.h:158
Order::GetStopLocation
OrderStopLocation GetStopLocation() const
Where must we stop at the platform?
Definition order_base.h:148
Order::GetWaitTime
uint16_t GetWaitTime() const
Get the time in ticks a vehicle will probably wait at the destination (timetabled or not).
Definition order_base.h:198
Order::GetRefitCargo
CargoType GetRefitCargo() const
Get the cargo to to refit to.
Definition order_base.h:127
Order::GetType
OrderType GetType() const
Get the type of order of this order.
Definition order_base.h:72
Order::IsFullLoadOrder
bool IsFullLoadOrder() const
Is this order a OrderLoadType::FullLoad or OrderLoadType::FullLoadAny?
Definition order_base.h:135
Order::MakeGoToStation
void MakeGoToStation(StationID destination)
Makes this order a Go To Station order.
Definition order_cmd.cpp:58
Order::type
uint8_t type
The type of order + non-stop flags.
Definition order_base.h:47
Order::wait_time
uint16_t wait_time
How long in ticks to wait at the destination.
Definition order_base.h:53
Order::SetRefit
void SetRefit(CargoType cargo)
Make this depot/station order also a refit order.
Definition order_cmd.cpp:148
Order::SetDepotOrderType
void SetDepotOrderType(OrderDepotTypeFlags depot_order_type)
Set the cause to go to the depot.
Definition order_base.h:171
Order::SetWaitTime
void SetWaitTime(uint16_t time)
Set the time in ticks to wait at the destination.
Definition order_base.h:218
Order::SetStopLocation
void SetStopLocation(OrderStopLocation stop_location)
Set where we must stop at the platform.
Definition order_base.h:169
Order::MakeDummy
void MakeDummy()
Makes this order a Dummy order.
Definition order_cmd.cpp:116
Order::MakeGoToWaypoint
void MakeGoToWaypoint(StationID destination)
Makes this order a Go To Waypoint order.
Definition order_cmd.cpp:87
Order::SetConditionVariable
void SetConditionVariable(OrderConditionVariable condition_variable)
Set variable we have to compare.
Definition order_base.h:175
Order::GetUnloadType
OrderUnloadType GetUnloadType() const
How must the consist be unloaded?
Definition order_base.h:144
Order::flags
uint8_t flags
Load/unload types, depot order/action types.
Definition order_base.h:48
Order::MakeGoToDepot
void MakeGoToDepot(DestinationID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=OrderNonStopFlag::NoIntermediate, OrderDepotActionFlags action={}, CargoType cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition order_cmd.cpp:73
Order::IsWaitTimetabled
bool IsWaitTimetabled() const
Does this order have an explicit wait time set?
Definition order_base.h:189
Order::dest
DestinationID dest
The destination of the order.
Definition order_base.h:49
Order::SetDestination
void SetDestination(DestinationID destination)
Sets the destination of this order.
Definition order_base.h:106
Order::SetWaitTimetabled
void SetWaitTimetabled(bool timetabled)
Set if the wait time is explicitly timetabled (unless the order is conditional).
Definition order_base.h:210
Order::IsTravelTimetabled
bool IsTravelTimetabled() const
Does this order have an explicit travel time set?
Definition order_base.h:191
Order::SetConditionComparator
void SetConditionComparator(OrderConditionComparator condition_comparator)
Set the comparator to use.
Definition order_base.h:177
Order::MakeConditional
void MakeConditional(VehicleOrderID order)
Makes this order an conditional order.
Definition order_cmd.cpp:126
Order::SetDepotActionType
void SetDepotActionType(OrderDepotActionFlags depot_service_type)
Set what we are going to do in the depot.
Definition order_base.h:173
Order::SetConditionSkipToOrder
void SetConditionSkipToOrder(VehicleOrderID order_id)
Get the order to skip to.
Definition order_base.h:179
Order::GetLoadType
OrderLoadType GetLoadType() const
How must the consist be loaded?
Definition order_base.h:142
Order::GetDepotActionType
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition order_base.h:152
Order::MakeLeaveStation
void MakeLeaveStation()
Makes this order a Leave Station order.
Definition order_cmd.cpp:107
Order::CanLeaveWithCargo
bool CanLeaveWithCargo(bool has_cargo) const
A vehicle can leave the current station with cargo if:
Definition order_cmd.cpp:2200
Order::SetConditionValue
void SetConditionValue(uint16_t value)
Set the value to base the skip on.
Definition order_base.h:181
Order::SetUnloadType
void SetUnloadType(OrderUnloadType unload_type)
Set how the consist must be unloaded.
Definition order_base.h:165
Order::Free
void Free()
'Free' the order
Definition order_cmd.cpp:47
Order::GetTimetabledWait
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:194
Order::ShouldStopAtStation
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...
Definition order_cmd.cpp:2176
Order::refit_cargo
CargoType refit_cargo
Refit CargoType.
Definition order_base.h:51
Order::GetTravelTime
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:200
Order::MakeImplicit
void MakeImplicit(StationID destination)
Makes this order an implicit order.
Definition order_cmd.cpp:137
Order::SetLoadType
void SetLoadType(OrderLoadType load_type)
Set how the consist must be loaded.
Definition order_base.h:163
Order::AssignOrder
void AssignOrder(const Order &other)
Assign data to an order (from another order) This function makes sure that the index is maintained co...
Definition order_cmd.cpp:235
Order::GetConditionComparator
OrderConditionComparator GetConditionComparator() const
What is the comparator to use?
Definition order_base.h:156
Order::GetNonStopType
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition order_base.h:146
Order::IsRefit
bool IsRefit() const
Is this order a refit order.
Definition order_base.h:113
Order::MakeLoading
void MakeLoading(bool ordered)
Makes this order a Loading order.
Definition order_cmd.cpp:98
Order::GetConditionValue
uint16_t GetConditionValue() const
Get the value to base the skip on.
Definition order_base.h:160
Order::travel_time
uint16_t travel_time
How long in ticks the journey to this destination should take.
Definition order_base.h:54
OrthogonalTileArea::tile
TileIndex tile
The base tile of the area.
Definition tilearea_type.h:19
PoolID
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:43
Pool::PoolItem<&_vehicle_pool >::Iterate
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition pool_type.hpp:436
Pool::PoolItem<&_station_pool >::Get
static Titem * Get(auto index)
Returns Titem with given index.
Definition pool_type.hpp:387
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:286
Pool::PoolItem<&_orderlist_pool >::CanAllocateItem
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition pool_type.hpp:357
Pool::PoolItem<&_station_pool >::GetIfValid
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Definition pool_type.hpp:398
Pool
Base class for all pools.
Definition pool_type.hpp:133
SpecializedStation< Station, false >::Get
static Station * Get(auto index)
Gets station with given index.
Definition base_station_base.h:248
SpecializedStation< Station, false >::GetIfValid
static Station * GetIfValid(auto index)
Returns station if the index is a valid index for this station type.
Definition base_station_base.h:257
SpecializedVehicle::From
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Definition vehicle_base.h:1134
Station
Station data structure.
Definition station_base.h:520
Station::ship_station
TileArea ship_station
Tile area the ship 'station' part covers.
Definition station_base.h:535
Station::airport
Airport airport
Tile area the airport covers.
Definition station_base.h:534
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > >
Vehicle
Vehicle data structure.
Definition vehicle_base.h:205
Vehicle::engine_type
EngineID engine_type
The type of engine used for this vehicle.
Definition vehicle_base.h:278
Vehicle::GetGroundVehicleFlags
uint16_t & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition vehicle.cpp:3173
Vehicle::IsOrderListShared
bool IsOrderListShared() const
Check if we share our orders with another vehicle.
Definition vehicle_base.h:699
Vehicle::GetEngine
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition vehicle.cpp:718
Vehicle::IncrementRealOrderIndex
void IncrementRealOrderIndex()
Advanced cur_real_order_index to the next real order, keeps care of the wrap-around and invalidates t...
Definition vehicle_base.h:854
Vehicle::GetOrder
Order * GetOrder(int index) const
Returns order 'index' of a vehicle or nullptr when it doesn't exists.
Definition vehicle_base.h:890
Vehicle::HasDepotOrder
bool HasDepotOrder() const
Checks if a vehicle has a depot in its order list.
Definition order_cmd.cpp:1819
Vehicle::LeaveStation
void LeaveStation()
Perform all actions when leaving a station.
Definition vehicle.cpp:2327
Vehicle::AddToShared
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:2956
Vehicle::HasUnbunchingOrder
bool HasUnbunchingOrder() const
Check if the current vehicle has an unbunching order.
Definition vehicle.cpp:2462
Vehicle::GetNumOrders
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
Definition vehicle_base.h:705
Vehicle::day_counter
uint8_t day_counter
Increased by one for each day.
Definition vehicle_base.h:304
Vehicle::GetDisplayMaxSpeed
virtual int GetDisplayMaxSpeed() const
Gets the maximum speed in km-ish/h that can be sent into string parameters for string processing.
Definition vehicle_base.h:485
Vehicle::IncrementImplicitOrderIndex
void IncrementImplicitOrderIndex()
Increments cur_implicit_order_index, keeps care of the wrap-around and invalidates the GUI.
Definition vehicle_base.h:830
Vehicle::IsGroundVehicle
bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
Definition vehicle_base.h:470
Vehicle::vehstatus
VehStates vehstatus
Status.
Definition vehicle_base.h:309
Vehicle::GetNumManualOrders
VehicleOrderID GetNumManualOrders() const
Get the number of manually added orders this vehicle has.
Definition vehicle_base.h:711
Vehicle::GetOrderStationLocation
virtual TileIndex GetOrderStationLocation(StationID station)
Determine the location for the station where the vehicle goes to next.
Definition vehicle_base.h:764
Vehicle::current_order
Order current_order
The current order (+ status, like: loading)
Definition vehicle_base.h:311
Vehicle::orders
OrderList * orders
Pointer to the order list for this vehicle.
Definition vehicle_base.h:314
Vehicle::FindClosestDepot
virtual ClosestDepot FindClosestDepot()
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
Definition vehicle_base.h:773
Vehicle::NextShared
Vehicle * NextShared() const
Get the next vehicle of the shared vehicle chain.
Definition vehicle_base.h:681
Vehicle::HasFullLoadOrder
bool HasFullLoadOrder() const
Check if the current vehicle has a full load order.
Definition vehicle.cpp:2442
Vehicle::IsPrimaryVehicle
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
Definition vehicle_base.h:432
Vehicle::age
TimerGameCalendar::Date age
Age in calendar days.
Definition vehicle_base.h:253
Vehicle::max_age
TimerGameCalendar::Date max_age
Maximum age.
Definition vehicle_base.h:255
Vehicle::reliability
uint16_t reliability
Reliability.
Definition vehicle_base.h:258
Vehicle::PreviousShared
Vehicle * PreviousShared() const
Get the previous vehicle of the shared vehicle chain.
Definition vehicle_base.h:687
Vehicle::FirstShared
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
Definition vehicle_base.h:693
Vehicle::RemoveFromShared
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition vehicle.cpp:2979
Vehicle::tile
TileIndex tile
Current tile index.
Definition vehicle_base.h:225
Vehicle::dest_tile
TileIndex dest_tile
Heading for this tile.
Definition vehicle_base.h:232
Vehicle::NeedsServicing
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
Vehicle::HasConditionalOrder
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition vehicle.cpp:2453
Vehicle::last_station_visited
StationID last_station_visited
The last station we stopped at.
Definition vehicle_base.h:292
Vehicle::owner
Owner owner
Which company owns the vehicle?
Definition vehicle_base.h:270
Vehicle::DeleteUnreachedImplicitOrders
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition vehicle.cpp:2145
Vehicle::UpdateRealOrderIndex
void UpdateRealOrderIndex()
Skip implicit orders until cur_real_order_index is a non-implicit order.
Definition vehicle_base.h:869
Waypoint
Representation of a waypoint.
Definition waypoint_base.h:23
IsTileType
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
GetTileOwner
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
INVALID_TILE
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
MP_STATION
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
timetable.h
Functions related to time tabling.
UpdateVehicleTimetable
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
Update the timetable for the vehicle.
Definition timetable_cmd.cpp:469
train_cmd.h
Command definitions related to trains.
GetVehicleCannotUseStationReason
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:3092
CalcPercentVehicleFilled
uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1461
CanVehicleUseStation
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3046
VehState::Crashed
@ Crashed
Vehicle is crashed.
VehState::Stopped
@ Stopped
Vehicle is stopped by the player.
vehicle_func.h
Functions related to vehicles.
VIWD_MODIFY_ORDERS
@ VIWD_MODIFY_ORDERS
Other order modifications.
Definition vehicle_gui.h:36
VIWD_REMOVE_ALL_ORDERS
@ VIWD_REMOVE_ALL_ORDERS
Removed / replaced all orders (after deleting / sharing).
Definition vehicle_gui.h:35
GetWindowClassForVehicleType
WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition vehicle_gui.h:97
VEH_ROAD
@ VEH_ROAD
Road vehicle type.
Definition vehicle_type.h:26
VEH_AIRCRAFT
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition vehicle_type.h:28
VEH_SHIP
@ VEH_SHIP
Ship vehicle type.
Definition vehicle_type.h:27
VEH_TRAIN
@ VEH_TRAIN
Train vehicle type.
Definition vehicle_type.h:25
IsShipDepotTile
bool IsShipDepotTile(Tile t)
Is it a ship depot tile?
Definition water_map.h:234
waypoint_base.h
Base of waypoints.
SetWindowClassesDirty
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3205
InvalidateWindowData
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:3297
SetWindowDirty
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3179
InvalidateWindowClassesData
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:3314
WC_STATION_LIST
@ WC_STATION_LIST
Station list; Window numbers:
Definition window_type.h:307
WC_VEHICLE_ORDERS
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
Definition window_type.h:217
WC_SHIPS_LIST
@ WC_SHIPS_LIST
Ships list; Window numbers:
Definition window_type.h:325
WC_VEHICLE_VIEW
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
Definition window_type.h:344
WC_VEHICLE_TIMETABLE
@ WC_VEHICLE_TIMETABLE
Vehicle timetable; Window numbers:
Definition window_type.h:229
WC_AIRCRAFT_LIST
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers:
Definition window_type.h:331