# order_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: order_cmd.cpp 16804 2009-07-13 10:16:50Z 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) {
    01098         if (src->cargo_type != dst->cargo_type && (IsCargoInClass(src->cargo_type, CC_PASSENGERS) || IsCargoInClass(dst->cargo_type, CC_PASSENGERS)))
    01099           return CMD_ERROR;
    01100       }
    01101
    01102       /* Is the vehicle already in the shared list? */
    01103       if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
    01104
    01105       const Order *order;
    01106
    01107       FOR_VEHICLE_ORDERS(src, order) {
    01108         if (OrderGoesToStation(dst, order) &&
    01109             !CanVehicleUseStation(dst, GetStation(order->GetDestination()))) {
    01110           return_cmd_error(STR_CAN_T_COPY_SHARE_ORDER);
    01111         }
    01112       }
    01113
    01114       if (flags & DC_EXEC) {
    01115         /* If the destination vehicle had a OrderList, destroy it */
    01116         DeleteVehicleOrders(dst);
    01117
    01118         dst->orders.list = src->orders.list;
    01119
    01120         /* Link this vehicle in the shared-list */
    01121         dst->AddToShared(src);
    01122
    01123         InvalidateVehicleOrder(dst, -1);
    01124         InvalidateVehicleOrder(src, 0);
    01125
    01126         InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
    01127       }
    01128     } break;
    01129
    01130     case CO_COPY: {
    01131       Vehicle *src;
    01132       int delta;
    01133
    01134       if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
    01135
    01136       src = GetVehicle(veh_src);
    01137
    01138       /* Sanity checks */
    01139       if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
    01140         return CMD_ERROR;
    01141
    01142       /* Trucks can't copy all the orders from busses (and visa versa),
    01143        * and neither can helicopters and aircarft. */
    01144       const Order *order;
    01145       FOR_VEHICLE_ORDERS(src, order) {
    01146         if (OrderGoesToStation(dst, order) &&
    01147             !CanVehicleUseStation(dst, GetStation(order->GetDestination()))) {
    01148           return_cmd_error(STR_CAN_T_COPY_SHARE_ORDER);
    01149         }
    01150       }
    01151
    01152       /* make sure there are orders available */
    01153       delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
    01154       if (!Order::CanAllocateItem(delta) ||
    01155           ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
    01156         return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
    01157       }
    01158
    01159       if (flags & DC_EXEC) {
    01160         const Order *order;
    01161         Order *first = NULL;
    01162         Order **order_dst;
    01163
    01164         /* If the destination vehicle had an order list, destroy the chain but keep the OrderList */
    01165         DeleteVehicleOrders(dst, true);
    01166
    01167         order_dst = &first;
    01168         FOR_VEHICLE_ORDERS(src, order) {
    01169           *order_dst = new Order();
    01170           (*order_dst)->AssignOrder(*order);
    01171           order_dst = &(*order_dst)->next;
    01172         }
    01173         if (dst->orders.list == NULL) dst->orders.list = new OrderList(first, dst);
    01174         else {
    01175           assert(dst->orders.list->GetFirstOrder() == NULL);
    01176           new (dst->orders.list) OrderList(first, dst);
    01177         }
    01178
    01179         InvalidateVehicleOrder(dst, -1);
    01180
    01181         InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
    01182       }
    01183     } break;
    01184
    01185     case CO_UNSHARE: return DecloneOrder(dst, flags);
    01186     default: return CMD_ERROR;
    01187   }
    01188
    01189   return CommandCost();
    01190 }
    01191
    01201 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01202 {
    01203   const Vehicle *v;
    01204   Order *order;
    01205   VehicleID veh = GB(p1, 0, 16);
    01206   VehicleOrderID order_number  = GB(p2, 16, 8);
    01207   CargoID cargo = GB(p2, 0, 8);
    01208   byte subtype  = GB(p2, 8, 8);
    01209
    01210   if (!IsValidVehicleID(veh)) return CMD_ERROR;
    01211
    01212   v = GetVehicle(veh);
    01213
    01214   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    01215
    01216   order = GetVehicleOrder(v, order_number);
    01217   if (order == NULL) return CMD_ERROR;
    01218
    01219   if (flags & DC_EXEC) {
    01220     order->SetRefit(cargo, subtype);
    01221
    01222     for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
    01223       /* Update any possible open window of the vehicle */
    01224       InvalidateVehicleOrder(u, 0);
    01225
    01226       /* If the vehicle already got the current depot set as current order, then update current order as well */
    01227       if (u->cur_order_index == order_number && u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01228         u->current_order.SetRefit(cargo, subtype);
    01229       }
    01230     }
    01231   }
    01232
    01233   return CommandCost();
    01234 }
    01235
    01242 void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
    01243 {
    01244   /* Make sure we always have freed the stuff */
    01245   free(bak->order);
    01246   bak->order = NULL;
    01247   free(bak->name);
    01248   bak->name = NULL;
    01249
    01250   /* Save general info */
    01251   bak->orderindex       = v->cur_order_index;
    01252   bak->group            = v->group_id;
    01253   bak->service_interval = v->service_interval;
    01254   if (v->name != NULL) bak->name = strdup(v->name);
    01255
    01256   /* If we have shared orders, store it on a special way */
    01257   if (v->IsOrderListShared()) {
    01258     const Vehicle *u = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
    01259
    01260     bak->clone = u->index;
    01261   } else {
    01262     /* Else copy the orders */
    01263
    01264     /* We do not have shared orders */
    01265     bak->clone = INVALID_VEHICLE;
    01266
    01267
    01268     /* Count the number of orders */
    01269     uint cnt = 0;
    01270     const Order *order;
    01271     FOR_VEHICLE_ORDERS(v, order) cnt++;
    01272
    01273     /* Allocate memory for the orders plus an end-of-orders marker */
    01274     bak->order = MallocT<Order>(cnt + 1);
    01275
    01276     Order *dest = bak->order;
    01277
    01278     /* Copy the orders */
    01279     FOR_VEHICLE_ORDERS(v, order) {
    01280       memcpy(dest, order, sizeof(Order));
    01281       dest++;
    01282     }
    01283     /* End the list with an empty order */
    01284     dest->Free();
    01285   }
    01286 }
    01287
    01293 void RestoreVehicleOrders(const Vehicle *v, const BackuppedOrders *bak)
    01294 {
    01295   /* If we have a custom name, process that */
    01296   if (bak->name != NULL) DoCommandP(0, v->index, 0, CMD_RENAME_VEHICLE, NULL, bak->name);
    01297
    01298   /* If we had shared orders, recover that */
    01299   if (bak->clone != INVALID_VEHICLE) {
    01300     DoCommandP(0, v->index | (bak->clone << 16), CO_SHARE, CMD_CLONE_ORDER);
    01301   } else {
    01302
    01303     /* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
    01304      *  order number is one more than the current amount of orders, and because
    01305      *  in network the commands are queued before send, the second insert always
    01306      *  fails in test mode. By bypassing the test-mode, that no longer is a problem. */
    01307     for (uint i = 0; bak->order[i].IsValid(); i++) {
    01308       Order o = bak->order[i];
    01309       /* Conditional orders need to have their destination to be valid on insertion. */
    01310       if (o.IsType(OT_CONDITIONAL)) o.SetConditionSkipToOrder(0);
    01311
    01312       if (!DoCommandP(0, v->index + (i << 16), o.Pack(),
    01313           CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
    01314         break;
    01315       }
    01316
    01317       /* Copy timetable if enabled */
    01318       if (_settings_game.order.timetabling && !DoCommandP(0, v->index | (i << 16) | (1 << 25),
    01319           o.wait_time << 16 | o.travel_time,
    01320           CMD_CHANGE_TIMETABLE | CMD_NO_TEST_IF_IN_NETWORK)) {
    01321         break;
    01322       }
    01323     }
    01324
    01325       /* Fix the conditional orders' destination. */
    01326     for (uint i = 0; bak->order[i].IsValid(); i++) {
    01327       if (!bak->order[i].IsType(OT_CONDITIONAL)) continue;
    01328
    01329       if (!DoCommandP(0, v->index + (i << 16), MOF_LOAD | (bak->order[i].GetConditionSkipToOrder() << 4),
    01330           CMD_MODIFY_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
    01331         break;
    01332       }
    01333     }
    01334   }
    01335
    01336   /* Restore vehicle order-index and service interval */
    01337   DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , CMD_RESTORE_ORDER_INDEX);
    01338
    01339   /* Restore vehicle group */
    01340   DoCommandP(0, bak->group, v->index, CMD_ADD_VEHICLE_GROUP);
    01341 }
    01342
    01357 CommandCost CmdRestoreOrderIndex(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    01358 {
    01359   Vehicle *v;
    01360   VehicleOrderID cur_ord = GB(p2,  0, 16);
    01361   uint16 serv_int = GB(p2, 16, 16);
    01362
    01363   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    01364
    01365   v = GetVehicle(p1);
    01366
    01367   /* Check the vehicle type and ownership, and if the service interval and order are in range */
    01368   if (!CheckOwnership(v->owner)) return CMD_ERROR;
    01369   if (serv_int != GetServiceIntervalClamped(serv_int) || cur_ord >= v->GetNumOrders()) return CMD_ERROR;
    01370
    01371   if (flags & DC_EXEC) {
    01372     v->cur_order_index = cur_ord;
    01373     v->service_interval = serv_int;
    01374   }
    01375
    01376   return CommandCost();
    01377 }
    01378
    01379
    01380 static TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st)
    01381 {
    01382   if (!CanVehicleUseStation(v, st)) return INVALID_TILE;
    01383
    01384   switch (v->type) {
    01385     default: NOT_REACHED();
    01386     case VEH_TRAIN:     return st->train_tile;
    01387     case VEH_AIRCRAFT:  return st->airport_tile;
    01388     case VEH_SHIP:      return st->dock_tile;
    01389     case VEH_ROAD:      return st->GetPrimaryRoadStop(v)->xy;
    01390   }
    01391 }
    01392
    01393
    01399 void CheckOrders(const Vehicle *v)
    01400 {
    01401   /* Does the user wants us to check things? */
    01402   if (_settings_client.gui.order_review_system == 0) return;
    01403
    01404   /* Do nothing for crashed vehicles */
    01405   if (v->vehstatus & VS_CRASHED) return;
    01406
    01407   /* Do nothing for stopped vehicles if setting is '1' */
    01408   if (_settings_client.gui.order_review_system == 1 && v->vehstatus & VS_STOPPED)
    01409     return;
    01410
    01411   /* do nothing we we're not the first vehicle in a share-chain */
    01412   if (v->FirstShared() != v) return;
    01413
    01414   /* Only check every 20 days, so that we don't flood the message log */
    01415   if (v->owner == _local_company && v->day_counter % 20 == 0) {
    01416     int n_st, problem_type = -1;
    01417     const Order *order;
    01418     int message = 0;
    01419
    01420     /* Check the order list */
    01421     n_st = 0;
    01422
    01423     FOR_VEHICLE_ORDERS(v, order) {
    01424       /* Dummy order? */
    01425       if (order->IsType(OT_DUMMY)) {
    01426         problem_type = 1;
    01427         break;
    01428       }
    01429       /* Does station have a load-bay for this vehicle? */
    01430       if (order->IsType(OT_GOTO_STATION)) {
    01431         const Station *st = GetStation(order->GetDestination());
    01432         TileIndex required_tile = GetStationTileForVehicle(v, st);
    01433
    01434         n_st++;
    01435         if (required_tile == INVALID_TILE) problem_type = 3;
    01436       }
    01437     }
    01438
    01439     /* Check if the last and the first order are the same */
    01440     if (v->GetNumOrders() > 1) {
    01441       const Order *last = GetLastVehicleOrder(v);
    01442
    01443       if (v->orders.list->GetFirstOrder()->Equals(*last)) {
    01444         problem_type = 2;
    01445       }
    01446     }
    01447
    01448     /* Do we only have 1 station in our order list? */
    01449     if (n_st < 2 && problem_type == -1) problem_type = 0;
    01450
    01451 #ifndef NDEBUG
    01452     if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
    01453 #endif
    01454
    01455     /* We don't have a problem */
    01456     if (problem_type < 0) return;
    01457
    01458     message = STR_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
    01459     //DEBUG(misc, 3, "Triggered News Item for vehicle %d", v->index);
    01460
    01461     SetDParam(0, v->index);
    01462     AddNewsItem(
    01463       message,
    01464       NS_ADVICE,
    01465       v->index,
    01466       0
    01467     );
    01468   }
    01469 }
    01470
    01476 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
    01477 {
    01478   Vehicle *v;
    01479
    01480   /* Aircraft have StationIDs for depot orders and never use DepotIDs
    01481    * This fact is handled specially below
    01482    */
    01483
    01484   /* Go through all vehicles */
    01485   FOR_ALL_VEHICLES(v) {
    01486     Order *order;
    01487
    01488     /* Forget about this station if this station is removed */
    01489     if (v->last_station_visited == destination && type == OT_GOTO_STATION) {
    01490       v->last_station_visited = INVALID_STATION;
    01491     }
    01492
    01493     order = &v->current_order;
    01494     if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
    01495         v->current_order.GetDestination() == destination) {
    01496       order->MakeDummy();
    01497       InvalidateWindow(WC_VEHICLE_VIEW, v->index);
    01498     }
    01499
    01500     /* Clear the order from the order-list */
    01501     int id = -1;
    01502     FOR_VEHICLE_ORDERS(v, order) {
    01503       id++;
    01504       if (order->IsType(OT_GOTO_DEPOT) && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
    01505       if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
    01506           order->GetDestination() == destination) {
    01507         order->MakeDummy();
    01508         for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
    01509           /* In GUI, simulate by removing the order and adding it back */
    01510           InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
    01511           InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
    01512         }
    01513       }
    01514     }
    01515   }
    01516 }
    01517
    01525 bool VehicleHasDepotOrders(const Vehicle *v)
    01526 {
    01527   const Order *order;
    01528
    01529   FOR_VEHICLE_ORDERS(v, order) {
    01530     if (order->IsType(OT_GOTO_DEPOT))
    01531       return true;
    01532   }
    01533
    01534   return false;
    01535 }
    01536
    01542 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist)
    01543 {
    01544   DeleteOrderWarnings(v);
    01545
    01546   if (v->IsOrderListShared()) {
    01547     /* Remove ourself from the shared order list. */
    01548     v->RemoveFromShared();
    01549     v->orders.list = NULL;
    01550   } else if (v->orders.list != NULL) {
    01551     /* Remove the orders */
    01552     v->orders.list->FreeChain(keep_orderlist);
    01553     if (!keep_orderlist) v->orders.list = NULL;
    01554   }
    01555 }
    01556
    01557 Date GetServiceIntervalClamped(uint index)
    01558 {
    01559   return (_settings_game.vehicle.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
    01560 }
    01561
    01569 static bool CheckForValidOrders(const Vehicle *v)
    01570 {
    01571   const Order *order;
    01572
    01573   FOR_VEHICLE_ORDERS(v, order) if (!order->IsType(OT_DUMMY)) return true;
    01574
    01575   return false;
    01576 }
    01577
    01581 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
    01582 {
    01583   switch (occ) {
    01584     case OCC_EQUALS:      return variable == value;
    01585     case OCC_NOT_EQUALS:  return variable != value;
    01586     case OCC_LESS_THAN:   return variable <  value;
    01587     case OCC_LESS_EQUALS: return variable <= value;
    01588     case OCC_MORE_THAN:   return variable >  value;
    01589     case OCC_MORE_EQUALS: return variable >= value;
    01590     case OCC_IS_TRUE:     return variable != 0;
    01591     case OCC_IS_FALSE:    return variable == 0;
    01592     default: NOT_REACHED();
    01593   }
    01594 }
    01595
    01602 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
    01603 {
    01604   if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
    01605
    01606   bool skip_order = false;
    01607   OrderConditionComparator occ = order->GetConditionComparator();
    01608   uint16 value = order->GetConditionValue();
    01609
    01610   switch (order->GetConditionVariable()) {
    01611     case OCV_LOAD_PERCENTAGE:  skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
    01612     case OCV_RELIABILITY:      skip_order = OrderConditionCompare(occ, v->reliability * 100 >> 16,        value); break;
    01613     case OCV_MAX_SPEED:        skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
    01614     case OCV_AGE:              skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR,        value); break;
    01615     case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(),               value); break;
    01616     case OCV_UNCONDITIONALLY:  skip_order = true; break;
    01617     default: NOT_REACHED();
    01618   }
    01619
    01620   return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
    01621 }
    01622
    01628 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
    01629 {
    01630   if (conditional_depth > v->GetNumOrders()) return false;
    01631
    01632   switch (order->GetType()) {
    01633     case OT_GOTO_STATION:
    01634       v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
    01635       return true;
    01636
    01637     case OT_GOTO_DEPOT:
    01638       if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
    01639         /* We need to search for the nearest depot (hangar). */
    01640         TileIndex location;
    01641         DestinationID destination;
    01642         bool reverse;
    01643
    01644         if (v->FindClosestDepot(&location, &destination, &reverse)) {
    01645           v->dest_tile = location;
    01646           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());
    01647
    01648           /* If there is no depot in front, reverse automatically (trains only) */
    01649           if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    01650
    01651           if (v->type == VEH_AIRCRAFT && v->u.air.state == FLYING && v->u.air.targetairport != destination) {
    01652             /* The aircraft is now heading for a different hangar than the next in the orders */
    01653             extern void AircraftNextAirportPos_and_Order(Vehicle *v);
    01654             AircraftNextAirportPos_and_Order(v);
    01655           }
    01656           return true;
    01657         }
    01658
    01659         UpdateVehicleTimetable(v, true);
    01660         v->cur_order_index++;
    01661       } else if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
    01662         UpdateVehicleTimetable(v, true);
    01663         v->cur_order_index++;
    01664       } else {
    01665         if (v->type != VEH_AIRCRAFT) {
    01666           v->dest_tile = GetDepot(order->GetDestination())->xy;
    01667         }
    01668         return true;
    01669       }
    01670       break;
    01671
    01672     case OT_GOTO_WAYPOINT:
    01673       v->dest_tile = GetWaypoint(order->GetDestination())->xy;
    01674       return true;
    01675
    01676     case OT_CONDITIONAL: {
    01677       VehicleOrderID next_order = ProcessConditionalOrder(order, v);
    01678       if (next_order != INVALID_VEH_ORDER_ID) {
    01679         UpdateVehicleTimetable(v, false);
    01680         v->cur_order_index = next_order;
    01681         v->current_order_time += GetVehicleOrder(v, next_order)->travel_time;
    01682       } else {
    01683         UpdateVehicleTimetable(v, true);
    01684         v->cur_order_index++;
    01685       }
    01686       break;
    01687     }
    01688
    01689     default:
    01690       v->dest_tile = 0;
    01691       return false;
    01692   }
    01693
    01694   /* Get the current order */
    01695   if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
    01696
    01697   order = GetVehicleOrder(v, v->cur_order_index);
    01698   v->current_order = *order;
    01699   return UpdateOrderDest(v, order, conditional_depth + 1);
    01700 }
    01701
    01709 bool ProcessOrders(Vehicle *v)
    01710 {
    01711   switch (v->current_order.GetType()) {
    01712     case OT_GOTO_DEPOT:
    01713       /* Let a depot order in the orderlist interrupt. */
    01714       if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
    01715       break;
    01716
    01717     case OT_LOADING:
    01718       return false;
    01719
    01720     case OT_LEAVESTATION:
    01721       if (v->type != VEH_AIRCRAFT) return false;
    01722       break;
    01723
    01724     default: break;
    01725   }
    01726
    01734   bool may_reverse = v->current_order.IsType(OT_NOTHING);
    01735
    01736   /* Check if we've reached the waypoint? */
    01737   if (v->current_order.IsType(OT_GOTO_WAYPOINT) && v->tile == v->dest_tile) {
    01738     UpdateVehicleTimetable(v, true);
    01739     v->cur_order_index++;
    01740   }
    01741
    01742   /* Check if we've reached a non-stop station.. */
    01743   if (v->current_order.IsType(OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
    01744       IsTileType(v->tile, MP_STATION) &&
    01745       v->current_order.GetDestination() == GetStationIndex(v->tile)) {
    01746     v->last_station_visited = v->current_order.GetDestination();
    01747     UpdateVehicleTimetable(v, true);
    01748     v->cur_order_index++;
    01749   }
    01750
    01751   /* Get the current order */
    01752   if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
    01753
    01754   const Order *order = GetVehicleOrder(v, v->cur_order_index);
    01755
    01756   /* If no order, do nothing. */
    01757   if (order == NULL || (v->type == VEH_AIRCRAFT && order->IsType(OT_DUMMY) && !CheckForValidOrders(v))) {
    01758     if (v->type == VEH_AIRCRAFT) {
    01759       /* Aircraft do something vastly different here, so handle separately */
    01760       extern void HandleMissingAircraftOrders(Vehicle *v);
    01761       HandleMissingAircraftOrders(v);
    01762       return false;
    01763     }
    01764
    01765     v->current_order.Free();
    01766     v->dest_tile = 0;
    01767     if (v->type == VEH_ROAD) ClearSlot(v);
    01768     return false;
    01769   }
    01770
    01771   /* If it is unchanged, keep it. */
    01772   if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
    01773       (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || GetStation(order->GetDestination())->dock_tile != INVALID_TILE)) {
    01774     return false;
    01775   }
    01776
    01777   /* Otherwise set it, and determine the destination tile. */
    01778   v->current_order = *order;
    01779
    01780   InvalidateVehicleOrder(v, 0);
    01781   switch (v->type) {
    01782     default:
    01783       NOT_REACHED();
    01784
    01785     case VEH_ROAD:
    01786     case VEH_TRAIN:
    01787       break;
    01788
    01789     case VEH_AIRCRAFT:
    01790     case VEH_SHIP:
    01791       InvalidateWindowClasses(GetWindowClassForVehicleType(v->type));
    01792       break;
    01793   }
    01794
    01795   return UpdateOrderDest(v, order) && may_reverse;
    01796 }
    01797
    01805 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
    01806 {
    01807   bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
    01808   return
    01809       (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
    01810       v->last_station_visited != station && // Do stop only when we've not just been there
    01811       /* Finally do stop when there is no non-stop flag set for this type of station. */
    01812       !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
    01813 }
    01814
    01815 void InitializeOrders()
    01816 {
    01817   _Order_pool.CleanPool();
    01818   _Order_pool.AddBlockToPool();
    01819
    01820   _OrderList_pool.CleanPool();
    01821   _OrderList_pool.AddBlockToPool();
    01822
    01823   _backup_orders_tile = 0;
    01824 }