OpenTTD
order_cmd.cpp
Go to the documentation of this file.
1 /* $Id: order_cmd.cpp 26694 2014-07-16 22:24:55Z frosch $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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/>.
8  */
9 
12 #include "stdafx.h"
13 #include "debug.h"
14 #include "cmd_helper.h"
15 #include "command_func.h"
16 #include "company_func.h"
17 #include "news_func.h"
18 #include "strings_func.h"
19 #include "timetable.h"
20 #include "vehicle_func.h"
21 #include "depot_base.h"
22 #include "core/pool_func.hpp"
23 #include "core/random_func.hpp"
24 #include "aircraft.h"
25 #include "roadveh.h"
26 #include "station_base.h"
27 #include "waypoint_base.h"
28 #include "company_base.h"
29 #include "order_backup.h"
30 #include "cheat_type.h"
31 
32 #include "table/strings.h"
33 
34 #include "safeguards.h"
35 
36 /* DestinationID must be at least as large as every these below, because it can
37  * be any of them
38  */
39 assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
40 assert_compile(sizeof(DestinationID) >= sizeof(StationID));
41 
42 OrderPool _order_pool("Order");
44 OrderListPool _orderlist_pool("OrderList");
45 INSTANTIATE_POOL_METHODS(OrderList)
46 
49 {
50  if (CleaningPool()) return;
51 
52  /* We can visit oil rigs and buoys that are not our own. They will be shown in
53  * the list of stations. So, we need to invalidate that window if needed. */
54  if (this->IsType(OT_GOTO_STATION) || this->IsType(OT_GOTO_WAYPOINT)) {
55  BaseStation *bs = BaseStation::GetIfValid(this->GetDestination());
56  if (bs != NULL && bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0);
57  }
58 }
59 
65 {
66  this->type = OT_NOTHING;
67  this->flags = 0;
68  this->dest = 0;
69  this->next = NULL;
70 }
71 
76 void Order::MakeGoToStation(StationID destination)
77 {
78  this->type = OT_GOTO_STATION;
79  this->flags = 0;
80  this->dest = destination;
81 }
82 
92 {
93  this->type = OT_GOTO_DEPOT;
94  this->SetDepotOrderType(order);
95  this->SetDepotActionType(action);
96  this->SetNonStopType(non_stop_type);
97  this->dest = destination;
98  this->SetRefit(cargo);
99 }
100 
105 void Order::MakeGoToWaypoint(StationID destination)
106 {
107  this->type = OT_GOTO_WAYPOINT;
108  this->flags = 0;
109  this->dest = destination;
110 }
111 
116 void Order::MakeLoading(bool ordered)
117 {
118  this->type = OT_LOADING;
119  if (!ordered) this->flags = 0;
120 }
121 
126 {
127  this->type = OT_LEAVESTATION;
128  this->flags = 0;
129 }
130 
135 {
136  this->type = OT_DUMMY;
137  this->flags = 0;
138 }
139 
145 {
146  this->type = OT_CONDITIONAL;
147  this->flags = order;
148  this->dest = 0;
149 }
150 
155 void Order::MakeImplicit(StationID destination)
156 {
157  this->type = OT_IMPLICIT;
158  this->dest = destination;
159 }
160 
167 {
168  this->refit_cargo = cargo;
169 }
170 
176 bool Order::Equals(const Order &other) const
177 {
178  /* In case of go to nearest depot orders we need "only" compare the flags
179  * with the other and not the nearest depot order bit or the actual
180  * destination because those get clear/filled in during the order
181  * evaluation. If we do not do this the order will continuously be seen as
182  * a different order and it will try to find a "nearest depot" every tick. */
183  if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
184  ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
185  (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
186  return this->GetDepotOrderType() == other.GetDepotOrderType() &&
188  }
189 
190  return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
191 }
192 
199 uint32 Order::Pack() const
200 {
201  return this->dest << 16 | this->flags << 8 | this->type;
202 }
203 
209 uint16 Order::MapOldOrder() const
210 {
211  uint16 order = this->GetType();
212  switch (this->type) {
213  case OT_GOTO_STATION:
214  if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
215  if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
217  order |= GB(this->GetDestination(), 0, 8) << 8;
218  break;
219  case OT_GOTO_DEPOT:
220  if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
221  SetBit(order, 7);
222  order |= GB(this->GetDestination(), 0, 8) << 8;
223  break;
224  case OT_LOADING:
225  if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
226  break;
227  }
228  return order;
229 }
230 
235 Order::Order(uint32 packed)
236 {
237  this->type = (OrderType)GB(packed, 0, 8);
238  this->flags = GB(packed, 8, 8);
239  this->dest = GB(packed, 16, 16);
240  this->next = NULL;
241  this->refit_cargo = CT_NO_REFIT;
242  this->wait_time = 0;
243  this->travel_time = 0;
244  this->max_speed = UINT16_MAX;
245 }
246 
252 void InvalidateVehicleOrder(const Vehicle *v, int data)
253 {
255 
256  if (data != 0) {
257  /* Calls SetDirty() too */
260  return;
261  }
262 
265 }
266 
274 void Order::AssignOrder(const Order &other)
275 {
276  this->type = other.type;
277  this->flags = other.flags;
278  this->dest = other.dest;
279 
280  this->refit_cargo = other.refit_cargo;
281 
282  this->wait_time = other.wait_time;
283  this->travel_time = other.travel_time;
284  this->max_speed = other.max_speed;
285 }
286 
293 {
294  this->first = chain;
295  this->first_shared = v;
296 
297  this->num_orders = 0;
298  this->num_manual_orders = 0;
299  this->num_vehicles = 1;
300  this->timetable_duration = 0;
301  this->total_duration = 0;
302 
303  for (Order *o = this->first; o != NULL; o = o->next) {
304  ++this->num_orders;
305  if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
306  this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
307  this->total_duration += o->GetWaitTime() + o->GetTravelTime();
308  }
309 
310  for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) {
311  ++this->num_vehicles;
312  this->first_shared = u;
313  }
314 
315  for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
316 }
317 
323 void OrderList::FreeChain(bool keep_orderlist)
324 {
325  Order *next;
326  for (Order *o = this->first; o != NULL; o = next) {
327  next = o->next;
328  delete o;
329  }
330 
331  if (keep_orderlist) {
332  this->first = NULL;
333  this->num_orders = 0;
334  this->num_manual_orders = 0;
335  this->timetable_duration = 0;
336  } else {
337  delete this;
338  }
339 }
340 
346 Order *OrderList::GetOrderAt(int index) const
347 {
348  if (index < 0) return NULL;
349 
350  Order *order = this->first;
351 
352  while (order != NULL && index-- > 0) {
353  order = order->next;
354  }
355  return order;
356 }
357 
369 const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const
370 {
371  if (hops > this->GetNumOrders() || next == NULL) return NULL;
372 
373  if (next->IsType(OT_CONDITIONAL)) {
374  if (next->GetConditionVariable() != OCV_UNCONDITIONALLY) return next;
375 
376  /* We can evaluate trivial conditions right away. They're conceptually
377  * the same as regular order progression. */
378  return this->GetNextDecisionNode(
379  this->GetOrderAt(next->GetConditionSkipToOrder()),
380  hops + 1);
381  }
382 
383  if (next->IsType(OT_GOTO_DEPOT)) {
384  if (next->GetDepotActionType() == ODATFB_HALT) return NULL;
385  if (next->IsRefit()) return next;
386  }
387 
388  if (!next->CanLoadOrUnload()) {
389  return this->GetNextDecisionNode(this->GetNext(next), hops + 1);
390  }
391 
392  return next;
393 }
394 
404 StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first, uint hops) const
405 {
406 
407  const Order *next = first;
408  if (first == NULL) {
409  next = this->GetOrderAt(v->cur_implicit_order_index);
410  if (next == NULL) {
411  next = this->GetFirstOrder();
412  if (next == NULL) return INVALID_STATION;
413  } else {
414  /* GetNext never returns NULL if there is a valid station in the list.
415  * As the given "next" is already valid and a station in the list, we
416  * don't have to check for NULL here. */
417  next = this->GetNext(next);
418  assert(next != NULL);
419  }
420  }
421 
422  do {
423  next = this->GetNextDecisionNode(next, ++hops);
424 
425  /* Resolve possibly nested conditionals by estimation. */
426  while (next != NULL && next->IsType(OT_CONDITIONAL)) {
427  /* We return both options of conditional orders. */
428  const Order *skip_to = this->GetNextDecisionNode(
429  this->GetOrderAt(next->GetConditionSkipToOrder()), hops);
430  const Order *advance = this->GetNextDecisionNode(
431  this->GetNext(next), hops);
432  if (advance == NULL || advance == first || skip_to == advance) {
433  next = (skip_to == first) ? NULL : skip_to;
434  } else if (skip_to == NULL || skip_to == first) {
435  next = (advance == first) ? NULL : advance;
436  } else {
437  StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
438  StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
439  while (!st2.IsEmpty()) st1.Push(st2.Pop());
440  return st1;
441  }
442  ++hops;
443  }
444 
445  /* Don't return a next stop if the vehicle has to unload everything. */
446  if (next == NULL || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) &&
447  next->GetDestination() == v->last_station_visited &&
448  (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
449  return INVALID_STATION;
450  }
451  } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
452 
453  return next->GetDestination();
454 }
455 
461 void OrderList::InsertOrderAt(Order *new_order, int index)
462 {
463  if (this->first == NULL) {
464  this->first = new_order;
465  } else {
466  if (index == 0) {
467  /* Insert as first or only order */
468  new_order->next = this->first;
469  this->first = new_order;
470  } else if (index >= this->num_orders) {
471  /* index is after the last order, add it to the end */
472  this->GetLastOrder()->next = new_order;
473  } else {
474  /* Put the new order in between */
475  Order *order = this->GetOrderAt(index - 1);
476  new_order->next = order->next;
477  order->next = new_order;
478  }
479  }
480  ++this->num_orders;
481  if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
482  this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
483  this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
484 
485  /* We can visit oil rigs and buoys that are not our own. They will be shown in
486  * the list of stations. So, we need to invalidate that window if needed. */
487  if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
488  BaseStation *bs = BaseStation::Get(new_order->GetDestination());
490  }
491 
492 }
493 
494 
500 {
501  if (index >= this->num_orders) return;
502 
503  Order *to_remove;
504 
505  if (index == 0) {
506  to_remove = this->first;
507  this->first = to_remove->next;
508  } else {
509  Order *prev = GetOrderAt(index - 1);
510  to_remove = prev->next;
511  prev->next = to_remove->next;
512  }
513  --this->num_orders;
514  if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
515  this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
516  this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
517  delete to_remove;
518 }
519 
525 void OrderList::MoveOrder(int from, int to)
526 {
527  if (from >= this->num_orders || to >= this->num_orders || from == to) return;
528 
529  Order *moving_one;
530 
531  /* Take the moving order out of the pointer-chain */
532  if (from == 0) {
533  moving_one = this->first;
534  this->first = moving_one->next;
535  } else {
536  Order *one_before = GetOrderAt(from - 1);
537  moving_one = one_before->next;
538  one_before->next = moving_one->next;
539  }
540 
541  /* Insert the moving_order again in the pointer-chain */
542  if (to == 0) {
543  moving_one->next = this->first;
544  this->first = moving_one;
545  } else {
546  Order *one_before = GetOrderAt(to - 1);
547  moving_one->next = one_before->next;
548  one_before->next = moving_one;
549  }
550 }
551 
558 {
559  --this->num_vehicles;
560  if (v == this->first_shared) this->first_shared = v->NextShared();
561 }
562 
568 {
569  for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
570  if (v_shared == v) return true;
571  }
572 
573  return false;
574 }
575 
582 {
583  int count = 0;
584  for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
585  return count;
586 }
587 
593 {
594  for (Order *o = this->first; o != NULL; o = o->next) {
595  /* Implicit orders are, by definition, not timetabled. */
596  if (o->IsType(OT_IMPLICIT)) continue;
597  if (!o->IsCompletelyTimetabled()) return false;
598  }
599  return true;
600 }
601 
606 {
607  VehicleOrderID check_num_orders = 0;
608  VehicleOrderID check_num_manual_orders = 0;
609  uint check_num_vehicles = 0;
610  Ticks check_timetable_duration = 0;
611  Ticks check_total_duration = 0;
612 
613  DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
614 
615  for (const Order *o = this->first; o != NULL; o = o->next) {
616  ++check_num_orders;
617  if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
618  check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
619  check_total_duration += o->GetWaitTime() + o->GetTravelTime();
620  }
621  assert(this->num_orders == check_num_orders);
622  assert(this->num_manual_orders == check_num_manual_orders);
623  assert(this->timetable_duration == check_timetable_duration);
624  assert(this->total_duration == check_total_duration);
625 
626  for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
627  ++check_num_vehicles;
628  assert(v->orders.list == this);
629  }
630  assert(this->num_vehicles == check_num_vehicles);
631  DEBUG(misc, 6, "... detected %u orders (%u manual), %u vehicles, %i timetabled, %i total",
632  (uint)this->num_orders, (uint)this->num_manual_orders,
633  this->num_vehicles, this->timetable_duration, this->total_duration);
634 }
635 
643 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
644 {
645  return o->IsType(OT_GOTO_STATION) ||
646  (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
647 }
648 
655 static void DeleteOrderWarnings(const Vehicle *v)
656 {
657  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
658  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
659  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
660  DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
661  DeleteVehicleNews(v->index, STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY);
662 }
663 
670 TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
671 {
672  switch (this->GetType()) {
673  case OT_GOTO_WAYPOINT:
674  case OT_GOTO_STATION:
675  case OT_IMPLICIT:
676  if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile;
677  return BaseStation::Get(this->GetDestination())->xy;
678 
679  case OT_GOTO_DEPOT:
680  if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
681  return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
682 
683  default:
684  return INVALID_TILE;
685  }
686 }
687 
697 uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
698 {
699  if (cur->IsType(OT_CONDITIONAL)) {
700  if (conditional_depth > v->GetNumOrders()) return 0;
701 
702  conditional_depth++;
703 
704  int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
705  int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
706  return max(dist1, dist2);
707  }
708 
709  TileIndex prev_tile = prev->GetLocation(v, true);
710  TileIndex cur_tile = cur->GetLocation(v, true);
711  if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
712  return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
713 }
714 
728 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
729 {
730  VehicleID veh = GB(p1, 0, 20);
731  VehicleOrderID sel_ord = GB(p1, 20, 8);
732  Order new_order(p2);
733 
734  Vehicle *v = Vehicle::GetIfValid(veh);
735  if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
736 
737  CommandCost ret = CheckOwnership(v->owner);
738  if (ret.Failed()) return ret;
739 
740  /* Check if the inserted order is to the correct destination (owner, type),
741  * and has the correct flags if any */
742  switch (new_order.GetType()) {
743  case OT_GOTO_STATION: {
744  const Station *st = Station::GetIfValid(new_order.GetDestination());
745  if (st == NULL) return CMD_ERROR;
746 
747  if (st->owner != OWNER_NONE) {
748  CommandCost ret = CheckOwnership(st->owner);
749  if (ret.Failed()) return ret;
750  }
751 
752  if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
753  for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
754  if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
755  }
756 
757  /* Non stop only allowed for ground vehicles. */
758  if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
759 
760  /* Filter invalid load/unload types. */
761  switch (new_order.GetLoadType()) {
763  default: return CMD_ERROR;
764  }
765  switch (new_order.GetUnloadType()) {
766  case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
767  default: return CMD_ERROR;
768  }
769 
770  /* Filter invalid stop locations */
771  switch (new_order.GetStopLocation()) {
773  case OSL_PLATFORM_MIDDLE:
774  if (v->type != VEH_TRAIN) return CMD_ERROR;
775  /* FALL THROUGH */
777  break;
778 
779  default:
780  return CMD_ERROR;
781  }
782 
783  break;
784  }
785 
786  case OT_GOTO_DEPOT: {
787  if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
788  if (v->type == VEH_AIRCRAFT) {
789  const Station *st = Station::GetIfValid(new_order.GetDestination());
790 
791  if (st == NULL) return CMD_ERROR;
792 
793  CommandCost ret = CheckOwnership(st->owner);
794  if (ret.Failed()) return ret;
795 
796  if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
797  return CMD_ERROR;
798  }
799  } else {
800  const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
801 
802  if (dp == NULL) return CMD_ERROR;
803 
804  CommandCost ret = CheckOwnership(GetTileOwner(dp->xy));
805  if (ret.Failed()) return ret;
806 
807  switch (v->type) {
808  case VEH_TRAIN:
809  if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
810  break;
811 
812  case VEH_ROAD:
813  if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
814  break;
815 
816  case VEH_SHIP:
817  if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
818  break;
819 
820  default: return CMD_ERROR;
821  }
822  }
823  }
824 
825  if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
826  if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
827  if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
828  if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
829  break;
830  }
831 
832  case OT_GOTO_WAYPOINT: {
833  const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
834  if (wp == NULL) return CMD_ERROR;
835 
836  switch (v->type) {
837  default: return CMD_ERROR;
838 
839  case VEH_TRAIN: {
840  if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
841 
842  CommandCost ret = CheckOwnership(wp->owner);
843  if (ret.Failed()) return ret;
844  break;
845  }
846 
847  case VEH_SHIP:
848  if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
849  if (wp->owner != OWNER_NONE) {
850  CommandCost ret = CheckOwnership(wp->owner);
851  if (ret.Failed()) return ret;
852  }
853  break;
854  }
855 
856  /* Order flags can be any of the following for waypoints:
857  * [non-stop]
858  * non-stop orders (if any) are only valid for trains */
859  if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
860  break;
861  }
862 
863  case OT_CONDITIONAL: {
864  VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
865  if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
866  if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
867 
869  if (occ >= OCC_END) return CMD_ERROR;
870  switch (new_order.GetConditionVariable()) {
872  if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
873  break;
874 
875  case OCV_UNCONDITIONALLY:
876  if (occ != OCC_EQUALS) return CMD_ERROR;
877  if (new_order.GetConditionValue() != 0) return CMD_ERROR;
878  break;
879 
880  case OCV_LOAD_PERCENTAGE:
881  case OCV_RELIABILITY:
882  if (new_order.GetConditionValue() > 100) return CMD_ERROR;
883  /* FALL THROUGH */
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 == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
899 
901  /* Make sure the new destination is not too far away from the previous */
902  const Order *prev = NULL;
903  uint n = 0;
904 
905  /* Find the last goto station or depot order before the insert location.
906  * If the order is to be inserted at the beginning of the order list this
907  * finds the last order in the list. */
908  const Order *o;
909  FOR_VEHICLE_ORDERS(v, o) {
910  switch (o->GetType()) {
911  case OT_GOTO_STATION:
912  case OT_GOTO_DEPOT:
913  case OT_GOTO_WAYPOINT:
914  prev = o;
915  break;
916 
917  default: break;
918  }
919  if (++n == sel_ord && prev != NULL) break;
920  }
921  if (prev != NULL) {
922  uint dist;
923  if (new_order.IsType(OT_CONDITIONAL)) {
924  /* The order is not yet inserted, so we have to do the first iteration here. */
925  dist = GetOrderDistance(prev, v->GetOrder(new_order.GetConditionSkipToOrder()), v);
926  } else {
927  dist = GetOrderDistance(prev, &new_order, v);
928  }
929 
930  if (dist >= 130) {
931  return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION);
932  }
933  }
934  }
935 
936  if (flags & DC_EXEC) {
937  Order *new_o = new Order();
938  new_o->AssignOrder(new_order);
939  InsertOrder(v, new_o, sel_ord);
940  }
941 
942  return CommandCost();
943 }
944 
951 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
952 {
953  /* Create new order and link in list */
954  if (v->orders.list == NULL) {
955  v->orders.list = new OrderList(new_o, v);
956  } else {
957  v->orders.list->InsertOrderAt(new_o, sel_ord);
958  }
959 
960  Vehicle *u = v->FirstShared();
962  for (; u != NULL; u = u->NextShared()) {
963  assert(v->orders.list == u->orders.list);
964 
965  /* If there is added an order before the current one, we need
966  * to update the selected order. We do not change implicit/real order indices though.
967  * If the new order is between the current implicit order and real order, the implicit order will
968  * later skip the inserted order. */
969  if (sel_ord <= u->cur_real_order_index) {
970  uint cur = u->cur_real_order_index + 1;
971  /* Check if we don't go out of bound */
972  if (cur < u->GetNumOrders()) {
973  u->cur_real_order_index = cur;
974  }
975  }
976  if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
977  /* We are inserting an order just before the current implicit order.
978  * We do not know whether we will reach current implicit or the newly inserted order first.
979  * So, disable creation of implicit orders until we are on track again. */
980  uint16 &gv_flags = u->GetGroundVehicleFlags();
982  }
983  if (sel_ord <= u->cur_implicit_order_index) {
984  uint cur = u->cur_implicit_order_index + 1;
985  /* Check if we don't go out of bound */
986  if (cur < u->GetNumOrders()) {
987  u->cur_implicit_order_index = cur;
988  }
989  }
990  /* Update any possible open window of the vehicle */
991  InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
992  }
993 
994  /* As we insert an order, the order to skip to will be 'wrong'. */
995  VehicleOrderID cur_order_id = 0;
996  Order *order;
997  FOR_VEHICLE_ORDERS(v, order) {
998  if (order->IsType(OT_CONDITIONAL)) {
999  VehicleOrderID order_id = order->GetConditionSkipToOrder();
1000  if (order_id >= sel_ord) {
1001  order->SetConditionSkipToOrder(order_id + 1);
1002  }
1003  if (order_id == cur_order_id) {
1004  order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
1005  }
1006  }
1007  cur_order_id++;
1008  }
1009 
1010  /* Make sure to rebuild the whole list */
1012 }
1013 
1020 {
1021  if (flags & DC_EXEC) {
1022  DeleteVehicleOrders(dst);
1025  }
1026  return CommandCost();
1027 }
1028 
1038 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1039 {
1040  VehicleID veh_id = GB(p1, 0, 20);
1041  VehicleOrderID sel_ord = GB(p2, 0, 8);
1042 
1043  Vehicle *v = Vehicle::GetIfValid(veh_id);
1044 
1045  if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
1046 
1047  CommandCost ret = CheckOwnership(v->owner);
1048  if (ret.Failed()) return ret;
1049 
1050  /* If we did not select an order, we maybe want to de-clone the orders */
1051  if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
1052 
1053  if (v->GetOrder(sel_ord) == NULL) return CMD_ERROR;
1054 
1055  if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
1056  return CommandCost();
1057 }
1058 
1064 {
1065  assert(v->current_order.IsType(OT_LOADING));
1066  /* NON-stop flag is misused to see if a train is in a station that is
1067  * on his order list or not */
1069  /* When full loading, "cancel" that order so the vehicle doesn't
1070  * stay indefinitely at this station anymore. */
1072 }
1073 
1080 {
1081  v->orders.list->DeleteOrderAt(sel_ord);
1082 
1083  Vehicle *u = v->FirstShared();
1085  for (; u != NULL; u = u->NextShared()) {
1086  assert(v->orders.list == u->orders.list);
1087 
1088  if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
1090  }
1091 
1092  if (sel_ord < u->cur_real_order_index) {
1093  u->cur_real_order_index--;
1094  } else if (sel_ord == u->cur_real_order_index) {
1095  u->UpdateRealOrderIndex();
1096  }
1097 
1098  if (sel_ord < u->cur_implicit_order_index) {
1100  } else if (sel_ord == u->cur_implicit_order_index) {
1101  /* Make sure the index is valid */
1103 
1104  /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
1105  while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) {
1108  }
1109  }
1110 
1111  /* Update any possible open window of the vehicle */
1112  InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
1113  }
1114 
1115  /* As we delete an order, the order to skip to will be 'wrong'. */
1116  VehicleOrderID cur_order_id = 0;
1117  Order *order = NULL;
1118  FOR_VEHICLE_ORDERS(v, order) {
1119  if (order->IsType(OT_CONDITIONAL)) {
1120  VehicleOrderID order_id = order->GetConditionSkipToOrder();
1121  if (order_id >= sel_ord) {
1122  order_id = max(order_id - 1, 0);
1123  }
1124  if (order_id == cur_order_id) {
1125  order_id = (order_id + 1) % v->GetNumOrders();
1126  }
1127  order->SetConditionSkipToOrder(order_id);
1128  }
1129  cur_order_id++;
1130  }
1131 
1133 }
1134 
1144 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1145 {
1146  VehicleID veh_id = GB(p1, 0, 20);
1147  VehicleOrderID sel_ord = GB(p2, 0, 8);
1148 
1149  Vehicle *v = Vehicle::GetIfValid(veh_id);
1150 
1151  if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
1152 
1153  CommandCost ret = CheckOwnership(v->owner);
1154  if (ret.Failed()) return ret;
1155 
1156  if (flags & DC_EXEC) {
1157  if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
1158 
1160  v->UpdateRealOrderIndex();
1161 
1163  }
1164 
1165  /* We have an aircraft/ship, they have a mini-schedule, so update them all */
1168 
1169  return CommandCost();
1170 }
1171 
1185 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1186 {
1187  VehicleID veh = GB(p1, 0, 20);
1188  VehicleOrderID moving_order = GB(p2, 0, 16);
1189  VehicleOrderID target_order = GB(p2, 16, 16);
1190 
1191  Vehicle *v = Vehicle::GetIfValid(veh);
1192  if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
1193 
1194  CommandCost ret = CheckOwnership(v->owner);
1195  if (ret.Failed()) return ret;
1196 
1197  /* Don't make senseless movements */
1198  if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
1199  moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
1200 
1201  Order *moving_one = v->GetOrder(moving_order);
1202  /* Don't move an empty order */
1203  if (moving_one == NULL) return CMD_ERROR;
1204 
1205  if (flags & DC_EXEC) {
1206  v->orders.list->MoveOrder(moving_order, target_order);
1207 
1208  /* Update shared list */
1209  Vehicle *u = v->FirstShared();
1210 
1212 
1213  for (; u != NULL; u = u->NextShared()) {
1214  /* Update the current order.
1215  * There are multiple ways to move orders, which result in cur_implicit_order_index
1216  * and cur_real_order_index to not longer make any sense. E.g. moving another
1217  * real order between them.
1218  *
1219  * Basically one could choose to preserve either of them, but not both.
1220  * While both ways are suitable in this or that case from a human point of view, neither
1221  * of them makes really sense.
1222  * However, from an AI point of view, preserving cur_real_order_index is the most
1223  * predictable and transparent behaviour.
1224  *
1225  * With that decision it basically does not matter what we do to cur_implicit_order_index.
1226  * If we change orders between the implicit- and real-index, the implicit orders are mostly likely
1227  * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well.
1228  * The worst which can happen is that a lot of implicit orders are removed when reaching current_order.
1229  */
1230  if (u->cur_real_order_index == moving_order) {
1231  u->cur_real_order_index = target_order;
1232  } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
1233  u->cur_real_order_index--;
1234  } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
1235  u->cur_real_order_index++;
1236  }
1237 
1238  if (u->cur_implicit_order_index == moving_order) {
1239  u->cur_implicit_order_index = target_order;
1240  } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
1242  } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
1244  }
1245 
1246  assert(v->orders.list == u->orders.list);
1247  /* Update any possible open window of the vehicle */
1248  InvalidateVehicleOrder(u, moving_order | (target_order << 8));
1249  }
1250 
1251  /* As we move an order, the order to skip to will be 'wrong'. */
1252  Order *order;
1253  FOR_VEHICLE_ORDERS(v, order) {
1254  if (order->IsType(OT_CONDITIONAL)) {
1255  VehicleOrderID order_id = order->GetConditionSkipToOrder();
1256  if (order_id == moving_order) {
1257  order_id = target_order;
1258  } else if (order_id > moving_order && order_id <= target_order) {
1259  order_id--;
1260  } else if (order_id < moving_order && order_id >= target_order) {
1261  order_id++;
1262  }
1263  order->SetConditionSkipToOrder(order_id);
1264  }
1265  }
1266 
1267  /* Make sure to rebuild the whole list */
1269  }
1270 
1271  return CommandCost();
1272 }
1273 
1289 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1290 {
1291  VehicleOrderID sel_ord = GB(p1, 20, 8);
1292  VehicleID veh = GB(p1, 0, 20);
1293  ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
1294  uint16 data = GB(p2, 4, 11);
1295 
1296  if (mof >= MOF_END) return CMD_ERROR;
1297 
1298  Vehicle *v = Vehicle::GetIfValid(veh);
1299  if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
1300 
1301  CommandCost ret = CheckOwnership(v->owner);
1302  if (ret.Failed()) return ret;
1303 
1304  /* Is it a valid order? */
1305  if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
1306 
1307  Order *order = v->GetOrder(sel_ord);
1308  switch (order->GetType()) {
1309  case OT_GOTO_STATION:
1310  if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR;
1311  break;
1312 
1313  case OT_GOTO_DEPOT:
1314  if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
1315  break;
1316 
1317  case OT_GOTO_WAYPOINT:
1318  if (mof != MOF_NON_STOP) return CMD_ERROR;
1319  break;
1320 
1321  case OT_CONDITIONAL:
1322  if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
1323  break;
1324 
1325  default:
1326  return CMD_ERROR;
1327  }
1328 
1329  switch (mof) {
1330  default: NOT_REACHED();
1331 
1332  case MOF_NON_STOP:
1333  if (!v->IsGroundVehicle()) return CMD_ERROR;
1334  if (data >= ONSF_END) return CMD_ERROR;
1335  if (data == order->GetNonStopType()) return CMD_ERROR;
1336  break;
1337 
1338  case MOF_STOP_LOCATION:
1339  if (v->type != VEH_TRAIN) return CMD_ERROR;
1340  if (data >= OSL_END) return CMD_ERROR;
1341  break;
1342 
1343  case MOF_UNLOAD:
1345  if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
1346  /* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
1347  if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
1348  if (data == order->GetUnloadType()) return CMD_ERROR;
1349  break;
1350 
1351  case MOF_LOAD:
1353  if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
1354  if (data == order->GetLoadType()) return CMD_ERROR;
1355  break;
1356 
1357  case MOF_DEPOT_ACTION:
1358  if (data >= DA_END) return CMD_ERROR;
1359  break;
1360 
1361  case MOF_COND_VARIABLE:
1362  if (data >= OCV_END) return CMD_ERROR;
1363  break;
1364 
1365  case MOF_COND_COMPARATOR:
1366  if (data >= OCC_END) return CMD_ERROR;
1367  switch (order->GetConditionVariable()) {
1368  case OCV_UNCONDITIONALLY: return CMD_ERROR;
1369 
1370  case OCV_REQUIRES_SERVICE:
1371  if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
1372  break;
1373 
1374  default:
1375  if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
1376  break;
1377  }
1378  break;
1379 
1380  case MOF_COND_VALUE:
1381  switch (order->GetConditionVariable()) {
1382  case OCV_UNCONDITIONALLY:
1383  case OCV_REQUIRES_SERVICE:
1384  return CMD_ERROR;
1385 
1386  case OCV_LOAD_PERCENTAGE:
1387  case OCV_RELIABILITY:
1388  if (data > 100) return CMD_ERROR;
1389  break;
1390 
1391  default:
1392  if (data > 2047) return CMD_ERROR;
1393  break;
1394  }
1395  break;
1396 
1397  case MOF_COND_DESTINATION:
1398  if (data >= v->GetNumOrders()) return CMD_ERROR;
1399  break;
1400  }
1401 
1402  if (flags & DC_EXEC) {
1403  switch (mof) {
1404  case MOF_NON_STOP:
1405  order->SetNonStopType((OrderNonStopFlags)data);
1407  order->SetRefit(CT_NO_REFIT);
1410  }
1411  break;
1412 
1413  case MOF_STOP_LOCATION:
1414  order->SetStopLocation((OrderStopLocation)data);
1415  break;
1416 
1417  case MOF_UNLOAD:
1418  order->SetUnloadType((OrderUnloadFlags)data);
1419  break;
1420 
1421  case MOF_LOAD:
1422  order->SetLoadType((OrderLoadFlags)data);
1423  if (data & OLFB_NO_LOAD) order->SetRefit(CT_NO_REFIT);
1424  break;
1425 
1426  case MOF_DEPOT_ACTION: {
1427  switch (data) {
1428  case DA_ALWAYS_GO:
1431  break;
1432 
1433  case DA_SERVICE:
1436  order->SetRefit(CT_NO_REFIT);
1437  break;
1438 
1439  case DA_STOP:
1442  order->SetRefit(CT_NO_REFIT);
1443  break;
1444 
1445  default:
1446  NOT_REACHED();
1447  }
1448  break;
1449  }
1450 
1451  case MOF_COND_VARIABLE: {
1453 
1455  switch (order->GetConditionVariable()) {
1456  case OCV_UNCONDITIONALLY:
1458  order->SetConditionValue(0);
1459  break;
1460 
1461  case OCV_REQUIRES_SERVICE:
1462  if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
1463  order->SetConditionValue(0);
1464  break;
1465 
1466  case OCV_LOAD_PERCENTAGE:
1467  case OCV_RELIABILITY:
1468  if (order->GetConditionValue() > 100) order->SetConditionValue(100);
1469  /* FALL THROUGH */
1470  default:
1471  if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
1472  break;
1473  }
1474  break;
1475  }
1476 
1477  case MOF_COND_COMPARATOR:
1479  break;
1480 
1481  case MOF_COND_VALUE:
1482  order->SetConditionValue(data);
1483  break;
1484 
1485  case MOF_COND_DESTINATION:
1486  order->SetConditionSkipToOrder(data);
1487  break;
1488 
1489  default: NOT_REACHED();
1490  }
1491 
1492  /* Update the windows and full load flags, also for vehicles that share the same order list */
1493  Vehicle *u = v->FirstShared();
1495  for (; u != NULL; u = u->NextShared()) {
1496  /* Toggle u->current_order "Full load" flag if it changed.
1497  * However, as the same flag is used for depot orders, check
1498  * whether we are not going to a depot as there are three
1499  * cases where the full load flag can be active and only
1500  * one case where the flag is used for depot orders. In the
1501  * other cases for the OrderTypeByte the flags are not used,
1502  * so do not care and those orders should not be active
1503  * when this function is called.
1504  */
1505  if (sel_ord == u->cur_real_order_index &&
1506  (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
1507  u->current_order.GetLoadType() != order->GetLoadType()) {
1508  u->current_order.SetLoadType(order->GetLoadType());
1509  }
1511  }
1512  }
1513 
1514  return CommandCost();
1515 }
1516 
1524 static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first)
1525 {
1526  if (first == NULL || v_new->acache.cached_max_range == 0) return true;
1527 
1528  /* Iterate over all orders to check the distance between all
1529  * 'goto' orders and their respective next order (of any type). */
1530  for (const Order *o = first; o != NULL; o = o->next) {
1531  switch (o->GetType()) {
1532  case OT_GOTO_STATION:
1533  case OT_GOTO_DEPOT:
1534  case OT_GOTO_WAYPOINT:
1535  /* If we don't have a next order, we've reached the end and must check the first order instead. */
1536  if (GetOrderDistance(o, o->next != NULL ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false;
1537  break;
1538 
1539  default: break;
1540  }
1541  }
1542 
1543  return true;
1544 }
1545 
1557 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1558 {
1559  VehicleID veh_src = GB(p2, 0, 20);
1560  VehicleID veh_dst = GB(p1, 0, 20);
1561 
1562  Vehicle *dst = Vehicle::GetIfValid(veh_dst);
1563  if (dst == NULL || !dst->IsPrimaryVehicle()) return CMD_ERROR;
1564 
1565  CommandCost ret = CheckOwnership(dst->owner);
1566  if (ret.Failed()) return ret;
1567 
1568  switch (GB(p1, 30, 2)) {
1569  case CO_SHARE: {
1570  Vehicle *src = Vehicle::GetIfValid(veh_src);
1571 
1572  /* Sanity checks */
1573  if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1574 
1575  CommandCost ret = CheckOwnership(src->owner);
1576  if (ret.Failed()) return ret;
1577 
1578  /* Trucks can't share orders with busses (and visa versa) */
1579  if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
1580  return CMD_ERROR;
1581  }
1582 
1583  /* Is the vehicle already in the shared list? */
1584  if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
1585 
1586  const Order *order;
1587 
1588  FOR_VEHICLE_ORDERS(src, order) {
1589  if (!OrderGoesToStation(dst, order)) continue;
1590 
1591  /* Allow copying unreachable destinations if they were already unreachable for the source.
1592  * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations
1593  * are temporarily invalid due to reconstruction. */
1594  const Station *st = Station::Get(order->GetDestination());
1595  if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) {
1596  return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
1597  }
1598  }
1599 
1600  /* Check for aircraft range limits. */
1601  if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1602  return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1603  }
1604 
1605  if (src->orders.list == NULL && !OrderList::CanAllocateItem()) {
1606  return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1607  }
1608 
1609  if (flags & DC_EXEC) {
1610  /* If the destination vehicle had a OrderList, destroy it.
1611  * We only reset the order indices, if the new orders are obviously different.
1612  * (We mainly do this to keep the order indices valid and in range.) */
1613  DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
1614 
1615  dst->orders.list = src->orders.list;
1616 
1617  /* Link this vehicle in the shared-list */
1618  dst->AddToShared(src);
1619 
1622 
1624  }
1625  break;
1626  }
1627 
1628  case CO_COPY: {
1629  Vehicle *src = Vehicle::GetIfValid(veh_src);
1630 
1631  /* Sanity checks */
1632  if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
1633 
1634  CommandCost ret = CheckOwnership(src->owner);
1635  if (ret.Failed()) return ret;
1636 
1637  /* Trucks can't copy all the orders from busses (and visa versa),
1638  * and neither can helicopters and aircraft. */
1639  const Order *order;
1640  FOR_VEHICLE_ORDERS(src, order) {
1641  if (OrderGoesToStation(dst, order) &&
1643  return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
1644  }
1645  }
1646 
1647  /* Check for aircraft range limits. */
1648  if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) {
1649  return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
1650  }
1651 
1652  /* make sure there are orders available */
1654  return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1655  }
1656 
1657  if (flags & DC_EXEC) {
1658  const Order *order;
1659  Order *first = NULL;
1660  Order **order_dst;
1661 
1662  /* If the destination vehicle had an order list, destroy the chain but keep the OrderList.
1663  * We only reset the order indices, if the new orders are obviously different.
1664  * (We mainly do this to keep the order indices valid and in range.) */
1665  DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
1666 
1667  order_dst = &first;
1668  FOR_VEHICLE_ORDERS(src, order) {
1669  *order_dst = new Order();
1670  (*order_dst)->AssignOrder(*order);
1671  order_dst = &(*order_dst)->next;
1672  }
1673  if (dst->orders.list == NULL) {
1674  dst->orders.list = new OrderList(first, dst);
1675  } else {
1676  assert(dst->orders.list->GetFirstOrder() == NULL);
1677  assert(!dst->orders.list->IsShared());
1678  delete dst->orders.list;
1679  assert(OrderList::CanAllocateItem());
1680  dst->orders.list = new OrderList(first, dst);
1681  }
1682 
1684 
1686  }
1687  break;
1688  }
1689 
1690  case CO_UNSHARE: return DecloneOrder(dst, flags);
1691  default: return CMD_ERROR;
1692  }
1693 
1694  return CommandCost();
1695 }
1696 
1708 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1709 {
1710  VehicleID veh = GB(p1, 0, 20);
1711  VehicleOrderID order_number = GB(p2, 16, 8);
1712  CargoID cargo = GB(p2, 0, 8);
1713 
1714  if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT && cargo != CT_AUTO_REFIT) return CMD_ERROR;
1715 
1716  const Vehicle *v = Vehicle::GetIfValid(veh);
1717  if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
1718 
1719  CommandCost ret = CheckOwnership(v->owner);
1720  if (ret.Failed()) return ret;
1721 
1722  Order *order = v->GetOrder(order_number);
1723  if (order == NULL) return CMD_ERROR;
1724 
1725  /* Automatic refit cargo is only supported for goto station orders. */
1726  if (cargo == CT_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
1727 
1728  if (order->GetLoadType() & OLFB_NO_LOAD) return CMD_ERROR;
1729 
1730  if (flags & DC_EXEC) {
1731  order->SetRefit(cargo);
1732 
1733  /* Make the depot order an 'always go' order. */
1734  if (cargo != CT_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) {
1737  }
1738 
1739  for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
1740  /* Update any possible open window of the vehicle */
1742 
1743  /* If the vehicle already got the current depot set as current order, then update current order as well */
1744  if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
1745  u->current_order.SetRefit(cargo);
1746  }
1747  }
1748  }
1749 
1750  return CommandCost();
1751 }
1752 
1753 
1759 void CheckOrders(const Vehicle *v)
1760 {
1761  /* Does the user wants us to check things? */
1762  if (_settings_client.gui.order_review_system == 0) return;
1763 
1764  /* Do nothing for crashed vehicles */
1765  if (v->vehstatus & VS_CRASHED) return;
1766 
1767  /* Do nothing for stopped vehicles if setting is '1' */
1768  if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
1769 
1770  /* do nothing we we're not the first vehicle in a share-chain */
1771  if (v->FirstShared() != v) return;
1772 
1773  /* Only check every 20 days, so that we don't flood the message log */
1774  if (v->owner == _local_company && v->day_counter % 20 == 0) {
1775  const Order *order;
1776  StringID message = INVALID_STRING_ID;
1777 
1778  /* Check the order list */
1779  int n_st = 0;
1780 
1781  FOR_VEHICLE_ORDERS(v, order) {
1782  /* Dummy order? */
1783  if (order->IsType(OT_DUMMY)) {
1784  message = STR_NEWS_VEHICLE_HAS_VOID_ORDER;
1785  break;
1786  }
1787  /* Does station have a load-bay for this vehicle? */
1788  if (order->IsType(OT_GOTO_STATION)) {
1789  const Station *st = Station::Get(order->GetDestination());
1790 
1791  n_st++;
1792  if (!CanVehicleUseStation(v, st)) {
1793  message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY;
1794  } else if (v->type == VEH_AIRCRAFT &&
1795  (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1799  message == INVALID_STRING_ID) {
1800  message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY;
1801  }
1802  }
1803  }
1804 
1805  /* Check if the last and the first order are the same */
1806  if (v->GetNumOrders() > 1) {
1807  const Order *last = v->GetLastOrder();
1808 
1809  if (v->orders.list->GetFirstOrder()->Equals(*last)) {
1810  message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY;
1811  }
1812  }
1813 
1814  /* Do we only have 1 station in our order list? */
1815  if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS;
1816 
1817 #ifndef NDEBUG
1818  if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
1819 #endif
1820 
1821  /* We don't have a problem */
1822  if (message == INVALID_STRING_ID) return;
1823 
1824  SetDParam(0, v->index);
1825  AddVehicleAdviceNewsItem(message, v->index);
1826  }
1827 }
1828 
1834 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
1835 {
1836  Vehicle *v;
1837 
1838  /* Aircraft have StationIDs for depot orders and never use DepotIDs
1839  * This fact is handled specially below
1840  */
1841 
1842  /* Go through all vehicles */
1843  FOR_ALL_VEHICLES(v) {
1844  Order *order;
1845 
1846  order = &v->current_order;
1847  if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
1848  v->current_order.GetDestination() == destination) {
1849  order->MakeDummy();
1851  }
1852 
1853  /* Clear the order from the order-list */
1854  int id = -1;
1855  FOR_VEHICLE_ORDERS(v, order) {
1856  id++;
1857 restart:
1858 
1859  OrderType ot = order->GetType();
1860  if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
1861  if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
1862  if (ot == type && order->GetDestination() == destination) {
1863  /* We want to clear implicit orders, but we don't want to make them
1864  * dummy orders. They should just vanish. Also check the actual order
1865  * type as ot is currently OT_GOTO_STATION. */
1866  if (order->IsType(OT_IMPLICIT)) {
1867  order = order->next; // DeleteOrder() invalidates current order
1868  DeleteOrder(v, id);
1869  if (order != NULL) goto restart;
1870  break;
1871  }
1872 
1873  /* Clear wait time */
1874  v->orders.list->UpdateTotalDuration(-order->GetWaitTime());
1875  if (order->IsWaitTimetabled()) {
1877  order->SetWaitTimetabled(false);
1878  }
1879  order->SetWaitTime(0);
1880 
1881  /* Clear order, preserving travel time */
1882  bool travel_timetabled = order->IsTravelTimetabled();
1883  order->MakeDummy();
1884  order->SetTravelTimetabled(travel_timetabled);
1885 
1886  for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
1887  /* In GUI, simulate by removing the order and adding it back */
1890  }
1891  }
1892  }
1893  }
1894 
1895  OrderBackup::RemoveOrder(type, destination);
1896 }
1897 
1903 {
1904  const Order *order;
1905 
1906  FOR_VEHICLE_ORDERS(this, order) {
1907  if (order->IsType(OT_GOTO_DEPOT)) return true;
1908  }
1909 
1910  return false;
1911 }
1912 
1922 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
1923 {
1925 
1926  if (v->IsOrderListShared()) {
1927  /* Remove ourself from the shared order list. */
1928  v->RemoveFromShared();
1929  v->orders.list = NULL;
1930  } else if (v->orders.list != NULL) {
1931  /* Remove the orders */
1932  v->orders.list->FreeChain(keep_orderlist);
1933  if (!keep_orderlist) v->orders.list = NULL;
1934  }
1935 
1936  if (reset_order_indices) {
1938  if (v->current_order.IsType(OT_LOADING)) {
1940  }
1941  }
1942 }
1943 
1951 uint16 GetServiceIntervalClamped(uint interval, bool ispercent)
1952 {
1953  return ispercent ? Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
1954 }
1955 
1964 static bool CheckForValidOrders(const Vehicle *v)
1965 {
1966  const Order *order;
1967 
1968  FOR_VEHICLE_ORDERS(v, order) {
1969  switch (order->GetType()) {
1970  case OT_GOTO_STATION:
1971  case OT_GOTO_DEPOT:
1972  case OT_GOTO_WAYPOINT:
1973  return true;
1974 
1975  default:
1976  break;
1977  }
1978  }
1979 
1980  return false;
1981 }
1982 
1986 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
1987 {
1988  switch (occ) {
1989  case OCC_EQUALS: return variable == value;
1990  case OCC_NOT_EQUALS: return variable != value;
1991  case OCC_LESS_THAN: return variable < value;
1992  case OCC_LESS_EQUALS: return variable <= value;
1993  case OCC_MORE_THAN: return variable > value;
1994  case OCC_MORE_EQUALS: return variable >= value;
1995  case OCC_IS_TRUE: return variable != 0;
1996  case OCC_IS_FALSE: return variable == 0;
1997  default: NOT_REACHED();
1998  }
1999 }
2000 
2008 {
2009  if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
2010 
2011  bool skip_order = false;
2013  uint16 value = order->GetConditionValue();
2014 
2015  switch (order->GetConditionVariable()) {
2016  case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
2017  case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
2018  case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
2019  case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
2020  case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
2021  case OCV_UNCONDITIONALLY: skip_order = true; break;
2022  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;
2023  default: NOT_REACHED();
2024  }
2025 
2026  return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
2027 }
2028 
2036 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
2037 {
2038  if (conditional_depth > v->GetNumOrders()) {
2039  v->current_order.Free();
2040  v->dest_tile = 0;
2041  return false;
2042  }
2043 
2044  switch (order->GetType()) {
2045  case OT_GOTO_STATION:
2047  return true;
2048 
2049  case OT_GOTO_DEPOT:
2050  if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
2051  assert(!pbs_look_ahead);
2052  UpdateVehicleTimetable(v, true);
2054  break;
2055  }
2056 
2058  /* We need to search for the nearest depot (hangar). */
2059  TileIndex location;
2060  DestinationID destination;
2061  bool reverse;
2062 
2063  if (v->FindClosestDepot(&location, &destination, &reverse)) {
2064  /* PBS reservations cannot reverse */
2065  if (pbs_look_ahead && reverse) return false;
2066 
2067  v->dest_tile = location;
2069 
2070  /* If there is no depot in front, reverse automatically (trains only) */
2071  if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
2072 
2073  if (v->type == VEH_AIRCRAFT) {
2074  Aircraft *a = Aircraft::From(v);
2075  if (a->state == FLYING && a->targetairport != destination) {
2076  /* The aircraft is now heading for a different hangar than the next in the orders */
2079  }
2080  }
2081  return true;
2082  }
2083 
2084  /* If there is no depot, we cannot help PBS either. */
2085  if (pbs_look_ahead) return false;
2086 
2087  UpdateVehicleTimetable(v, true);
2089  } else {
2090  if (v->type != VEH_AIRCRAFT) {
2091  v->dest_tile = Depot::Get(order->GetDestination())->xy;
2092  }
2093  return true;
2094  }
2095  break;
2096 
2097  case OT_GOTO_WAYPOINT:
2098  v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
2099  return true;
2100 
2101  case OT_CONDITIONAL: {
2102  assert(!pbs_look_ahead);
2103  VehicleOrderID next_order = ProcessConditionalOrder(order, v);
2104  if (next_order != INVALID_VEH_ORDER_ID) {
2105  /* Jump to next_order. cur_implicit_order_index becomes exactly that order,
2106  * cur_real_order_index might come after next_order. */
2107  UpdateVehicleTimetable(v, false);
2108  v->cur_implicit_order_index = v->cur_real_order_index = next_order;
2109  v->UpdateRealOrderIndex();
2111 
2112  /* Disable creation of implicit orders.
2113  * When inserting them we do not know that we would have to make the conditional orders point to them. */
2114  if (v->IsGroundVehicle()) {
2115  uint16 &gv_flags = v->GetGroundVehicleFlags();
2117  }
2118  } else {
2119  UpdateVehicleTimetable(v, true);
2121  }
2122  break;
2123  }
2124 
2125  default:
2126  v->dest_tile = 0;
2127  return false;
2128  }
2129 
2130  assert(v->cur_implicit_order_index < v->GetNumOrders());
2131  assert(v->cur_real_order_index < v->GetNumOrders());
2132 
2133  /* Get the current order */
2134  order = v->GetOrder(v->cur_real_order_index);
2135  if (order != NULL && order->IsType(OT_IMPLICIT)) {
2136  assert(v->GetNumManualOrders() == 0);
2137  order = NULL;
2138  }
2139 
2140  if (order == NULL) {
2141  v->current_order.Free();
2142  v->dest_tile = 0;
2143  return false;
2144  }
2145 
2146  v->current_order = *order;
2147  return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
2148 }
2149 
2158 {
2159  switch (v->current_order.GetType()) {
2160  case OT_GOTO_DEPOT:
2161  /* Let a depot order in the orderlist interrupt. */
2162  if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
2163  break;
2164 
2165  case OT_LOADING:
2166  return false;
2167 
2168  case OT_LEAVESTATION:
2169  if (v->type != VEH_AIRCRAFT) return false;
2170  break;
2171 
2172  default: break;
2173  }
2174 
2182  bool may_reverse = v->current_order.IsType(OT_NOTHING);
2183 
2184  /* Check if we've reached a 'via' destination. */
2185  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)) &&
2186  IsTileType(v->tile, MP_STATION) &&
2189  /* We set the last visited station here because we do not want
2190  * the train to stop at this 'via' station if the next order
2191  * is a no-non-stop order; in that case not setting the last
2192  * visited station will cause the vehicle to still stop. */
2194  UpdateVehicleTimetable(v, true);
2196  }
2197 
2198  /* Get the current order */
2199  assert(v->cur_implicit_order_index == 0 || v->cur_implicit_order_index < v->GetNumOrders());
2200  v->UpdateRealOrderIndex();
2201 
2202  const Order *order = v->GetOrder(v->cur_real_order_index);
2203  if (order != NULL && order->IsType(OT_IMPLICIT)) {
2204  assert(v->GetNumManualOrders() == 0);
2205  order = NULL;
2206  }
2207 
2208  /* If no order, do nothing. */
2209  if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
2210  if (v->type == VEH_AIRCRAFT) {
2211  /* Aircraft do something vastly different here, so handle separately */
2212  extern void HandleMissingAircraftOrders(Aircraft *v);
2213  HandleMissingAircraftOrders(Aircraft::From(v));
2214  return false;
2215  }
2216 
2217  v->current_order.Free();
2218  v->dest_tile = 0;
2219  return false;
2220  }
2221 
2222  /* If it is unchanged, keep it. */
2223  if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
2224  (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
2225  return false;
2226  }
2227 
2228  /* Otherwise set it, and determine the destination tile. */
2229  v->current_order = *order;
2230 
2232  switch (v->type) {
2233  default:
2234  NOT_REACHED();
2235 
2236  case VEH_ROAD:
2237  case VEH_TRAIN:
2238  break;
2239 
2240  case VEH_AIRCRAFT:
2241  case VEH_SHIP:
2243  break;
2244  }
2245 
2246  return UpdateOrderDest(v, order) && may_reverse;
2247 }
2248 
2256 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
2257 {
2258  bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
2259 
2260  return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
2261  v->last_station_visited != station && // Do stop only when we've not just been there
2262  /* Finally do stop when there is no non-stop flag set for this type of station. */
2264 }
2265 
2266 bool Order::CanLoadOrUnload() const
2267 {
2268  return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
2270  ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
2271  (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
2272 }
2273 
2280 bool Order::CanLeaveWithCargo(bool has_cargo) const
2281 {
2282  return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
2283  (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
2284 }