# order_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: order_cmd.cpp 18476 2009-12-13 00:13:06Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "debug.h"
    00007 #include "command_func.h"
    00008 #include "company_func.h"
    00009 #include "news_func.h"
    00010 #include "vehicle_gui.h"
    00011 #include "cargotype.h"
    00012 #include "station_map.h"
    00013 #include "vehicle_base.h"
    00014 #include "strings_func.h"
    00015 #include "functions.h"
    00016 #include "window_func.h"
    00017 #include "newgrf_cargo.h"
    00018 #include "timetable.h"
    00019 #include "vehicle_func.h"
    00020 #include "oldpool_func.h"
    00021 #include "depot_base.h"
    00022 #include "settings_type.h"
    00023
    00024 #include "table/strings.h"
    00025
    00026 /* DestinationID must be at least as large as every these below, because it can
    00027  * be any of them
    00028  */
    00029 assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
    00030 assert_compile(sizeof(DestinationID) >= sizeof(WaypointID));
    00031 assert_compile(sizeof(DestinationID) >= sizeof(StationID));
    00032
    00033 TileIndex _backup_orders_tile;
    00034 BackuppedOrders _backup_orders_data;
    00035
    00036 DEFINE_OLD_POOL_GENERIC(Order, Order);
    00037 DEFINE_OLD_POOL_GENERIC(OrderList, OrderList);
    00038
    00039 void Order::Free()
    00040 {
    00041   this->type  = OT_NOTHING;
    00042   this->flags = 0;
    00043   this->dest  = 0;
    00044   this->next  = NULL;
    00045 }
    00046
    00047 void Order::MakeGoToStation(StationID destination)
    00048 {
    00049   this->type = OT_GOTO_STATION;
    00050   this->flags = 0;
    00051   this->dest = destination;
    00052 }
    00053
    00054 void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo, byte subtype)
    00055 {
    00056   this->type = OT_GOTO_DEPOT;
    00057   this->SetDepotOrderType(order);
    00058   this->SetDepotActionType(action);
    00059   this->SetNonStopType(non_stop_type);
    00060   this->dest = destination;
    00061   this->SetRefit(cargo, subtype);
    00062 }
    00063
    00064 void Order::MakeGoToWaypoint(WaypointID destination)
    00065 {
    00066   this->type = OT_GOTO_WAYPOINT;
    00067   this->flags = 0;
    00068   this->dest = destination;
    00069 }
    00070
    00071 void Order::MakeLoading(bool ordered)
    00072 {
    00073   this->type = OT_LOADING;
    00074   if (!ordered) this->flags = 0;
    00075 }
    00076
    00077 void Order::MakeLeaveStation()
    00078 {
    00079   this->type = OT_LEAVESTATION;
    00080   this->flags = 0;
    00081 }
    00082
    00083 void Order::MakeDummy()
    00084 {
    00085   this->type = OT_DUMMY;
    00086   this->flags = 0;
    00087 }
    00088
    00089 void Order::MakeConditional(VehicleOrderID order)
    00090 {
    00091   this->type = OT_CONDITIONAL;
    00092   this->flags = order;
    00093   this->dest = 0;
    00094 }
    00095
    00096 void Order::SetRefit(CargoID cargo, byte subtype)
    00097 {
    00098   this->refit_cargo = cargo;
    00099   this->refit_subtype = subtype;
    00100 }
    00101
    00102 bool Order::Equals(const Order &other) const
    00103 {
    00104   /* In case of go to nearest depot orders we need "only" compare the flags
    00105    * with the other and not the nearest depot order bit or the actual
    00106    * destination because those get clear/filled in during the order
    00107    * evaluation. If we do not do this the order will continuously be seen as
    00108    * a different order and it will try to find a "nearest depot" every tick. */
    00109   if ((this->type == OT_GOTO_DEPOT && this->type == other.type) &&
    00110       ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
    00111        (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
    00112     return
    00113       this->GetDepotOrderType() == other.GetDepotOrderType() &&
    00114       (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
    00115   }
    00116
    00117   return
    00118       this->type  == other.type &&
    00119       this->flags == other.flags &&
    00120       this->dest  == other.dest;
    00121 }
    00122
    00123 uint32 Order::Pack() const
    00124 {
    00125   return this->dest << 16 | this->flags << 8 | this->type;
    00126 }
    00127
    00128 uint16 Order::MapOldOrder() const
    00129 {
    00130   uint16 order = this->GetType();
    00131   switch (this->type) {
    00132     case OT_GOTO_STATION:
    00133       if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
    00134       if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
    00135       if (this->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) SetBit(order, 7);
    00136       order |= GB(this->GetDestination(), 0, 8) << 8;
    00137       break;
    00138     case OT_GOTO_DEPOT:
    00139       if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
    00140       SetBit(order, 7);
    00141       order |= GB(this->GetDestination(), 0, 8) << 8;
    00142       break;
    00143     case OT_LOADING:
    00144       if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
    00145       break;
    00146   }
    00147   return order;
    00148 }
    00149
    00150 Order::Order(uint32 packed)
    00151 {
    00152   this->type    = (OrderType)GB(packed,  0,  8);
    00153   this->flags   = GB(packed,  8,  8);
    00154   this->dest    = GB(packed, 16, 16);
    00155   this->next    = NULL;
    00156   this->refit_cargo   = CT_NO_REFIT;
    00157   this->refit_subtype = 0;
    00158   this->wait_time     = 0;
    00159   this->travel_time   = 0;
    00160 }
    00161
    00167 void InvalidateVehicleOrder(const Vehicle *v, int data)
    00168 {
    00169   InvalidateWindow(WC_VEHICLE_VIEW, v->index);
    00170
    00171   if (data != 0) {
    00172     /* Calls SetDirty() too */
    00173     InvalidateWindowData(WC_VEHICLE_ORDERS,    v->index, data);
    00174     InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data);
    00175     return;
    00176   }
    00177
    00178   InvalidateWindow(WC_VEHICLE_ORDERS,    v->index);
    00179   InvalidateWindow(WC_VEHICLE_TIMETABLE, v->index);
    00180 }
    00181
    00188 void Order::AssignOrder(const Order &other)
    00189 {
    00190   this->type  = other.type;
    00191   this->flags = other.flags;
    00192   this->dest  = other.dest;
    00193
    00194   this->refit_cargo   = other.refit_cargo;
    00195   this->refit_subtype = other.refit_subtype;
    00196
    00197   this->wait_time   = other.wait_time;
    00198   this->travel_time = other.travel_time;
    00199 }
    00200
    00201
    00202 OrderList::OrderList(Order *chain, Vehicle *v) :
    00203     first(chain), num_orders(0), num_vehicles(1), first_shared(v),
    00204     timetable_duration(0)
    00205 {
    00206   for (Order *o = this->first; o != NULL; o = o->next) {
    00207     ++this->num_orders;
    00208     this->timetable_duration += o->wait_time + o->travel_time;
    00209   }
    00210
    00211   for (Vehicle *u = v->PreviousShared(); u != NULL; u = u->PreviousShared()) {
    00212     ++this->num_vehicles;
    00213     this->first_shared = u;
    00214   }
    00215
    00216   for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
    00217 }
    00218
    00219 void OrderList::FreeChain(bool keep_orderlist)
    00220 {
    00221   Order *next;
    00222   for(Order *o = this->first; o != NULL; o = next) {
    00223     next = o->next;
    00224     delete o;
    00225   }
    00226
    00227   if (keep_orderlist) {
    00228     this->first = NULL;
    00229     this->num_orders = 0;
    00230     this->timetable_duration = 0;
    00231   } else {
    00232     delete this;
    00233   }
    00234 }
    00235
    00236 Order *OrderList::GetOrderAt(int index) const
    00237 {
    00238   if (index < 0) return NULL;
    00239
    00240   Order *order = this->first;
    00241
    00242   while (order != NULL && index-- > 0)
    00243     order = order->next;
    00244
    00245   return order;
    00246 }
    00247
    00248 void OrderList::InsertOrderAt(Order *new_order, int index)
    00249 {
    00250   if (this->first == NULL) {
    00251     this->first = new_order;
    00252   } else {
    00253     if (index == 0) {
    00254       /* Insert as first or only order */
    00255       new_order->next = this->first;
    00256       this->first = new_order;
    00257     } else if (index >= this->num_orders) {
    00258       /* index is after the last order, add it to the end */
    00259       this->GetLastOrder()->next = new_order;
    00260     } else {
    00261       /* Put the new order in between */
    00262       Order *order = this->GetOrderAt(index - 1);
    00263       new_order->next = order->next;
    00264       order->next = new_order;
    00265     }
    00266   }
    00267   ++this->num_orders;
    00268   this->timetable_duration += new_order->wait_time + new_order->travel_time;
    00269 }
    00270
    00271
    00272 void OrderList::DeleteOrderAt(int index)
    00273 {
    00274   if (index >= this->num_orders) return;
    00275
    00276   Order *to_remove;
    00277
    00278   if (index == 0) {
    00279     to_remove = this->first;
    00280     this->first = to_remove->next;
    00281   } else {
    00282     Order *prev = GetOrderAt(index - 1);
    00283     to_remove = prev->next;
    00284     prev->next = to_remove->next;
    00285   }
    00286   --this->num_orders;
    00287   this->timetable_duration -= (to_remove->wait_time + to_remove->travel_time);
    00288   delete to_remove;
    00289 }
    00290
    00291 void OrderList::MoveOrder(int from, int to)
    00292 {
    00293   if (from >= this->num_orders || to >= this->num_orders || from == to) return;
    00294
    00295   Order *moving_one;
    00296
    00297   /* Take the moving order out of the pointer-chain */
    00298   if (from == 0) {
    00299     moving_one = this->first;
    00300     this->first = moving_one->next;
    00301   } else {
    00302     Order *one_before = GetOrderAt(from - 1);
    00303     moving_one = one_before->next;
    00304     one_before->next = moving_one->next;
    00305   }
    00306
    00307   /* Insert the moving_order again in the pointer-chain */
    00308   if (to == 0) {
    00309     moving_one->next = this->first;
    00310     this->first = moving_one;
    00311   } else {
    00312     Order *one_before = GetOrderAt(to - 1);
    00313     moving_one->next = one_before->next;
    00314     one_before->next = moving_one;
    00315   }
    00316 }
    00317
    00318 void OrderList::RemoveVehicle(Vehicle *v)
    00319 {
    00320   --this->num_vehicles;
    00321   if (v == this->first_shared) this->first_shared = v->NextShared();
    00322 }
    00323
    00324 bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
    00325 {
    00326   for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
    00327     if (v_shared == v) return true;
    00328   }
    00329
    00330   return false;
    00331 }
    00332
    00333 int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
    00334 {
    00335   int count = 0;
    00336   for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
    00337   return count;
    00338 }
    00339
    00340 bool OrderList::IsCompleteTimetable() const
    00341 {
    00342   for (Order *o = this->first; o != NULL; o = o->next) {
    00343     if (!o->IsCompletelyTimetabled()) return false;
    00344   }
    00345   return true;
    00346 }
    00347
    00348 void OrderList::DebugCheckSanity() const
    00349 {
    00350   VehicleOrderID check_num_orders = 0;
    00351   uint check_num_vehicles = 0;
    00352   uint check_timetable_duration = 0;
    00353
    00354   DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
    00355
    00356   for (const Order *o = this->first; o != NULL; o = o->next) {
    00357     ++check_num_orders;
    00358     check_timetable_duration += o->wait_time + o->travel_time;
    00359   }
    00360   assert(this->num_orders == check_num_orders);
    00361   assert(this->timetable_duration == check_timetable_duration);
    00362
    00363   for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
    00364     ++check_num_vehicles;
    00365     assert(v->orders.list == this);
    00366   }
    00367   assert(this->num_vehicles == check_num_vehicles);
    00368   DEBUG(misc, 6, "... detected %u orders, %u vehicles, %u ticks", (uint)this->num_orders,
    00369         this->num_vehicles, this->timetable_duration);
    00370 }
    00371
    00379 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
    00380 {
    00381   return o->IsType(OT_GOTO_STATION) ||
    00382       (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
    00383 }
    00384
    00391 static void DeleteOrderWarnings(const Vehicle *v)
    00392 {
    00393   DeleteVehicleNews(v->index, STR_VEHICLE_HAS_TOO_FEW_ORDERS);
    00394   DeleteVehicleNews(v->index, STR_VEHICLE_HAS_VOID_ORDER);
    00395   DeleteVehicleNews(v->index, STR_VEHICLE_HAS_DUPLICATE_ENTRY);
    00396   DeleteVehicleNews(v->index, STR_VEHICLE_HAS_INVALID_ENTRY);
    00397 }
    00398
    00399
    00400 static TileIndex GetOrderLocation(const Order& o)
    00401 {
    00402   switch (o.GetType()) {
    00403     default: NOT_REACHED();
    00404     case OT_GOTO_STATION: return GetStation(o.GetDestination())->xy;
    00405     case OT_GOTO_DEPOT:   return GetDepot(o.GetDestination())->xy;
    00406   }
    00407 }
    00408
    00409 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
    00410 {
    00411   if (cur->IsType(OT_CONDITIONAL)) {
    00412     if (conditional_depth > v->GetNumOrders()) return 0;
    00413
    00414     conditional_depth++;
    00415
    00416     int dist1 = GetOrderDistance(prev, GetVehicleOrder(v, cur->GetConditionSkipToOrder()), v, conditional_depth);
    00417     int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
    00418     return max(dist1, dist2);
    00419   }
    00420
    00421   return DistanceManhattan(GetOrderLocation(*prev), GetOrderLocation(*cur));
    00422 }
    00423
    00434 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00435 {
    00436   Vehicle *v;
    00437   VehicleID veh   = GB(p1,  0, 16);
    00438   VehicleOrderID sel_ord = GB(p1, 16, 16);
    00439   Order new_order(p2);
    00440
    00441   if (!IsValidVehicleID(veh)) return CMD_ERROR;
    00442
    00443   v = GetVehicle(veh);
    00444
    00445   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    00446
    00447   /* Check if the inserted order is to the correct destination (owner, type),
    00448    * and has the correct flags if any */
    00449   switch (new_order.GetType()) {
    00450     case OT_GOTO_STATION: {
    00451       if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR;
    00452
    00453       const Station *st = GetStation(new_order.GetDestination());
    00454
    00455       if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) return CMD_ERROR;
    00456
    00457       if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_CAN_T_ADD_ORDER);
    00458       for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
    00459         if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_CAN_T_ADD_ORDER_SHARED);
    00460       }
    00461
    00462       /* Non stop not allowed for non-trains. */
    00463       if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
    00464
    00465       /* No load and no unload are mutual exclusive. */
    00466       if ((new_order.GetLoadType() & OLFB_NO_LOAD) && (new_order.GetUnloadType() & OUFB_NO_UNLOAD)) return CMD_ERROR;
    00467
    00468       /* Filter invalid load/unload types. */
    00469       switch (new_order.GetLoadType()) {
    00470         case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
    00471         default: return CMD_ERROR;
    00472       }
    00473       switch (new_order.GetUnloadType()) {
    00474         case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
    00475         default: return CMD_ERROR;
    00476       }
    00477       break;
    00478     }
    00479
    00480     case OT_GOTO_DEPOT: {
    00481       if (new_order.GetDepotActionType() != ODATFB_NEAREST_DEPOT) {
    00482         if (v->type == VEH_AIRCRAFT) {
    00483           if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR;
    00484
    00485           const Station *st = GetStation(new_order.GetDestination());
    00486
    00487           if (!CheckOwnership(st->owner) ||
    00488               !CanVehicleUseStation(v, st) ||
    00489               st->Airport()->nof_depots == 0) {
    00490             return CMD_ERROR;
    00491           }
    00492         } else {
    00493           if (!IsValidDepotID(new_order.GetDestination())) return CMD_ERROR;
    00494
    00495           const Depot *dp = GetDepot(new_order.GetDestination());
    00496
    00497           if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
    00498
    00499           switch (v->type) {
    00500             case VEH_TRAIN:
    00501               if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
    00502               break;
    00503
    00504             case VEH_ROAD:
    00505               if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
    00506               break;
    00507
    00508             case VEH_SHIP:
    00509               if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
    00510               break;
    00511
    00512             default: return CMD_ERROR;
    00513           }
    00514         }
    00515       } else {
    00516         if (!IsCompanyBuildableVehicleType(v)) return CMD_ERROR;
    00517       }
    00518
    00519       if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
    00520       if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
    00521       if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
    00522       if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
    00523       break;
    00524     }
    00525
    00526     case OT_GOTO_WAYPOINT: {
    00527       if (v->type != VEH_TRAIN) return CMD_ERROR;
    00528
    00529       if (!IsValidWaypointID(new_order.GetDestination())) return CMD_ERROR;
    00530       const Waypoint *wp = GetWaypoint(new_order.GetDestination());
    00531
    00532       if (!CheckOwnership(wp->owner)) return CMD_ERROR;
    00533
    00534       /* Order flags can be any of the following for waypoints:
    00535        * [non-stop]
    00536        * non-stop orders (if any) are only valid for trains */
    00537       if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
    00538       break;
    00539     }
    00540
    00541     case OT_CONDITIONAL: {
    00542       VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
    00543       if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
    00544       if (new_order.GetConditionVariable() > OCV_END) return CMD_ERROR;
    00545
    00546       OrderConditionComparator occ = new_order.GetConditionComparator();
    00547       if (occ > OCC_END) return CMD_ERROR;
    00548       switch (new_order.GetConditionVariable()) {
    00549         case OCV_REQUIRES_SERVICE:
    00550           if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
    00551           break;
    00552
    00553         case OCV_UNCONDITIONALLY:
    00554           if (occ != OCC_EQUALS) return CMD_ERROR;
    00555           if (new_order.GetConditionValue() != 0) return CMD_ERROR;
    00556           break;
    00557
    00558         case OCV_LOAD_PERCENTAGE:
    00559         case OCV_RELIABILITY:
    00560           if (new_order.GetConditionValue() > 100) return CMD_ERROR;
    00561           /* FALL THROUGH */
    00562         default:
    00563           if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
    00564           break;
    00565       }
    00566     } break;
    00567
    00568     default: return CMD_ERROR;
    00569   }
    00570
    00571   if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
    00572
    00573   if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
    00574   if (!Order::CanAllocateItem()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
    00575   if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
    00576
    00577   if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
    00578     /* Make sure the new destination is not too far away from the previous */
    00579     const Order *prev = NULL;
    00580     uint n = 0;
    00581
    00582     /* Find the last goto station or depot order before the insert location.
    00583      * If the order is to be inserted at the beginning of the order list this
    00584      * finds the last order in the list. */
    00585     const Order *o;
    00586     FOR_VEHICLE_ORDERS(v, o) {
    00587       if (o->IsType(OT_GOTO_STATION) || o->IsType(OT_GOTO_DEPOT)) prev = o;
    00588       if (++n == sel_ord && prev != NULL) break;
    00589     }
    00590     if (prev != NULL) {
    00591       uint dist = GetOrderDistance(prev, &new_order, v);
    00592       if (dist >= 130) {
    00593         return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
    00594       }
    00595     }
    00596   }
    00597
    00598   if (flags & DC_EXEC) {
    00599     Order *new_o = new Order();
    00600     new_o->AssignOrder(new_order);
    00601
    00602     /* Create new order and link in list */
    00603     if (v->orders.list == NULL) {
    00604       v->orders.list = new OrderList(new_o, v);
    00605     } else {
    00606       v->orders.list->InsertOrderAt(new_o, sel_ord);
    00607     }
    00608
    00609     Vehicle *u = v->FirstShared();
    00610     DeleteOrderWarnings(u);
    00611     for (; u != NULL; u = u->NextShared()) {
    00612       assert(v->orders.list == u->orders.list);
    00613
    00614       /* If there is added an order before the current one, we need
    00615       to update the selected order */
    00616       if (sel_ord <= u->cur_order_index) {
    00617         uint cur = u->cur_order_index + 1;
    00618         /* Check if we don't go out of bound */
    00619         if (cur < u->GetNumOrders())
    00620           u->cur_order_index = cur;
    00621       }
    00622       /* Update any possible open window of the vehicle */
    00623       InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
    00624     }
    00625
    00626     /* As we insert an order, the order to skip to will be 'wrong'. */
    00627     VehicleOrderID cur_order_id = 0;
    00628     Order *order;
    00629     FOR_VEHICLE_ORDERS(v, order) {
    00630       if (order->IsType(OT_CONDITIONAL)) {
    00631         VehicleOrderID order_id = order->GetConditionSkipToOrder();
    00632         if (order_id >= sel_ord) {
    00633           order->SetConditionSkipToOrder(order_id + 1);
    00634         }
    00635         if (order_id == cur_order_id) {
    00636           order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
    00637         }
    00638       }
    00639       cur_order_id++;
    00640     }
    00641
    00642     /* Make sure to rebuild the whole list */
    00643     InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
    00644   }
    00645
    00646   return CommandCost();
    00647 }
    00648
    00653 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
    00654 {
    00655   if (flags & DC_EXEC) {
    00656     DeleteVehicleOrders(dst);
    00657     InvalidateVehicleOrder(dst, -1);
    00658     InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
    00659   }
    00660   return CommandCost();
    00661 }
    00662
    00669 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00670 {
    00671   Vehicle *v;
    00672   VehicleID veh_id = p1;
    00673   VehicleOrderID sel_ord = p2;
    00674   Order *order;
    00675
    00676   if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
    00677
    00678   v = GetVehicle(veh_id);
    00679
    00680   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    00681
    00682   /* If we did not select an order, we maybe want to de-clone the orders */
    00683   if (sel_ord >= v->GetNumOrders())
    00684     return DecloneOrder(v, flags);
    00685
    00686   order = GetVehicleOrder(v, sel_ord);
    00687   if (order == NULL) return CMD_ERROR;
    00688
    00689   if (flags & DC_EXEC) {
    00690     v->orders.list->DeleteOrderAt(sel_ord);
    00691
    00692     Vehicle *u = v->FirstShared();
    00693     DeleteOrderWarnings(u);
    00694     for (; u != NULL; u = u->NextShared()) {
    00695       if (sel_ord < u->cur_order_index)
    00696         u->cur_order_index--;
    00697
    00698       assert(v->orders.list == u->orders.list);
    00699
    00700       /* NON-stop flag is misused to see if a train is in a station that is
    00701        * on his order list or not */
    00702       if (sel_ord == u->cur_order_index && u->current_order.IsType(OT_LOADING)) {
    00703         u->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
    00704       }
    00705
    00706       /* Update any possible open window of the vehicle */
    00707       InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
    00708     }
    00709
    00710     /* As we delete an order, the order to skip to will be 'wrong'. */
    00711     VehicleOrderID cur_order_id = 0;
    00712     FOR_VEHICLE_ORDERS(v, order) {
    00713       if (order->IsType(OT_CONDITIONAL)) {
    00714         VehicleOrderID order_id = order->GetConditionSkipToOrder();
    00715         if (order_id >= sel_ord) {
    00716           order->SetConditionSkipToOrder(max(order_id - 1, 0));
    00717         }
    00718         if (order_id == cur_order_id) {
    00719           order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
    00720         }
    00721       }
    00722       cur_order_id++;
    00723     }
    00724
    00725     InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
    00726   }
    00727
    00728   return CommandCost();
    00729 }
    00730
    00737 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00738 {
    00739   Vehicle *v;
    00740   VehicleID veh_id = p1;
    00741   VehicleOrderID sel_ord = p2;
    00742
    00743   if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
    00744
    00745   v = GetVehicle(veh_id);
    00746
    00747   if (!CheckOwnership(v->owner) || sel_ord == v->cur_order_index ||
    00748       sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
    00749
    00750   if (flags & DC_EXEC) {
    00751     v->cur_order_index = sel_ord;
    00752
    00753     if (v->type == VEH_ROAD) ClearSlot(v);
    00754
    00755     if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
    00756
    00757     InvalidateVehicleOrder(v, 0);
    00758   }
    00759
    00760   /* We have an aircraft/ship, they have a mini-schedule, so update them all */
    00761   if (v->type == VEH_AIRCRAFT) InvalidateWindowClasses(WC_AIRCRAFT_LIST);
    00762   if (v->type == VEH_SHIP) InvalidateWindowClasses(WC_SHIPS_LIST);
    00763
    00764   return CommandCost();
    00765 }
    00766
    00777 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00778 {
    00779   VehicleID veh = p1;
    00780   VehicleOrderID moving_order = GB(p2,  0, 16);
    00781   VehicleOrderID target_order = GB(p2, 16, 16);
    00782
    00783   if (!IsValidVehicleID(veh)) return CMD_ERROR;
    00784
    00785   Vehicle *v = GetVehicle(veh);
    00786   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    00787
    00788   /* Don't make senseless movements */
    00789   if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
    00790       moving_order == target_order || v->GetNumOrders() <= 1)
    00791     return CMD_ERROR;
    00792
    00793   Order *moving_one = GetVehicleOrder(v, moving_order);
    00794   /* Don't move an empty order */
    00795   if (moving_one == NULL) return CMD_ERROR;
    00796
    00797   if (flags & DC_EXEC) {
    00798     v->orders.list->MoveOrder(moving_order, target_order);
    00799
    00800     /* Update shared list */
    00801     Vehicle *u = v->FirstShared();
    00802
    00803     DeleteOrderWarnings(u);
    00804
    00805     for (; u != NULL; u = u->NextShared()) {
    00806       /* Update the current order */
    00807       if (u->cur_order_index == moving_order) {
    00808         u->cur_order_index = target_order;
    00809       } else if(u->cur_order_index > moving_order && u->cur_order_index <= target_order) {
    00810         u->cur_order_index--;
    00811       } else if(u->cur_order_index < moving_order && u->cur_order_index >= target_order) {
    00812         u->cur_order_index++;
    00813       }
    00814
    00815       assert(v->orders.list == u->orders.list);
    00816       /* Update any possible open window of the vehicle */
    00817       InvalidateVehicleOrder(u, moving_order | (target_order << 8));
    00818     }
    00819
    00820     /* As we move an order, the order to skip to will be 'wrong'. */
    00821     Order *order;
    00822     FOR_VEHICLE_ORDERS(v, order) {
    00823       if (order->IsType(OT_CONDITIONAL)) {
    00824         VehicleOrderID order_id = order->GetConditionSkipToOrder();
    00825         if (order_id == moving_order) {
    00826           order_id = target_order;
    00827         } else if(order_id > moving_order && order_id <= target_order) {
    00828           order_id--;
    00829         } else if(order_id < moving_order && order_id >= target_order) {
    00830           order_id++;
    00831         }
    00832         order->SetConditionSkipToOrder(order_id);
    00833       }
    00834     }
    00835
    00836     /* Make sure to rebuild the whole list */
    00837     InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
    00838   }
    00839
    00840   return CommandCost();
    00841 }
    00842
    00855 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00856 {
    00857   VehicleOrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
    00858   VehicleID veh          = GB(p1,  0, 16);
    00859   ModifyOrderFlags mof   = (ModifyOrderFlags)GB(p2,  0,  4);
    00860   uint16 data             = GB(p2, 4, 11);
    00861
    00862   if (mof >= MOF_END) return CMD_ERROR;
    00863   if (!IsValidVehicleID(veh)) return CMD_ERROR;
    00864
    00865   Vehicle *v = GetVehicle(veh);
    00866   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    00867
    00868   /* Is it a valid order? */
    00869   if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
    00870
    00871   Order *order = GetVehicleOrder(v, sel_ord);
    00872   switch (order->GetType()) {
    00873     case OT_GOTO_STATION:
    00874       if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE || GetStation(order->GetDestination())->IsBuoy()) return CMD_ERROR;
    00875       break;
    00876
    00877     case OT_GOTO_DEPOT:
    00878       if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
    00879       break;
    00880
    00881     case OT_GOTO_WAYPOINT:
    00882       if (mof != MOF_NON_STOP) return CMD_ERROR;
    00883       break;
    00884
    00885     case OT_CONDITIONAL:
    00886       if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
    00887       break;
    00888
    00889     default:
    00890       return CMD_ERROR;
    00891   }
    00892
    00893   switch (mof) {
    00894     default: NOT_REACHED();
    00895
    00896     case MOF_NON_STOP:
    00897       if (v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
    00898       if (data >= ONSF_END) return CMD_ERROR;
    00899       if (data == order->GetNonStopType()) return CMD_ERROR;
    00900       break;
    00901
    00902     case MOF_UNLOAD:
    00903       if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
    00904       /* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
    00905       if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
    00906       if (data == order->GetUnloadType()) return CMD_ERROR;
    00907       break;
    00908
    00909     case MOF_LOAD:
    00910       if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
    00911       if (data == order->GetLoadType()) return CMD_ERROR;
    00912       break;
    00913
    00914     case MOF_DEPOT_ACTION:
    00915       if (data >= DA_END) return CMD_ERROR;
    00916       break;
    00917
    00918     case MOF_COND_VARIABLE:
    00919       if (data >= OCV_END) return CMD_ERROR;
    00920       break;
    00921
    00922     case MOF_COND_COMPARATOR:
    00923       if (data >= OCC_END) return CMD_ERROR;
    00924       switch (order->GetConditionVariable()) {
    00925         case OCV_UNCONDITIONALLY: return CMD_ERROR;
    00926
    00927         case OCV_REQUIRES_SERVICE:
    00928           if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
    00929           break;
    00930
    00931         default:
    00932           if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
    00933           break;
    00934       }
    00935       break;
    00936
    00937     case MOF_COND_VALUE:
    00938       switch (order->GetConditionVariable()) {
    00939         case OCV_UNCONDITIONALLY: return CMD_ERROR;
    00940
    00941         case OCV_LOAD_PERCENTAGE:
    00942         case OCV_RELIABILITY:
    00943           if (data > 100) return CMD_ERROR;
    00944           break;
    00945
    00946         default:
    00947           if (data > 2047) return CMD_ERROR;
    00948           break;
    00949       }
    00950       break;
    00951
    00952     case MOF_COND_DESTINATION:
    00953       if (data >= v->GetNumOrders()) return CMD_ERROR;
    00954       break;
    00955   }
    00956
    00957   if (flags & DC_EXEC) {
    00958     switch (mof) {
    00959       case MOF_NON_STOP:
    00960         order->SetNonStopType((OrderNonStopFlags)data);
    00961         break;
    00962
    00963       case MOF_UNLOAD:
    00964         order->SetUnloadType((OrderUnloadFlags)data);
    00965         if ((data & OUFB_NO_UNLOAD) != 0 && (order->GetLoadType() & OLFB_NO_LOAD) != 0) {
    00966           order->SetLoadType((OrderLoadFlags)(order->GetLoadType() & ~OLFB_NO_LOAD));
    00967         }
    00968         break;
    00969
    00970       case MOF_LOAD:
    00971         order->SetLoadType((OrderLoadFlags)data);
    00972         if ((data & OLFB_NO_LOAD) != 0 && (order->GetUnloadType() & OUFB_NO_UNLOAD) != 0) {
    00973           /* No load + no unload isn't compatible */
    00974           order->SetUnloadType((OrderUnloadFlags)(order->GetUnloadType() & ~OUFB_NO_UNLOAD));
    00975         }
    00976         break;
    00977
    00978       case MOF_DEPOT_ACTION: {
    00979         switch (data) {
    00980           case DA_ALWAYS_GO:
    00981             order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
    00982             order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
    00983             break;
    00984
    00985           case DA_SERVICE:
    00986             order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
    00987             order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
    00988             break;
    00989
    00990           case DA_STOP:
    00991             order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
    00992             order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
    00993             break;
    00994
    00995           default:
    00996             NOT_REACHED();
    00997         }
    00998       } break;
    00999
    01000       case MOF_COND_VARIABLE: {
    01001         order->SetConditionVariable((OrderConditionVariable)data);
    01002
    01003         OrderConditionComparator occ = order->GetConditionComparator();
    01004         switch (order->GetConditionVariable()) {
    01005           case OCV_UNCONDITIONALLY:
    01006             order->SetConditionComparator(OCC_EQUALS);
    01007             order->SetConditionValue(0);
    01008             break;
    01009
    01010           case OCV_REQUIRES_SERVICE:
    01011             if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
    01012             break;
    01013
    01014           case OCV_LOAD_PERCENTAGE:
    01015           case OCV_RELIABILITY:
    01016             if (order->GetConditionValue() > 100) order->SetConditionValue(100);
    01017             /* FALL THROUGH */
    01018           default:
    01019             if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
    01020             break;
    01021         }
    01022       } break;
    01023
    01024       case MOF_COND_COMPARATOR:
    01025         order->SetConditionComparator((OrderConditionComparator)data);
    01026         break;
    01027
    01028       case MOF_COND_VALUE:
    01029         order->SetConditionValue(data);
    01030         break;
    01031
    01032       case MOF_COND_DESTINATION:
    01033         order->SetConditionSkipToOrder(data);
    01034         break;
    01035
    01036       default: NOT_REACHED();
    01037     }
    01038
    01039     /* Update the windows and full load flags, also for vehicles that share the same order list */
    01040     Vehicle *u = v->FirstShared();
    01041     DeleteOrderWarnings(u);
    01042     for (; u != NULL; u = u->NextShared()) {
    01043       /* Toggle u->current_order "Full load" flag if it changed.
    01044        * However, as the same flag is used for depot orders, check
    01045        * whether we are not going to a depot as there are three
    01046        * cases where the full load flag can be active and only
    01047        * one case where the flag is used for depot orders. In the
    01048        * other cases for the OrderTypeByte the flags are not used,
    01049        * so do not care and those orders should not be active
    01050        * when this function is called.
    01051        */
    01052       if (sel_ord == u->cur_order_index &&
    01053           (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
    01054           u->current_order.GetLoadType() != order->GetLoadType()) {
    01055         u->current_order.SetLoadType(order->GetLoadType());
    01056       }
    01057       InvalidateVehicleOrder(u, 0);
    01058     }
    01059   }
    01060
    01061   return CommandCost();
    01062 }
    01063
    01072 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01073 {
    01074   Vehicle *dst;
    01075   VehicleID veh_src = GB(p1, 16, 16);
    01076   VehicleID veh_dst = GB(p1,  0, 16);
    01077
    01078   if (!IsValidVehicleID(veh_dst)) return CMD_ERROR;
    01079
    01080   dst = GetVehicle(veh_dst);
    01081
    01082   if (!CheckOwnership(dst->owner)) return CMD_ERROR;
    01083
    01084   switch (p2) {
    01085     case CO_SHARE: {
    01086       Vehicle *src;
    01087
    01088       if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
    01089
    01090       src = GetVehicle(veh_src);
    01091
    01092       /* Sanity checks */
    01093       if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
    01094         return CMD_ERROR;
    01095
    01096       /* Trucks can't share orders with busses (and visa versa) */
    01097       if (src->type == VEH_ROAD && IsCargoInClass(src->cargo_type, CC_PASSENGERS) != IsCargoInClass(dst->cargo_type, CC_PASSENGERS)) {
    01098         return CMD_ERROR;
    01099       }
    01100
    01101       /* Is the vehicle already in the shared list? */
    01102       if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
    01103
    01104       const Order *order;
    01105
    01106       FOR_VEHICLE_ORDERS(src, order) {
    01107         if (OrderGoesToStation(dst, order) &&
    01108             !CanVehicleUseStation(dst, GetStation(order->GetDestination()))) {
    01109           return_cmd_error(STR_CAN_T_COPY_SHARE_ORDER);
    01110         }
    01111       }
    01112
    01113       if (flags & DC_EXEC) {
    01114         /* If the destination vehicle had a OrderList, destroy it */
    01115         DeleteVehicleOrders(dst);
    01116
    01117         dst->orders.list = src->orders.list;
    01118
    01119         /* Link this vehicle in the shared-list */
    01120         dst->AddToShared(src);
    01121
    01122         InvalidateVehicleOrder(dst, -1);
    01123         InvalidateVehicleOrder(src, 0);
    01124
    01125         InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
    01126       }
    01127     } break;
    01128
    01129     case CO_COPY: {
    01130       Vehicle *src;
    01131       int delta;
    01132
    01133       if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
    01134
    01135       src = GetVehicle(veh_src);
    01136
    01137       /* Sanity checks */
    01138       if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
    01139         return CMD_ERROR;
    01140
    01141       /* Trucks can't copy all the orders from busses (and visa versa),
    01142        * and neither can helicopters and aircarft. */
    01143       const Order *order;
    01144       FOR_VEHICLE_ORDERS(src, order) {
    01145         if (OrderGoesToStation(dst, order) &&
    01146             !CanVehicleUseStation(dst, GetStation(order->GetDestination()))) {
    01147           return_cmd_error(STR_CAN_T_COPY_SHARE_ORDER);
    01148         }
    01149       }
    01150
    01151       /* make sure there are orders available */
    01152       delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
    01153       if (!Order::CanAllocateItem(delta) ||
    01154           ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
    01155         return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
    01156       }
    01157
    01158       if (flags & DC_EXEC) {
    01159         const Order *order;
    01160         Order *first = NULL;
    01161         Order **order_dst;
    01162
    01163         /* If the destination vehicle had an order list, destroy the chain but keep the OrderList */
    01164         DeleteVehicleOrders(dst, true);
    01165
    01166         order_dst = &first;
    01167         FOR_VEHICLE_ORDERS(src, order) {
    01168           *order_dst = new Order();
    01169           (*order_dst)->AssignOrder(*order);
    01170           order_dst = &(*order_dst)->next;
    01171         }
    01172         if (dst->orders.list == NULL) dst->orders.list = new OrderList(first, dst);
    01173         else {
    01174           assert(dst->orders.list->GetFirstOrder() == NULL);
    01175           new (dst->orders.list) OrderList(first, dst);
    01176         }
    01177
    01178         InvalidateVehicleOrder(dst, -1);
    01179
    01180         InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
    01181       }
    01182     } break;
    01183
    01184     case CO_UNSHARE: return DecloneOrder(dst, flags);
    01185     default: return CMD_ERROR;
    01186   }
    01187
    01188   return CommandCost();
    01189 }
    01190
    01200 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01201 {
    01202   const Vehicle *v;
    01203   Order *order;
    01204   VehicleID veh = GB(p1, 0, 16);
    01205   VehicleOrderID order_number  = GB(p2, 16, 8);
    01206   CargoID cargo = GB(p2, 0, 8);
    01207   byte subtype  = GB(p2, 8, 8);
    01208
    01209   if (!IsValidVehicleID(veh)) return CMD_ERROR;
    01210
    01211   v = GetVehicle(veh);
    01212
    01213   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    01214
    01215   order = GetVehicleOrder(v, order_number);
    01216   if (order == NULL) return CMD_ERROR;
    01217
    01218   if (flags & DC_EXEC) {
    01219     order->SetRefit(cargo, subtype);
    01220
    01221     for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
    01222       /* Update any possible open window of the vehicle */
    01223       InvalidateVehicleOrder(u, 0);
    01224
    01225       /* If the vehicle already got the current depot set as current order, then update current order as well */
    01226       if (u->cur_order_index == order_number && u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01227         u->current_order.SetRefit(cargo, subtype);
    01228       }
    01229     }
    01230   }
    01231
    01232   return CommandCost();
    01233 }
    01234
    01241 void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
    01242 {
    01243   /* Make sure we always have freed the stuff */
    01244   free(bak->order);
    01245   bak->order = NULL;
    01246   free(bak->name);
    01247   bak->name = NULL;
    01248
    01249   /* Save general info */
    01250   bak->orderindex       = v->cur_order_index;
    01251   bak->group            = v->group_id;
    01252   bak->service_interval = v->service_interval;
    01253   if (v->name != NULL) bak->name = strdup(v->name);
    01254
    01255   /* If we have shared orders, store it on a special way */
    01256   if (v->IsOrderListShared()) {
    01257     const Vehicle *u = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
    01258
    01259     bak->clone = u->index;
    01260   } else {
    01261     /* Else copy the orders */
    01262
    01263     /* We do not have shared orders */
    01264     bak->clone = INVALID_VEHICLE;
    01265
    01266
    01267     /* Count the number of orders */
    01268     uint cnt = 0;
    01269     const Order *order;
    01270     FOR_VEHICLE_ORDERS(v, order) cnt++;
    01271
    01272     /* Allocate memory for the orders plus an end-of-orders marker */
    01273     bak->order = MallocT<Order>(cnt + 1);
    01274
    01275     Order *dest = bak->order;
    01276
    01277     /* Copy the orders */
    01278     FOR_VEHICLE_ORDERS(v, order) {
    01279       memcpy(dest, order, sizeof(Order));
    01280       dest++;
    01281     }
    01282     /* End the list with an empty order */
    01283     dest->Free();
    01284   }
    01285 }
    01286
    01292 void RestoreVehicleOrders(const Vehicle *v, const BackuppedOrders *bak)
    01293 {
    01294   /* If we have a custom name, process that */
    01295   if (bak->name != NULL) DoCommandP(0, v->index, 0, CMD_RENAME_VEHICLE, NULL, bak->name);
    01296
    01297   /* If we had shared orders, recover that */
    01298   if (bak->clone != INVALID_VEHICLE) {
    01299     DoCommandP(0, v->index | (bak->clone << 16), CO_SHARE, CMD_CLONE_ORDER);
    01300   } else {
    01301
    01302     /* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
    01303      *  order number is one more than the current amount of orders, and because
    01304      *  in network the commands are queued before send, the second insert always
    01305      *  fails in test mode. By bypassing the test-mode, that no longer is a problem. */
    01306     for (uint i = 0; bak->order[i].IsValid(); i++) {
    01307       Order o = bak->order[i];
    01308       /* Conditional orders need to have their destination to be valid on insertion. */
    01309       if (o.IsType(OT_CONDITIONAL)) o.SetConditionSkipToOrder(0);
    01310
    01311       if (!DoCommandP(0, v->index + (i << 16), o.Pack(),
    01312           CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
    01313         break;
    01314       }
    01315
    01316       /* Copy timetable if enabled */
    01317       if (_settings_game.order.timetabling && !DoCommandP(0, v->index | (i << 16) | (1 << 25),
    01318           o.wait_time << 16 | o.travel_time,
    01319           CMD_CHANGE_TIMETABLE | CMD_NO_TEST_IF_IN_NETWORK)) {
    01320         break;
    01321       }
    01322     }
    01323
    01324       /* Fix the conditional orders' destination. */
    01325     for (uint i = 0; bak->order[i].IsValid(); i++) {
    01326       if (!bak->order[i].IsType(OT_CONDITIONAL)) continue;
    01327
    01328       if (!DoCommandP(0, v->index + (i << 16), MOF_LOAD | (bak->order[i].GetConditionSkipToOrder() << 4),
    01329           CMD_MODIFY_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
    01330         break;
    01331       }
    01332     }
    01333   }
    01334
    01335   /* Restore vehicle order-index and service interval */
    01336   DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , CMD_RESTORE_ORDER_INDEX);
    01337
    01338   /* Restore vehicle group */
    01339   DoCommandP(0, bak->group, v->index, CMD_ADD_VEHICLE_GROUP);
    01340 }
    01341
    01356 CommandCost CmdRestoreOrderIndex(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01357 {
    01358   Vehicle *v;
    01359   VehicleOrderID cur_ord = GB(p2,  0, 16);
    01360   uint16 serv_int = GB(p2, 16, 16);
    01361
    01362   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    01363
    01364   v = GetVehicle(p1);
    01365
    01366   /* Check the vehicle type and ownership, and if the service interval and order are in range */
    01367   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    01368   if (serv_int != GetServiceIntervalClamped(serv_int) || cur_ord >= v->GetNumOrders()) return CMD_ERROR;
    01369
    01370   if (flags & DC_EXEC) {
    01371     v->cur_order_index = cur_ord;
    01372     v->service_interval = serv_int;
    01373   }
    01374
    01375   return CommandCost();
    01376 }
    01377
    01378
    01379 static TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st)
    01380 {
    01381   if (!CanVehicleUseStation(v, st)) return INVALID_TILE;
    01382
    01383   switch (v->type) {
    01384     default: NOT_REACHED();
    01385     case VEH_TRAIN:     return st->train_tile;
    01386     case VEH_AIRCRAFT:  return st->airport_tile;
    01387     case VEH_SHIP:      return st->dock_tile;
    01388     case VEH_ROAD:      return st->GetPrimaryRoadStop(v)->xy;
    01389   }
    01390 }
    01391
    01392
    01398 void CheckOrders(const Vehicle *v)
    01399 {
    01400   /* Does the user wants us to check things? */
    01401   if (_settings_client.gui.order_review_system == 0) return;
    01402
    01403   /* Do nothing for crashed vehicles */
    01404   if (v->vehstatus & VS_CRASHED) return;
    01405
    01406   /* Do nothing for stopped vehicles if setting is '1' */
    01407   if (_settings_client.gui.order_review_system == 1 && v->vehstatus & VS_STOPPED)
    01408     return;
    01409
    01410   /* do nothing we we're not the first vehicle in a share-chain */
    01411   if (v->FirstShared() != v) return;
    01412
    01413   /* Only check every 20 days, so that we don't flood the message log */
    01414   if (v->owner == _local_company && v->day_counter % 20 == 0) {
    01415     int n_st, problem_type = -1;
    01416     const Order *order;
    01417     int message = 0;
    01418
    01419     /* Check the order list */
    01420     n_st = 0;
    01421
    01422     FOR_VEHICLE_ORDERS(v, order) {
    01423       /* Dummy order? */
    01424       if (order->IsType(OT_DUMMY)) {
    01425         problem_type = 1;
    01426         break;
    01427       }
    01428       /* Does station have a load-bay for this vehicle? */
    01429       if (order->IsType(OT_GOTO_STATION)) {
    01430         const Station *st = GetStation(order->GetDestination());
    01431         TileIndex required_tile = GetStationTileForVehicle(v, st);
    01432
    01433         n_st++;
    01434         if (required_tile == INVALID_TILE) problem_type = 3;
    01435       }
    01436     }
    01437
    01438     /* Check if the last and the first order are the same */
    01439     if (v->GetNumOrders() > 1) {
    01440       const Order *last = GetLastVehicleOrder(v);
    01441
    01442       if (v->orders.list->GetFirstOrder()->Equals(*last)) {
    01443         problem_type = 2;
    01444       }
    01445     }
    01446
    01447     /* Do we only have 1 station in our order list? */
    01448     if (n_st < 2 && problem_type == -1) problem_type = 0;
    01449
    01450 #ifndef NDEBUG
    01451     if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
    01452 #endif
    01453
    01454     /* We don't have a problem */
    01455     if (problem_type < 0) return;
    01456
    01457     message = STR_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
    01458     //DEBUG(misc, 3, "Triggered News Item for vehicle %d", v->index);
    01459
    01460     SetDParam(0, v->index);
    01461     AddNewsItem(
    01462       message,
    01463       NS_ADVICE,
    01464       v->index,
    01465       0
    01466     );
    01467   }
    01468 }
    01469
    01475 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
    01476 {
    01477   Vehicle *v;
    01478
    01479   /* Aircraft have StationIDs for depot orders and never use DepotIDs
    01480    * This fact is handled specially below
    01481    */
    01482
    01483   /* Go through all vehicles */
    01484   FOR_ALL_VEHICLES(v) {
    01485     Order *order;
    01486
    01487     /* Forget about this station if this station is removed */
    01488     if (v->last_station_visited == destination && type == OT_GOTO_STATION) {
    01489       v->last_station_visited = INVALID_STATION;
    01490     }
    01491
    01492     order = &v->current_order;
    01493     if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
    01494         v->current_order.GetDestination() == destination) {
    01495       order->MakeDummy();
    01496       InvalidateWindow(WC_VEHICLE_VIEW, v->index);
    01497     }
    01498
    01499     /* Clear the order from the order-list */
    01500     int id = -1;
    01501     FOR_VEHICLE_ORDERS(v, order) {
    01502       id++;
    01503       if (order->IsType(OT_GOTO_DEPOT) && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
    01504       if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
    01505           order->GetDestination() == destination) {
    01506         order->MakeDummy();
    01507         for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
    01508           /* In GUI, simulate by removing the order and adding it back */
    01509           InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
    01510           InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
    01511         }
    01512       }
    01513     }
    01514   }
    01515 }
    01516
    01524 bool VehicleHasDepotOrders(const Vehicle *v)
    01525 {
    01526   const Order *order;
    01527
    01528   FOR_VEHICLE_ORDERS(v, order) {
    01529     if (order->IsType(OT_GOTO_DEPOT))
    01530       return true;
    01531   }
    01532
    01533   return false;
    01534 }
    01535
    01541 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist)
    01542 {
    01543   DeleteOrderWarnings(v);
    01544
    01545   if (v->IsOrderListShared()) {
    01546     /* Remove ourself from the shared order list. */
    01547     v->RemoveFromShared();
    01548     v->orders.list = NULL;
    01549   } else if (v->orders.list != NULL) {
    01550     /* Remove the orders */
    01551     v->orders.list->FreeChain(keep_orderlist);
    01552     if (!keep_orderlist) v->orders.list = NULL;
    01553   }
    01554 }
    01555
    01556 Date GetServiceIntervalClamped(uint index)
    01557 {
    01558   return (_settings_game.vehicle.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
    01559 }
    01560
    01568 static bool CheckForValidOrders(const Vehicle *v)
    01569 {
    01570   const Order *order;
    01571
    01572   FOR_VEHICLE_ORDERS(v, order) if (!order->IsType(OT_DUMMY)) return true;
    01573
    01574   return false;
    01575 }
    01576
    01580 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
    01581 {
    01582   switch (occ) {
    01583     case OCC_EQUALS:      return variable == value;
    01584     case OCC_NOT_EQUALS:  return variable != value;
    01585     case OCC_LESS_THAN:   return variable <  value;
    01586     case OCC_LESS_EQUALS: return variable <= value;
    01587     case OCC_MORE_THAN:   return variable >  value;
    01588     case OCC_MORE_EQUALS: return variable >= value;
    01589     case OCC_IS_TRUE:     return variable != 0;
    01590     case OCC_IS_FALSE:    return variable == 0;
    01591     default: NOT_REACHED();
    01592   }
    01593 }
    01594
    01601 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
    01602 {
    01603   if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
    01604
    01605   bool skip_order = false;
    01606   OrderConditionComparator occ = order->GetConditionComparator();
    01607   uint16 value = order->GetConditionValue();
    01608
    01609   switch (order->GetConditionVariable()) {
    01610     case OCV_LOAD_PERCENTAGE:  skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
    01611     case OCV_RELIABILITY:      skip_order = OrderConditionCompare(occ, v->reliability * 100 >> 16,        value); break;
    01612     case OCV_MAX_SPEED:        skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
    01613     case OCV_AGE:              skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR,        value); break;
    01614     case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(),               value); break;
    01615     case OCV_UNCONDITIONALLY:  skip_order = true; break;
    01616     default: NOT_REACHED();
    01617   }
    01618
    01619   return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
    01620 }
    01621
    01627 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
    01628 {
    01629   if (conditional_depth > v->GetNumOrders()) return false;
    01630
    01631   switch (order->GetType()) {
    01632     case OT_GOTO_STATION:
    01633       v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
    01634       return true;
    01635
    01636     case OT_GOTO_DEPOT:
    01637       if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
    01638         /* We need to search for the nearest depot (hangar). */
    01639         TileIndex location;
    01640         DestinationID destination;
    01641         bool reverse;
    01642
    01643         if (v->FindClosestDepot(&location, &destination, &reverse)) {
    01644           v->dest_tile = location;
    01645           v->current_order.MakeGoToDepot(destination, v->current_order.GetDepotOrderType(), v->current_order.GetNonStopType(), (OrderDepotActionFlags)(v->current_order.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT), v->current_order.GetRefitCargo(), v->current_order.GetRefitSubtype());
    01646
    01647           /* If there is no depot in front, reverse automatically (trains only) */
    01648           if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    01649
    01650           if (v->type == VEH_AIRCRAFT && v->u.air.state == FLYING && v->u.air.targetairport != destination) {
    01651             /* The aircraft is now heading for a different hangar than the next in the orders */
    01652             extern void AircraftNextAirportPos_and_Order(Vehicle *v);
    01653             AircraftNextAirportPos_and_Order(v);
    01654           }
    01655           return true;
    01656         }
    01657
    01658         UpdateVehicleTimetable(v, true);
    01659         v->cur_order_index++;
    01660       } else if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
    01661         UpdateVehicleTimetable(v, true);
    01662         v->cur_order_index++;
    01663       } else {
    01664         if (v->type != VEH_AIRCRAFT) {
    01665           v->dest_tile = GetDepot(order->GetDestination())->xy;
    01666         }
    01667         return true;
    01668       }
    01669       break;
    01670
    01671     case OT_GOTO_WAYPOINT:
    01672       v->dest_tile = GetWaypoint(order->GetDestination())->xy;
    01673       return true;
    01674
    01675     case OT_CONDITIONAL: {
    01676       VehicleOrderID next_order = ProcessConditionalOrder(order, v);
    01677       if (next_order != INVALID_VEH_ORDER_ID) {
    01678         UpdateVehicleTimetable(v, false);
    01679         v->cur_order_index = next_order;
    01680         v->current_order_time += GetVehicleOrder(v, next_order)->travel_time;
    01681       } else {
    01682         UpdateVehicleTimetable(v, true);
    01683         v->cur_order_index++;
    01684       }
    01685       break;
    01686     }
    01687
    01688     default:
    01689       v->dest_tile = 0;
    01690       return false;
    01691   }
    01692
    01693   /* Get the current order */
    01694   if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
    01695
    01696   order = GetVehicleOrder(v, v->cur_order_index);
    01697   v->current_order = *order;
    01698   return UpdateOrderDest(v, order, conditional_depth + 1);
    01699 }
    01700
    01708 bool ProcessOrders(Vehicle *v)
    01709 {
    01710   switch (v->current_order.GetType()) {
    01711     case OT_GOTO_DEPOT:
    01712       /* Let a depot order in the orderlist interrupt. */
    01713       if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
    01714       break;
    01715
    01716     case OT_LOADING:
    01717       return false;
    01718
    01719     case OT_LEAVESTATION:
    01720       if (v->type != VEH_AIRCRAFT) return false;
    01721       break;
    01722
    01723     default: break;
    01724   }
    01725
    01733   bool may_reverse = v->current_order.IsType(OT_NOTHING);
    01734
    01735   /* Check if we've reached the waypoint? */
    01736   if (v->current_order.IsType(OT_GOTO_WAYPOINT) && v->tile == v->dest_tile) {
    01737     UpdateVehicleTimetable(v, true);
    01738     v->cur_order_index++;
    01739   }
    01740
    01741   /* Check if we've reached a non-stop station.. */
    01742   if (v->current_order.IsType(OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
    01743       IsTileType(v->tile, MP_STATION) &&
    01744       v->current_order.GetDestination() == GetStationIndex(v->tile)) {
    01745     v->last_station_visited = v->current_order.GetDestination();
    01746     UpdateVehicleTimetable(v, true);
    01747     v->cur_order_index++;
    01748   }
    01749
    01750   /* Get the current order */
    01751   if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
    01752
    01753   const Order *order = GetVehicleOrder(v, v->cur_order_index);
    01754
    01755   /* If no order, do nothing. */
    01756   if (order == NULL || (v->type == VEH_AIRCRAFT && order->IsType(OT_DUMMY) && !CheckForValidOrders(v))) {
    01757     if (v->type == VEH_AIRCRAFT) {
    01758       /* Aircraft do something vastly different here, so handle separately */
    01759       extern void HandleMissingAircraftOrders(Vehicle *v);
    01760       HandleMissingAircraftOrders(v);
    01761       return false;
    01762     }
    01763
    01764     v->current_order.Free();
    01765     v->dest_tile = 0;
    01766     if (v->type == VEH_ROAD) ClearSlot(v);
    01767     return false;
    01768   }
    01769
    01770   /* If it is unchanged, keep it. */
    01771   if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
    01772       (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || GetStation(order->GetDestination())->dock_tile != INVALID_TILE)) {
    01773     return false;
    01774   }
    01775
    01776   /* Otherwise set it, and determine the destination tile. */
    01777   v->current_order = *order;
    01778
    01779   InvalidateVehicleOrder(v, 0);
    01780   switch (v->type) {
    01781     default:
    01782       NOT_REACHED();
    01783
    01784     case VEH_ROAD:
    01785     case VEH_TRAIN:
    01786       break;
    01787
    01788     case VEH_AIRCRAFT:
    01789     case VEH_SHIP:
    01790       InvalidateWindowClasses(GetWindowClassForVehicleType(v->type));
    01791       break;
    01792   }
    01793
    01794   return UpdateOrderDest(v, order) && may_reverse;
    01795 }
    01796
    01804 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
    01805 {
    01806   bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
    01807   return
    01808       (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
    01809       v->last_station_visited != station && // Do stop only when we've not just been there
    01810       /* Finally do stop when there is no non-stop flag set for this type of station. */
    01811       !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
    01812 }
    01813
    01814 void InitializeOrders()
    01815 {
    01816   _Order_pool.CleanPool();
    01817   _Order_pool.AddBlockToPool();
    01818
    01819   _OrderList_pool.CleanPool();
    01820   _OrderList_pool.AddBlockToPool();
    01821
    01822   _backup_orders_tile = 0;
    01823 }