OpenTTD
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 "cmd_helper.h"
13 #include "command_func.h"
14 #include "company_func.h"
15 #include "news_func.h"
16 #include "strings_func.h"
17 #include "timetable.h"
18 #include "vehicle_func.h"
19 #include "depot_base.h"
20 #include "core/pool_func.hpp"
21 #include "core/random_func.hpp"
22 #include "aircraft.h"
23 #include "roadveh.h"
24 #include "station_base.h"
25 #include "waypoint_base.h"
26 #include "company_base.h"
27 #include "order_backup.h"
28 #include "cheat_type.h"
29 
30 #include "table/strings.h"
31 
32 #include "safeguards.h"
33 
34 /* DestinationID must be at least as large as every these below, because it can
35  * be any of them
36  */
37 assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
38 assert_compile(sizeof(DestinationID) >= sizeof(StationID));
39 
40 OrderPool _order_pool("Order");
42 OrderListPool _orderlist_pool("OrderList");
44 
45 
47 {
48  if (CleaningPool()) return;
49 
50  /* We can visit oil rigs and buoys that are not our own. They will be shown in
51  * the list of stations. So, we need to invalidate that window if needed. */
52  if (this->IsType(OT_GOTO_STATION) || this->IsType(OT_GOTO_WAYPOINT)) {
53  BaseStation *bs = BaseStation::GetIfValid(this->GetDestination());
54  if (bs != nullptr && bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0);
55  }
56 }
57 
63 {
64  this->type = OT_NOTHING;
65  this->flags = 0;
66  this->dest = 0;
67  this->next = nullptr;
68 }
69 
74 void Order::MakeGoToStation(StationID destination)
75 {
76  this->type = OT_GOTO_STATION;
77  this->flags = 0;
78  this->dest = destination;
79 }
80 
90 {
91  this->type = OT_GOTO_DEPOT;
92  this->SetDepotOrderType(order);
93  this->SetDepotActionType(action);
94  this->SetNonStopType(non_stop_type);
95  this->dest = destination;
96  this->SetRefit(cargo);
97 }
98 
103 void Order::MakeGoToWaypoint(StationID destination)
104 {
105  this->type = OT_GOTO_WAYPOINT;
106  this->flags = 0;
107  this->dest = destination;
108 }
109 
114 void Order::MakeLoading(bool ordered)
115 {
116  this->type = OT_LOADING;
117  if (!ordered) this->flags = 0;
118 }
119 
124 {
125  this->type = OT_LEAVESTATION;
126  this->flags = 0;
127 }
128 
133 {
134  this->type = OT_DUMMY;
135  this->flags = 0;
136 }
137 
143 {
144  this->type = OT_CONDITIONAL;
145  this->flags = order;
146  this->dest = 0;
147 }
148 
153 void Order::MakeImplicit(StationID destination)
154 {
155  this->type = OT_IMPLICIT;
156  this->dest = destination;
157 }
158 
165 {
166  this->refit_cargo = cargo;
167 }
168 
174 bool Order::Equals(const Order &other) const
175 {
176  /* In case of go to nearest depot orders we need "only" compare the flags
177  * with the other and not the nearest depot order bit or the actual
178  * destination because those get clear/filled in during the order
179  * evaluation. If we do not do this the order will continuously be seen as
180  * a different order and it will try to find a "nearest depot" every tick. */
181  if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
182  ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
183  (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
184  return this->GetDepotOrderType() == other.GetDepotOrderType() &&
186  }
187 
188  return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
189 }
190 
197 uint32 Order::Pack() const
198 {
199  return this->dest << 16 | this->flags << 8 | this->type;
200 }
201 
207 uint16 Order::MapOldOrder() const
208 {
209  uint16 order = this->GetType();
210  switch (this->type) {
211  case OT_GOTO_STATION:
212  if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
213  if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
215  order |= GB(this->GetDestination(), 0, 8) << 8;
216  break;
217  case OT_GOTO_DEPOT:
218  if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
219  SetBit(order, 7);
220  order |= GB(this->GetDestination(), 0, 8) << 8;
221  break;
222  case OT_LOADING:
223  if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
224  break;
225  }
226  return order;
227 }
228 
233 Order::Order(uint32 packed)
234 {
235  this->type = (OrderType)GB(packed, 0, 8);
236  this->flags = GB(packed, 8, 8);
237  this->dest = GB(packed, 16, 16);
238  this->next = nullptr;
239  this->refit_cargo = CT_NO_REFIT;
240  this->wait_time = 0;
241  this->travel_time = 0;
242  this->max_speed = UINT16_MAX;
243 }
244 
250 void InvalidateVehicleOrder(const Vehicle *v, int data)
251 {
253 
254  if (data != 0) {
255  /* Calls SetDirty() too */
258  return;
259  }
260 
263 }
264 
272 void Order::AssignOrder(const Order &other)
273 {
274  this->type = other.type;
275  this->flags = other.flags;
276  this->dest = other.dest;
277 
278  this->refit_cargo = other.refit_cargo;
279 
280  this->wait_time = other.wait_time;
281  this->travel_time = other.travel_time;
282  this->max_speed = other.max_speed;
283 }
284 
291 {
292  this->first = chain;
293  this->first_shared = v;
294 
295  this->num_orders = 0;
296  this->num_manual_orders = 0;
297  this->num_vehicles = 1;
298  this->timetable_duration = 0;
299  this->total_duration = 0;
300 
301  for (Order *o = this->first; o != nullptr; o = o->next) {
302  ++this->num_orders;
303  if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
304  this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
305  this->total_duration += o->GetWaitTime() + o->GetTravelTime();
306  }
307 
308  for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) {
309  ++this->num_vehicles;
310  this->first_shared = u;
311  }
312 
313  for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles;
314 }
315 
321 void OrderList::FreeChain(bool keep_orderlist)
322 {
323  Order *next;
324  for (Order *o = this->first; o != nullptr; o = next) {
325  next = o->next;
326  delete o;
327  }
328 
329  if (keep_orderlist) {
330  this->first = nullptr;
331  this->num_orders = 0;
332  this->num_manual_orders = 0;
333  this->timetable_duration = 0;
334  } else {
335  delete this;
336  }
337 }
338 
345 {
346  if (index < 0) return nullptr;
347 
348  Order *order = this->first;
349 
350  while (order != nullptr && index-- > 0) {
351  order = order->next;
352  }
353  return order;
354 }
355 
367 const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
368 {
369  if (hops > this->GetNumOrders() || next == nullptr) return nullptr;
370 
371  if (next->IsType(OT_CONDITIONAL)) {
372  if (next->GetConditionVariable() != OCV_UNCONDITIONALLY) return next;
373 
374  /* We can evaluate trivial conditions right away. They're conceptually
375  * the same as regular order progression. */
376  return this->GetNextDecisionNode(
377  this->GetOrderAt(next->GetConditionSkipToOrder()),
378  hops + 1);
379  }
380 
381  if (next->IsType(OT_GOTO_DEPOT)) {
382  if (next->GetDepotActionType() == ODATFB_HALT) return nullptr;
383  if (next->IsRefit()) return next;
384  }
385 
386  if (!next->CanLoadOrUnload()) {
387  return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
388  }
389 
390  return next;
391 }
392 
402 StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first, uint hops) const
403 {
404 
405  const Order *next = first;
406  if (first == nullptr) {
407  next = this->GetOrderAt(v->cur_implicit_order_index);
408  if (next == nullptr) {
409  next = this->GetFirstOrder();
410  if (next == nullptr) return INVALID_STATION;
411  } else {
412  /* GetNext never returns nullptr if there is a valid station in the list.
413  * As the given "next" is already valid and a station in the list, we
414  * don't have to check for nullptr here. */
415  next = this->GetNext(next);
416  assert(next != nullptr);
417  }
418  }
419 
420  do {
421  next = this->GetNextDecisionNode(next, ++hops);
422 
423  /* Resolve possibly nested conditionals by estimation. */
424  while (next != nullptr && next->IsType(OT_CONDITIONAL)) {
425  /* We return both options of conditional orders. */
426  const Order *skip_to = this->GetNextDecisionNode(
427  this->GetOrderAt(next->GetConditionSkipToOrder()), hops);
428  const Order *advance = this->GetNextDecisionNode(
429  this->GetNext(next), hops);
430  if (advance == nullptr || advance == first || skip_to == advance) {
431  next = (skip_to == first) ? nullptr : skip_to;
432  } else if (skip_to == nullptr || skip_to == first) {
433  next = (advance == first) ? nullptr : advance;
434  } else {
435  StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
436  StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
437  while (!st2.IsEmpty()) st1.Push(st2.Pop());
438  return st1;
439  }
440  ++hops;
441  }
442 
443  /* Don't return a next stop if the vehicle has to unload everything. */
444  if (next == nullptr || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) &&
445  next->GetDestination() == v->last_station_visited &&
446  (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
447  return INVALID_STATION;
448  }
449  } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
450 
451  return next->GetDestination();
452 }
453 
459 void OrderList::InsertOrderAt(Order *new_order, int index)
460 {
461  if (this->first == nullptr) {
462  this->first = new_order;
463  } else {
464  if (index == 0) {
465  /* Insert as first or only order */
466  new_order->next = this->first;
467  this->first = new_order;
468  } else if (index >= this->num_orders) {
469  /* index is after the last order, add it to the end */
470  this->GetLastOrder()->next = new_order;
471  } else {
472  /* Put the new order in between */
473  Order *order = this->GetOrderAt(index - 1);
474  new_order->next = order->next;
475  order->next = new_order;
476  }
477  }
478  ++this->num_orders;
479  if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
480  this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
481  this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
482 
483  /* We can visit oil rigs and buoys that are not our own. They will be shown in
484  * the list of stations. So, we need to invalidate that window if needed. */
485  if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
486  BaseStation *bs = BaseStation::Get(new_order->GetDestination());
488  }
489 
490 }
491 
492 
498 {
499  if (index >= this->num_orders) return;
500 
501  Order *to_remove;
502 
503  if (index == 0) {
504  to_remove = this->first;
505  this->first = to_remove->next;
506  } else {
507  Order *prev = GetOrderAt(index - 1);
508  to_remove = prev->next;
509  prev->next = to_remove->next;
510  }
511  --this->num_orders;
512  if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
513  this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
514  this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
515  delete to_remove;
516 }
517 
523 void OrderList::MoveOrder(int from, int to)
524 {
525  if (from >= this->num_orders || to >= this->num_orders || from == to) return;
526 
527  Order *moving_one;
528 
529  /* Take the moving order out of the pointer-chain */
530  if (from == 0) {
531  moving_one = this->first;
532  this->first = moving_one->next;
533  } else {
534  Order *one_before = GetOrderAt(from - 1);
535  moving_one = one_before->next;
536  one_before->next = moving_one->next;
537  }
538 
539  /* Insert the moving_order again in the pointer-chain */
540  if (to == 0) {
541  moving_one->next = this->first;
542  this->first = moving_one;
543  } else {
544  Order *one_before = GetOrderAt(to - 1);
545  moving_one->next = one_before->next;
546  one_before->next = moving_one;
547  }
548 }
549 
556 {
557  --this->num_vehicles;
558  if (v == this->first_shared) this->first_shared = v->NextShared();
559 }
560 
566 {
567  for (const Vehicle *v_shared = this->first_shared; v_shared != nullptr; v_shared = v_shared->NextShared()) {
568  if (v_shared == v) return true;
569  }
570 
571  return false;
572 }
573 
580 {
581  int count = 0;
582  for (const Vehicle *v_shared = v->PreviousShared(); v_shared != nullptr; v_shared = v_shared->PreviousShared()) count++;
583  return count;
584 }
585 
591 {
592  for (Order *o = this->first; o != nullptr; o = o->next) {
593  /* Implicit orders are, by definition, not timetabled. */
594  if (o->IsType(OT_IMPLICIT)) continue;
595  if (!o->IsCompletelyTimetabled()) return false;
596  }
597  return true;
598 }
599 
604 {
605  VehicleOrderID check_num_orders = 0;
606  VehicleOrderID check_num_manual_orders = 0;
607  uint check_num_vehicles = 0;
608  Ticks check_timetable_duration = 0;
609  Ticks check_total_duration = 0;
610 
611  DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
612 
613  for (const Order *o = this->first; o != nullptr; o = o->next) {
614  ++check_num_orders;
615  if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
616  check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
617  check_total_duration += o->GetWaitTime() + o->GetTravelTime();
618  }
619  assert(this->num_orders == check_num_orders);
620  assert(this->num_manual_orders == check_num_manual_orders);
621  assert(this->timetable_duration == check_timetable_duration);
622  assert(this->total_duration == check_total_duration);
623 
624  for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
625  ++check_num_vehicles;
626  assert(v->orders.list == this);
627  }
628  assert(this->num_vehicles == check_num_vehicles);
629  DEBUG(misc, 6, "... detected %u orders (%u manual), %u vehicles, %i timetabled, %i total",
630  (uint)this->num_orders, (uint)this->num_manual_orders,
631  this->num_vehicles, this->timetable_duration, this->total_duration);
632 }
633 
641 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
642 {
643  return o->IsType(OT_GOTO_STATION) ||
644  (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
645 }
646 
653 static void DeleteOrderWarnings(const Vehicle *v)
654 {
655  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
656  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
657  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
658  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
659  DeleteVehicleNews(v->index, STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY);
660 }
661 
668 TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
669 {
670  switch (this->GetType()) {
671  case OT_GOTO_WAYPOINT:
672  case OT_GOTO_STATION:
673  case OT_IMPLICIT:
674  if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile;
675  return BaseStation::Get(this->GetDestination())->xy;
676 
677  case OT_GOTO_DEPOT:
678  if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
679  return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
680 
681  default:
682  return INVALID_TILE;
683  }
684 }
685 
695 uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
696 {
697  if (cur->IsType(OT_CONDITIONAL)) {
698  if (conditional_depth > v->GetNumOrders()) return 0;
699 
700  conditional_depth++;
701 
702  int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
703  int dist2 = GetOrderDistance(prev, cur->next == nullptr ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
704  return max(dist1, dist2);
705  }
706 
707  TileIndex prev_tile = prev->GetLocation(v, true);
708  TileIndex cur_tile = cur->GetLocation(v, true);
709  if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
710  return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
711 }
712 
726 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
727 {
728  VehicleID veh = GB(p1, 0, 20);
729  VehicleOrderID sel_ord = GB(p1, 20, 8);
730  Order new_order(p2);
731 
732  Vehicle *v = Vehicle::GetIfValid(veh);
733  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
734 
735  CommandCost ret = CheckOwnership(v->owner);
736  if (ret.Failed()) return ret;
737 
738  /* Check if the inserted order is to the correct destination (owner, type),
739  * and has the correct flags if any */
740  switch (new_order.GetType()) {
741  case OT_GOTO_STATION: {
742  const Station *st = Station::GetIfValid(new_order.GetDestination());
743  if (st == nullptr) return CMD_ERROR;
744 
745  if (st->owner != OWNER_NONE) {
746  CommandCost ret = CheckOwnership(st->owner);
747  if (ret.Failed()) return ret;
748  }
749 
750  if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
751  for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
752  if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
753  }
754 
755  /* Non stop only allowed for ground vehicles. */
756  if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
757 
758  /* Filter invalid load/unload types. */
759  switch (new_order.GetLoadType()) {
761  default: return CMD_ERROR;
762  }
763  switch (new_order.GetUnloadType()) {
764  case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
765  default: return CMD_ERROR;
766  }
767 
768  /* Filter invalid stop locations */
769  switch (new_order.GetStopLocation()) {
771  case OSL_PLATFORM_MIDDLE:
772  if (v->type != VEH_TRAIN) return CMD_ERROR;
773  FALLTHROUGH;
774 
776  break;
777 
778  default:
779  return CMD_ERROR;
780  }
781 
782  break;
783  }
784 
785  case OT_GOTO_DEPOT: {
786  if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
787  if (v->type == VEH_AIRCRAFT) {
788  const Station *st = Station::GetIfValid(new_order.GetDestination());
789 
790  if (st == nullptr) return CMD_ERROR;
791 
792  CommandCost ret = CheckOwnership(st->owner);
793  if (ret.Failed()) return ret;
794 
795  if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
796  return CMD_ERROR;
797  }
798  } else {
799  const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
800 
801  if (dp == nullptr) return CMD_ERROR;
802 
803  CommandCost ret = CheckOwnership(GetTileOwner(dp->xy));
804  if (ret.Failed()) return ret;
805 
806  switch (v->type) {
807  case VEH_TRAIN:
808  if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
809  break;
810 
811  case VEH_ROAD:
812  if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
813  break;
814 
815  case VEH_SHIP:
816  if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
817  break;
818 
819  default: return CMD_ERROR;
820  }
821  }
822  }
823 
824  if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
825  if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
826  if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
827  if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
828  break;
829  }
830 
831  case OT_GOTO_WAYPOINT: {
832  const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
833  if (wp == nullptr) return CMD_ERROR;
834 
835  switch (v->type) {
836  default: return CMD_ERROR;
837 
838  case VEH_TRAIN: {
839  if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
840 
841  CommandCost ret = CheckOwnership(wp->owner);
842  if (ret.Failed()) return ret;
843  break;
844  }
845 
846  case VEH_SHIP:
847  if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
848  if (wp->owner != OWNER_NONE) {
849  CommandCost ret = CheckOwnership(wp->owner);
850  if (ret.Failed()) return ret;
851  }
852  break;
853  }
854 
855  /* Order flags can be any of the following for waypoints:
856  * [non-stop]
857  * non-stop orders (if any) are only valid for trains */
858  if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
859  break;
860  }
861 
862  case OT_CONDITIONAL: {
863  VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
864  if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
865  if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
866 
868  if (occ >= OCC_END) return CMD_ERROR;
869  switch (new_order.GetConditionVariable()) {
871  if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
872  break;
873 
874  case OCV_UNCONDITIONALLY:
875  if (occ != OCC_EQUALS) return CMD_ERROR;
876  if (new_order.GetConditionValue() != 0) return CMD_ERROR;
877  break;
878 
879  case OCV_LOAD_PERCENTAGE:
880  case OCV_RELIABILITY:
881  if (new_order.GetConditionValue() > 100) return CMD_ERROR;
882  FALLTHROUGH;
883 
884  default:
885  if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
886  break;
887  }
888  break;
889  }
890 
891  default: return CMD_ERROR;
892  }
893 
894  if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
895 
896  if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
897  if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
898  if (v->orders.list == nullptr && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
899 
900  if (flags & DC_EXEC) {
901  Order *new_o = new Order();
902  new_o->AssignOrder(new_order);
903  InsertOrder(v, new_o, sel_ord);
904  }
905 
906  return CommandCost();
907 }
908 
915 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
916 {
917  /* Create new order and link in list */
918  if (v->orders.list == nullptr) {
919  v->orders.list = new OrderList(new_o, v);
920  } else {
921  v->orders.list->InsertOrderAt(new_o, sel_ord);
922  }
923 
924  Vehicle *u = v->FirstShared();
926  for (; u != nullptr; u = u->NextShared()) {
927  assert(v->orders.list == u->orders.list);
928 
929  /* If there is added an order before the current one, we need
930  * to update the selected order. We do not change implicit/real order indices though.
931  * If the new order is between the current implicit order and real order, the implicit order will
932  * later skip the inserted order. */
933  if (sel_ord <= u->cur_real_order_index) {
934  uint cur = u->cur_real_order_index + 1;
935  /* Check if we don't go out of bound */
936  if (cur < u->GetNumOrders()) {
937  u->cur_real_order_index = cur;
938  }
939  }
940  if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
941  /* We are inserting an order just before the current implicit order.
942  * We do not know whether we will reach current implicit or the newly inserted order first.
943  * So, disable creation of implicit orders until we are on track again. */
944  uint16 &gv_flags = u->GetGroundVehicleFlags();
946  }
947  if (sel_ord <= u->cur_implicit_order_index) {
948  uint cur = u->cur_implicit_order_index + 1;
949  /* Check if we don't go out of bound */
950  if (cur < u->GetNumOrders()) {
951  u->cur_implicit_order_index = cur;
952  }
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  Order *order;
961  FOR_VEHICLE_ORDERS(v, order) {
962  if (order->IsType(OT_CONDITIONAL)) {
963  VehicleOrderID order_id = order->GetConditionSkipToOrder();
964  if (order_id >= sel_ord) {
965  order->SetConditionSkipToOrder(order_id + 1);
966  }
967  if (order_id == cur_order_id) {
968  order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
969  }
970  }
971  cur_order_id++;
972  }
973 
974  /* Make sure to rebuild the whole list */
976 }
977 
984 {
985  if (flags & DC_EXEC) {
986  DeleteVehicleOrders(dst);
989  }
990  return CommandCost();
991 }
992 
1002 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1003 {
1004  VehicleID veh_id = GB(p1, 0, 20);
1005  VehicleOrderID sel_ord = GB(p2, 0, 8);
1006 
1007  Vehicle *v = Vehicle::GetIfValid(veh_id);
1008 
1009  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1010 
1011  CommandCost ret = CheckOwnership(v->owner);
1012  if (ret.Failed()) return ret;
1013 
1014  /* If we did not select an order, we maybe want to de-clone the orders */
1015  if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
1016 
1017  if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
1018 
1019  if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
1020  return CommandCost();
1021 }
1022 
1028 {
1029  assert(v->current_order.IsType(OT_LOADING));
1030  /* NON-stop flag is misused to see if a train is in a station that is
1031  * on his order list or not */
1033  /* When full loading, "cancel" that order so the vehicle doesn't
1034  * stay indefinitely at this station anymore. */
1036 }
1037 
1044 {
1045  v->orders.list->DeleteOrderAt(sel_ord);
1046 
1047  Vehicle *u = v->FirstShared();
1049  for (; u != nullptr; u = u->NextShared()) {
1050  assert(v->orders.list == u->orders.list);
1051 
1052  if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
1054  }
1055 
1056  if (sel_ord < u->cur_real_order_index) {
1057  u->cur_real_order_index--;
1058  } else if (sel_ord == u->cur_real_order_index) {
1059  u->UpdateRealOrderIndex();
1060  }
1061 
1062  if (sel_ord < u->cur_implicit_order_index) {
1064  } else if (sel_ord == u->cur_implicit_order_index) {
1065  /* Make sure the index is valid */
1067 
1068  /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
1069  while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) {
1072  }
1073  }
1074 
1075  /* Update any possible open window of the vehicle */
1076  InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1077  }
1078 
1079  /* As we delete an order, the order to skip to will be 'wrong'. */
1080  VehicleOrderID cur_order_id = 0;
1081  Order *order = nullptr;
1082  FOR_VEHICLE_ORDERS(v, order) {
1083  if (order->IsType(OT_CONDITIONAL)) {
1084  VehicleOrderID order_id = order->GetConditionSkipToOrder();
1085  if (order_id >= sel_ord) {
1086  order_id = max(order_id - 1, 0);
1087  }
1088  if (order_id == cur_order_id) {
1089  order_id = (order_id + 1) % v->GetNumOrders();
1090  }
1091  order->SetConditionSkipToOrder(order_id);
1092  }
1093  cur_order_id++;
1094  }
1095 
1097 }
1098 
1108 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1109 {
1110  VehicleID veh_id = GB(p1, 0, 20);
1111  VehicleOrderID sel_ord = GB(p2, 0, 8);
1112 
1113  Vehicle *v = Vehicle::GetIfValid(veh_id);
1114 
1115  if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1116 
1117  CommandCost ret = CheckOwnership(v->owner);
1118  if (ret.Failed()) return ret;
1119 
1120  if (flags & DC_EXEC) {
1121  if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1122 
1124  v->UpdateRealOrderIndex();
1125 
1127  }
1128 
1129  /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1132 
1133  return CommandCost();
1134 }
1135 
1149 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1150 {
1151  VehicleID veh = GB(p1, 0, 20);
1152  VehicleOrderID moving_order = GB(p2, 0, 16);
1153  VehicleOrderID target_order = GB(p2, 16, 16);
1154 
1155  Vehicle *v = Vehicle::GetIfValid(veh);
1156  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1157 
1158  CommandCost ret = CheckOwnership(v->owner);
1159  if (ret.Failed()) return ret;
1160 
1161  /* Don't make senseless movements */
1162  if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1163  moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1164 
1165  Order *moving_one = v->GetOrder(moving_order);
1166  /* Don't move an empty order */
1167  if (moving_one == nullptr) return CMD_ERROR;
1168 
1169  if (flags & DC_EXEC) {
1170  v->orders.list->MoveOrder(moving_order, target_order);
1171 
1172  /* Update shared list */
1173  Vehicle *u = v->FirstShared();
1174 
1176 
1177  for (; u != nullptr; u = u->NextShared()) {
1178  /* Update the current order.
1179  * There are multiple ways to move orders, which result in cur_implicit_order_index
1180  * and cur_real_order_index to not longer make any sense. E.g. moving another
1181  * real order between them.
1182  *
1183  * Basically one could choose to preserve either of them, but not both.
1184  * While both ways are suitable in this or that case from a human point of view, neither
1185  * of them makes really sense.
1186  * However, from an AI point of view, preserving cur_real_order_index is the most
1187  * predictable and transparent behaviour.
1188  *
1189  * With that decision it basically does not matter what we do to cur_implicit_order_index.
1190  * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1191  * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1192  * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1193  */
1194  if (u->cur_real_order_index == moving_order) {
1195  u->cur_real_order_index = target_order;
1196  } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1197  u->cur_real_order_index--;
1198  } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1199  u->cur_real_order_index++;
1200  }
1201 
1202  if (u->cur_implicit_order_index == moving_order) {
1203  u->cur_implicit_order_index = target_order;
1204  } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1206  } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1208  }
1209 
1210  assert(v->orders.list == u->orders.list);
1211  /* Update any possible open window of the vehicle */
1212  InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1213  }
1214 
1215  /* As we move an order, the order to skip to will be 'wrong'. */
1216  Order *order;
1217  FOR_VEHICLE_ORDERS(v, order) {
1218  if (order->IsType(OT_CONDITIONAL)) {
1219  VehicleOrderID order_id = order->GetConditionSkipToOrder();
1220  if (order_id == moving_order) {
1221  order_id = target_order;
1222  } else if (order_id > moving_order && order_id <= target_order) {
1223  order_id--;
1224  } else if (order_id < moving_order && order_id >= target_order) {
1225  order_id++;
1226  }
1227  order->SetConditionSkipToOrder(order_id);
1228  }
1229  }
1230 
1231  /* Make sure to rebuild the whole list */
1233  }
1234 
1235  return CommandCost();
1236 }
1237 
1253 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1254 {
1255  VehicleOrderID sel_ord = GB(p1, 20, 8);
1256  VehicleID veh = GB(p1, 0, 20);
1257  ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
1258  uint16 data = GB(p2, 4, 11);
1259 
1260  if (mof >= MOF_END) return CMD_ERROR;
1261 
1262  Vehicle *v = Vehicle::GetIfValid(veh);
1263  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1264 
1265  CommandCost ret = CheckOwnership(v->owner);
1266  if (ret.Failed()) return ret;
1267 
1268  /* Is it a valid order? */
1269  if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1270 
1271  Order *order = v->GetOrder(sel_ord);
1272  switch (order->GetType()) {
1273  case OT_GOTO_STATION:
1274  if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1275  break;
1276 
1277  case OT_GOTO_DEPOT:
1278  if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1279  break;
1280 
1281  case OT_GOTO_WAYPOINT:
1282  if (mof != MOF_NON_STOP) return CMD_ERROR;
1283  break;
1284 
1285  case OT_CONDITIONAL:
1286  if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1287  break;
1288 
1289  default:
1290  return CMD_ERROR;
1291  }
1292 
1293  switch (mof) {
1294  default: NOT_REACHED();
1295 
1296  case MOF_NON_STOP:
1297  if (!v->IsGroundVehicle()) return CMD_ERROR;
1298  if (data >= ONSF_END) return CMD_ERROR;
1299  if (data == order->GetNonStopType()) return CMD_ERROR;
1300  break;
1301 
1302  case MOF_STOP_LOCATION:
1303  if (v->type != VEH_TRAIN) return CMD_ERROR;
1304  if (data >= OSL_END) return CMD_ERROR;
1305  break;
1306 
1307  case MOF_UNLOAD:
1309  if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
1310  /* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
1311  if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
1312  if (data == order->GetUnloadType()) return CMD_ERROR;
1313  break;
1314 
1315  case MOF_LOAD:
1317  if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
1318  if (data == order->GetLoadType()) return CMD_ERROR;
1319  break;
1320 
1321  case MOF_DEPOT_ACTION:
1322  if (data >= DA_END) return CMD_ERROR;
1323  break;
1324 
1325  case MOF_COND_VARIABLE:
1326  if (data >= OCV_END) return CMD_ERROR;
1327  break;
1328 
1329  case MOF_COND_COMPARATOR:
1330  if (data >= OCC_END) return CMD_ERROR;
1331  switch (order->GetConditionVariable()) {
1332  case OCV_UNCONDITIONALLY: return CMD_ERROR;
1333 
1334  case OCV_REQUIRES_SERVICE:
1335  if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
1336  break;
1337 
1338  default:
1339  if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
1340  break;
1341  }
1342  break;
1343 
1344  case MOF_COND_VALUE:
1345  switch (order->GetConditionVariable()) {
1346  case OCV_UNCONDITIONALLY:
1347  case OCV_REQUIRES_SERVICE:
1348  return CMD_ERROR;
1349 
1350  case OCV_LOAD_PERCENTAGE:
1351  case OCV_RELIABILITY:
1352  if (data > 100) return CMD_ERROR;
1353  break;
1354 
1355  default:
1356  if (data > 2047) return CMD_ERROR;
1357  break;
1358  }
1359  break;
1360 
1361  case MOF_COND_DESTINATION:
1362  if (data >= v->GetNumOrders()) return CMD_ERROR;
1363  break;
1364  }
1365 
1366  if (flags & DC_EXEC) {
1367  switch (mof) {
1368  case MOF_NON_STOP:
1369  order->SetNonStopType((OrderNonStopFlags)data);
1371  order->SetRefit(CT_NO_REFIT);
1374  }
1375  break;
1376 
1377  case MOF_STOP_LOCATION:
1378  order->SetStopLocation((OrderStopLocation)data);
1379  break;
1380 
1381  case MOF_UNLOAD:
1382  order->SetUnloadType((OrderUnloadFlags)data);
1383  break;
1384 
1385  case MOF_LOAD:
1386  order->SetLoadType((OrderLoadFlags)data);
1387  if (data & OLFB_NO_LOAD) order->SetRefit(CT_NO_REFIT);
1388  break;
1389 
1390  case MOF_DEPOT_ACTION: {
1391  switch (data) {
1392  case DA_ALWAYS_GO:
1395  break;
1396 
1397  case DA_SERVICE:
1400  order->SetRefit(CT_NO_REFIT);
1401  break;
1402 
1403  case DA_STOP:
1406  order->SetRefit(CT_NO_REFIT);
1407  break;
1408 
1409  default:
1410  NOT_REACHED();
1411  }
1412  break;
1413  }
1414 
1415  case MOF_COND_VARIABLE: {
1417 
1419  switch (order->GetConditionVariable()) {
1420  case OCV_UNCONDITIONALLY:
1422  order->SetConditionValue(0);
1423  break;
1424 
1425  case OCV_REQUIRES_SERVICE:
1426  if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
1427  order->SetConditionValue(0);
1428  break;
1429 
1430  case OCV_LOAD_PERCENTAGE:
1431  case OCV_RELIABILITY:
1432  if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1433  FALLTHROUGH;
1434 
1435  default:
1436  if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
1437  break;
1438  }
1439  break;
1440  }
1441 
1442  case MOF_COND_COMPARATOR:
1444  break;
1445 
1446  case MOF_COND_VALUE:
1447  order->SetConditionValue(data);
1448  break;
1449 
1450  case MOF_COND_DESTINATION:
1451  order->SetConditionSkipToOrder(data);
1452  break;
1453 
1454  default: NOT_REACHED();
1455  }
1456 
1457  /* Update the windows and full load flags, also for vehicles that share the same order list */
1458  Vehicle *u = v->FirstShared();
1460  for (; u != nullptr; u = u->NextShared()) {
1461  /* Toggle u->current_order "Full load" flag if it changed.
1462  * However, as the same flag is used for depot orders, check
1463  * whether we are not going to a depot as there are three
1464  * cases where the full load flag can be active and only
1465  * one case where the flag is used for depot orders. In the
1466  * other cases for the OrderType the flags are not used,
1467  * so do not care and those orders should not be active
1468  * when this function is called.
1469  */
1470  if (sel_ord == u->cur_real_order_index &&
1471  (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1472  u->current_order.GetLoadType() != order->GetLoadType()) {
1473  u->current_order.SetLoadType(order->GetLoadType());
1474  }
1476  }
1477  }
1478 
1479  return CommandCost();
1480 }
1481 
1489 static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first)
1490 {
1491  if (first == nullptr || v_new->acache.cached_max_range == 0) return true;
1492 
1493  /* Iterate over all orders to check the distance between all
1494  * 'goto' orders and their respective next order (of any type). */
1495  for (const Order *o = first; o != nullptr; o = o->next) {
1496  switch (o->GetType()) {
1497  case OT_GOTO_STATION:
1498  case OT_GOTO_DEPOT:
1499  case OT_GOTO_WAYPOINT:
1500  /* If we don't have a next order, we've reached the end and must check the first order instead. */
1501  if (GetOrderDistance(o, o->next != nullptr ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false;
1502  break;
1503 
1504  default: break;
1505  }
1506  }
1507 
1508  return true;
1509 }
1510 
1522 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1523 {
1524  VehicleID veh_src = GB(p2, 0, 20);
1525  VehicleID veh_dst = GB(p1, 0, 20);
1526 
1527  Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1528  if (dst == nullptr || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1529 
1530  CommandCost ret = CheckOwnership(dst->owner);
1531  if (ret.Failed()) return ret;
1532 
1533  switch (GB(p1, 30, 2)) {
1534  case CO_SHARE: {
1535  Vehicle *src = Vehicle::GetIfValid(veh_src);
1536 
1537  /* Sanity checks */
1538  if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1539 
1540  CommandCost ret = CheckOwnership(src->owner);
1541  if (ret.Failed()) return ret;
1542 
1543  /* Trucks can't share orders with busses (and visa versa) */
1544  if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1545  return CMD_ERROR;
1546  }
1547 
1548  /* Is the vehicle already in the shared list? */
1549  if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1550 
1551  const Order *order;
1552 
1553  FOR_VEHICLE_ORDERS(src, order) {
1554  if (!OrderGoesToStation(dst, order)) continue;
1555 
1556  /* Allow copying unreachable destinations if they were already unreachable for the source.
1557  * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1558  * are temporarily invalid due to reconstruction. */
1559  const Station *st = Station::Get(order->GetDestination());
1560  if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1561  return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
1562  }
1563  }
1564 
1565  /* Check for aircraft range limits. */
1566  if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1567  return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1568  }
1569 
1570  if (src->orders.list == nullptr && !OrderList::CanAllocateItem()) {
1571  return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1572  }
1573 
1574  if (flags & DC_EXEC) {
1575  /* If the destination vehicle had a OrderList, destroy it.
1576  * We only reset the order indices, if the new orders are obviously different.
1577  * (We mainly do this to keep the order indices valid and in range.) */
1578  DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1579 
1580  dst->orders.list = src->orders.list;
1581 
1582  /* Link this vehicle in the shared-list */
1583  dst->AddToShared(src);
1584 
1587 
1589  }
1590  break;
1591  }
1592 
1593  case CO_COPY: {
1594  Vehicle *src = Vehicle::GetIfValid(veh_src);
1595 
1596  /* Sanity checks */
1597  if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1598 
1599  CommandCost ret = CheckOwnership(src->owner);
1600  if (ret.Failed()) return ret;
1601 
1602  /* Trucks can't copy all the orders from busses (and visa versa),
1603  * and neither can helicopters and aircraft. */
1604  const Order *order;
1605  FOR_VEHICLE_ORDERS(src, order) {
1606  if (OrderGoesToStation(dst, order) &&
1608  return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
1609  }
1610  }
1611 
1612  /* Check for aircraft range limits. */
1613  if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1614  return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1615  }
1616 
1617  /* make sure there are orders available */
1619  return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1620  }
1621 
1622  if (flags & DC_EXEC) {
1623  const Order *order;
1624  Order *first = nullptr;
1625  Order **order_dst;
1626 
1627  /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1628  * We only reset the order indices, if the new orders are obviously different.
1629  * (We mainly do this to keep the order indices valid and in range.) */
1630  DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1631 
1632  order_dst = &first;
1633  FOR_VEHICLE_ORDERS(src, order) {
1634  *order_dst = new Order();
1635  (*order_dst)->AssignOrder(*order);
1636  order_dst = &(*order_dst)->next;
1637  }
1638  if (dst->orders.list == nullptr) {
1639  dst->orders.list = new OrderList(first, dst);
1640  } else {
1641  assert(dst->orders.list->GetFirstOrder() == nullptr);
1642  assert(!dst->orders.list->IsShared());
1643  delete dst->orders.list;
1644  assert(OrderList::CanAllocateItem());
1645  dst->orders.list = new OrderList(first, dst);
1646  }
1647 
1649 
1651  }
1652  break;
1653  }
1654 
1655  case CO_UNSHARE: return DecloneOrder(dst, flags);
1656  default: return CMD_ERROR;
1657  }
1658 
1659  return CommandCost();
1660 }
1661 
1673 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1674 {
1675  VehicleID veh = GB(p1, 0, 20);
1676  VehicleOrderID order_number = GB(p2, 16, 8);
1677  CargoID cargo = GB(p2, 0, 8);
1678 
1679  if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT && cargo != CT_AUTO_REFIT) return CMD_ERROR;
1680 
1681  const Vehicle *v = Vehicle::GetIfValid(veh);
1682  if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
1683 
1684  CommandCost ret = CheckOwnership(v->owner);
1685  if (ret.Failed()) return ret;
1686 
1687  Order *order = v->GetOrder(order_number);
1688  if (order == nullptr) return CMD_ERROR;
1689 
1690  /* Automatic refit cargo is only supported for goto station orders. */
1691  if (cargo == CT_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1692 
1693  if (order->GetLoadType() & OLFB_NO_LOAD) return CMD_ERROR;
1694 
1695  if (flags & DC_EXEC) {
1696  order->SetRefit(cargo);
1697 
1698  /* Make the depot order an 'always go' order. */
1699  if (cargo != CT_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1702  }
1703 
1704  for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
1705  /* Update any possible open window of the vehicle */
1707 
1708  /* If the vehicle already got the current depot set as current order, then update current order as well */
1709  if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
1710  u->current_order.SetRefit(cargo);
1711  }
1712  }
1713  }
1714 
1715  return CommandCost();
1716 }
1717 
1718 
1724 void CheckOrders(const Vehicle *v)
1725 {
1726  /* Does the user wants us to check things? */
1727  if (_settings_client.gui.order_review_system == 0) return;
1728 
1729  /* Do nothing for crashed vehicles */
1730  if (v->vehstatus & VS_CRASHED) return;
1731 
1732  /* Do nothing for stopped vehicles if setting is '1' */
1733  if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
1734 
1735  /* do nothing we we're not the first vehicle in a share-chain */
1736  if (v->FirstShared() != v) return;
1737 
1738  /* Only check every 20 days, so that we don't flood the message log */
1739  if (v->owner == _local_company && v->day_counter % 20 == 0) {
1740  const Order *order;
1741  StringID message = INVALID_STRING_ID;
1742 
1743  /* Check the order list */
1744  int n_st = 0;
1745 
1746  FOR_VEHICLE_ORDERS(v, order) {
1747  /* Dummy order? */
1748  if (order->IsType(OT_DUMMY)) {
1749  message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1750  break;
1751  }
1752  /* Does station have a load-bay for this vehicle? */
1753  if (order->IsType(OT_GOTO_STATION)) {
1754  const Station *st = Station::Get(order->GetDestination());
1755 
1756  n_st++;
1757  if (!CanVehicleUseStation(v, st)) {
1758  message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1759  } else if (v->type == VEH_AIRCRAFT &&
1760  (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1763  message == INVALID_STRING_ID) {
1764  message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1765  }
1766  }
1767  }
1768 
1769  /* Check if the last and the first order are the same */
1770  if (v->GetNumOrders() > 1) {
1771  const Order *last = v->GetLastOrder();
1772 
1773  if (v->orders.list->GetFirstOrder()->Equals(*last)) {
1774  message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1775  }
1776  }
1777 
1778  /* Do we only have 1 station in our order list? */
1779  if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1780 
1781 #ifndef NDEBUG
1782  if (v->orders.list != nullptr) v->orders.list->DebugCheckSanity();
1783 #endif
1784 
1785  /* We don't have a problem */
1786  if (message == INVALID_STRING_ID) return;
1787 
1788  SetDParam(0, v->index);
1789  AddVehicleAdviceNewsItem(message, v->index);
1790  }
1791 }
1792 
1801 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
1802 {
1803  /* Aircraft have StationIDs for depot orders and never use DepotIDs
1804  * This fact is handled specially below
1805  */
1806 
1807  /* Go through all vehicles */
1808  for (Vehicle *v : Vehicle::Iterate()) {
1809  Order *order;
1810 
1811  order = &v->current_order;
1812  if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : order->GetType()) == type &&
1813  (!hangar || v->type == VEH_AIRCRAFT) && v->current_order.GetDestination() == destination) {
1814  order->MakeDummy();
1815  SetWindowDirty(WC_VEHICLE_VIEW, v->index);
1816  }
1817 
1818  /* Clear the order from the order-list */
1819  int id = -1;
1820  FOR_VEHICLE_ORDERS(v, order) {
1821  id++;
1822 restart:
1823 
1824  OrderType ot = order->GetType();
1825  if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
1826  if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) continue; // Not an aircraft? Can't have a hangar order.
1827  if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
1828  if (ot == type && order->GetDestination() == destination) {
1829  /* We want to clear implicit orders, but we don't want to make them
1830  * dummy orders. They should just vanish. Also check the actual order
1831  * type as ot is currently OT_GOTO_STATION. */
1832  if (order->IsType(OT_IMPLICIT)) {
1833  order = order->next; // DeleteOrder() invalidates current order
1834  DeleteOrder(v, id);
1835  if (order != nullptr) goto restart;
1836  break;
1837  }
1838 
1839  /* Clear wait time */
1840  v->orders.list->UpdateTotalDuration(-order->GetWaitTime());
1841  if (order->IsWaitTimetabled()) {
1842  v->orders.list->UpdateTimetableDuration(-order->GetTimetabledWait());
1843  order->SetWaitTimetabled(false);
1844  }
1845  order->SetWaitTime(0);
1846 
1847  /* Clear order, preserving travel time */
1848  bool travel_timetabled = order->IsTravelTimetabled();
1849  order->MakeDummy();
1850  order->SetTravelTimetabled(travel_timetabled);
1851 
1852  for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) {
1853  /* In GUI, simulate by removing the order and adding it back */
1856  }
1857  }
1858  }
1859  }
1860 
1861  OrderBackup::RemoveOrder(type, destination, hangar);
1862 }
1863 
1869 {
1870  const Order *order;
1871 
1872  FOR_VEHICLE_ORDERS(this, order) {
1873  if (order->IsType(OT_GOTO_DEPOT)) return true;
1874  }
1875 
1876  return false;
1877 }
1878 
1888 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1889 {
1891 
1892  if (v->IsOrderListShared()) {
1893  /* Remove ourself from the shared order list. */
1894  v->RemoveFromShared();
1895  v->orders.list = nullptr;
1896  } else if (v->orders.list != nullptr) {
1897  /* Remove the orders */
1898  v->orders.list->FreeChain(keep_orderlist);
1899  if (!keep_orderlist) v->orders.list = nullptr;
1900  }
1901 
1902  if (reset_order_indices) {
1904  if (v->current_order.IsType(OT_LOADING)) {
1906  }
1907  }
1908 }
1909 
1916 uint16 GetServiceIntervalClamped(uint interval, bool ispercent)
1917 {
1918  return ispercent ? Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1919 }
1920 
1929 static bool CheckForValidOrders(const Vehicle *v)
1930 {
1931  const Order *order;
1932 
1933  FOR_VEHICLE_ORDERS(v, order) {
1934  switch (order->GetType()) {
1935  case OT_GOTO_STATION:
1936  case OT_GOTO_DEPOT:
1937  case OT_GOTO_WAYPOINT:
1938  return true;
1939 
1940  default:
1941  break;
1942  }
1943  }
1944 
1945  return false;
1946 }
1947 
1951 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1952 {
1953  switch (occ) {
1954  case OCC_EQUALS: return variable == value;
1955  case OCC_NOT_EQUALS: return variable != value;
1956  case OCC_LESS_THAN: return variable < value;
1957  case OCC_LESS_EQUALS: return variable <= value;
1958  case OCC_MORE_THAN: return variable > value;
1959  case OCC_MORE_EQUALS: return variable >= value;
1960  case OCC_IS_TRUE: return variable != 0;
1961  case OCC_IS_FALSE: return variable == 0;
1962  default: NOT_REACHED();
1963  }
1964 }
1965 
1973 {
1974  if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
1975 
1976  bool skip_order = false;
1978  uint16 value = order->GetConditionValue();
1979 
1980  switch (order->GetConditionVariable()) {
1981  case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
1982  case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
1983  case OCV_MAX_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability), value); break;
1984  case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
1985  case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
1986  case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
1987  case OCV_UNCONDITIONALLY: skip_order = true; break;
1988  case OCV_REMAINING_LIFETIME: skip_order = OrderConditionCompare(occ, max(v->max_age - v->age + DAYS_IN_LEAP_YEAR - 1, 0) / DAYS_IN_LEAP_YEAR, value); break;
1989  default: NOT_REACHED();
1990  }
1991 
1992  return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
1993 }
1994 
2002 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
2003 {
2004  if (conditional_depth > v->GetNumOrders()) {
2005  v->current_order.Free();
2006  v->SetDestTile(0);
2007  return false;
2008  }
2009 
2010  switch (order->GetType()) {
2011  case OT_GOTO_STATION:
2012  v->SetDestTile(v->GetOrderStationLocation(order->GetDestination()));
2013  return true;
2014 
2015  case OT_GOTO_DEPOT:
2016  if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
2017  assert(!pbs_look_ahead);
2018  UpdateVehicleTimetable(v, true);
2020  break;
2021  }
2022 
2024  /* We need to search for the nearest depot (hangar). */
2025  TileIndex location;
2026  DestinationID destination;
2027  bool reverse;
2028 
2029  if (v->FindClosestDepot(&location, &destination, &reverse)) {
2030  /* PBS reservations cannot reverse */
2031  if (pbs_look_ahead && reverse) return false;
2032 
2033  v->SetDestTile(location);
2035 
2036  /* If there is no depot in front, reverse automatically (trains only) */
2037  if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
2038 
2039  if (v->type == VEH_AIRCRAFT) {
2040  Aircraft *a = Aircraft::From(v);
2041  if (a->state == FLYING && a->targetairport != destination) {
2042  /* The aircraft is now heading for a different hangar than the next in the orders */
2045  }
2046  }
2047  return true;
2048  }
2049 
2050  /* If there is no depot, we cannot help PBS either. */
2051  if (pbs_look_ahead) return false;
2052 
2053  UpdateVehicleTimetable(v, true);
2055  } else {
2056  if (v->type != VEH_AIRCRAFT) {
2057  v->SetDestTile(Depot::Get(order->GetDestination())->xy);
2058  } else {
2059  Aircraft *a = Aircraft::From(v);
2060  DestinationID destination = a->current_order.GetDestination();
2061  if (a->targetairport != destination) {
2062  /* The aircraft is now heading for a different hangar than the next in the orders */
2063  a->SetDestTile(a->GetOrderStationLocation(destination));
2064  }
2065  }
2066  return true;
2067  }
2068  break;
2069 
2070  case OT_GOTO_WAYPOINT:
2071  v->SetDestTile(Waypoint::Get(order->GetDestination())->xy);
2072  return true;
2073 
2074  case OT_CONDITIONAL: {
2075  assert(!pbs_look_ahead);
2076  VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2077  if (next_order != INVALID_VEH_ORDER_ID) {
2078  /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2079  * cur_real_order_index might come after next_order. */
2080  UpdateVehicleTimetable(v, false);
2081  v->cur_implicit_order_index = v->cur_real_order_index = next_order;
2082  v->UpdateRealOrderIndex();
2084 
2085  /* Disable creation of implicit orders.
2086  * When inserting them we do not know that we would have to make the conditional orders point to them. */
2087  if (v->IsGroundVehicle()) {
2088  uint16 &gv_flags = v->GetGroundVehicleFlags();
2090  }
2091  } else {
2092  UpdateVehicleTimetable(v, true);
2094  }
2095  break;
2096  }
2097 
2098  default:
2099  v->SetDestTile(0);
2100  return false;
2101  }
2102 
2103  assert(v->cur_implicit_order_index < v->GetNumOrders());
2104  assert(v->cur_real_order_index < v->GetNumOrders());
2105 
2106  /* Get the current order */
2107  order = v->GetOrder(v->cur_real_order_index);
2108  if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2109  assert(v->GetNumManualOrders() == 0);
2110  order = nullptr;
2111  }
2112 
2113  if (order == nullptr) {
2114  v->current_order.Free();
2115  v->SetDestTile(0);
2116  return false;
2117  }
2118 
2119  v->current_order = *order;
2120  return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2121 }
2122 
2131 {
2132  switch (v->current_order.GetType()) {
2133  case OT_GOTO_DEPOT:
2134  /* Let a depot order in the orderlist interrupt. */
2135  if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
2136  break;
2137 
2138  case OT_LOADING:
2139  return false;
2140 
2141  case OT_LEAVESTATION:
2142  if (v->type != VEH_AIRCRAFT) return false;
2143  break;
2144 
2145  default: break;
2146  }
2147 
2155  bool may_reverse = v->current_order.IsType(OT_NOTHING);
2156 
2157  /* Check if we've reached a 'via' destination. */
2158  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)) &&
2159  IsTileType(v->tile, MP_STATION) &&
2162  /* We set the last visited station here because we do not want
2163  * the train to stop at this 'via' station if the next order
2164  * is a no-non-stop order; in that case not setting the last
2165  * visited station will cause the vehicle to still stop. */
2167  UpdateVehicleTimetable(v, true);
2169  }
2170 
2171  /* Get the current order */
2172  assert(v->cur_implicit_order_index == 0 || v->cur_implicit_order_index < v->GetNumOrders());
2173  v->UpdateRealOrderIndex();
2174 
2175  const Order *order = v->GetOrder(v->cur_real_order_index);
2176  if (order != nullptr && order->IsType(OT_IMPLICIT)) {
2177  assert(v->GetNumManualOrders() == 0);
2178  order = nullptr;
2179  }
2180 
2181  /* If no order, do nothing. */
2182  if (order == nullptr || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
2183  if (v->type == VEH_AIRCRAFT) {
2184  /* Aircraft do something vastly different here, so handle separately */
2185  extern void HandleMissingAircraftOrders(Aircraft *v);
2186  HandleMissingAircraftOrders(Aircraft::From(v));
2187  return false;
2188  }
2189 
2190  v->current_order.Free();
2191  v->SetDestTile(0);
2192  return false;
2193  }
2194 
2195  /* If it is unchanged, keep it. */
2196  if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
2197  (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->ship_station.tile != INVALID_TILE)) {
2198  return false;
2199  }
2200 
2201  /* Otherwise set it, and determine the destination tile. */
2202  v->current_order = *order;
2203 
2205  switch (v->type) {
2206  default:
2207  NOT_REACHED();
2208 
2209  case VEH_ROAD:
2210  case VEH_TRAIN:
2211  break;
2212 
2213  case VEH_AIRCRAFT:
2214  case VEH_SHIP:
2216  break;
2217  }
2218 
2219  return UpdateOrderDest(v, order) && may_reverse;
2220 }
2221 
2229 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2230 {
2231  bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2232 
2233  return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
2234  v->last_station_visited != station && // Do stop only when we've not just been there
2235  /* Finally do stop when there is no non-stop flag set for this type of station. */
2237 }
2238 
2239 bool Order::CanLoadOrUnload() const
2240 {
2241  return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2243  ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
2244  (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
2245 }
2246 
2253 bool Order::CanLeaveWithCargo(bool has_cargo) const
2254 {
2255  return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
2256  (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
2257 }
OrderConditionVariable
Variables (of a vehicle) to &#39;cause&#39; skipping on.
Definition: order_type.h:112
Functions related to OTTD&#39;s strings.
Road vehicle states.
uint16 reliability
Current reliability of the engine.
Definition: engine_base.h:25
Date max_age
Maximum age.
Definition: vehicle_base.h:257
StationFacility facilities
The facilities that this station has.
Vehicle is stopped by the player.
Definition: vehicle_base.h:31
This airport has a short landing strip, dangerous for fast aircraft.
Definition: airport.h:150
void InsertOrderAt(Order *new_order, int index)
Insert a new order into the order chain.
Definition: order_cmd.cpp:459
bool IsVehicleInSharedOrdersList(const Vehicle *v) const
Checks whether a vehicle is part of the shared vehicle chain.
Definition: order_cmd.cpp:565
Definition of stuff that is very close to a company, like the company struct itself.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:302
CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Delete an order from the orderlist of a vehicle.
Definition: order_cmd.cpp:1002
uint16 DepotID
Type for the unique identifier of depots.
Definition: depot_type.h:13
Passes an OrderUnloadType.
Definition: order_type.h:146
uint16 GetTravelTime() const
Get the time in ticks a vehicle will probably take to reach the destination (timetabled or not)...
Definition: order_base.h:185
StationID targetairport
Airport to go to next.
Definition: aircraft.h:78
Minimal stack that uses a pool to avoid pointers.
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3215
Skip if both values are equal.
Definition: order_type.h:128
Load as long as there is cargo that fits in the train.
Definition: order_type.h:63
OrderConditionComparator GetConditionComparator() const
What is the comparator to use?
Definition: order_base.h:141
uint16 GetServiceIntervalClamped(uint interval, bool ispercent)
Clamp the service interval to the correct min/max.
Definition: order_cmd.cpp:1916
void SetConditionValue(uint16 value)
Set the value to base the skip on.
Definition: order_base.h:166
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
Definition: order_cmd.cpp:1724
Functions related to time tabling.
bool HasHangar() const
Check if this airport has at least one hangar.
Definition: station_base.h:338
void InvalidateVehicleOrder(const Vehicle *v, int data)
Updates the widgets of a vehicle which contains the order-data.
Definition: order_cmd.cpp:250
Train vehicle type.
Definition: vehicle_type.h:24
union Vehicle::@49 orders
The orders currently assigned to the vehicle.
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:291
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:332
VehicleOrderID GetConditionSkipToOrder() const
Get the order to skip to.
Definition: order_base.h:143
void SetWaitTime(uint16 time)
Set the time in ticks to wait at the destination.
Definition: order_base.h:203
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition: order_type.h:21
Other order modifications.
Definition: vehicle_gui.h:33
Functions related to debugging.
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
void SetDepotOrderType(OrderDepotTypeFlags depot_order_type)
Set the cause to go to the depot.
Definition: order_base.h:156
static void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition: news_func.h:40
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:23
Ship vehicle type.
Definition: vehicle_type.h:26
Maximal number of cargo types in a game.
Definition: cargo_type.h:64
void SetDepotActionType(OrderDepotActionFlags depot_service_type)
Set what we are going to do in the depot.
Definition: order_base.h:158
Selects the OrderDepotAction.
Definition: order_type.h:148
OrderList * list
Pointer to the order list for this vehicle.
Definition: vehicle_base.h:319
Skip if the variable is true.
Definition: order_type.h:134
static void RemoveOrder(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
TileIndex dest_tile
Heading for this tile.
Definition: vehicle_base.h:235
bool IsCompleteTimetable() const
Checks whether all orders of the list have a filled timetable.
Definition: order_cmd.cpp:590
bool IsTravelTimetabled() const
Does this order have an explicit travel time set?
Definition: order_base.h:176
Skip based on the reliability.
Definition: order_type.h:114
Functions related to vehicles.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition: aircraft.h:74
void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
Insert a new order but skip the validation.
Definition: order_cmd.cpp:915
Stop at the middle of the platform.
Definition: order_type.h:85
A comparator changes.
Definition: order_type.h:150
void IncrementImplicitOrderIndex()
Increments cur_implicit_order_index, keeps care of the wrap-around and invalidates the GUI...
Definition: vehicle_base.h:798
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:822
uint32 current_order_time
How many ticks have passed since this order started.
Definition: base_consist.h:21
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
Process a conditional order and determine the next order.
Definition: order_cmd.cpp:1972
Vehicle data structure.
Definition: vehicle_base.h:210
Base for all depots (except hangars)
void SetRefit(CargoID cargo)
Make this depot/station order also a refit order.
Definition: order_cmd.cpp:164
Flags flags
Flags for this airport type.
Definition: airport.h:180
Unload all cargo that the station accepts.
Definition: order_type.h:53
void LeaveStation()
Perform all actions when leaving a station.
Definition: vehicle.cpp:2180
Tindex index
Index of this pool item.
Definition: pool_type.hpp:189
Vehicle is flying in the air.
Definition: airport.h:75
Helper functions to extract data from command parameters.
CargoID refit_cargo
Refit CargoID.
Definition: order_base.h:42
Base for aircraft.
Representation of a waypoint.
Definition: waypoint_base.h:16
StationID last_station_visited
The last station we stopped at.
Definition: vehicle_base.h:300
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
Definition: order_cmd.cpp:1888
OrderNonStopFlags
Non-stop order flags.
Definition: order_type.h:72
void SetUnloadType(OrderUnloadFlags unload_type)
Set how the consist must be unloaded.
Definition: order_base.h:150
Skip if the value is more or equal to the limit.
Definition: order_type.h:133
void AircraftNextAirportPos_and_Order(Aircraft *v)
set the right pos when heading to other airports after takeoff
void SetConditionComparator(OrderConditionComparator condition_comparator)
Set the comparator to use.
Definition: order_base.h:162
Automatically choose cargo type when doing auto refitting.
Definition: cargo_type.h:66
Common return value for all commands.
Definition: command_type.h:23
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:24
uint16 MapOldOrder() const
Pack this order into a 16 bits integer as close to the TTD representation as possible.
Definition: order_cmd.cpp:207
void SetConditionVariable(OrderConditionVariable condition_variable)
Set variable we have to compare.
Definition: order_base.h:160
byte vehstatus
Status.
Definition: vehicle_base.h:315
Skip based on the age.
Definition: order_type.h:116
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:367
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:668
static RoadVehicle * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition: vehicle.cpp:741
bool CanLeaveWithCargo(bool has_cargo) const
A vehicle can leave the current station with cargo if:
Definition: order_cmd.cpp:2253
Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-new).
Definition: cargo_type.h:67
void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
Delete an order but skip the parameter validation.
Definition: order_cmd.cpp:1043
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition: order_base.h:137
The vehicle will stop at any station it passes except the destination.
Definition: order_type.h:75
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:695
Stop at the near end of the platform.
Definition: order_type.h:84
Order * next
Pointer to next order. If nullptr, end of list.
Definition: order_base.h:49
void DeleteOrderAt(int index)
Remove an order from the order list and delete it.
Definition: order_cmd.cpp:497
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
Definition: vehicle_base.h:673
Order * GetOrderAt(int index) const
Get a certain order of the order chain.
Definition: order_cmd.cpp:344
Cheat no_jetcrash
no jet will crash on small airports anymore
Definition: cheat_type.h:32
Pseudo random number generator.
void MoveOrder(int from, int to)
Move an order to another position within the order list.
Definition: order_cmd.cpp:523
void SetConditionSkipToOrder(VehicleOrderID order_id)
Get the order to skip to.
Definition: order_base.h:164
Stop at the far end of the platform.
Definition: order_type.h:86
DestinationID dest
The destination of the order.
Definition: order_base.h:40
uint16 travel_time
How long in ticks the journey to this destination should take.
Definition: order_base.h:45
The vehicle will stop at any station it passes and the destination.
Definition: order_type.h:73
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:3334
void MakeConditional(VehicleOrderID order)
Makes this order an conditional order.
Definition: order_cmd.cpp:142
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:2229
Passes an OrderStopLocation.
Definition: order_type.h:145
void RemoveVehicle(Vehicle *v)
Removes the vehicle from the shared order list.
Definition: order_cmd.cpp:555
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition: order_base.h:250
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition: order_base.h:135
static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
Declone an order-list.
Definition: order_cmd.cpp:983
Vehicle orders; Window numbers:
Definition: window_type.h:205
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:484
bool IsEmpty() const
Check if the stack is empty.
Some methods of Pool are placed here in order to reduce compilation time and binary size...
OrderConditionVariable GetConditionVariable() const
What variable do we have to compare?
Definition: order_base.h:139
Vehicle is crashed.
Definition: vehicle_base.h:37
The tile has no ownership.
Definition: company_type.h:25
Types related to cheating.
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
Definition: vehicle_base.h:431
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
uint8 type
The type of order + non-stop flags.
Definition: order_base.h:38
void SetNonStopType(OrderNonStopFlags non_stop_type)
Set whether we must stop at stations or not.
Definition: order_base.h:152
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags)
Shorthand for calling the long DoCommand with a container.
Definition: command.cpp:441
void MakeImplicit(StationID destination)
Makes this order an implicit order.
Definition: order_cmd.cpp:153
void DeleteVehicleNews(VehicleID vid, StringID news)
Delete a news item type about a vehicle.
Definition: news_gui.cpp:897
bool IsRefit() const
Is this order a refit order.
Definition: order_base.h:108
virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
Definition: vehicle_base.h:748
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:183
void MakeDummy()
Makes this order a Dummy order.
Definition: order_cmd.cpp:132
Do not load anything.
Definition: order_type.h:66
uint32 VehicleID
The type all our vehicle IDs have.
Definition: vehicle_type.h:16
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:61
static Owner GetTileOwner(TileIndex tile)
Returns the owner of a tile.
Definition: tile_map.h:178
DoCommandFlag
List of flags for a command.
Definition: command_type.h:342
Skip if the value is less or equal to the limit.
Definition: order_type.h:131
CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Add an order to the orderlist of a vehicle.
Definition: order_cmd.cpp:726
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:78
Definition of base types and functions in a cross-platform compatible way.
Removed / replaced all orders (after deleting / sharing).
Definition: vehicle_gui.h:32
A number of safeguards to prevent using unsafe methods.
bool value
tells if the bool cheat is active or not
Definition: cheat_type.h:18
Change the destination of a conditional order.
Definition: order_type.h:152
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
Definition: order_cmd.cpp:2130
Always skip.
Definition: order_type.h:118
Base of waypoints.
void MakeLoading(bool ordered)
Makes this order a Loading order.
Definition: order_cmd.cpp:114
static bool IsRoadDepotTile(TileIndex t)
Return whether a tile is a road depot tile.
Definition: road_map.h:115
void FreeChain(bool keep_orderlist=false)
Free a complete order chain.
Definition: order_cmd.cpp:321
Titem Pop()
Pop an item from the stack.
void UpdateRealOrderIndex()
Skip implicit orders until cur_real_order_index is a non-implicit order.
Definition: vehicle_base.h:837
OrderDepotActionFlags
Actions that can be performed when the vehicle enters the depot.
Definition: order_type.h:102
uint8 flags
Load/unload types, depot order/action types.
Definition: order_base.h:39
CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Move an order inside the orderlist.
Definition: order_cmd.cpp:1149
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition: vehicle.cpp:2688
Vehicle view; Window numbers:
Definition: window_type.h:332
bool IsWaitTimetabled() const
Does this order have an explicit wait time set?
Definition: order_base.h:174
Functions related to order backups.
uint16 GetTimetabledTravel() const
Get the time in ticks a vehicle should take to reach the destination or 0 if it&#39;s not timetabled...
Definition: order_base.h:181
bool IsShared() const
Is this a shared order list?
Definition: order_base.h:329
Order * GetFirstOrder() const
Get the first order of the order chain.
Definition: order_base.h:288
void Initialize(Order *chain, Vehicle *v)
Recomputes everything.
Definition: order_cmd.cpp:290
TileIndex tile
Current tile index.
Definition: vehicle_base.h:228
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
void Push(const Titem &item)
Pushes a new item onto the stack if there is still space in the underlying pool.
Vehicle timetable; Window numbers:
Definition: window_type.h:217
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition: vehicle.cpp:2779
OrderConditionComparator
Comparator for the skip reasoning.
Definition: order_type.h:127
Always go to the depot.
Definition: order_type.h:161
OrderLoadFlags GetLoadType() const
How must the consist be loaded?
Definition: order_base.h:127
Service the vehicle and then halt it.
Definition: order_type.h:104
virtual TileIndex GetOrderStationLocation(StationID station)
Determine the location for the station where the vehicle goes to next.
Definition: vehicle_base.h:738
void SetWaitTimetabled(bool timetabled)
Set if the wait time is explicitly timetabled (unless the order is conditional).
Definition: order_base.h:195
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:271
bool Equals(const Order &other) const
Does this order have the same type, flags and destination?
Definition: order_cmd.cpp:174
static bool IsShipDepotTile(TileIndex t)
Is it a ship depot tile?
Definition: water_map.h:226
Service only if needed.
Definition: order_type.h:162
Order * GetLastOrder() const
Returns the last order of a vehicle, or nullptr if it doesn&#39;t exists.
Definition: vehicle_base.h:867
uint16 reliability
Reliability.
Definition: vehicle_base.h:259
static void CancelLoadingDueToDeletedOrder(Vehicle *v)
Cancel the current loading order of the vehicle as the order was deleted.
Definition: order_cmd.cpp:1027
CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Goto order of order-list.
Definition: order_cmd.cpp:1108
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
bool Failed() const
Did this command fail?
Definition: command_type.h:159
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
Update the vehicle&#39;s destination tile from an order.
Definition: order_cmd.cpp:2002
Order * GetFirstOrder() const
Get the first order of the vehicles order list.
Definition: vehicle_base.h:652
CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Modify an order in the orderlist of a vehicle.
Definition: order_cmd.cpp:1253
The value to set the condition to.
Definition: order_type.h:151
static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
Compare the variable and value based on the given comparator.
Definition: order_cmd.cpp:1951
Skip based on the remaining lifetime.
Definition: order_type.h:119
Skip if the value is less than the limit.
Definition: order_type.h:130
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:653
Transfer all cargo onto the platform.
Definition: order_type.h:55
#define return_cmd_error(errcode)
Returns from a function with a specific StringID as error.
Definition: command_func.h:33
byte state
State of the airport.
Definition: aircraft.h:79
Base class for all pools.
Definition: pool_type.hpp:82
Station list; Window numbers:
Definition: window_type.h:295
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:137
OrderUnloadFlags GetUnloadType() const
How must the consist be unloaded?
Definition: order_base.h:129
void SetLoadType(OrderLoadFlags load_type)
Set how the consist must be loaded.
Definition: order_base.h:148
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:35
Skip when the vehicle requires service.
Definition: order_type.h:117
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:17
bool HasDepotOrder() const
Checks if a vehicle has a depot in its order list.
Definition: order_cmd.cpp:1868
OrderUnloadFlags
Flags related to the unloading order.
Definition: order_type.h:52
uint16 GetWaitTime() const
Get the time in ticks a vehicle will probably wait at the destination (timetabled or not)...
Definition: order_base.h:183
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don&#39;t get linker errors.
Definition: pool_func.hpp:224
TileIndex GetOrderStationLocation(StationID station)
Determine the location for the station where the vehicle goes to next.
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition: vehicle.cpp:2711
execute the given command
Definition: command_type.h:344
A conditional variable changes.
Definition: order_type.h:149
Functions related to companies.
Station with a dock.
Definition: station_type.h:56
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
Definition: station_map.h:28
OrderStopLocation
Where to stop the trains.
Definition: order_type.h:83
uint16 GetTimetabledWait() const
Get the time in ticks a vehicle should wait at the destination or 0 if it&#39;s not timetabled.
Definition: order_base.h:179
bool IsBus() const
Check whether a roadvehicle is a bus.
Definition: roadveh_cmd.cpp:79
Passes an OrderNonStopFlags.
Definition: order_type.h:144
uint16 cached_max_range
Cached maximum range.
Definition: aircraft.h:68
bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
Definition: vehicle_base.h:469
GUISettings gui
settings related to the GUI
DestinationID GetDestination() const
Gets the destination of this order.
Definition: order_base.h:94
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:340
static bool IsRailDepotTile(TileIndex t)
Is this tile rail tile and a rail depot?
Definition: rail_map.h:105
void MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoID cargo=CT_NO_REFIT)
Makes this order a Go To Depot order.
Definition: order_cmd.cpp:89
static bool CheckForValidOrders(const Vehicle *v)
Check if a vehicle has any valid orders.
Definition: order_cmd.cpp:1929
OrderStopLocation GetStopLocation() const
Where must we stop at the platform?
Definition: order_base.h:133
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
Update the timetable for the vehicle.
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:402
Ships list; Window numbers:
Definition: window_type.h:313
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:78
Skip if both values are not equal.
Definition: order_type.h:129
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition: map.cpp:157
OrderLoadFlags
Flags related to the loading order.
Definition: order_type.h:62
void MakeLeaveStation()
Makes this order a Leave Station order.
Definition: order_cmd.cpp:123
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:641
Vehicle * PreviousShared() const
Get the previous vehicle of the shared vehicle chain.
Definition: vehicle_base.h:667
uint16 wait_time
How long in ticks to wait at the destination.
Definition: order_base.h:44
Send the vehicle to the nearest depot.
Definition: order_type.h:105
int32 Ticks
The type to store ticks in.
Definition: date_type.h:16
void Free()
&#39;Free&#39; the order
Definition: order_cmd.cpp:62
turn a train around
Definition: command_type.h:222
uint16 GetConditionValue() const
Get the value to base the skip on.
Definition: order_base.h:145
TileIndex xy
Base tile of the station.
void SetTravelTimetabled(bool timetabled)
Set if the travel time is explicitly timetabled (unless the order is conditional).
Definition: order_base.h:197
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
uint32 cached_max_range_sqr
Cached squared maximum range.
Definition: aircraft.h:67
Full load all cargoes of the consist.
Definition: order_type.h:64
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:52
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition: vehicle.cpp:1994
A tile of a station.
Definition: tile_type.h:46
Skip based on the amount of load.
Definition: order_type.h:113
OrderType
Order types.
Definition: order_type.h:35
int GetPositionInSharedOrderList(const Vehicle *v) const
Gets the position of the given vehicle within the shared order vehicle list.
Definition: order_cmd.cpp:579
Totally no unloading will be done.
Definition: order_type.h:56
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function() ...
Definition: pool_type.hpp:261
static uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
Definition: math_func.hpp:298
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:272
The vehicle will not stop at any stations it passes except the destination.
Definition: order_type.h:74
Skip based on the maximum speed.
Definition: order_type.h:115
Aircraft list; Window numbers:
Definition: window_type.h:319
uint16 & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition: vehicle.cpp:2854
Functions related to commands.
CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Add/remove refit orders from an order.
Definition: order_cmd.cpp:1673
uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
Calculates how full a vehicle is.
Definition: vehicle.cpp:1377
void DebugCheckSanity() const
Checks for internal consistency of order list.
Definition: order_cmd.cpp:603
Passes an OrderLoadType.
Definition: order_type.h:147
Owner owner
The owner of this station.
ModifyOrderFlags
Enumeration for the data to set in CmdModifyOrder.
Definition: order_type.h:143
static WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition: vehicle_gui.h:91
CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
Clone/share/copy an order-list of another vehicle.
Definition: order_cmd.cpp:1522
Order * GetOrder(int index) const
Returns order &#39;index&#39; of a vehicle or nullptr when it doesn&#39;t exists.
Definition: vehicle_base.h:858
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
Definition: vehicle_base.h:685
Aircraft vehicle type.
Definition: vehicle_type.h:27
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:1489
Airport airport
Tile area the airport covers.
Definition: station_base.h:464
bool IsOrderListShared() const
Check if we share our orders with another vehicle.
Definition: vehicle_base.h:679
void MakeGoToWaypoint(StationID destination)
Makes this order a Go To Waypoint order.
Definition: order_cmd.cpp:103
EngineID engine_type
The type of engine used for this vehicle.
Definition: vehicle_base.h:286
byte VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition: order_type.h:15
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:83
uint32 Pack() const
Pack this order into a 32 bits integer, or actually only the type, flags and destination.
Definition: order_cmd.cpp:197
void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
Definition: order_cmd.cpp:1801
OrderType GetType() const
Get the type of order of this order.
Definition: order_base.h:67
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:20
uint8 order_review_system
perform order reviews on vehicles
Definition: settings_type.h:85
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the &#39;Square&#39; distance between the two given tiles.
Definition: map.cpp:174
Vehicle * NextShared() const
Get the next vehicle of the shared vehicle chain.
Definition: vehicle_base.h:661
Station with train station.
Definition: station_type.h:52
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
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition: window.cpp:3243
This depot order is because of a regular order.
Definition: order_type.h:96
Functions related to news.
Go to the depot and stop there.
Definition: order_type.h:163
Base classes/functions for stations.
static Station * Get(size_t index)
Gets station with given index.
VehicleOrderID cur_implicit_order_index
The index to the current implicit order.
Definition: base_consist.h:28
Skip if the value is more than the limit.
Definition: order_type.h:132
uint16 max_speed
How fast the vehicle may go on the way to the destination.
Definition: order_base.h:46
Date age
Age in days.
Definition: vehicle_base.h:256
Full load a single cargo of the consist.
Definition: order_type.h:65
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:44
This depot order is because of the servicing limit.
Definition: order_type.h:95
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
Definition: base_consist.h:27
Skip if the variable is false.
Definition: order_type.h:135
Skip based on the maximum reliability.
Definition: order_type.h:120
void SetStopLocation(OrderStopLocation stop_location)
Set where we must stop at the platform.
Definition: order_base.h:154
Base class for all station-ish types.
Station data structure.
Definition: station_base.h:450
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition: order_base.h:131
Disable insertion and removal of automatic orders until the vehicle completes the real order...
Road vehicle type.
Definition: vehicle_type.h:25
byte day_counter
Increased by one for each day.
Definition: vehicle_base.h:311
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:316
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:3316
static const int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
Definition: date_type.h:30
void MakeGoToStation(StationID destination)
Makes this order a Go To Station order.
Definition: order_cmd.cpp:74
OrderDepotTypeFlags
Reasons that could cause us to go to the depot.
Definition: order_type.h:93
CargoID GetRefitCargo() const
Get the cargo to to refit to.
Definition: order_base.h:122
Cheats _cheats
All the cheats.
Definition: cheat.cpp:16
VehicleOrderID GetNumManualOrders() const
Get the number of manually added orders this vehicle has.
Definition: vehicle_base.h:691
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:199
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.