OpenTTD Source  20241120-master-g6d3adc6169
order_cmd.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "debug.h"
12 #include "command_func.h"
13 #include "company_func.h"
14 #include "news_func.h"
15 #include "strings_func.h"
16 #include "timetable.h"
17 #include "vehicle_func.h"
18 #include "depot_base.h"
19 #include "core/pool_func.hpp"
20 #include "core/random_func.hpp"
21 #include "aircraft.h"
22 #include "roadveh.h"
23 #include "station_base.h"
24 #include "waypoint_base.h"
25 #include "company_base.h"
26 #include "order_backup.h"
27 #include "cheat_type.h"
28 #include "order_cmd.h"
29 #include "train_cmd.h"
30 
31 #include "table/strings.h"
32 
33 #include "safeguards.h"
34 
35 /* DestinationID must be at least as large as every these below, because it can
36  * be any of them
37  */
38 static_assert(sizeof(DestinationID) >= sizeof(DepotID));
39 static_assert(sizeof(DestinationID) >= sizeof(StationID));
40 
41 OrderPool _order_pool("Order");
43 OrderListPool _orderlist_pool("OrderList");
45 
46 
48 {
49  if (CleaningPool()) return;
50 
51  /* We can visit oil rigs and buoys that are not our own. They will be shown in
52  * the list of stations. So, we need to invalidate that window if needed. */
53  if (this->IsType(OT_GOTO_STATION) || this->IsType(OT_GOTO_WAYPOINT)) {
54  BaseStation *bs = BaseStation::GetIfValid(this->GetDestination());
55  if (bs != nullptr && bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0);
56  }
57 }
58 
64 {
65  this->type = OT_NOTHING;
66  this->flags = 0;
67  this->dest = 0;
68  this->next = nullptr;
69 }
70 
75 void Order::MakeGoToStation(StationID destination)
76 {
77  this->type = OT_GOTO_STATION;
78  this->flags = 0;
79  this->dest = destination;
80 }
81 
91 {
92  this->type = OT_GOTO_DEPOT;
93  this->SetDepotOrderType(order);
94  this->SetDepotActionType(action);
95  this->SetNonStopType(non_stop_type);
96  this->dest = destination;
97  this->SetRefit(cargo);
98 }
99 
104 void Order::MakeGoToWaypoint(StationID destination)
105 {
106  this->type = OT_GOTO_WAYPOINT;
107  this->flags = 0;
108  this->dest = destination;
109 }
110 
115 void Order::MakeLoading(bool ordered)
116 {
117  this->type = OT_LOADING;
118  if (!ordered) this->flags = 0;
119 }
120 
125 {
126  this->type = OT_LEAVESTATION;
127  this->flags = 0;
128 }
129 
134 {
135  this->type = OT_DUMMY;
136  this->flags = 0;
137 }
138 
144 {
145  this->type = OT_CONDITIONAL;
146  this->flags = order;
147  this->dest = 0;
148 }
149 
154 void Order::MakeImplicit(StationID destination)
155 {
156  this->type = OT_IMPLICIT;
157  this->dest = destination;
158 }
159 
166 {
167  this->refit_cargo = cargo;
168 }
169 
175 bool Order::Equals(const Order &other) const
176 {
177  /* In case of go to nearest depot orders we need "only" compare the flags
178  * with the other and not the nearest depot order bit or the actual
179  * destination because those get clear/filled in during the order
180  * evaluation. If we do not do this the order will continuously be seen as
181  * a different order and it will try to find a "nearest depot" every tick. */
182  if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
183  ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
184  (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
185  return this->GetDepotOrderType() == other.GetDepotOrderType() &&
187  }
188 
189  return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
190 }
191 
198 uint32_t Order::Pack() const
199 {
200  return this->dest << 16 | this->flags << 8 | this->type;
201 }
202 
208 uint16_t Order::MapOldOrder() const
209 {
210  uint16_t order = this->GetType();
211  switch (this->type) {
212  case OT_GOTO_STATION:
213  if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
214  if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
216  order |= GB(this->GetDestination(), 0, 8) << 8;
217  break;
218  case OT_GOTO_DEPOT:
219  if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
220  SetBit(order, 7);
221  order |= GB(this->GetDestination(), 0, 8) << 8;
222  break;
223  case OT_LOADING:
224  if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
225  break;
226  }
227  return order;
228 }
229 
235 void InvalidateVehicleOrder(const Vehicle *v, int data)
236 {
238 
239  if (data != 0) {
240  /* Calls SetDirty() too */
243  return;
244  }
245 
248 }
249 
257 void Order::AssignOrder(const Order &other)
258 {
259  this->type = other.type;
260  this->flags = other.flags;
261  this->dest = other.dest;
262 
263  this->refit_cargo = other.refit_cargo;
264 
265  this->wait_time = other.wait_time;
266  this->travel_time = other.travel_time;
267  this->max_speed = other.max_speed;
268 }
269 
276 {
277  this->first = chain;
278  this->first_shared = v;
279 
280  this->num_orders = 0;
281  this->num_manual_orders = 0;
282  this->num_vehicles = 1;
283  this->timetable_duration = 0;
284 
285  for (Order *o = this->first; o != nullptr; o = o->next) {
286  ++this->num_orders;
287  if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
288  this->total_duration += o->GetWaitTime() + o->GetTravelTime();
289  }
290 
292 
293  for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
294  ++this->num_vehicles;
295  this->first_shared = u;
296  }
297 
298  for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
299 }
300 
306 {
307  this->timetable_duration = 0;
308  for (Order *o = this->first; o != nullptr; o = o->next) {
309  this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
310  }
311 }
312 
318 void OrderList::FreeChain(bool keep_orderlist)
319 {
320  Order *next;
321  for (Order *o = this->first; o != nullptr; o = next) {
322  next = o->next;
323  delete o;
324  }
325 
326  if (keep_orderlist) {
327  this->first = nullptr;
328  this->num_orders = 0;
329  this->num_manual_orders = 0;
330  this->timetable_duration = 0;
331  } else {
332  delete this;
333  }
334 }
335 
341 Order *OrderList::GetOrderAt(int index) const
342 {
343  if (index < 0) return nullptr;
344 
345  Order *order = this->first;
346 
347  while (order != nullptr && index-- > 0) {
348  order = order->next;
349  }
350  return order;
351 }
352 
364 const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
365 {
366  if (hops > this->GetNumOrders() || next == nullptr) return nullptr;
367 
368  if (next->IsType(OT_CONDITIONAL)) {
369  if (next->GetConditionVariable() != OCV_UNCONDITIONALLY) return next;
370 
371  /* We can evaluate trivial conditions right away. They're conceptually
372  * the same as regular order progression. */
373  return this->GetNextDecisionNode(
374  this->GetOrderAt(next->GetConditionSkipToOrder()),
375  hops + 1);
376  }
377 
378  if (next->IsType(OT_GOTO_DEPOT)) {
379  if ((next->GetDepotActionType() & ODATFB_HALT) != 0) return nullptr;
380  if (next->IsRefit()) return next;
381  }
382 
383  if (!next->CanLoadOrUnload()) {
384  return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
385  }
386 
387  return next;
388 }
389 
399 StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first, uint hops) const
400 {
401 
402  const Order *next = first;
403  if (first == nullptr) {
404  next = this->GetOrderAt(v->cur_implicit_order_index);
405  if (next == nullptr) {
406  next = this->GetFirstOrder();
407  if (next == nullptr) return INVALID_STATION;
408  } else {
409  /* GetNext never returns nullptr if there is a valid station in the list.
410  * As the given "next" is already valid and a station in the list, we
411  * don't have to check for nullptr here. */
412  next = this->GetNext(next);
413  assert(next != nullptr);
414  }
415  }
416 
417  do {
418  next = this->GetNextDecisionNode(next, ++hops);
419 
420  /* Resolve possibly nested conditionals by estimation. */
421  while (next != nullptr && next->IsType(OT_CONDITIONAL)) {
422  /* We return both options of conditional orders. */
423  const Order *skip_to = this->GetNextDecisionNode(
424  this->GetOrderAt(next->GetConditionSkipToOrder()), hops);
425  const Order *advance = this->GetNextDecisionNode(
426  this->GetNext(next), hops);
427  if (advance == nullptr || advance == first || skip_to == advance) {
428  next = (skip_to == first) ? nullptr : skip_to;
429  } else if (skip_to == nullptr || skip_to == first) {
430  next = (advance == first) ? nullptr : advance;
431  } else {
432  StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
433  StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
434  while (!st2.IsEmpty()) st1.Push(st2.Pop());
435  return st1;
436  }
437  ++hops;
438  }
439 
440  /* Don't return a next stop if the vehicle has to unload everything. */
441  if (next == nullptr || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) &&
442  next->GetDestination() == v->last_station_visited &&
443  (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
444  return INVALID_STATION;
445  }
446  } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
447 
448  return next->GetDestination();
449 }
450 
456 void OrderList::InsertOrderAt(Order *new_order, int index)
457 {
458  if (this->first == nullptr) {
459  this->first = new_order;
460  } else {
461  if (index == 0) {
462  /* Insert as first or only order */
463  new_order->next = this->first;
464  this->first = new_order;
465  } else if (index >= this->num_orders) {
466  /* index is after the last order, add it to the end */
467  this->GetLastOrder()->next = new_order;
468  } else {
469  /* Put the new order in between */
470  Order *order = this->GetOrderAt(index - 1);
471  new_order->next = order->next;
472  order->next = new_order;
473  }
474  }
475  ++this->num_orders;
476  if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
477  this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
478  this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
479 
480  /* We can visit oil rigs and buoys that are not our own. They will be shown in
481  * the list of stations. So, we need to invalidate that window if needed. */
482  if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
483  BaseStation *bs = BaseStation::Get(new_order->GetDestination());
485  }
486 
487 }
488 
489 
495 {
496  if (index >= this->num_orders) return;
497 
498  Order *to_remove;
499 
500  if (index == 0) {
501  to_remove = this->first;
502  this->first = to_remove->next;
503  } else {
504  Order *prev = GetOrderAt(index - 1);
505  to_remove = prev->next;
506  prev->next = to_remove->next;
507  }
508  --this->num_orders;
509  if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
510  this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
511  this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
512  delete to_remove;
513 }
514 
520 void OrderList::MoveOrder(int from, int to)
521 {
522  if (from >= this->num_orders || to >= this->num_orders || from == to) return;
523 
524  Order *moving_one;
525 
526  /* Take the moving order out of the pointer-chain */
527  if (from == 0) {
528  moving_one = this->first;
529  this->first = moving_one->next;
530  } else {
531  Order *one_before = GetOrderAt(from - 1);
532  moving_one = one_before->next;
533  one_before->next = moving_one->next;
534  }
535 
536  /* Insert the moving_order again in the pointer-chain */
537  if (to == 0) {
538  moving_one->next = this->first;
539  this->first = moving_one;
540  } else {
541  Order *one_before = GetOrderAt(to - 1);
542  moving_one->next = one_before->next;
543  one_before->next = moving_one;
544  }
545 }
546 
553 {
554  --this->num_vehicles;
555  if (v == this->first_shared) this->first_shared = v->NextShared();
556 }
557 
563 {
564  for (Order *o = this->first; o != nullptr; o = o->next) {
565  /* Implicit orders are, by definition, not timetabled. */
566  if (o->IsType(OT_IMPLICIT)) continue;
567  if (!o->IsCompletelyTimetabled()) return false;
568  }
569  return true;
570 }
571 
572 #ifdef WITH_ASSERT
576 void OrderList::DebugCheckSanity() const
577 {
578  VehicleOrderID check_num_orders = 0;
579  VehicleOrderID check_num_manual_orders = 0;
580  uint check_num_vehicles = 0;
581  TimerGameTick::Ticks check_timetable_duration = 0;
582  TimerGameTick::Ticks check_total_duration = 0;
583 
584  Debug(misc, 6, "Checking OrderList {} for sanity...", this->index);
585 
586  for (const Order *o = this->first; o != nullptr; o = o->next) {
587  ++check_num_orders;
588  if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
589  check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
590  check_total_duration += o->GetWaitTime() + o->GetTravelTime();
591  }
592  assert(this->num_orders == check_num_orders);
593  assert(this->num_manual_orders == check_num_manual_orders);
594  assert(this->timetable_duration == check_timetable_duration);
595  assert(this->total_duration == check_total_duration);
596 
597  for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
598  ++check_num_vehicles;
599  assert(v->orders == this);
600  }
601  assert(this->num_vehicles == check_num_vehicles);
602  Debug(misc, 6, "... detected {} orders ({} manual), {} vehicles, {} timetabled, {} total",
603  (uint)this->num_orders, (uint)this->num_manual_orders,
604  this->num_vehicles, this->timetable_duration, this->total_duration);
605 }
606 #endif
607 
615 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
616 {
617  return o->IsType(OT_GOTO_STATION) ||
618  (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && o->GetDestination() != INVALID_STATION);
619 }
620 
627 static void DeleteOrderWarnings(const Vehicle *v)
628 {
629  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
630  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
631  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
632  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
633  DeleteVehicleNews(v->index, STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY);
634 }
635 
642 TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
643 {
644  switch (this->GetType()) {
645  case OT_GOTO_WAYPOINT:
646  case OT_GOTO_STATION:
647  case OT_IMPLICIT:
648  if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile;
649  return BaseStation::Get(this->GetDestination())->xy;
650 
651  case OT_GOTO_DEPOT:
652  if (this->GetDestination() == INVALID_DEPOT) return INVALID_TILE;
653  return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
654 
655  default:
656  return INVALID_TILE;
657  }
658 }
659 
669 uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
670 {
671  if (cur->IsType(OT_CONDITIONAL)) {
672  if (conditional_depth > v->GetNumOrders()) return 0;
673 
674  conditional_depth++;
675 
676  int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
677  int dist2 = GetOrderDistance(prev, cur->next == nullptr ? v->orders->GetFirstOrder() : cur->next, v, conditional_depth);
678  return std::max(dist1, dist2);
679  }
680 
681  TileIndex prev_tile = prev->GetLocation(v, true);
682  TileIndex cur_tile = cur->GetLocation(v, true);
683  if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
684  return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
685 }
686 
698 {
699  Vehicle *v = Vehicle::GetIfValid(veh);
700  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
701 
702  CommandCost ret = CheckOwnership(v->owner);
703  if (ret.Failed()) return ret;
704 
705  /* Validate properties we don't want to have different from default as they are set by other commands. */
706  if (new_order.GetRefitCargo() != CARGO_NO_REFIT || new_order.GetWaitTime() != 0 || new_order.GetTravelTime() != 0 || new_order.GetMaxSpeed() != UINT16_MAX) return CMD_ERROR;
707 
708  /* Check if the inserted order is to the correct destination (owner, type),
709  * and has the correct flags if any */
710  switch (new_order.GetType()) {
711  case OT_GOTO_STATION: {
712  const Station *st = Station::GetIfValid(new_order.GetDestination());
713  if (st == nullptr) return CMD_ERROR;
714 
715  if (st->owner != OWNER_NONE) {
716  ret = CheckOwnership(st->owner);
717  if (ret.Failed()) return ret;
718  }
719 
720  if (!CanVehicleUseStation(v, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, GetVehicleCannotUseStationReason(v, st));
721  for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
722  if (!CanVehicleUseStation(u, st)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER_SHARED, GetVehicleCannotUseStationReason(u, st));
723  }
724 
725  /* Non stop only allowed for ground vehicles. */
726  if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
727 
728  /* Filter invalid load/unload types. */
729  switch (new_order.GetLoadType()) {
731  case OLFB_NO_LOAD:
732  break;
733 
734  case OLFB_FULL_LOAD:
735  case OLF_FULL_LOAD_ANY:
736  if (v->HasUnbunchingOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
737  break;
738 
739  default:
740  return CMD_ERROR;
741  }
742  switch (new_order.GetUnloadType()) {
743  case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
744  default: return CMD_ERROR;
745  }
746 
747  /* Filter invalid stop locations */
748  switch (new_order.GetStopLocation()) {
750  case OSL_PLATFORM_MIDDLE:
751  if (v->type != VEH_TRAIN) return CMD_ERROR;
752  [[fallthrough]];
753 
755  break;
756 
757  default:
758  return CMD_ERROR;
759  }
760 
761  break;
762  }
763 
764  case OT_GOTO_DEPOT: {
765  if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
766  if (v->type == VEH_AIRCRAFT) {
767  const Station *st = Station::GetIfValid(new_order.GetDestination());
768 
769  if (st == nullptr) return CMD_ERROR;
770 
771  ret = CheckOwnership(st->owner);
772  if (ret.Failed()) return ret;
773 
774  if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
775  return CMD_ERROR;
776  }
777  } else {
778  const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
779 
780  if (dp == nullptr) return CMD_ERROR;
781 
782  ret = CheckOwnership(GetTileOwner(dp->xy));
783  if (ret.Failed()) return ret;
784 
785  switch (v->type) {
786  case VEH_TRAIN:
787  if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
788  break;
789 
790  case VEH_ROAD:
791  if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
792  break;
793 
794  case VEH_SHIP:
795  if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
796  break;
797 
798  default: return CMD_ERROR;
799  }
800  }
801  }
802 
803  if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
804  if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
806 
807  /* Vehicles cannot have a "service if needed" order that also has a depot action. */
808  if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & (ODATFB_HALT | ODATFB_UNBUNCH))) return CMD_ERROR;
809 
810  /* Check if we're allowed to have a new unbunching order. */
811  if ((new_order.GetDepotActionType() & ODATFB_UNBUNCH)) {
812  if (v->HasFullLoadOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
813  if (v->HasUnbunchingOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
814  if (v->HasConditionalOrder()) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
815  }
816  break;
817  }
818 
819  case OT_GOTO_WAYPOINT: {
820  const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
821  if (wp == nullptr) return CMD_ERROR;
822 
823  switch (v->type) {
824  default: return CMD_ERROR;
825 
826  case VEH_TRAIN: {
827  if (!(wp->facilities & FACIL_TRAIN)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_RAIL_WAYPOINT);
828 
829  ret = CheckOwnership(wp->owner);
830  if (ret.Failed()) return ret;
831  break;
832  }
833 
834  case VEH_ROAD: {
835  if (!(wp->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP))) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_ROAD_WAYPOINT);
836 
837  ret = CheckOwnership(wp->owner);
838  if (ret.Failed()) return ret;
839  break;
840  }
841 
842  case VEH_SHIP:
843  if (!(wp->facilities & FACIL_DOCK)) return CommandCost(STR_ERROR_CAN_T_ADD_ORDER, STR_ERROR_NO_BUOY);
844  if (wp->owner != OWNER_NONE) {
845  ret = CheckOwnership(wp->owner);
846  if (ret.Failed()) return ret;
847  }
848  break;
849  }
850 
851  /* Order flags can be any of the following for waypoints:
852  * [non-stop]
853  * non-stop orders (if any) are only valid for trains and road vehicles */
854  if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
855  break;
856  }
857 
858  case OT_CONDITIONAL: {
859  VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
860  if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
861  if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
862  if (v->HasUnbunchingOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_CONDITIONAL);
863 
865  if (occ >= OCC_END) return CMD_ERROR;
866  switch (new_order.GetConditionVariable()) {
868  if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
869  break;
870 
871  case OCV_UNCONDITIONALLY:
872  if (occ != OCC_EQUALS) return CMD_ERROR;
873  if (new_order.GetConditionValue() != 0) return CMD_ERROR;
874  break;
875 
876  case OCV_LOAD_PERCENTAGE:
877  case OCV_RELIABILITY:
878  if (new_order.GetConditionValue() > 100) return CMD_ERROR;
879  [[fallthrough]];
880 
881  default:
882  if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
883  break;
884  }
885  break;
886  }
887 
888  default: return CMD_ERROR;
889  }
890 
891  if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
892 
893  if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
894  if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
895  if (v->orders == nullptr && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
896 
897  if (flags & DC_EXEC) {
898  Order *new_o = new Order();
899  new_o->AssignOrder(new_order);
900  InsertOrder(v, new_o, sel_ord);
901  }
902 
903  return CommandCost();
904 }
905 
912 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
913 {
914  /* Create new order and link in list */
915  if (v->orders == nullptr) {
916  v->orders = new OrderList(new_o, v);
917  } else {
918  v->orders->InsertOrderAt(new_o, sel_ord);
919  }
920 
921  Vehicle *u = v->FirstShared();
923  for (; u != nullptr; u = u->NextShared()) {
924  assert(v->orders == u->orders);
925 
926  /* If there is added an order before the current one, we need
927  * to update the selected order. We do not change implicit/real order indices though.
928  * If the new order is between the current implicit order and real order, the implicit order will
929  * later skip the inserted order. */
930  if (sel_ord <= u->cur_real_order_index) {
931  uint cur = u->cur_real_order_index + 1;
932  /* Check if we don't go out of bound */
933  if (cur < u->GetNumOrders()) {
934  u->cur_real_order_index = cur;
935  }
936  }
937  if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
938  /* We are inserting an order just before the current implicit order.
939  * We do not know whether we will reach current implicit or the newly inserted order first.
940  * So, disable creation of implicit orders until we are on track again. */
941  uint16_t &gv_flags = u->GetGroundVehicleFlags();
943  }
944  if (sel_ord <= u->cur_implicit_order_index) {
945  uint cur = u->cur_implicit_order_index + 1;
946  /* Check if we don't go out of bound */
947  if (cur < u->GetNumOrders()) {
948  u->cur_implicit_order_index = cur;
949  }
950  }
951  /* Unbunching data is no longer valid. */
953 
954  /* Update any possible open window of the vehicle */
955  InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
956  }
957 
958  /* As we insert an order, the order to skip to will be 'wrong'. */
959  VehicleOrderID cur_order_id = 0;
960  for (Order *order : v->Orders()) {
961  if (order->IsType(OT_CONDITIONAL)) {
962  VehicleOrderID order_id = order->GetConditionSkipToOrder();
963  if (order_id >= sel_ord) {
964  order->SetConditionSkipToOrder(order_id + 1);
965  }
966  if (order_id == cur_order_id) {
967  order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
968  }
969  }
970  cur_order_id++;
971  }
972 
973  /* Make sure to rebuild the whole list */
975 }
976 
983 {
984  if (flags & DC_EXEC) {
985  DeleteVehicleOrders(dst);
988  }
989  return CommandCost();
990 }
991 
1000 {
1001  Vehicle *v = Vehicle::GetIfValid(veh_id);
1002 
1003  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1004 
1005  CommandCost ret = CheckOwnership(v->owner);
1006  if (ret.Failed()) return ret;
1007 
1008  /* If we did not select an order, we maybe want to de-clone the orders */
1009  if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
1010 
1011  if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
1012 
1013  if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
1014  return CommandCost();
1015 }
1016 
1022 {
1023  assert(v->current_order.IsType(OT_LOADING));
1024  /* NON-stop flag is misused to see if a train is in a station that is
1025  * on its order list or not */
1027  /* When full loading, "cancel" that order so the vehicle doesn't
1028  * stay indefinitely at this station anymore. */
1030 }
1031 
1038 {
1039  v->orders->DeleteOrderAt(sel_ord);
1040 
1041  Vehicle *u = v->FirstShared();
1043  for (; u != nullptr; u = u->NextShared()) {
1044  assert(v->orders == u->orders);
1045 
1046  if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
1048  }
1049 
1050  if (sel_ord < u->cur_real_order_index) {
1051  u->cur_real_order_index--;
1052  } else if (sel_ord == u->cur_real_order_index) {
1053  u->UpdateRealOrderIndex();
1054  }
1055 
1056  if (sel_ord < u->cur_implicit_order_index) {
1058  } else if (sel_ord == u->cur_implicit_order_index) {
1059  /* Make sure the index is valid */
1061 
1062  /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
1063  while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) {
1066  }
1067  }
1068  /* Unbunching data is no longer valid. */
1069  u->ResetDepotUnbunching();
1070 
1071  /* Update any possible open window of the vehicle */
1072  InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1073  }
1074 
1075  /* As we delete an order, the order to skip to will be 'wrong'. */
1076  VehicleOrderID cur_order_id = 0;
1077  for (Order *order : v->Orders()) {
1078  if (order->IsType(OT_CONDITIONAL)) {
1079  VehicleOrderID order_id = order->GetConditionSkipToOrder();
1080  if (order_id >= sel_ord) {
1081  order_id = std::max(order_id - 1, 0);
1082  }
1083  if (order_id == cur_order_id) {
1084  order_id = (order_id + 1) % v->GetNumOrders();
1085  }
1086  order->SetConditionSkipToOrder(order_id);
1087  }
1088  cur_order_id++;
1089  }
1090 
1092 }
1093 
1102 {
1103  Vehicle *v = Vehicle::GetIfValid(veh_id);
1104 
1105  if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1106 
1107  CommandCost ret = CheckOwnership(v->owner);
1108  if (ret.Failed()) return ret;
1109 
1110  if (flags & DC_EXEC) {
1111  if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1112 
1114  v->UpdateRealOrderIndex();
1115 
1116  /* Unbunching data is no longer valid. */
1117  v->ResetDepotUnbunching();
1118 
1120 
1121  /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1124  }
1125 
1126  return CommandCost();
1127 }
1128 
1140 {
1141  Vehicle *v = Vehicle::GetIfValid(veh);
1142  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1143 
1144  CommandCost ret = CheckOwnership(v->owner);
1145  if (ret.Failed()) return ret;
1146 
1147  /* Don't make senseless movements */
1148  if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1149  moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1150 
1151  Order *moving_one = v->GetOrder(moving_order);
1152  /* Don't move an empty order */
1153  if (moving_one == nullptr) return CMD_ERROR;
1154 
1155  if (flags & DC_EXEC) {
1156  v->orders->MoveOrder(moving_order, target_order);
1157 
1158  /* Update shared list */
1159  Vehicle *u = v->FirstShared();
1160 
1162 
1163  for (; u != nullptr; u = u->NextShared()) {
1164  /* Update the current order.
1165  * There are multiple ways to move orders, which result in cur_implicit_order_index
1166  * and cur_real_order_index to not longer make any sense. E.g. moving another
1167  * real order between them.
1168  *
1169  * Basically one could choose to preserve either of them, but not both.
1170  * While both ways are suitable in this or that case from a human point of view, neither
1171  * of them makes really sense.
1172  * However, from an AI point of view, preserving cur_real_order_index is the most
1173  * predictable and transparent behaviour.
1174  *
1175  * With that decision it basically does not matter what we do to cur_implicit_order_index.
1176  * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1177  * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1178  * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1179  */
1180  if (u->cur_real_order_index == moving_order) {
1181  u->cur_real_order_index = target_order;
1182  } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1183  u->cur_real_order_index--;
1184  } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1185  u->cur_real_order_index++;
1186  }
1187 
1188  if (u->cur_implicit_order_index == moving_order) {
1189  u->cur_implicit_order_index = target_order;
1190  } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1192  } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1194  }
1195  /* Unbunching data is no longer valid. */
1196  u->ResetDepotUnbunching();
1197 
1198 
1199  assert(v->orders == u->orders);
1200  /* Update any possible open window of the vehicle */
1201  InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1202  }
1203 
1204  /* As we move an order, the order to skip to will be 'wrong'. */
1205  for (Order *order : v->Orders()) {
1206  if (order->IsType(OT_CONDITIONAL)) {
1207  VehicleOrderID order_id = order->GetConditionSkipToOrder();
1208  if (order_id == moving_order) {
1209  order_id = target_order;
1210  } else if (order_id > moving_order && order_id <= target_order) {
1211  order_id--;
1212  } else if (order_id < moving_order && order_id >= target_order) {
1213  order_id++;
1214  }
1215  order->SetConditionSkipToOrder(order_id);
1216  }
1217  }
1218 
1219  /* Make sure to rebuild the whole list */
1221  }
1222 
1223  return CommandCost();
1224 }
1225 
1238 {
1239  if (mof >= MOF_END) return CMD_ERROR;
1240 
1241  Vehicle *v = Vehicle::GetIfValid(veh);
1242  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1243 
1244  CommandCost ret = CheckOwnership(v->owner);
1245  if (ret.Failed()) return ret;
1246 
1247  /* Is it a valid order? */
1248  if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1249 
1250  Order *order = v->GetOrder(sel_ord);
1251  assert(order != nullptr);
1252  switch (order->GetType()) {
1253  case OT_GOTO_STATION:
1254  if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1255  break;
1256 
1257  case OT_GOTO_DEPOT:
1258  if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1259  break;
1260 
1261  case OT_GOTO_WAYPOINT:
1262  if (mof != MOF_NON_STOP) return CMD_ERROR;
1263  break;
1264 
1265  case OT_CONDITIONAL:
1266  if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1267  break;
1268 
1269  default:
1270  return CMD_ERROR;
1271  }
1272 
1273  switch (mof) {
1274  default: NOT_REACHED();
1275 
1276  case MOF_NON_STOP:
1277  if (!v->IsGroundVehicle()) return CMD_ERROR;
1278  if (data >= ONSF_END) return CMD_ERROR;
1279  if (data == order->GetNonStopType()) return CMD_ERROR;
1280  break;
1281 
1282  case MOF_STOP_LOCATION:
1283  if (v->type != VEH_TRAIN) return CMD_ERROR;
1284  if (data >= OSL_END) return CMD_ERROR;
1285  break;
1286 
1287  case MOF_UNLOAD:
1289  if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
1290  /* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
1291  if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
1292  if (data == order->GetUnloadType()) return CMD_ERROR;
1293  break;
1294 
1295  case MOF_LOAD:
1297  if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
1298  if (data == order->GetLoadType()) return CMD_ERROR;
1299  if ((data & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) && v->HasUnbunchingOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
1300  break;
1301 
1302  case MOF_DEPOT_ACTION:
1303  if (data >= DA_END) return CMD_ERROR;
1304  /* Check if we are allowed to add unbunching. We are always allowed to remove it. */
1305  if (data == DA_UNBUNCH) {
1306  /* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */
1307  if (v->HasUnbunchingOrder() && !(order->GetDepotActionType() & ODATFB_UNBUNCH)) return_cmd_error(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
1308  /* We don't allow unbunching if the vehicle has a conditional order. */
1309  if (v->HasConditionalOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
1310  /* We don't allow unbunching if the vehicle has a full load order. */
1311  if (v->HasFullLoadOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
1312  }
1313  break;
1314 
1315  case MOF_COND_VARIABLE:
1316  if (data >= OCV_END) return CMD_ERROR;
1317  break;
1318 
1319  case MOF_COND_COMPARATOR:
1320  if (data >= OCC_END) return CMD_ERROR;
1321  switch (order->GetConditionVariable()) {
1322  case OCV_UNCONDITIONALLY: return CMD_ERROR;
1323 
1324  case OCV_REQUIRES_SERVICE:
1325  if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
1326  break;
1327 
1328  default:
1329  if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
1330  break;
1331  }
1332  break;
1333 
1334  case MOF_COND_VALUE:
1335  switch (order->GetConditionVariable()) {
1336  case OCV_UNCONDITIONALLY:
1337  case OCV_REQUIRES_SERVICE:
1338  return CMD_ERROR;
1339 
1340  case OCV_LOAD_PERCENTAGE:
1341  case OCV_RELIABILITY:
1342  if (data > 100) return CMD_ERROR;
1343  break;
1344 
1345  default:
1346  if (data > 2047) return CMD_ERROR;
1347  break;
1348  }
1349  break;
1350 
1351  case MOF_COND_DESTINATION:
1352  if (data >= v->GetNumOrders()) return CMD_ERROR;
1353  break;
1354  }
1355 
1356  if (flags & DC_EXEC) {
1357  switch (mof) {
1358  case MOF_NON_STOP:
1359  order->SetNonStopType((OrderNonStopFlags)data);
1361  order->SetRefit(CARGO_NO_REFIT);
1364  }
1365  break;
1366 
1367  case MOF_STOP_LOCATION:
1368  order->SetStopLocation((OrderStopLocation)data);
1369  break;
1370 
1371  case MOF_UNLOAD:
1372  order->SetUnloadType((OrderUnloadFlags)data);
1373  break;
1374 
1375  case MOF_LOAD:
1376  order->SetLoadType((OrderLoadFlags)data);
1377  if (data & OLFB_NO_LOAD) order->SetRefit(CARGO_NO_REFIT);
1378  break;
1379 
1380  case MOF_DEPOT_ACTION: {
1381  switch (data) {
1382  case DA_ALWAYS_GO:
1386  break;
1387 
1388  case DA_SERVICE:
1392  order->SetRefit(CARGO_NO_REFIT);
1393  break;
1394 
1395  case DA_STOP:
1399  order->SetRefit(CARGO_NO_REFIT);
1400  break;
1401 
1402  case DA_UNBUNCH:
1406  break;
1407 
1408  default:
1409  NOT_REACHED();
1410  }
1411  break;
1412  }
1413 
1414  case MOF_COND_VARIABLE: {
1416 
1418  switch (order->GetConditionVariable()) {
1419  case OCV_UNCONDITIONALLY:
1421  order->SetConditionValue(0);
1422  break;
1423 
1424  case OCV_REQUIRES_SERVICE:
1425  if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
1426  order->SetConditionValue(0);
1427  break;
1428 
1429  case OCV_LOAD_PERCENTAGE:
1430  case OCV_RELIABILITY:
1431  if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1432  [[fallthrough]];
1433 
1434  default:
1435  if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
1436  break;
1437  }
1438  break;
1439  }
1440 
1441  case MOF_COND_COMPARATOR:
1443  break;
1444 
1445  case MOF_COND_VALUE:
1446  order->SetConditionValue(data);
1447  break;
1448 
1449  case MOF_COND_DESTINATION:
1450  order->SetConditionSkipToOrder(data);
1451  break;
1452 
1453  default: NOT_REACHED();
1454  }
1455 
1456  /* Update the windows and full load flags, also for vehicles that share the same order list */
1457  Vehicle *u = v->FirstShared();
1459  for (; u != nullptr; u = u->NextShared()) {
1460  /* Toggle u->current_order "Full load" flag if it changed.
1461  * However, as the same flag is used for depot orders, check
1462  * whether we are not going to a depot as there are three
1463  * cases where the full load flag can be active and only
1464  * one case where the flag is used for depot orders. In the
1465  * other cases for the OrderType the flags are not used,
1466  * so do not care and those orders should not be active
1467  * when this function is called.
1468  */
1469  if (sel_ord == u->cur_real_order_index &&
1470  (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1471  u->current_order.GetLoadType() != order->GetLoadType()) {
1472  u->current_order.SetLoadType(order->GetLoadType());
1473  }
1474 
1475  /* Unbunching data is no longer valid. */
1476  u->ResetDepotUnbunching();
1477 
1479  }
1480  }
1481 
1482  return CommandCost();
1483 }
1484 
1492 static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first)
1493 {
1494  if (first == nullptr || v_new->acache.cached_max_range == 0) return true;
1495 
1496  /* Iterate over all orders to check the distance between all
1497  * 'goto' orders and their respective next order (of any type). */
1498  for (const Order *o = first; o != nullptr; o = o->next) {
1499  switch (o->GetType()) {
1500  case OT_GOTO_STATION:
1501  case OT_GOTO_DEPOT:
1502  case OT_GOTO_WAYPOINT:
1503  /* If we don't have a next order, we've reached the end and must check the first order instead. */
1504  if (GetOrderDistance(o, o->next != nullptr ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false;
1505  break;
1506 
1507  default: break;
1508  }
1509  }
1510 
1511  return true;
1512 }
1513 
1523 {
1524  Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1525  if (dst == nullptr || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1526 
1527  CommandCost ret = CheckOwnership(dst->owner);
1528  if (ret.Failed()) return ret;
1529 
1530  switch (action) {
1531  case CO_SHARE: {
1532  Vehicle *src = Vehicle::GetIfValid(veh_src);
1533 
1534  /* Sanity checks */
1535  if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1536 
1537  ret = CheckOwnership(src->owner);
1538  if (ret.Failed()) return ret;
1539 
1540  /* Trucks can't share orders with busses (and visa versa) */
1541  if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1542  return CMD_ERROR;
1543  }
1544 
1545  /* Is the vehicle already in the shared list? */
1546  if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1547 
1548  for (const Order *order : src->Orders()) {
1549  if (!OrderGoesToStation(dst, order)) continue;
1550 
1551  /* Allow copying unreachable destinations if they were already unreachable for the source.
1552  * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1553  * are temporarily invalid due to reconstruction. */
1554  const Station *st = Station::Get(order->GetDestination());
1555  if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1556  return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1557  }
1558  }
1559 
1560  /* Check for aircraft range limits. */
1561  if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1562  return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1563  }
1564 
1565  if (src->orders == nullptr && !OrderList::CanAllocateItem()) {
1566  return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1567  }
1568 
1569  if (flags & DC_EXEC) {
1570  /* If the destination vehicle had a OrderList, destroy it.
1571  * We only reset the order indices, if the new orders are obviously different.
1572  * (We mainly do this to keep the order indices valid and in range.) */
1573  DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1574 
1575  dst->orders = src->orders;
1576 
1577  /* Link this vehicle in the shared-list */
1578  dst->AddToShared(src);
1579 
1582 
1584  }
1585  break;
1586  }
1587 
1588  case CO_COPY: {
1589  Vehicle *src = Vehicle::GetIfValid(veh_src);
1590 
1591  /* Sanity checks */
1592  if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1593 
1594  ret = CheckOwnership(src->owner);
1595  if (ret.Failed()) return ret;
1596 
1597  /* Trucks can't copy all the orders from busses (and visa versa),
1598  * and neither can helicopters and aircraft. */
1599  for (const Order *order : src->Orders()) {
1600  if (!OrderGoesToStation(dst, order)) continue;
1601  Station *st = Station::Get(order->GetDestination());
1602  if (!CanVehicleUseStation(dst, st)) {
1603  return CommandCost(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st));
1604  }
1605  }
1606 
1607  /* Check for aircraft range limits. */
1608  if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1609  return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1610  }
1611 
1612  /* make sure there are orders available */
1614  return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1615  }
1616 
1617  if (flags & DC_EXEC) {
1618  Order *first = nullptr;
1619  Order **order_dst;
1620 
1621  /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1622  * We only reset the order indices, if the new orders are obviously different.
1623  * (We mainly do this to keep the order indices valid and in range.) */
1624  DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1625 
1626  order_dst = &first;
1627  for (const Order *order : src->Orders()) {
1628  *order_dst = new Order();
1629  (*order_dst)->AssignOrder(*order);
1630  order_dst = &(*order_dst)->next;
1631  }
1632  if (dst->orders == nullptr) {
1633  dst->orders = new OrderList(first, dst);
1634  } else {
1635  assert(dst->orders->GetFirstOrder() == nullptr);
1636  assert(!dst->orders->IsShared());
1637  delete dst->orders;
1638  assert(OrderList::CanAllocateItem());
1639  dst->orders = new OrderList(first, dst);
1640  }
1641 
1643 
1645  }
1646  break;
1647  }
1648 
1649  case CO_UNSHARE: return DecloneOrder(dst, flags);
1650  default: return CMD_ERROR;
1651  }
1652 
1653  return CommandCost();
1654 }
1655 
1665 {
1666  if (cargo >= NUM_CARGO && cargo != CARGO_NO_REFIT && cargo != CARGO_AUTO_REFIT) return CMD_ERROR;
1667 
1668  const Vehicle *v = Vehicle::GetIfValid(veh);
1669  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1670 
1671  CommandCost ret = CheckOwnership(v->owner);
1672  if (ret.Failed()) return ret;
1673 
1674  Order *order = v->GetOrder(order_number);
1675  if (order == nullptr) return CMD_ERROR;
1676 
1677  /* Automatic refit cargo is only supported for goto station orders. */
1678  if (cargo == CARGO_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1679 
1680  if (order->GetLoadType() & OLFB_NO_LOAD) return CMD_ERROR;
1681 
1682  if (flags & DC_EXEC) {
1683  order->SetRefit(cargo);
1684 
1685  /* Make the depot order an 'always go' order. */
1686  if (cargo != CARGO_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1689  }
1690 
1691  for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1692  /* Update any possible open window of the vehicle */
1694 
1695  /* If the vehicle already got the current depot set as current order, then update current order as well */
1696  if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
1697  u->current_order.SetRefit(cargo);
1698  }
1699  }
1700  }
1701 
1702  return CommandCost();
1703 }
1704 
1705 
1711 void CheckOrders(const Vehicle *v)
1712 {
1713  /* Does the user wants us to check things? */
1714  if (_settings_client.gui.order_review_system == 0) return;
1715 
1716  /* Do nothing for crashed vehicles */
1717  if (v->vehstatus & VS_CRASHED) return;
1718 
1719  /* Do nothing for stopped vehicles if setting is '1' */
1720  if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
1721 
1722  /* do nothing we we're not the first vehicle in a share-chain */
1723  if (v->FirstShared() != v) return;
1724 
1725  /* Only check every 20 days, so that we don't flood the message log */
1726  if (v->owner == _local_company && v->day_counter % 20 == 0) {
1727  StringID message = INVALID_STRING_ID;
1728 
1729  /* Check the order list */
1730  int n_st = 0;
1731 
1732  for (const Order *order : v->Orders()) {
1733  /* Dummy order? */
1734  if (order->IsType(OT_DUMMY)) {
1735  message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1736  break;
1737  }
1738  /* Does station have a load-bay for this vehicle? */
1739  if (order->IsType(OT_GOTO_STATION)) {
1740  const Station *st = Station::Get(order->GetDestination());
1741 
1742  n_st++;
1743  if (!CanVehicleUseStation(v, st)) {
1744  message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1745  } else if (v->type == VEH_AIRCRAFT &&
1746  (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1749  message == INVALID_STRING_ID) {
1750  message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1751  }
1752  }
1753  }
1754 
1755  /* Check if the last and the first order are the same */
1756  if (v->GetNumOrders() > 1) {
1757  const Order *last = v->GetLastOrder();
1758 
1759  if (v->orders->GetFirstOrder()->Equals(*last)) {
1760  message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1761  }
1762  }
1763 
1764  /* Do we only have 1 station in our order list? */
1765  if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1766 
1767 #ifdef WITH_ASSERT
1768  if (v->orders != nullptr) v->orders->DebugCheckSanity();
1769 #endif
1770 
1771  /* We don't have a problem */
1772  if (message == INVALID_STRING_ID) return;
1773 
1774  SetDParam(0, v->index);
1775  AddVehicleAdviceNewsItem(message, v->index);
1776  }
1777 }
1778 
1787 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1788 {
1789  /* Aircraft have StationIDs for depot orders and never use DepotIDs
1790  * This fact is handled specially below
1791  */
1792 
1793  /* Go through all vehicles */
1794  for (Vehicle *v : Vehicle::Iterate()) {
1795  if ((v->type == VEH_AIRCRAFT && v->current_order.IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : v->current_order.GetType()) == type &&
1796  (!hangar || v->type == VEH_AIRCRAFT) && v->current_order.GetDestination() == destination) {
1797  v->current_order.MakeDummy();
1798  SetWindowDirty(WC_VEHICLE_VIEW, v->index);
1799  }
1800 
1801  /* Clear the order from the order-list */
1802  int id = -1;
1803  for (Order *order : v->Orders()) {
1804  id++;
1805 restart:
1806 
1807  OrderType ot = order->GetType();
1808  if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
1809  if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) continue; // Not an aircraft? Can't have a hangar order.
1810  if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1811  if (ot == type && order->GetDestination() == destination) {
1812  /* We want to clear implicit orders, but we don't want to make them
1813  * dummy orders. They should just vanish. Also check the actual order
1814  * type as ot is currently OT_GOTO_STATION. */
1815  if (order->IsType(OT_IMPLICIT)) {
1816  order = order->next; // DeleteOrder() invalidates current order
1817  DeleteOrder(v, id);
1818  if (order != nullptr) goto restart;
1819  break;
1820  }
1821 
1822  /* Clear wait time */
1823  v->orders->UpdateTotalDuration(-order->GetWaitTime());
1824  if (order->IsWaitTimetabled()) {
1825  v->orders->UpdateTimetableDuration(-order->GetTimetabledWait());
1826  order->SetWaitTimetabled(false);
1827  }
1828  order->SetWaitTime(0);
1829 
1830  /* Clear order, preserving travel time */
1831  bool travel_timetabled = order->IsTravelTimetabled();
1832  order->MakeDummy();
1833  order->SetTravelTimetabled(travel_timetabled);
1834 
1835  for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1836  /* In GUI, simulate by removing the order and adding it back */
1839  }
1840  }
1841  }
1842  }
1843 
1844  OrderBackup::RemoveOrder(type, destination, hangar);
1845 }
1846 
1852 {
1853  for (const Order *order : this->Orders()) {
1854  if (order->IsType(OT_GOTO_DEPOT)) return true;
1855  }
1856 
1857  return false;
1858 }
1859 
1869 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1870 {
1872 
1873  if (v->IsOrderListShared()) {
1874  /* Remove ourself from the shared order list. */
1875  v->RemoveFromShared();
1876  v->orders = nullptr;
1877  } else if (v->orders != nullptr) {
1878  /* Remove the orders */
1879  v->orders->FreeChain(keep_orderlist);
1880  if (!keep_orderlist) v->orders = nullptr;
1881  }
1882 
1883  /* Unbunching data is no longer valid. */
1884  v->ResetDepotUnbunching();
1885 
1886  if (reset_order_indices) {
1888  if (v->current_order.IsType(OT_LOADING)) {
1890  }
1891  }
1892 }
1893 
1901 uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
1902 {
1903  /* Service intervals are in percents. */
1904  if (ispercent) return Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT);
1905 
1906  /* Service intervals are in minutes. */
1907  if (TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU)) return Clamp(interval, MIN_SERVINT_MINUTES, MAX_SERVINT_MINUTES);
1908 
1909  /* Service intervals are in days. */
1910  return Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1911 }
1912 
1921 static bool CheckForValidOrders(const Vehicle *v)
1922 {
1923  for (const Order *order : v->Orders()) {
1924  switch (order->GetType()) {
1925  case OT_GOTO_STATION:
1926  case OT_GOTO_DEPOT:
1927  case OT_GOTO_WAYPOINT:
1928  return true;
1929 
1930  default:
1931  break;
1932  }
1933  }
1934 
1935  return false;
1936 }
1937 
1941 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1942 {
1943  switch (occ) {
1944  case OCC_EQUALS: return variable == value;
1945  case OCC_NOT_EQUALS: return variable != value;
1946  case OCC_LESS_THAN: return variable < value;
1947  case OCC_LESS_EQUALS: return variable <= value;
1948  case OCC_MORE_THAN: return variable > value;
1949  case OCC_MORE_EQUALS: return variable >= value;
1950  case OCC_IS_TRUE: return variable != 0;
1951  case OCC_IS_FALSE: return variable == 0;
1952  default: NOT_REACHED();
1953  }
1954 }
1955 
1956 template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
1957 static bool OrderConditionCompare(OrderConditionComparator occ, T variable, int value)
1958 {
1959  return OrderConditionCompare(occ, variable.base(), value);
1960 }
1961 
1969 {
1970  if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1971 
1972  bool skip_order = false;
1974  uint16_t value = order->GetConditionValue();
1975 
1976  switch (order->GetConditionVariable()) {
1977  case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1978  case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
1979  case OCV_MAX_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability), value); break;
1980  case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1981  case OCV_AGE: skip_order = OrderConditionCompare(occ, TimerGameCalendar::DateToYear(v->age), value); break;
1982  case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
1983  case OCV_UNCONDITIONALLY: skip_order = true; break;
1985  default: NOT_REACHED();
1986  }
1987 
1988  return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1989 }
1990 
1998 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
1999 {
2000  if (conditional_depth > v->GetNumOrders()) {
2001  v->current_order.Free();
2002  v->SetDestTile(0);
2003  return false;
2004  }
2005 
2006  switch (order->GetType()) {
2007  case OT_GOTO_STATION:
2008  v->SetDestTile(v->GetOrderStationLocation(order->GetDestination()));
2009  return true;
2010 
2011  case OT_GOTO_DEPOT:
2012  if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
2013  assert(!pbs_look_ahead);
2014  UpdateVehicleTimetable(v, true);
2016  break;
2017  }
2018 
2020  /* If the vehicle can't find its destination, delay its next search.
2021  * In case many vehicles are in this state, use the vehicle index to spread out pathfinder calls. */
2022  if (v->dest_tile == 0 && TimerGameEconomy::date_fract != (v->index % Ticks::DAY_TICKS)) break;
2023 
2024  /* We need to search for the nearest depot (hangar). */
2025  ClosestDepot closestDepot = v->FindClosestDepot();
2026 
2027  if (closestDepot.found) {
2028  /* PBS reservations cannot reverse */
2029  if (pbs_look_ahead && closestDepot.reverse) return false;
2030 
2031  v->SetDestTile(closestDepot.location);
2032  v->current_order.SetDestination(closestDepot.destination);
2033 
2034  /* If there is no depot in front, reverse automatically (trains only) */
2035  if (v->type == VEH_TRAIN && closestDepot.reverse) Command<CMD_REVERSE_TRAIN_DIRECTION>::Do(DC_EXEC, v->index, false);
2036 
2037  if (v->type == VEH_AIRCRAFT) {
2038  Aircraft *a = Aircraft::From(v);
2039  if (a->state == FLYING && a->targetairport != closestDepot.destination) {
2040  /* The aircraft is now heading for a different hangar than the next in the orders */
2042  }
2043  }
2044  return true;
2045  }
2046 
2047  /* If there is no depot, we cannot help PBS either. */
2048  if (pbs_look_ahead) return false;
2049 
2050  UpdateVehicleTimetable(v, true);
2052  } else {
2053  if (v->type != VEH_AIRCRAFT) {
2054  v->SetDestTile(Depot::Get(order->GetDestination())->xy);
2055  } else {
2056  Aircraft *a = Aircraft::From(v);
2057  DestinationID destination = a->current_order.GetDestination();
2058  if (a->targetairport != destination) {
2059  /* The aircraft is now heading for a different hangar than the next in the orders */
2060  a->SetDestTile(a->GetOrderStationLocation(destination));
2061  }
2062  }
2063  return true;
2064  }
2065  break;
2066 
2067  case OT_GOTO_WAYPOINT:
2068  v->SetDestTile(Waypoint::Get(order->GetDestination())->xy);
2069  return true;
2070 
2071  case OT_CONDITIONAL: {
2072  assert(!pbs_look_ahead);
2073  VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2074  if (next_order != INVALID_VEH_ORDER_ID) {
2075  /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2076  * cur_real_order_index might come after next_order. */
2077  UpdateVehicleTimetable(v, false);
2078  v->cur_implicit_order_index = v->cur_real_order_index = next_order;
2079  v->UpdateRealOrderIndex();
2081 
2082  /* Disable creation of implicit orders.
2083  * When inserting them we do not know that we would have to make the conditional orders point to them. */
2084  if (v->IsGroundVehicle()) {
2085  uint16_t &gv_flags = v->GetGroundVehicleFlags();
2087  }
2088  } else {
2089  UpdateVehicleTimetable(v, true);
2091  }
2092  break;
2093  }
2094 
2095  default:
2096  v->SetDestTile(0);
2097  return false;
2098  }
2099 
2100  assert(v->cur_implicit_order_index < v->GetNumOrders());
2101  assert(v->cur_real_order_index < v->GetNumOrders());
2102 
2103  /* Get the current order */
2104  order = v->GetOrder(v->cur_real_order_index);
2105  if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2106  assert(v->GetNumManualOrders() == 0);
2107  order = nullptr;
2108  }
2109 
2110  if (order == nullptr) {
2111  v->current_order.Free();
2112  v->SetDestTile(0);
2113  return false;
2114  }
2115 
2116  v->current_order = *order;
2117  return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2118 }
2119 
2128 {
2129  switch (v->current_order.GetType()) {
2130  case OT_GOTO_DEPOT:
2131  /* Let a depot order in the orderlist interrupt. */
2132  if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
2133  break;
2134 
2135  case OT_LOADING:
2136  return false;
2137 
2138  case OT_LEAVESTATION:
2139  if (v->type != VEH_AIRCRAFT) return false;
2140  break;
2141 
2142  default: break;
2143  }
2144 
2152  bool may_reverse = v->current_order.IsType(OT_NOTHING);
2153 
2154  /* Check if we've reached a 'via' destination. */
2155  if (((v->current_order.IsType(OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) || v->current_order.IsType(OT_GOTO_WAYPOINT)) &&
2156  IsTileType(v->tile, MP_STATION) &&
2159  /* We set the last visited station here because we do not want
2160  * the train to stop at this 'via' station if the next order
2161  * is a no-non-stop order; in that case not setting the last
2162  * visited station will cause the vehicle to still stop. */
2164  UpdateVehicleTimetable(v, true);
2166  }
2167 
2168  /* Get the current order */
2169  assert(v->cur_implicit_order_index == 0 || v->cur_implicit_order_index < v->GetNumOrders());
2170  v->UpdateRealOrderIndex();
2171 
2172  const Order *order = v->GetOrder(v->cur_real_order_index);
2173  if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2174  assert(v->GetNumManualOrders() == 0);
2175  order = nullptr;
2176  }
2177 
2178  /* If no order, do nothing. */
2179  if (order == nullptr || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
2180  if (v->type == VEH_AIRCRAFT) {
2181  /* Aircraft do something vastly different here, so handle separately */
2182  HandleMissingAircraftOrders(Aircraft::From(v));
2183  return false;
2184  }
2185 
2186  v->current_order.Free();
2187  v->SetDestTile(0);
2188  return false;
2189  }
2190 
2191  /* If it is unchanged, keep it. */
2192  if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
2193  (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->ship_station.tile != INVALID_TILE)) {
2194  return false;
2195  }
2196 
2197  /* Otherwise set it, and determine the destination tile. */
2198  v->current_order = *order;
2199 
2201  switch (v->type) {
2202  default:
2203  NOT_REACHED();
2204 
2205  case VEH_ROAD:
2206  case VEH_TRAIN:
2207  break;
2208 
2209  case VEH_AIRCRAFT:
2210  case VEH_SHIP:
2212  break;
2213  }
2214 
2215  return UpdateOrderDest(v, order) && may_reverse;
2216 }
2217 
2225 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2226 {
2227  bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2228 
2229  return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
2230  v->last_station_visited != station && // Do stop only when we've not just been there
2231  /* Finally do stop when there is no non-stop flag set for this type of station. */
2233 }
2234 
2235 bool Order::CanLoadOrUnload() const
2236 {
2237  return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2239  ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
2240  (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
2241 }
2242 
2249 bool Order::CanLeaveWithCargo(bool has_cargo) const
2250 {
2251  return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
2252  (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
2253 }
Base for aircraft.
void AircraftNextAirportPos_and_Order(Aircraft *v)
set the right pos when heading to other airports after takeoff
@ FLYING
Vehicle is flying in the air.
Definition: airport.h:75
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr static debug_inline uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
static const CargoID CARGO_NO_REFIT
Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-renew).
Definition: cargo_type.h:78
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
static const CargoID NUM_CARGO
Maximum number of cargo types in a game.
Definition: cargo_type.h:74
static const CargoID CARGO_AUTO_REFIT
Automatically choose cargo type when doing auto refitting.
Definition: cargo_type.h:77
Cheats _cheats
All the cheats.
Definition: cheat.cpp:16
Types related to cheating.
Common return value for all commands.
Definition: command_type.h:23
bool Failed() const
Did this command fail?
Definition: command_type.h:171
Minimal stack that uses a pool to avoid pointers.
Titem Pop()
Pop an item from the stack.
bool IsEmpty() const
Check if the stack is empty.
void Push(const Titem &item)
Pushes a new item onto the stack if there is still space in the underlying pool.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static DateFract date_fract
Fractional part of the day.
int32_t Ticks
The type to store ticks in.
static constexpr Year DateToYear(Date date)
Calculate the year of a given date.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:28
#define return_cmd_error(errcode)
Returns from a function with a specific StringID as error.
Definition: command_func.h:38
DoCommandFlag
List of flags for a command.
Definition: command_type.h:374
@ DC_EXEC
execute the given command
Definition: command_type.h:376
Definition of stuff that is very close to a company, like the company struct itself.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
Functions related to companies.
@ OWNER_NONE
The tile has no ownership.
Definition: company_type.h:25
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
Base for all depots (except hangars)
uint16_t DepotID
Type for the unique identifier of depots.
Definition: depot_type.h:13
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition: map.cpp:163
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition: map.cpp:146
constexpr uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
Definition: math_func.hpp:306
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:79
Functions related to news.
void DeleteVehicleNews(VehicleID vid, StringID news)
Delete a news item type about a vehicle.
Definition: news_gui.cpp:930
void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition: news_func.h:40
Functions related to order backups.
CommandCost CmdMoveOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID moving_order, VehicleOrderID target_order)
Move an order inside the orderlist.
Definition: order_cmd.cpp:1139
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:615
static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first)
Check if an aircraft has enough range for an order list.
Definition: order_cmd.cpp:1492
uint16_t GetServiceIntervalClamped(int interval, bool ispercent)
Clamp the service interval to the correct min/max.
Definition: order_cmd.cpp:1901
static bool CheckForValidOrders(const Vehicle *v)
Check if a vehicle has any valid orders.
Definition: order_cmd.cpp:1921
CommandCost CmdOrderRefit(DoCommandFlag flags, VehicleID veh, VehicleOrderID order_number, CargoID cargo)
Add/remove refit orders from an order.
Definition: order_cmd.cpp:1664
CommandCost CmdCloneOrder(DoCommandFlag flags, CloneOptions action, VehicleID veh_dst, VehicleID veh_src)
Clone/share/copy an order-list of another vehicle.
Definition: order_cmd.cpp:1522
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
Definition: order_cmd.cpp:2127
static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
Compare the variable and value based on the given comparator.
Definition: order_cmd.cpp:1941
static void CancelLoadingDueToDeletedOrder(Vehicle *v)
Cancel the current loading order of the vehicle as the order was deleted.
Definition: order_cmd.cpp:1021
CommandCost CmdInsertOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID sel_ord, const Order &new_order)
Add an order to the orderlist of a vehicle.
Definition: order_cmd.cpp:697
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:1998
void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
Insert a new order but skip the validation.
Definition: order_cmd.cpp:912
void InvalidateVehicleOrder(const Vehicle *v, int data)
Updates the widgets of a vehicle which contains the order-data.
Definition: order_cmd.cpp:235
CommandCost CmdModifyOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID sel_ord, ModifyOrderFlags mof, uint16_t data)
Modify an order in the orderlist of a vehicle.
Definition: order_cmd.cpp:1237
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
Definition: order_cmd.cpp:1711
CommandCost CmdDeleteOrder(DoCommandFlag flags, VehicleID veh_id, VehicleOrderID sel_ord)
Delete an order from the orderlist of a vehicle.
Definition: order_cmd.cpp:999
CommandCost CmdSkipToOrder(DoCommandFlag flags, VehicleID veh_id, VehicleOrderID sel_ord)
Goto order of order-list.
Definition: order_cmd.cpp:1101
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
Definition: order_cmd.cpp:1869
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:627
void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
Delete an order but skip the parameter validation.
Definition: order_cmd.cpp:1037
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
Process a conditional order and determine the next order.
Definition: order_cmd.cpp:1968
static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
Declone an order-list.
Definition: order_cmd.cpp:982
uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
Get the distance between two orders of a vehicle.
Definition: order_cmd.cpp:669
void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
Definition: order_cmd.cpp:1787
Command definitions related to orders.
OrderDepotActionFlags
Actions that can be performed when the vehicle enters the depot.
Definition: order_type.h:102
@ ODATFB_UNBUNCH
Service the vehicle and then unbunch it.
Definition: order_type.h:106
@ ODATFB_NEAREST_DEPOT
Send the vehicle to the nearest depot.
Definition: order_type.h:105
@ ODATFB_HALT
Service the vehicle and then halt it.
Definition: order_type.h:104
OrderConditionComparator
Comparator for the skip reasoning.
Definition: order_type.h:128
@ OCC_LESS_EQUALS
Skip if the value is less or equal to the limit.
Definition: order_type.h:132
@ OCC_EQUALS
Skip if both values are equal.
Definition: order_type.h:129
@ OCC_NOT_EQUALS
Skip if both values are not equal.
Definition: order_type.h:130
@ OCC_MORE_THAN
Skip if the value is more than the limit.
Definition: order_type.h:133
@ OCC_IS_TRUE
Skip if the variable is true.
Definition: order_type.h:135
@ OCC_LESS_THAN
Skip if the value is less than the limit.
Definition: order_type.h:131
@ OCC_MORE_EQUALS
Skip if the value is more or equal to the limit.
Definition: order_type.h:134
@ OCC_IS_FALSE
Skip if the variable is false.
Definition: order_type.h:136
ModifyOrderFlags
Enumeration for the data to set in CmdModifyOrder.
Definition: order_type.h:144
@ MOF_COND_VARIABLE
A conditional variable changes.
Definition: order_type.h:150
@ MOF_LOAD
Passes an OrderLoadType.
Definition: order_type.h:148
@ MOF_UNLOAD
Passes an OrderUnloadType.
Definition: order_type.h:147
@ MOF_STOP_LOCATION
Passes an OrderStopLocation.
Definition: order_type.h:146
@ MOF_COND_DESTINATION
Change the destination of a conditional order.
Definition: order_type.h:153
@ MOF_COND_COMPARATOR
A comparator changes.
Definition: order_type.h:151
@ MOF_COND_VALUE
The value to set the condition to.
Definition: order_type.h:152
@ MOF_DEPOT_ACTION
Selects the OrderDepotAction.
Definition: order_type.h:149
@ MOF_NON_STOP
Passes an OrderNonStopFlags.
Definition: order_type.h:145
OrderLoadFlags
Flags related to the loading order.
Definition: order_type.h:62
@ OLFB_FULL_LOAD
Full load all cargoes of the consist.
Definition: order_type.h:64
@ OLFB_NO_LOAD
Do not load anything.
Definition: order_type.h:66
@ OLF_LOAD_IF_POSSIBLE
Load as long as there is cargo that fits in the train.
Definition: order_type.h:63
@ OLF_FULL_LOAD_ANY
Full load a single cargo of the consist.
Definition: order_type.h:65
OrderStopLocation
Where to stop the trains.
Definition: order_type.h:83
@ OSL_PLATFORM_MIDDLE
Stop at the middle of the platform.
Definition: order_type.h:85
@ OSL_PLATFORM_FAR_END
Stop at the far end of the platform.
Definition: order_type.h:86
@ OSL_PLATFORM_NEAR_END
Stop at the near end of the platform.
Definition: order_type.h:84
OrderConditionVariable
Variables (of a vehicle) to 'cause' skipping on.
Definition: order_type.h:113
@ OCV_AGE
Skip based on the age.
Definition: order_type.h:117
@ OCV_UNCONDITIONALLY
Always skip.
Definition: order_type.h:119
@ OCV_MAX_SPEED
Skip based on the maximum speed.
Definition: order_type.h:116
@ OCV_LOAD_PERCENTAGE
Skip based on the amount of load.
Definition: order_type.h:114
@ OCV_REQUIRES_SERVICE
Skip when the vehicle requires service.
Definition: order_type.h:118
@ OCV_RELIABILITY
Skip based on the reliability.
Definition: order_type.h:115
@ OCV_REMAINING_LIFETIME
Skip based on the remaining lifetime.
Definition: order_type.h:120
@ OCV_MAX_RELIABILITY
Skip based on the maximum reliability.
Definition: order_type.h:121
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition: order_type.h:15
OrderUnloadFlags
Flags related to the unloading order.
Definition: order_type.h:52
@ OUFB_TRANSFER
Transfer all cargo onto the platform.
Definition: order_type.h:55
@ OUFB_NO_UNLOAD
Totally no unloading will be done.
Definition: order_type.h:56
@ OUF_UNLOAD_IF_POSSIBLE
Unload all cargo that the station accepts.
Definition: order_type.h:53
@ OUFB_UNLOAD
Force unloading all cargo onto the platform, possibly not getting paid.
Definition: order_type.h:54
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition: order_type.h:23
OrderNonStopFlags
Non-stop order flags.
Definition: order_type.h:72
@ ONSF_NO_STOP_AT_DESTINATION_STATION
The vehicle will stop at any station it passes except the destination.
Definition: order_type.h:75
@ ONSF_STOP_EVERYWHERE
The vehicle will stop at any station it passes and the destination.
Definition: order_type.h:73
@ ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
The vehicle will not stop at any stations it passes except the destination.
Definition: order_type.h:74
OrderDepotTypeFlags
Reasons that could cause us to go to the depot.
Definition: order_type.h:93
@ ODTFB_PART_OF_ORDERS
This depot order is because of a regular order.
Definition: order_type.h:96
@ ODTFB_SERVICE
This depot order is because of the servicing limit.
Definition: order_type.h:95
@ DA_SERVICE
Service only if needed.
Definition: order_type.h:162
@ DA_STOP
Go to the depot and stop there.
Definition: order_type.h:163
@ DA_ALWAYS_GO
Always go to the depot.
Definition: order_type.h:161
@ DA_UNBUNCH
Go to the depot and unbunch.
Definition: order_type.h:164
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition: order_type.h:21
CloneOptions
Clone actions.
Definition: order_type.h:179
OrderType
Order types.
Definition: order_type.h:35
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
Definition: pool_func.hpp:237
static debug_inline bool IsRailDepotTile(Tile t)
Is this tile rail tile and a rail depot?
Definition: rail_map.h:105
Pseudo random number generator.
static debug_inline bool IsRoadDepotTile(Tile t)
Return whether a tile is a road depot tile.
Definition: road_map.h:116
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
Base classes/functions for stations.
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition: station_map.h:28
@ FACIL_DOCK
Station with a dock.
Definition: station_type.h:58
@ FACIL_BUS_STOP
Station with bus stops.
Definition: station_type.h:56
@ FACIL_TRUCK_STOP
Station with truck stops.
Definition: station_type.h:55
@ FACIL_TRAIN
Station with train station.
Definition: station_type.h:54
Definition of base types and functions in a cross-platform compatible way.
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
uint32_t cached_max_range_sqr
Cached squared maximum range.
Definition: aircraft.h:65
uint16_t cached_max_range
Cached maximum range.
Definition: aircraft.h:66
uint8_t subtype
Type of aircraft.
Definition: engine_type.h:104
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition: aircraft.h:72
uint8_t state
State of the airport.
Definition: aircraft.h:77
StationID targetairport
Airport to go to next.
Definition: aircraft.h:76
Flags flags
Flags for this airport type.
Definition: airport.h:180
@ SHORT_STRIP
This airport has a short landing strip, dangerous for fast aircraft.
Definition: airport.h:150
bool HasHangar() const
Check if this airport has at least one hangar.
Definition: station_base.h:323
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:317
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
Definition: base_consist.h:21
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
Definition: base_consist.h:31
VehicleOrderID cur_implicit_order_index
The index to the current implicit order.
Definition: base_consist.h:32
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
Base class for all station-ish types.
StationFacility facilities
The facilities that this station has.
TileIndex xy
Base tile of the station.
Owner owner
The owner of this station.
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:51
bool value
tells if the bool cheat is active or not
Definition: cheat_type.h:18
Cheat no_jetcrash
no jet will crash on small airports anymore
Definition: cheat_type.h:31
GUISettings gui
settings related to the GUI
Structure to return information about the closest depot location, and whether it could be found.
Definition: vehicle_base.h:230
DestinationID destination
The DestinationID as used for orders.
Definition: vehicle_base.h:232
uint16_t reliability
Current reliability of the engine.
Definition: engine_base.h:41
uint8_t order_review_system
perform order reviews on vehicles
static void RemoveOrder(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition: order_base.h:259
void DeleteOrderAt(int index)
Remove an order from the order list and delete it.
Definition: order_cmd.cpp:494
StationIDStack GetNextStoppingStation(const Vehicle *v, const Order *first=nullptr, uint hops=0) const
Recursively determine the next deterministic station to stop at.
Definition: order_cmd.cpp:399
bool IsCompleteTimetable() const
Checks whether all orders of the list have a filled timetable.
Definition: order_cmd.cpp:562
const Order * GetNextDecisionNode(const Order *next, uint hops) const
Get the next order which will make the given vehicle stop at a station or refit at a depot or evaluat...
Definition: order_cmd.cpp:364
void Initialize(Order *chain, Vehicle *v)
Recomputes everything.
Definition: order_cmd.cpp:275
Order * GetLastOrder() const
Get the last order of the order chain.
Definition: order_base.h:305
void RemoveVehicle(Vehicle *v)
Removes the vehicle from the shared order list.
Definition: order_cmd.cpp:552
uint num_vehicles
NOSAVE: Number of vehicles that share this order list.
Definition: order_base.h:266
VehicleOrderID num_orders
NOSAVE: How many orders there are in the list.
Definition: order_base.h:264
void InsertOrderAt(Order *new_order, int index)
Insert a new order into the order chain.
Definition: order_cmd.cpp:456
Order * GetOrderAt(int index) const
Get a certain order of the order chain.
Definition: order_cmd.cpp:341
void MoveOrder(int from, int to)
Move an order to another position within the order list.
Definition: order_cmd.cpp:520
TimerGameTick::Ticks timetable_duration
NOSAVE: Total timetabled duration of the order list.
Definition: order_base.h:270
Order * first
First order of the order list.
Definition: order_base.h:268
Vehicle * first_shared
NOSAVE: pointer to the first vehicle in the shared order chain.
Definition: order_base.h:267
VehicleOrderID num_manual_orders
NOSAVE: How many manually added orders are there in the list.
Definition: order_base.h:265
const Order * GetNext(const Order *curr) const
Get the order after the given one or the first one, if the given one is the last one.
Definition: order_base.h:313
VehicleOrderID GetNumOrders() const
Get number of orders in the order list.
Definition: order_base.h:319
void RecalculateTimetableDuration()
Recomputes Timetable duration.
Definition: order_cmd.cpp:305
void FreeChain(bool keep_orderlist=false)
Free a complete order chain.
Definition: order_cmd.cpp:318
Order * GetFirstOrder() const
Get the first order of the order chain.
Definition: order_base.h:297
bool IsShared() const
Is this a shared order list?
Definition: order_base.h:338
TimerGameTick::Ticks total_duration
NOSAVE: Total (timetabled or not) duration of the order list.
Definition: order_base.h:271
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:642
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition: order_base.h:144
CargoID GetRefitCargo() const
Get the cargo to to refit to.
Definition: order_base.h:131
uint16_t GetTimetabledTravel() const
Get the time in ticks a vehicle should take to reach the destination or 0 if it's not timetabled.
Definition: order_base.h:190
OrderConditionVariable GetConditionVariable() const
What variable do we have to compare?
Definition: order_base.h:148
bool Equals(const Order &other) const
Does this order have the same type, flags and destination?
Definition: order_cmd.cpp:175
uint16_t MapOldOrder() const
Pack this order into a 16 bits integer as close to the TTD representation as possible.
Definition: order_cmd.cpp:208
uint16_t GetMaxSpeed() const
Get the maxmimum speed in km-ish/h a vehicle is allowed to reach on the way to the destination.
Definition: order_base.h:201
void SetUnloadType(OrderUnloadFlags unload_type)
Set how the consist must be unloaded.
Definition: order_base.h:159
void SetLoadType(OrderLoadFlags load_type)
Set how the consist must be loaded.
Definition: order_base.h:157
uint16_t max_speed
How fast the vehicle may go on the way to the destination.
Definition: order_base.h:56
DestinationID GetDestination() const
Gets the destination of this order.
Definition: order_base.h:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:70
void SetNonStopType(OrderNonStopFlags non_stop_type)
Set whether we must stop at stations or not.
Definition: order_base.h:161
VehicleOrderID GetConditionSkipToOrder() const
Get the order to skip to.
Definition: order_base.h:152
OrderStopLocation GetStopLocation() const
Where must we stop at the platform?
Definition: order_base.h:142
uint16_t GetWaitTime() const
Get the time in ticks a vehicle will probably wait at the destination (timetabled or not).
Definition: order_base.h:192
OrderType GetType() const
Get the type of order of this order.
Definition: order_base.h:76
void MakeGoToStation(StationID destination)
Makes this order a Go To Station order.
Definition: order_cmd.cpp:75
uint8_t type
The type of order + non-stop flags.
Definition: order_base.h:48
uint16_t wait_time
How long in ticks to wait at the destination.
Definition: order_base.h:54
void SetDepotOrderType(OrderDepotTypeFlags depot_order_type)
Set the cause to go to the depot.
Definition: order_base.h:165
OrderLoadFlags GetLoadType() const
How must the consist be loaded?
Definition: order_base.h:136
void SetStopLocation(OrderStopLocation stop_location)
Set where we must stop at the platform.
Definition: order_base.h:163
void MakeDummy()
Makes this order a Dummy order.
Definition: order_cmd.cpp:133
void MakeGoToWaypoint(StationID destination)
Makes this order a Go To Waypoint order.
Definition: order_cmd.cpp:104
void SetConditionVariable(OrderConditionVariable condition_variable)
Set variable we have to compare.
Definition: order_base.h:169
uint8_t flags
Load/unload types, depot order/action types.
Definition: order_base.h:49
void MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoID cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition: order_cmd.cpp:90
Order * next
Pointer to next order. If nullptr, end of list.
Definition: order_base.h:59
DestinationID dest
The destination of the order.
Definition: order_base.h:50
void SetDestination(DestinationID destination)
Sets the destination of this order.
Definition: order_base.h:110
void SetRefit(CargoID cargo)
Make this depot/station order also a refit order.
Definition: order_cmd.cpp:165
uint32_t Pack() const
Pack this order into a 32 bits integer, or actually only the type, flags and destination.
Definition: order_cmd.cpp:198
void SetConditionComparator(OrderConditionComparator condition_comparator)
Set the comparator to use.
Definition: order_base.h:171
void MakeConditional(VehicleOrderID order)
Makes this order an conditional order.
Definition: order_cmd.cpp:143
void SetDepotActionType(OrderDepotActionFlags depot_service_type)
Set what we are going to do in the depot.
Definition: order_base.h:167
void SetConditionSkipToOrder(VehicleOrderID order_id)
Get the order to skip to.
Definition: order_base.h:173
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition: order_base.h:146
void MakeLeaveStation()
Makes this order a Leave Station order.
Definition: order_cmd.cpp:124
bool CanLeaveWithCargo(bool has_cargo) const
A vehicle can leave the current station with cargo if:
Definition: order_cmd.cpp:2249
void SetConditionValue(uint16_t value)
Set the value to base the skip on.
Definition: order_base.h:175
void Free()
'Free' the order
Definition: order_cmd.cpp:63
CargoID refit_cargo
Refit CargoID.
Definition: order_base.h:52
uint16_t GetTimetabledWait() const
Get the time in ticks a vehicle should wait at the destination or 0 if it's not timetabled.
Definition: order_base.h:188
bool ShouldStopAtStation(const Vehicle *v, StationID station) const
Check whether the given vehicle should stop at the given station based on this order and the non-stop...
Definition: order_cmd.cpp:2225
uint16_t GetTravelTime() const
Get the time in ticks a vehicle will probably take to reach the destination (timetabled or not).
Definition: order_base.h:194
void MakeImplicit(StationID destination)
Makes this order an implicit order.
Definition: order_cmd.cpp:154
OrderUnloadFlags GetUnloadType() const
How must the consist be unloaded?
Definition: order_base.h:138
void AssignOrder(const Order &other)
Assign data to an order (from another order) This function makes sure that the index is maintained co...
Definition: order_cmd.cpp:257
OrderConditionComparator GetConditionComparator() const
What is the comparator to use?
Definition: order_base.h:150
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition: order_base.h:140
bool IsRefit() const
Is this order a refit order.
Definition: order_base.h:117
void MakeLoading(bool ordered)
Makes this order a Loading order.
Definition: order_cmd.cpp:115
uint16_t GetConditionValue() const
Get the value to base the skip on.
Definition: order_base.h:154
uint16_t travel_time
How long in ticks the journey to this destination should take.
Definition: order_base.h:55
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:19
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition: pool_type.hpp:309
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:350
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
Base class for all pools.
Definition: pool_type.hpp:80
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.
static Station * Get(size_t index)
Gets station with given index.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Station data structure.
Definition: station_base.h:439
TileArea ship_station
Tile area the ship 'station' part covers.
Definition: station_base.h:454
Airport airport
Tile area the airport covers.
Definition: station_base.h:453
Vehicle data structure.
Definition: vehicle_base.h:244
EngineID engine_type
The type of engine used for this vehicle.
Definition: vehicle_base.h:323
uint16_t & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition: vehicle.cpp:3185
bool IsOrderListShared() const
Check if we share our orders with another vehicle.
Definition: vehicle_base.h:732
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition: vehicle.cpp:747
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:886
bool HasDepotOrder() const
Checks if a vehicle has a depot in its order list.
Definition: order_cmd.cpp:1851
void LeaveStation()
Perform all actions when leaving a station.
Definition: vehicle.cpp:2350
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition: vehicle.cpp:2966
bool HasUnbunchingOrder() const
Check if the current vehicle has an unbunching order.
Definition: vehicle.cpp:2489
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
Definition: vehicle_base.h:738
uint8_t day_counter
Increased by one for each day.
Definition: vehicle_base.h:349
virtual int GetDisplayMaxSpeed() const
Gets the maximum speed in km-ish/h that can be sent into SetDParam for string processing.
Definition: vehicle_base.h:530
void IncrementImplicitOrderIndex()
Increments cur_implicit_order_index, keeps care of the wrap-around and invalidates the GUI.
Definition: vehicle_base.h:862
virtual TileIndex GetOrderStationLocation([[maybe_unused]] StationID station)
Determine the location for the station where the vehicle goes to next.
Definition: vehicle_base.h:796
Order * GetOrder(int index) const
Returns order 'index' of a vehicle or nullptr when it doesn't exists.
Definition: vehicle_base.h:922
VehicleOrderID GetNumManualOrders() const
Get the number of manually added orders this vehicle has.
Definition: vehicle_base.h:744
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:356
OrderList * orders
Pointer to the order list for this vehicle.
Definition: vehicle_base.h:359
virtual ClosestDepot FindClosestDepot()
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
Definition: vehicle_base.h:805
uint8_t vehstatus
Status.
Definition: vehicle_base.h:354
Order * GetFirstOrder() const
Get the first order of the vehicles order list.
Definition: vehicle_base.h:705
bool HasFullLoadOrder() const
Check if the current vehicle has a full load order.
Definition: vehicle.cpp:2465
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
Definition: vehicle_base.h:477
TimerGameCalendar::Date age
Age in calendar days.
Definition: vehicle_base.h:292
IterateWrapper Orders() const
Returns an iterable ensemble of orders of a vehicle.
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
Definition: vehicle_base.h:726
TimerGameCalendar::Date max_age
Maximum age.
Definition: vehicle_base.h:294
uint16_t reliability
Reliability.
Definition: vehicle_base.h:297
Vehicle * NextShared() const
Get the next vehicle of the shared vehicle chain.
Definition: vehicle_base.h:714
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition: vehicle.cpp:2989
debug_inline bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
Definition: vehicle_base.h:515
TileIndex tile
Current tile index.
Definition: vehicle_base.h:264
TileIndex dest_tile
Heading for this tile.
Definition: vehicle_base.h:271
bool NeedsServicing() const
Check if the vehicle needs to go to a depot in near future (if a opportunity presents itself) for ser...
Definition: vehicle.cpp:190
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition: vehicle.cpp:2477
StationID last_station_visited
The last station we stopped at.
Definition: vehicle_base.h:337
Vehicle * PreviousShared() const
Get the previous vehicle of the shared vehicle chain.
Definition: vehicle_base.h:720
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:309
Order * GetLastOrder() const
Returns the last order of a vehicle, or nullptr if it doesn't exists.
Definition: vehicle_base.h:931
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition: vehicle.cpp:2164
void UpdateRealOrderIndex()
Skip implicit orders until cur_real_order_index is a non-implicit order.
Definition: vehicle_base.h:901
Representation of a waypoint.
Definition: waypoint_base.h:23
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition: tile_map.h:178
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
@ MP_STATION
A tile of a station.
Definition: tile_type.h:53
Functions related to time tabling.
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
Update the timetable for the vehicle.
Command definitions related to trains.
StringID GetVehicleCannotUseStationReason(const Vehicle *v, const Station *st)
Get reason string why this station can't be used by the given vehicle.
Definition: vehicle.cpp:3104
uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
Calculates how full a vehicle is.
Definition: vehicle.cpp:1493
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition: vehicle.cpp:3058
@ VS_STOPPED
Vehicle is stopped by the player.
Definition: vehicle_base.h:34
@ VS_CRASHED
Vehicle is crashed.
Definition: vehicle_base.h:40
Functions related to vehicles.
@ VIWD_MODIFY_ORDERS
Other order modifications.
Definition: vehicle_gui.h:36
@ VIWD_REMOVE_ALL_ORDERS
Removed / replaced all orders (after deleting / sharing).
Definition: vehicle_gui.h:35
WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition: vehicle_gui.h:97
@ VEH_ROAD
Road vehicle type.
Definition: vehicle_type.h:25
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition: vehicle_type.h:27
@ VEH_SHIP
Ship vehicle type.
Definition: vehicle_type.h:26
@ VEH_TRAIN
Train vehicle type.
Definition: vehicle_type.h:24
uint32_t VehicleID
The type all our vehicle IDs have.
Definition: vehicle_type.h:16
bool IsShipDepotTile(Tile t)
Is it a ship depot tile?
Definition: water_map.h:232
Base of waypoints.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition: window.cpp:3119
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:3211
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3093
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:3228
@ WC_STATION_LIST
Station list; Window numbers:
Definition: window_type.h:302
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
Definition: window_type.h:212
@ WC_SHIPS_LIST
Ships list; Window numbers:
Definition: window_type.h:320
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
Definition: window_type.h:339
@ WC_VEHICLE_TIMETABLE
Vehicle timetable; Window numbers:
Definition: window_type.h:224
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers:
Definition: window_type.h:326