00001
00002
00005 #include "ai_order.hpp"
00006 #include "ai_vehicle.hpp"
00007 #include "../ai_instance.hpp"
00008 #include "../../debug.h"
00009 #include "../../vehicle_base.h"
00010 #include "../../depot_base.h"
00011 #include "../../station_map.h"
00012 #include "../../waypoint.h"
00013
00019 static OrderType GetOrderTypeByTile(TileIndex t)
00020 {
00021 if (!::IsValidTile(t)) return OT_END;
00022
00023 switch (::GetTileType(t)) {
00024 default: break;
00025 case MP_STATION: return OT_GOTO_STATION; break;
00026 case MP_WATER: if (::IsShipDepot(t)) return OT_GOTO_DEPOT; break;
00027 case MP_ROAD: if (::GetRoadTileType(t) == ROAD_TILE_DEPOT) return OT_GOTO_DEPOT; break;
00028 case MP_RAILWAY:
00029 switch (::GetRailTileType(t)) {
00030 case RAIL_TILE_DEPOT: return OT_GOTO_DEPOT;
00031 case RAIL_TILE_WAYPOINT: return OT_GOTO_WAYPOINT;
00032 default: break;
00033 }
00034 break;
00035 }
00036
00037 return OT_END;
00038 }
00039
00040 bool AIOrder::IsValidVehicleOrder(VehicleID vehicle_id, OrderPosition order_position)
00041 {
00042 return AIVehicle::IsValidVehicle(vehicle_id) && order_position >= 0 && (order_position < ::GetVehicle(vehicle_id)->GetNumOrders() || order_position == ORDER_CURRENT);
00043 }
00044
00045 AIOrder::OrderPosition AIOrder::ResolveOrderPosition(VehicleID vehicle_id, OrderPosition order_position)
00046 {
00047 if (!AIVehicle::IsValidVehicle(vehicle_id)) return ORDER_INVALID;
00048
00049 if (order_position == ORDER_CURRENT) return (AIOrder::OrderPosition)::GetVehicle(vehicle_id)->cur_order_index;
00050 return (order_position >= 0 && order_position < ::GetVehicle(vehicle_id)->GetNumOrders()) ? order_position : ORDER_INVALID;
00051 }
00052
00053
00054 bool AIOrder::AreOrderFlagsValid(TileIndex destination, AIOrderFlags order_flags)
00055 {
00056 switch (::GetOrderTypeByTile(destination)) {
00057 case OT_GOTO_STATION:
00058 return ((order_flags & ~(AIOF_NON_STOP_FLAGS | AIOF_UNLOAD_FLAGS | AIOF_LOAD_FLAGS)) == 0) &&
00059
00060 (((order_flags & AIOF_TRANSFER) == 0) || ((order_flags & AIOF_UNLOAD) == 0)) &&
00061 (((order_flags & AIOF_TRANSFER) == 0) || ((order_flags & AIOF_NO_UNLOAD) == 0)) &&
00062 (((order_flags & AIOF_UNLOAD) == 0) || ((order_flags & AIOF_NO_UNLOAD) == 0)) &&
00063 (((order_flags & AIOF_UNLOAD) == 0) || ((order_flags & AIOF_NO_UNLOAD) == 0)) &&
00064 (((order_flags & AIOF_NO_UNLOAD) == 0) || ((order_flags & AIOF_NO_LOAD) == 0)) &&
00065 (((order_flags & AIOF_FULL_LOAD_ANY) == 0) || ((order_flags & AIOF_NO_LOAD) == 0));
00066
00067 case OT_GOTO_DEPOT: return (order_flags & ~(AIOF_NON_STOP_FLAGS | AIOF_SERVICE_IF_NEEDED)) == 0;
00068 case OT_GOTO_WAYPOINT: return (order_flags & ~(AIOF_NON_STOP_FLAGS)) == 0;
00069 default: return false;
00070 }
00071 }
00072
00073 int32 AIOrder::GetOrderCount(VehicleID vehicle_id)
00074 {
00075 return AIVehicle::IsValidVehicle(vehicle_id) ? ::GetVehicle(vehicle_id)->GetNumOrders() : -1;
00076 }
00077
00078 TileIndex AIOrder::GetOrderDestination(VehicleID vehicle_id, OrderPosition order_position)
00079 {
00080 if (!IsValidVehicleOrder(vehicle_id, order_position)) return INVALID_TILE;
00081
00082 const Order *order;
00083 const Vehicle *v = ::GetVehicle(vehicle_id);
00084 if (order_position == ORDER_CURRENT) {
00085 order = &v->current_order;
00086 } else {
00087 order = v->GetFirstOrder();
00088 for (int i = 0; i < order_position; i++) order = order->next;
00089 }
00090
00091 switch (order->GetType()) {
00092 case OT_GOTO_DEPOT:
00093 if (v->type != VEH_AIRCRAFT) return ::GetDepot(order->GetDestination())->xy;
00094
00095
00096 case OT_GOTO_STATION: return ::GetStation(order->GetDestination())->xy;
00097 case OT_GOTO_WAYPOINT: return ::GetWaypoint(order->GetDestination())->xy;
00098 default: return INVALID_TILE;
00099 }
00100 }
00101
00102 AIOrder::AIOrderFlags AIOrder::GetOrderFlags(VehicleID vehicle_id, OrderPosition order_position)
00103 {
00104 if (!IsValidVehicleOrder(vehicle_id, order_position)) return AIOF_INVALID;
00105
00106 const Order *order;
00107 if (order_position == ORDER_CURRENT) {
00108 order = &::GetVehicle(vehicle_id)->current_order;
00109 } else {
00110 order = ::GetVehicle(vehicle_id)->GetFirstOrder();
00111 for (int i = 0; i < order_position; i++) order = order->next;
00112 }
00113
00114 AIOrderFlags order_flags = AIOF_NONE;
00115 order_flags |= (AIOrderFlags)order->GetNonStopType();
00116 switch (order->GetType()) {
00117 case OT_GOTO_DEPOT:
00118 if (order->GetDepotOrderType() & ODTFB_SERVICE) order_flags |= AIOF_SERVICE_IF_NEEDED;
00119 break;
00120
00121 case OT_GOTO_STATION:
00122 order_flags |= (AIOrderFlags)(order->GetLoadType() << 5);
00123 order_flags |= (AIOrderFlags)(order->GetUnloadType() << 2);
00124 break;
00125
00126 default: break;
00127 }
00128
00129 return order_flags;
00130 }
00131
00132 bool AIOrder::AppendOrder(VehicleID vehicle_id, TileIndex destination, AIOrderFlags order_flags)
00133 {
00134 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00135 return InsertOrder(vehicle_id, (AIOrder::OrderPosition)::GetVehicle(vehicle_id)->GetNumOrders(), destination, order_flags);
00136 }
00137
00138 bool AIOrder::InsertOrder(VehicleID vehicle_id, OrderPosition order_position, TileIndex destination, AIOrder::AIOrderFlags order_flags)
00139 {
00140
00141 if (order_position == ORDER_CURRENT) order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
00142
00143 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00144 EnforcePrecondition(false, order_position >= 0 && order_position <= ::GetVehicle(vehicle_id)->GetNumOrders());
00145 EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags));
00146
00147 Order order;
00148 switch (::GetOrderTypeByTile(destination)) {
00149 case OT_GOTO_DEPOT:
00150 order.MakeGoToDepot(::GetDepotByTile(destination)->index, (OrderDepotTypeFlags)(ODTFB_PART_OF_ORDERS | ((order_flags & AIOF_SERVICE_IF_NEEDED) ? ODTFB_SERVICE : 0)));
00151 break;
00152
00153 case OT_GOTO_STATION:
00154 order.MakeGoToStation(::GetStationIndex(destination));
00155 order.SetLoadType((OrderLoadFlags)GB(order_flags, 5, 3));
00156 order.SetUnloadType((OrderUnloadFlags)GB(order_flags, 2, 3));
00157 break;
00158
00159 case OT_GOTO_WAYPOINT:
00160 order.MakeGoToWaypoint(::GetWaypointIndex(destination));
00161 break;
00162
00163 default:
00164 return false;
00165 }
00166
00167 order.SetNonStopType((OrderNonStopFlags)GB(order_flags, 0, 2));
00168
00169 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), order.Pack(), CMD_INSERT_ORDER);
00170 }
00171
00172 bool AIOrder::RemoveOrder(VehicleID vehicle_id, OrderPosition order_position)
00173 {
00174 order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
00175
00176 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
00177
00178 return AIObject::DoCommand(0, vehicle_id, order_position, CMD_DELETE_ORDER);
00179 }
00180
00189 static void _DoCommandReturnChangeOrder(class AIInstance *instance)
00190 {
00191 AIObject::SetLastCommandRes(AIOrder::_ChangeOrder());
00192 AIInstance::DoCommandReturn(instance);
00193 }
00194
00195 bool AIOrder::_ChangeOrder()
00196 {
00197
00198 int retry = AIObject::GetCallbackVariable(3) - 1;
00199 if (retry < 0) {
00200 DEBUG(ai, 0, "Possible infinite loop in ChangeOrder detected");
00201 return false;
00202 }
00203 AIObject::SetCallbackVariable(3, retry);
00204
00205 VehicleID vehicle_id = (VehicleID)AIObject::GetCallbackVariable(0);
00206 OrderPosition order_position = (OrderPosition)AIObject::GetCallbackVariable(1);
00207 AIOrderFlags order_flags = (AIOrderFlags)AIObject::GetCallbackVariable(2);
00208
00209 order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
00210
00211 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
00212 EnforcePrecondition(false, AreOrderFlagsValid(GetOrderDestination(vehicle_id, order_position), order_flags));
00213
00214 Order *order = ::GetVehicle(vehicle_id)->GetFirstOrder();
00215 for (int i = 0; i < order_position; i++) order = order->next;
00216
00217 AIOrderFlags current = GetOrderFlags(vehicle_id, order_position);
00218
00219 if ((current & AIOF_NON_STOP_FLAGS) != (order_flags & AIOF_NON_STOP_FLAGS)) {
00220 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), (order_flags & AIOF_NON_STOP_FLAGS) << 4 | MOF_NON_STOP, CMD_MODIFY_ORDER, NULL, &_DoCommandReturnChangeOrder);
00221 }
00222
00223 switch (order->GetType()) {
00224 case OT_GOTO_DEPOT:
00225 if ((current & AIOF_SERVICE_IF_NEEDED) != (order_flags & AIOF_SERVICE_IF_NEEDED)) {
00226 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), MOF_DEPOT_ACTION, CMD_MODIFY_ORDER, NULL, &_DoCommandReturnChangeOrder);
00227 }
00228 break;
00229
00230 case OT_GOTO_STATION:
00231 if ((current & AIOF_UNLOAD_FLAGS) != (order_flags & AIOF_UNLOAD_FLAGS)) {
00232 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), (order_flags & AIOF_UNLOAD_FLAGS) << 2 | MOF_UNLOAD, CMD_MODIFY_ORDER, NULL, &_DoCommandReturnChangeOrder);
00233 }
00234 if ((current & AIOF_LOAD_FLAGS) != (order_flags & AIOF_LOAD_FLAGS)) {
00235 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), (order_flags & AIOF_LOAD_FLAGS) >> 1 | MOF_LOAD, CMD_MODIFY_ORDER, NULL, &_DoCommandReturnChangeOrder);
00236 }
00237 break;
00238
00239 default: break;
00240 }
00241
00242 assert(GetOrderFlags(vehicle_id, order_position) == order_flags);
00243
00244 return true;
00245 }
00246
00247 bool AIOrder::ChangeOrder(VehicleID vehicle_id, OrderPosition order_position, AIOrder::AIOrderFlags order_flags)
00248 {
00249 AIObject::SetCallbackVariable(0, vehicle_id);
00250 AIObject::SetCallbackVariable(1, order_position);
00251 AIObject::SetCallbackVariable(2, order_flags);
00252
00253
00254 AIObject::SetCallbackVariable(3, 8);
00255 return AIOrder::_ChangeOrder();
00256 }
00257
00258 bool AIOrder::MoveOrder(VehicleID vehicle_id, OrderPosition order_position_move, OrderPosition order_position_target)
00259 {
00260 order_position_move = AIOrder::ResolveOrderPosition(vehicle_id, order_position_move);
00261 order_position_target = AIOrder::ResolveOrderPosition(vehicle_id, order_position_target);
00262
00263 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_move));
00264 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_target));
00265
00266 return AIObject::DoCommand(0, vehicle_id, order_position_move | (order_position_target << 16), CMD_MOVE_ORDER);
00267 }
00268
00269 bool AIOrder::CopyOrders(VehicleID vehicle_id, VehicleID main_vehicle_id)
00270 {
00271 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00272 EnforcePrecondition(false, AIVehicle::IsValidVehicle(main_vehicle_id));
00273
00274 return AIObject::DoCommand(0, vehicle_id | (main_vehicle_id << 16), CO_COPY, CMD_CLONE_ORDER);
00275 }
00276
00277 bool AIOrder::ShareOrders(VehicleID vehicle_id, VehicleID main_vehicle_id)
00278 {
00279 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00280 EnforcePrecondition(false, AIVehicle::IsValidVehicle(main_vehicle_id));
00281
00282 return AIObject::DoCommand(0, vehicle_id | (main_vehicle_id << 16), CO_SHARE, CMD_CLONE_ORDER);
00283 }
00284
00285 bool AIOrder::UnshareOrders(VehicleID vehicle_id)
00286 {
00287 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00288
00289 return AIObject::DoCommand(0, vehicle_id, CO_UNSHARE, CMD_CLONE_ORDER);
00290 }