# ai_order.cpp

Go to the documentation of this file.

    00001 /* $Id: ai_order.cpp 23256 2011-11-18 21:10:44Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "../../stdafx.h"
    00013 #include "ai_order.hpp"
    00014 #include "ai_vehicle.hpp"
    00015 #include "../ai_instance.hpp"
    00016 #include "../../debug.h"
    00017 #include "../../vehicle_base.h"
    00018 #include "../../roadstop_base.h"
    00019 #include "../../depot_base.h"
    00020 #include "../../station_base.h"
    00021 #include "../../waypoint_base.h"
    00022
    00028 static OrderType GetOrderTypeByTile(TileIndex t)
    00029 {
    00030   if (!::IsValidTile(t)) return OT_END;
    00031
    00032   switch (::GetTileType(t)) {
    00033     default: break;
    00034     case MP_STATION:
    00035       if (IsBuoy(t) || IsRailWaypoint(t)) return OT_GOTO_WAYPOINT;
    00036       if (IsHangar(t)) return OT_GOTO_DEPOT;
    00037       return OT_GOTO_STATION;
    00038
    00039     case MP_WATER:   if (::IsShipDepot(t)) return OT_GOTO_DEPOT; break;
    00040     case MP_ROAD:    if (::GetRoadTileType(t) == ROAD_TILE_DEPOT) return OT_GOTO_DEPOT; break;
    00041     case MP_RAILWAY:
    00042       if (IsRailDepot(t)) return OT_GOTO_DEPOT;
    00043       break;
    00044   }
    00045
    00046   return OT_END;
    00047 }
    00048
    00049 /* static */ bool AIOrder::IsValidVehicleOrder(VehicleID vehicle_id, OrderPosition order_position)
    00050 {
    00051   return AIVehicle::IsValidVehicle(vehicle_id) && order_position >= 0 && (order_position < ::Vehicle::Get(vehicle_id)->GetNumManualOrders() || order_position == ORDER_CURRENT);
    00052 }
    00053
    00059 static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition order_position)
    00060 {
    00061   const Vehicle *v = ::Vehicle::Get(vehicle_id);
    00062   if (order_position == AIOrder::ORDER_CURRENT) {
    00063     const Order *order = &v->current_order;
    00064     if (order->GetType() == OT_GOTO_DEPOT && !(order->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return order;
    00065     order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
    00066     if (order_position == AIOrder::ORDER_INVALID) return NULL;
    00067   }
    00068   const Order *order = v->orders.list->GetFirstOrder();
    00069   while (order->GetType() == OT_IMPLICIT) order = order->next;
    00070   while (order_position > 0) {
    00071     order_position = (AIOrder::OrderPosition)(order_position - 1);
    00072     order = order->next;
    00073     while (order->GetType() == OT_IMPLICIT) order = order->next;
    00074   }
    00075   return order;
    00076 }
    00077
    00084 static int AIOrderPositionToRealOrderPosition(VehicleID vehicle_id, AIOrder::OrderPosition order_position)
    00085 {
    00086   const Vehicle *v = ::Vehicle::Get(vehicle_id);
    00087   if (order_position == v->GetNumManualOrders()) return v->GetNumOrders();
    00088
    00089   assert(AIOrder::IsValidVehicleOrder(vehicle_id, order_position));
    00090
    00091   int res = (int)order_position;
    00092   const Order *order = v->orders.list->GetFirstOrder();
    00093   for (; order->GetType() == OT_IMPLICIT; order = order->next) res++;
    00094   while (order_position > 0) {
    00095     order_position = (AIOrder::OrderPosition)(order_position - 1);
    00096     order = order->next;
    00097     for (; order->GetType() == OT_IMPLICIT; order = order->next) res++;
    00098   }
    00099
    00100   return res;
    00101 }
    00102
    00103 /* static */ bool AIOrder::IsGotoStationOrder(VehicleID vehicle_id, OrderPosition order_position)
    00104 {
    00105   if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
    00106
    00107   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00108   return order != NULL && order->GetType() == OT_GOTO_STATION;
    00109 }
    00110
    00111 /* static */ bool AIOrder::IsGotoDepotOrder(VehicleID vehicle_id, OrderPosition order_position)
    00112 {
    00113   if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
    00114
    00115   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00116   return order != NULL && order->GetType() == OT_GOTO_DEPOT;
    00117 }
    00118
    00119 /* static */ bool AIOrder::IsGotoWaypointOrder(VehicleID vehicle_id, OrderPosition order_position)
    00120 {
    00121   if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
    00122
    00123   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00124   return order != NULL && order->GetType() == OT_GOTO_WAYPOINT;
    00125 }
    00126
    00127 /* static */ bool AIOrder::IsConditionalOrder(VehicleID vehicle_id, OrderPosition order_position)
    00128 {
    00129   if (order_position == ORDER_CURRENT) return false;
    00130   if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
    00131
    00132   const Order *order = ::Vehicle::Get(vehicle_id)->GetOrder(AIOrderPositionToRealOrderPosition(vehicle_id, order_position));
    00133   return order->GetType() == OT_CONDITIONAL;
    00134 }
    00135
    00136 /* static */ bool AIOrder::IsVoidOrder(VehicleID vehicle_id, OrderPosition order_position)
    00137 {
    00138   if (order_position == ORDER_CURRENT) return false;
    00139   if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
    00140
    00141   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00142   return order->GetType() == OT_DUMMY;
    00143 }
    00144
    00145 /* static */ bool AIOrder::IsCurrentOrderPartOfOrderList(VehicleID vehicle_id)
    00146 {
    00147   if (!AIVehicle::IsValidVehicle(vehicle_id)) return false;
    00148   if (GetOrderCount(vehicle_id) == 0) return false;
    00149
    00150   const Order *order = &::Vehicle::Get(vehicle_id)->current_order;
    00151   if (order->GetType() != OT_GOTO_DEPOT) return true;
    00152   return (order->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0;
    00153 }
    00154
    00155 /* static */ AIOrder::OrderPosition AIOrder::ResolveOrderPosition(VehicleID vehicle_id, OrderPosition order_position)
    00156 {
    00157   if (!AIVehicle::IsValidVehicle(vehicle_id)) return ORDER_INVALID;
    00158
    00159   if (order_position == ORDER_CURRENT) {
    00160     int cur_order_pos = ::Vehicle::Get(vehicle_id)->cur_real_order_index;
    00161     const Order *order = ::Vehicle::Get(vehicle_id)->GetOrder(0);
    00162     if (order == NULL) return ORDER_INVALID;
    00163     int num_implicit_orders = 0;
    00164     for (int i = 0; i < cur_order_pos; i++) {
    00165       if (order->GetType() == OT_IMPLICIT) num_implicit_orders++;
    00166       order = order->next;
    00167     }
    00168     return (AIOrder::OrderPosition)(cur_order_pos - num_implicit_orders);
    00169   }
    00170   return (order_position >= 0 && order_position < ::Vehicle::Get(vehicle_id)->GetNumManualOrders()) ? order_position : ORDER_INVALID;
    00171 }
    00172
    00173
    00174 /* static */ bool AIOrder::AreOrderFlagsValid(TileIndex destination, AIOrderFlags order_flags)
    00175 {
    00176   OrderType ot = (order_flags & AIOF_GOTO_NEAREST_DEPOT) ? OT_GOTO_DEPOT : ::GetOrderTypeByTile(destination);
    00177   switch (ot) {
    00178     case OT_GOTO_STATION:
    00179       return (order_flags & ~(AIOF_NON_STOP_FLAGS | AIOF_UNLOAD_FLAGS | AIOF_LOAD_FLAGS)) == 0 &&
    00180           /* Test the different mutual exclusive flags. */
    00181           ((order_flags & AIOF_TRANSFER)      == 0 || (order_flags & AIOF_UNLOAD)    == 0) &&
    00182           ((order_flags & AIOF_TRANSFER)      == 0 || (order_flags & AIOF_NO_UNLOAD) == 0) &&
    00183           ((order_flags & AIOF_UNLOAD)        == 0 || (order_flags & AIOF_NO_UNLOAD) == 0) &&
    00184           ((order_flags & AIOF_UNLOAD)        == 0 || (order_flags & AIOF_NO_UNLOAD) == 0) &&
    00185           ((order_flags & AIOF_NO_UNLOAD)     == 0 || (order_flags & AIOF_NO_LOAD)   == 0) &&
    00186           ((order_flags & AIOF_FULL_LOAD_ANY) == 0 || (order_flags & AIOF_NO_LOAD)   == 0);
    00187
    00188     case OT_GOTO_DEPOT:
    00189       return (order_flags & ~(AIOF_NON_STOP_FLAGS | AIOF_DEPOT_FLAGS)) == 0 &&
    00190           ((order_flags & AIOF_SERVICE_IF_NEEDED) == 0 || (order_flags & AIOF_STOP_IN_DEPOT) == 0);
    00191
    00192     case OT_GOTO_WAYPOINT: return (order_flags & ~(AIOF_NON_STOP_FLAGS)) == 0;
    00193     default:               return false;
    00194   }
    00195 }
    00196
    00197 /* static */ bool AIOrder::IsValidConditionalOrder(OrderCondition condition, CompareFunction compare)
    00198 {
    00199   switch (condition) {
    00200     case OC_LOAD_PERCENTAGE:
    00201     case OC_RELIABILITY:
    00202     case OC_MAX_SPEED:
    00203     case OC_AGE:
    00204       return compare >= CF_EQUALS && compare <= CF_MORE_EQUALS;
    00205
    00206     case OC_REQUIRES_SERVICE:
    00207       return compare == CF_IS_TRUE || compare == CF_IS_FALSE;
    00208
    00209     case OC_UNCONDITIONALLY:
    00210       return true;
    00211
    00212     default: return false;
    00213   }
    00214 }
    00215
    00216 /* static */ int32 AIOrder::GetOrderCount(VehicleID vehicle_id)
    00217 {
    00218   return AIVehicle::IsValidVehicle(vehicle_id) ? ::Vehicle::Get(vehicle_id)->GetNumManualOrders() : -1;
    00219 }
    00220
    00221 /* static */ TileIndex AIOrder::GetOrderDestination(VehicleID vehicle_id, OrderPosition order_position)
    00222 {
    00223   if (!IsValidVehicleOrder(vehicle_id, order_position)) return INVALID_TILE;
    00224
    00225   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00226   if (order == NULL || order->GetType() == OT_CONDITIONAL) return INVALID_TILE;
    00227   const Vehicle *v = ::Vehicle::Get(vehicle_id);
    00228
    00229   switch (order->GetType()) {
    00230     case OT_GOTO_DEPOT: {
    00231       /* We don't know where the nearest depot is... (yet) */
    00232       if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) return INVALID_TILE;
    00233
    00234       if (v->type != VEH_AIRCRAFT) return ::Depot::Get(order->GetDestination())->xy;
    00235       /* Aircraft's hangars are referenced by StationID, not DepotID */
    00236       const Station *st = ::Station::Get(order->GetDestination());
    00237       if (!st->airport.HasHangar()) return INVALID_TILE;
    00238       return st->airport.GetHangarTile(0);
    00239     }
    00240
    00241     case OT_GOTO_STATION: {
    00242       const Station *st = ::Station::Get(order->GetDestination());
    00243       if (st->train_station.tile != INVALID_TILE) {
    00244         TILE_AREA_LOOP(t, st->train_station) {
    00245           if (st->TileBelongsToRailStation(t)) return t;
    00246         }
    00247       } else if (st->dock_tile != INVALID_TILE) {
    00248         return st->dock_tile;
    00249       } else if (st->bus_stops != NULL) {
    00250         return st->bus_stops->xy;
    00251       } else if (st->truck_stops != NULL) {
    00252         return st->truck_stops->xy;
    00253       } else if (st->airport.tile != INVALID_TILE) {
    00254         TILE_AREA_LOOP(tile, st->airport) {
    00255           if (st->TileBelongsToAirport(tile) && !::IsHangar(tile)) return tile;
    00256         }
    00257       }
    00258       return INVALID_TILE;
    00259     }
    00260
    00261     case OT_GOTO_WAYPOINT: {
    00262       const Waypoint *wp = ::Waypoint::Get(order->GetDestination());
    00263       if (wp->train_station.tile != INVALID_TILE) {
    00264         TILE_AREA_LOOP(t, wp->train_station) {
    00265           if (wp->TileBelongsToRailStation(t)) return t;
    00266         }
    00267       }
    00268       /* If the waypoint has no rail waypoint tiles, it must have a buoy */
    00269       return wp->xy;
    00270     }
    00271     default:               return INVALID_TILE;
    00272   }
    00273 }
    00274
    00275 /* static */ AIOrder::AIOrderFlags AIOrder::GetOrderFlags(VehicleID vehicle_id, OrderPosition order_position)
    00276 {
    00277   if (!IsValidVehicleOrder(vehicle_id, order_position)) return AIOF_INVALID;
    00278
    00279   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00280   if (order == NULL || order->GetType() == OT_CONDITIONAL || order->GetType() == OT_DUMMY) return AIOF_INVALID;
    00281
    00282   AIOrderFlags order_flags = AIOF_NONE;
    00283   order_flags |= (AIOrderFlags)order->GetNonStopType();
    00284   switch (order->GetType()) {
    00285     case OT_GOTO_DEPOT:
    00286       if (order->GetDepotOrderType() & ODTFB_SERVICE) order_flags |= AIOF_SERVICE_IF_NEEDED;
    00287       if (order->GetDepotActionType() & ODATFB_HALT) order_flags |= AIOF_STOP_IN_DEPOT;
    00288       if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) order_flags |= AIOF_GOTO_NEAREST_DEPOT;
    00289       break;
    00290
    00291     case OT_GOTO_STATION:
    00292       order_flags |= (AIOrderFlags)(order->GetLoadType()   << 5);
    00293       order_flags |= (AIOrderFlags)(order->GetUnloadType() << 2);
    00294       break;
    00295
    00296     default: break;
    00297   }
    00298
    00299   return order_flags;
    00300 }
    00301
    00302 /* static */ AIOrder::OrderPosition AIOrder::GetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position)
    00303 {
    00304   if (!IsValidVehicleOrder(vehicle_id, order_position)) return ORDER_INVALID;
    00305   if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return ORDER_INVALID;
    00306
    00307   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00308   return (OrderPosition)order->GetConditionSkipToOrder();
    00309 }
    00310
    00311 /* static */ AIOrder::OrderCondition AIOrder::GetOrderCondition(VehicleID vehicle_id, OrderPosition order_position)
    00312 {
    00313   if (!IsValidVehicleOrder(vehicle_id, order_position)) return OC_INVALID;
    00314   if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return OC_INVALID;
    00315
    00316   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00317   return (OrderCondition)order->GetConditionVariable();
    00318 }
    00319
    00320 /* static */ AIOrder::CompareFunction AIOrder::GetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position)
    00321 {
    00322   if (!IsValidVehicleOrder(vehicle_id, order_position)) return CF_INVALID;
    00323   if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return CF_INVALID;
    00324
    00325   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00326   return (CompareFunction)order->GetConditionComparator();
    00327 }
    00328
    00329 /* static */ int32 AIOrder::GetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position)
    00330 {
    00331   if (!IsValidVehicleOrder(vehicle_id, order_position)) return -1;
    00332   if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return -1;
    00333
    00334   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00335   int32 value = order->GetConditionValue();
    00336   if (order->GetConditionVariable() == OCV_MAX_SPEED) value = value * 16 / 10;
    00337   return value;
    00338 }
    00339
    00340 /* static */ AIOrder::StopLocation AIOrder::GetStopLocation(VehicleID vehicle_id, OrderPosition order_position)
    00341 {
    00342   if (!IsValidVehicleOrder(vehicle_id, order_position)) return STOPLOCATION_INVALID;
    00343   if (AIVehicle::GetVehicleType(vehicle_id) != AIVehicle::VT_RAIL) return STOPLOCATION_INVALID;
    00344   if (!IsGotoStationOrder(vehicle_id, order_position)) return STOPLOCATION_INVALID;
    00345
    00346   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00347   return (AIOrder::StopLocation)order->GetStopLocation();
    00348 }
    00349
    00350 /* static */ bool AIOrder::SetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to)
    00351 {
    00352   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
    00353   EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
    00354   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to) && jump_to != ORDER_CURRENT);
    00355
    00356   return AIObject::DoCommand(0, vehicle_id | (order_position << 20), MOF_COND_DESTINATION | (jump_to << 4), CMD_MODIFY_ORDER);
    00357 }
    00358
    00359 /* static */ bool AIOrder::SetOrderCondition(VehicleID vehicle_id, OrderPosition order_position, OrderCondition condition)
    00360 {
    00361   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
    00362   EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
    00363   EnforcePrecondition(false, condition >= OC_LOAD_PERCENTAGE && condition <= OC_UNCONDITIONALLY);
    00364
    00365   int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
    00366   return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), MOF_COND_VARIABLE | (condition << 4), CMD_MODIFY_ORDER);
    00367 }
    00368
    00369 /* static */ bool AIOrder::SetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position, CompareFunction compare)
    00370 {
    00371   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
    00372   EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
    00373   EnforcePrecondition(false, compare >= CF_EQUALS && compare <= CF_IS_FALSE);
    00374
    00375   int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
    00376   return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), MOF_COND_COMPARATOR | (compare << 4), CMD_MODIFY_ORDER);
    00377 }
    00378
    00379 /* static */ bool AIOrder::SetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position, int32 value)
    00380 {
    00381   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
    00382   EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
    00383   EnforcePrecondition(false, value >= 0 && value < 2048);
    00384   if (GetOrderCondition(vehicle_id, order_position) == OC_MAX_SPEED) value = value * 10 / 16;
    00385
    00386   int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
    00387   return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), MOF_COND_VALUE | (value << 4), CMD_MODIFY_ORDER);
    00388 }
    00389
    00390 /* static */ bool AIOrder::SetStopLocation(VehicleID vehicle_id, OrderPosition order_position, StopLocation stop_location)
    00391 {
    00392   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
    00393   EnforcePrecondition(false, AIVehicle::GetVehicleType(vehicle_id) == AIVehicle::VT_RAIL);
    00394   EnforcePrecondition(false, IsGotoStationOrder(vehicle_id, order_position));
    00395   EnforcePrecondition(false, stop_location >= STOPLOCATION_NEAR && stop_location <= STOPLOCATION_FAR);
    00396
    00397   order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
    00398
    00399   int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
    00400   uint32 p1 = vehicle_id | (order_pos << 20);
    00401   uint32 p2 = MOF_STOP_LOCATION | (stop_location << 4);
    00402   return AIObject::DoCommand(0, p1, p2, CMD_MODIFY_ORDER);
    00403 }
    00404
    00405 /* static */ bool AIOrder::AppendOrder(VehicleID vehicle_id, TileIndex destination, AIOrderFlags order_flags)
    00406 {
    00407   EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
    00408   EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags));
    00409
    00410   return InsertOrder(vehicle_id, (AIOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumManualOrders(), destination, order_flags);
    00411 }
    00412
    00413 /* static */ bool AIOrder::AppendConditionalOrder(VehicleID vehicle_id, OrderPosition jump_to)
    00414 {
    00415   EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
    00416   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to));
    00417
    00418   return InsertConditionalOrder(vehicle_id, (AIOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumManualOrders(), jump_to);
    00419 }
    00420
    00421 /* static */ bool AIOrder::InsertOrder(VehicleID vehicle_id, OrderPosition order_position, TileIndex destination, AIOrder::AIOrderFlags order_flags)
    00422 {
    00423   /* IsValidVehicleOrder is not good enough because it does not allow appending. */
    00424   if (order_position == ORDER_CURRENT) order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
    00425
    00426   EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
    00427   EnforcePrecondition(false, order_position >= 0 && order_position <= ::Vehicle::Get(vehicle_id)->GetNumManualOrders());
    00428   EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags));
    00429
    00430   Order order;
    00431   OrderType ot = (order_flags & AIOF_GOTO_NEAREST_DEPOT) ? OT_GOTO_DEPOT : ::GetOrderTypeByTile(destination);
    00432   switch (ot) {
    00433     case OT_GOTO_DEPOT: {
    00434       OrderDepotTypeFlags odtf = (OrderDepotTypeFlags)(ODTFB_PART_OF_ORDERS | ((order_flags & AIOF_SERVICE_IF_NEEDED) ? ODTFB_SERVICE : 0));
    00435       OrderDepotActionFlags odaf = (OrderDepotActionFlags)(ODATF_SERVICE_ONLY | ((order_flags & AIOF_STOP_IN_DEPOT) ? ODATFB_HALT : 0));
    00436       if (order_flags & AIOF_GOTO_NEAREST_DEPOT) odaf |= ODATFB_NEAREST_DEPOT;
    00437       OrderNonStopFlags onsf = (OrderNonStopFlags)((order_flags & AIOF_NON_STOP_INTERMEDIATE) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
    00438       if (order_flags & AIOF_GOTO_NEAREST_DEPOT) {
    00439         order.MakeGoToDepot(0, odtf, onsf, odaf);
    00440       } else {
    00441         /* Check explicitly if the order is to a station (for aircraft) or
    00442          * to a depot (other vehicle types). */
    00443         if (::Vehicle::Get(vehicle_id)->type == VEH_AIRCRAFT) {
    00444           if (!::IsTileType(destination, MP_STATION)) return false;
    00445           order.MakeGoToDepot(::GetStationIndex(destination), odtf, onsf, odaf);
    00446         } else {
    00447           if (::IsTileType(destination, MP_STATION)) return false;
    00448           order.MakeGoToDepot(::GetDepotIndex(destination), odtf, onsf, odaf);
    00449         }
    00450       }
    00451       break;
    00452     }
    00453
    00454     case OT_GOTO_STATION:
    00455       order.MakeGoToStation(::GetStationIndex(destination));
    00456       order.SetLoadType((OrderLoadFlags)GB(order_flags, 5, 3));
    00457       order.SetUnloadType((OrderUnloadFlags)GB(order_flags, 2, 3));
    00458       order.SetStopLocation(OSL_PLATFORM_FAR_END);
    00459       break;
    00460
    00461     case OT_GOTO_WAYPOINT:
    00462       order.MakeGoToWaypoint(::GetStationIndex(destination));
    00463       break;
    00464
    00465     default:
    00466       return false;
    00467   }
    00468
    00469   order.SetNonStopType((OrderNonStopFlags)GB(order_flags, 0, 2));
    00470
    00471   int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
    00472   return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), order.Pack(), CMD_INSERT_ORDER);
    00473 }
    00474
    00475 /* static */ bool AIOrder::InsertConditionalOrder(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to)
    00476 {
    00477   /* IsValidVehicleOrder is not good enough because it does not allow appending. */
    00478   if (order_position == ORDER_CURRENT) order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
    00479
    00480   EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
    00481   EnforcePrecondition(false, order_position >= 0 && order_position <= ::Vehicle::Get(vehicle_id)->GetNumManualOrders());
    00482   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to) && jump_to != ORDER_CURRENT);
    00483
    00484   Order order;
    00485   order.MakeConditional(jump_to);
    00486
    00487   int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
    00488   return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), order.Pack(), CMD_INSERT_ORDER);
    00489 }
    00490
    00491 /* static */ bool AIOrder::RemoveOrder(VehicleID vehicle_id, OrderPosition order_position)
    00492 {
    00493   order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
    00494
    00495   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
    00496
    00497   int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
    00498   return AIObject::DoCommand(0, vehicle_id, order_pos, CMD_DELETE_ORDER);
    00499 }
    00500
    00501 /* static */ bool AIOrder::SkipToOrder(VehicleID vehicle_id, OrderPosition next_order)
    00502 {
    00503   next_order = AIOrder::ResolveOrderPosition(vehicle_id, next_order);
    00504
    00505   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, next_order));
    00506
    00507   int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, next_order);
    00508   return AIObject::DoCommand(0, vehicle_id, order_pos, CMD_SKIP_TO_ORDER);
    00509 }
    00510
    00519 static void _DoCommandReturnSetOrderFlags(class AIInstance *instance)
    00520 {
    00521   AIObject::SetLastCommandRes(AIOrder::_SetOrderFlags());
    00522   AIInstance::DoCommandReturn(instance);
    00523 }
    00524
    00525 /* static */ bool AIOrder::_SetOrderFlags()
    00526 {
    00527   /* Make sure we don't go into an infinite loop */
    00528   int retry = AIObject::GetCallbackVariable(3) - 1;
    00529   if (retry < 0) {
    00530     DEBUG(ai, 0, "Possible infinite loop in SetOrderFlags() detected");
    00531     return false;
    00532   }
    00533   AIObject::SetCallbackVariable(3, retry);
    00534
    00535   VehicleID vehicle_id = (VehicleID)AIObject::GetCallbackVariable(0);
    00536   OrderPosition order_position = (OrderPosition)AIObject::GetCallbackVariable(1);
    00537   AIOrderFlags order_flags = (AIOrderFlags)AIObject::GetCallbackVariable(2);
    00538
    00539   order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
    00540
    00541   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
    00542   EnforcePrecondition(false, AreOrderFlagsValid(GetOrderDestination(vehicle_id, order_position), order_flags));
    00543
    00544   const Order *order = ::ResolveOrder(vehicle_id, order_position);
    00545   int order_pos = AIOrderPositionToRealOrderPosition(vehicle_id, order_position);
    00546
    00547   AIOrderFlags current = GetOrderFlags(vehicle_id, order_position);
    00548
    00549   EnforcePrecondition(false, (order_flags & AIOF_GOTO_NEAREST_DEPOT) == (current & AIOF_GOTO_NEAREST_DEPOT));
    00550
    00551   if ((current & AIOF_NON_STOP_FLAGS) != (order_flags & AIOF_NON_STOP_FLAGS)) {
    00552     return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & AIOF_NON_STOP_FLAGS) << 4 | MOF_NON_STOP, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
    00553   }
    00554
    00555   switch (order->GetType()) {
    00556     case OT_GOTO_DEPOT:
    00557       if ((current & AIOF_DEPOT_FLAGS) != (order_flags & AIOF_DEPOT_FLAGS)) {
    00558         uint data = DA_ALWAYS_GO;
    00559         if (order_flags & AIOF_SERVICE_IF_NEEDED) data = DA_SERVICE;
    00560         if (order_flags & AIOF_STOP_IN_DEPOT) data = DA_STOP;
    00561         return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), (data << 4) | MOF_DEPOT_ACTION, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
    00562       }
    00563       break;
    00564
    00565     case OT_GOTO_STATION:
    00566       if ((current & AIOF_UNLOAD_FLAGS) != (order_flags & AIOF_UNLOAD_FLAGS)) {
    00567         return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & AIOF_UNLOAD_FLAGS) << 2 | MOF_UNLOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
    00568       }
    00569       if ((current & AIOF_LOAD_FLAGS) != (order_flags & AIOF_LOAD_FLAGS)) {
    00570         return AIObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & AIOF_LOAD_FLAGS) >> 1 | MOF_LOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags);
    00571       }
    00572       break;
    00573
    00574     default: break;
    00575   }
    00576
    00577   assert(GetOrderFlags(vehicle_id, order_position) == order_flags);
    00578
    00579   return true;
    00580 }
    00581
    00582 /* static */ bool AIOrder::SetOrderFlags(VehicleID vehicle_id, OrderPosition order_position, AIOrder::AIOrderFlags order_flags)
    00583 {
    00584   AIObject::SetCallbackVariable(0, vehicle_id);
    00585   AIObject::SetCallbackVariable(1, order_position);
    00586   AIObject::SetCallbackVariable(2, order_flags);
    00587   /* In case another client(s) change orders at the same time we could
    00588    * end in an infinite loop. This stops that from happening ever. */
    00589   AIObject::SetCallbackVariable(3, 8);
    00590   return AIOrder::_SetOrderFlags();
    00591 }
    00592
    00593 /* static */ bool AIOrder::MoveOrder(VehicleID vehicle_id, OrderPosition order_position_move, OrderPosition order_position_target)
    00594 {
    00595   order_position_move   = AIOrder::ResolveOrderPosition(vehicle_id, order_position_move);
    00596   order_position_target = AIOrder::ResolveOrderPosition(vehicle_id, order_position_target);
    00597
    00598   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_move));
    00599   EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_target));
    00600
    00601   int order_pos_move = AIOrderPositionToRealOrderPosition(vehicle_id, order_position_move);
    00602   int order_pos_target = AIOrderPositionToRealOrderPosition(vehicle_id, order_position_target);
    00603   return AIObject::DoCommand(0, vehicle_id, order_pos_move | (order_pos_target << 16), CMD_MOVE_ORDER);
    00604 }
    00605
    00606 /* static */ bool AIOrder::CopyOrders(VehicleID vehicle_id, VehicleID main_vehicle_id)
    00607 {
    00608   EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
    00609   EnforcePrecondition(false, AIVehicle::IsValidVehicle(main_vehicle_id));
    00610
    00611   return AIObject::DoCommand(0, vehicle_id | CO_COPY << 30, main_vehicle_id, CMD_CLONE_ORDER);
    00612 }
    00613
    00614 /* static */ bool AIOrder::ShareOrders(VehicleID vehicle_id, VehicleID main_vehicle_id)
    00615 {
    00616   EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
    00617   EnforcePrecondition(false, AIVehicle::IsValidVehicle(main_vehicle_id));
    00618
    00619   return AIObject::DoCommand(0, vehicle_id | CO_SHARE << 30, main_vehicle_id, CMD_CLONE_ORDER);
    00620 }
    00621
    00622 /* static */ bool AIOrder::UnshareOrders(VehicleID vehicle_id)
    00623 {
    00624   EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
    00625
    00626   return AIObject::DoCommand(0, vehicle_id | CO_UNSHARE << 30, 0, CMD_CLONE_ORDER);
    00627 }