00001
00002
00005 #include "ai_order.hpp"
00006 #include "ai_vehicle.hpp"
00007 #include "ai_log.hpp"
00008 #include "../ai_instance.hpp"
00009 #include "../../debug.h"
00010 #include "../../vehicle_base.h"
00011 #include "../../depot_base.h"
00012 #include "../../station_map.h"
00013 #include "../../waypoint.h"
00014
00020 static OrderType GetOrderTypeByTile(TileIndex t)
00021 {
00022 if (!::IsValidTile(t)) return OT_END;
00023
00024 switch (::GetTileType(t)) {
00025 default: break;
00026 case MP_STATION: return OT_GOTO_STATION; break;
00027 case MP_WATER: if (::IsShipDepot(t)) return OT_GOTO_DEPOT; break;
00028 case MP_ROAD: if (::GetRoadTileType(t) == ROAD_TILE_DEPOT) return OT_GOTO_DEPOT; break;
00029 case MP_RAILWAY:
00030 switch (::GetRailTileType(t)) {
00031 case RAIL_TILE_DEPOT: return OT_GOTO_DEPOT;
00032 case RAIL_TILE_WAYPOINT: return OT_GOTO_WAYPOINT;
00033 default: break;
00034 }
00035 break;
00036 }
00037
00038 return OT_END;
00039 }
00040
00041 bool AIOrder::IsValidVehicleOrder(VehicleID vehicle_id, OrderPosition order_position)
00042 {
00043 return AIVehicle::IsValidVehicle(vehicle_id) && order_position >= 0 && (order_position < ::GetVehicle(vehicle_id)->GetNumOrders() || order_position == ORDER_CURRENT);
00044 }
00045
00046 bool AIOrder::IsConditionalOrder(VehicleID vehicle_id, OrderPosition order_position)
00047 {
00048 if (order_position == ORDER_CURRENT) return false;
00049 if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
00050
00051 const Order *order = ::GetVehicleOrder(GetVehicle(vehicle_id), order_position);
00052 return order->GetType() == OT_CONDITIONAL;
00053 }
00054
00055 AIOrder::OrderPosition AIOrder::ResolveOrderPosition(VehicleID vehicle_id, OrderPosition order_position)
00056 {
00057 if (!AIVehicle::IsValidVehicle(vehicle_id)) return ORDER_INVALID;
00058
00059 if (order_position == ORDER_CURRENT) return (AIOrder::OrderPosition)::GetVehicle(vehicle_id)->cur_order_index;
00060 return (order_position >= 0 && order_position < ::GetVehicle(vehicle_id)->GetNumOrders()) ? order_position : ORDER_INVALID;
00061 }
00062
00063
00064 bool AIOrder::AreOrderFlagsValid(TileIndex destination, AIOrderFlags order_flags)
00065 {
00066 switch (::GetOrderTypeByTile(destination)) {
00067 case OT_GOTO_STATION:
00068 return ((order_flags & ~(AIOF_NON_STOP_FLAGS | AIOF_UNLOAD_FLAGS | AIOF_LOAD_FLAGS)) == 0) &&
00069
00070 (((order_flags & AIOF_TRANSFER) == 0) || ((order_flags & AIOF_UNLOAD) == 0)) &&
00071 (((order_flags & AIOF_TRANSFER) == 0) || ((order_flags & AIOF_NO_UNLOAD) == 0)) &&
00072 (((order_flags & AIOF_UNLOAD) == 0) || ((order_flags & AIOF_NO_UNLOAD) == 0)) &&
00073 (((order_flags & AIOF_UNLOAD) == 0) || ((order_flags & AIOF_NO_UNLOAD) == 0)) &&
00074 (((order_flags & AIOF_NO_UNLOAD) == 0) || ((order_flags & AIOF_NO_LOAD) == 0)) &&
00075 (((order_flags & AIOF_FULL_LOAD_ANY) == 0) || ((order_flags & AIOF_NO_LOAD) == 0));
00076
00077 case OT_GOTO_DEPOT: return (order_flags & ~(AIOF_NON_STOP_FLAGS | AIOF_SERVICE_IF_NEEDED)) == 0;
00078 case OT_GOTO_WAYPOINT: return (order_flags & ~(AIOF_NON_STOP_FLAGS)) == 0;
00079 default: return false;
00080 }
00081 }
00082
00083 bool AIOrder::IsValidConditionalOrder(OrderCondition condition, CompareFunction compare)
00084 {
00085 switch (condition) {
00086 case OC_LOAD_PERCENTAGE:
00087 case OC_RELIABILITY:
00088 case OC_MAX_SPEED:
00089 case OC_AGE:
00090 return compare >= CF_EQUALS && compare <= CF_MORE_EQUALS;
00091
00092 case OC_REQUIRES_SERVICE:
00093 return compare == CF_IS_TRUE || compare == CF_IS_FALSE;
00094
00095 case OC_UNCONDITIONALLY:
00096 return true;
00097
00098 default: return false;
00099 }
00100 }
00101
00102 int32 AIOrder::GetOrderCount(VehicleID vehicle_id)
00103 {
00104 return AIVehicle::IsValidVehicle(vehicle_id) ? ::GetVehicle(vehicle_id)->GetNumOrders() : -1;
00105 }
00106
00107 TileIndex AIOrder::GetOrderDestination(VehicleID vehicle_id, OrderPosition order_position)
00108 {
00109 if (!IsValidVehicleOrder(vehicle_id, order_position)) return INVALID_TILE;
00110
00111 const Order *order;
00112 const Vehicle *v = ::GetVehicle(vehicle_id);
00113 if (order_position == ORDER_CURRENT) {
00114 order = &v->current_order;
00115 } else {
00116 order = ::GetVehicleOrder(GetVehicle(vehicle_id), order_position);
00117 if (order->GetType() == OT_CONDITIONAL) return INVALID_TILE;
00118 }
00119
00120 switch (order->GetType()) {
00121 case OT_GOTO_DEPOT:
00122 if (v->type != VEH_AIRCRAFT) return ::GetDepot(order->GetDestination())->xy;
00123
00124
00125 case OT_GOTO_STATION: return ::GetStation(order->GetDestination())->xy;
00126 case OT_GOTO_WAYPOINT: return ::GetWaypoint(order->GetDestination())->xy;
00127 default: return INVALID_TILE;
00128 }
00129 }
00130
00131 AIOrder::AIOrderFlags AIOrder::GetOrderFlags(VehicleID vehicle_id, OrderPosition order_position)
00132 {
00133 if (!IsValidVehicleOrder(vehicle_id, order_position)) return AIOF_INVALID;
00134
00135 const Order *order;
00136 if (order_position == ORDER_CURRENT) {
00137 order = &::GetVehicle(vehicle_id)->current_order;
00138 } else {
00139 order = ::GetVehicleOrder(GetVehicle(vehicle_id), order_position);
00140 if (order->GetType() == OT_CONDITIONAL) return AIOF_INVALID;
00141 }
00142
00143 AIOrderFlags order_flags = AIOF_NONE;
00144 order_flags |= (AIOrderFlags)order->GetNonStopType();
00145 switch (order->GetType()) {
00146 case OT_GOTO_DEPOT:
00147 if (order->GetDepotOrderType() & ODTFB_SERVICE) order_flags |= AIOF_SERVICE_IF_NEEDED;
00148 break;
00149
00150 case OT_GOTO_STATION:
00151 order_flags |= (AIOrderFlags)(order->GetLoadType() << 5);
00152 order_flags |= (AIOrderFlags)(order->GetUnloadType() << 2);
00153 break;
00154
00155 default: break;
00156 }
00157
00158 return order_flags;
00159 }
00160
00161 AIOrder::OrderPosition AIOrder::GetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position)
00162 {
00163 if (!IsValidVehicleOrder(vehicle_id, order_position)) return ORDER_INVALID;
00164 if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return ORDER_INVALID;
00165
00166 const Order *order = ::GetVehicleOrder(GetVehicle(vehicle_id), order_position);
00167 return (OrderPosition)order->GetConditionSkipToOrder();
00168 }
00169
00170 AIOrder::OrderCondition AIOrder::GetOrderCondition(VehicleID vehicle_id, OrderPosition order_position)
00171 {
00172 if (!IsValidVehicleOrder(vehicle_id, order_position)) return OC_INVALID;
00173 if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return OC_INVALID;
00174
00175 const Order *order = ::GetVehicleOrder(GetVehicle(vehicle_id), order_position);
00176 return (OrderCondition)order->GetConditionVariable();
00177 }
00178
00179 AIOrder::CompareFunction AIOrder::GetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position)
00180 {
00181 if (!IsValidVehicleOrder(vehicle_id, order_position)) return CF_INVALID;
00182 if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return CF_INVALID;
00183
00184 const Order *order = ::GetVehicleOrder(GetVehicle(vehicle_id), order_position);
00185 return (CompareFunction)order->GetConditionComparator();
00186 }
00187
00188 int32 AIOrder::GetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position)
00189 {
00190 if (!IsValidVehicleOrder(vehicle_id, order_position)) return -1;
00191 if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return -1;
00192
00193 const Order *order = ::GetVehicleOrder(GetVehicle(vehicle_id), order_position);
00194 int32 value = order->GetConditionValue();
00195 if (order->GetConditionVariable() == OCV_MAX_SPEED) value = value * 16 / 10;
00196 return value;
00197 }
00198
00199 bool AIOrder::SetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to)
00200 {
00201 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
00202 EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
00203 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to) && jump_to != ORDER_CURRENT);
00204
00205 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), MOF_COND_DESTINATION | (jump_to << 4), CMD_MODIFY_ORDER);
00206 }
00207
00208 bool AIOrder::SetOrderCondition(VehicleID vehicle_id, OrderPosition order_position, OrderCondition condition)
00209 {
00210 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
00211 EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
00212 EnforcePrecondition(false, condition >= OC_LOAD_PERCENTAGE && condition <= OC_UNCONDITIONALLY);
00213
00214 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), MOF_COND_VARIABLE | (condition << 4), CMD_MODIFY_ORDER);
00215 }
00216
00217 bool AIOrder::SetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position, CompareFunction compare)
00218 {
00219 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
00220 EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
00221 EnforcePrecondition(false, compare >= CF_EQUALS && compare <= CF_IS_FALSE);
00222
00223 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), MOF_COND_COMPARATOR | (compare << 4), CMD_MODIFY_ORDER);
00224 }
00225
00226 bool AIOrder::SetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position, int32 value)
00227 {
00228 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
00229 EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
00230 EnforcePrecondition(false, value >= 0 && value < 2048);
00231 if (GetOrderCondition(vehicle_id, order_position) == OC_MAX_SPEED) value = value * 10 / 16;
00232
00233 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), MOF_COND_VALUE | (value << 4), CMD_MODIFY_ORDER);
00234 }
00235
00236 bool AIOrder::AppendOrder(VehicleID vehicle_id, TileIndex destination, AIOrderFlags order_flags)
00237 {
00238 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00239 EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags));
00240
00241 return InsertOrder(vehicle_id, (AIOrder::OrderPosition)::GetVehicle(vehicle_id)->GetNumOrders(), destination, order_flags);
00242 }
00243
00244 bool AIOrder::AppendConditionalOrder(VehicleID vehicle_id, OrderPosition jump_to)
00245 {
00246 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00247 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to));
00248
00249 return InsertConditionalOrder(vehicle_id, (AIOrder::OrderPosition)::GetVehicle(vehicle_id)->GetNumOrders(), jump_to);
00250 }
00251
00252 bool AIOrder::InsertOrder(VehicleID vehicle_id, OrderPosition order_position, TileIndex destination, AIOrder::AIOrderFlags order_flags)
00253 {
00254
00255 if (order_position == ORDER_CURRENT) order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
00256
00257 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00258 EnforcePrecondition(false, order_position >= 0 && order_position <= ::GetVehicle(vehicle_id)->GetNumOrders());
00259 EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags));
00260
00261 Order order;
00262 switch (::GetOrderTypeByTile(destination)) {
00263 case OT_GOTO_DEPOT:
00264 order.MakeGoToDepot(::GetDepotByTile(destination)->index, (OrderDepotTypeFlags)(ODTFB_PART_OF_ORDERS | ((order_flags & AIOF_SERVICE_IF_NEEDED) ? ODTFB_SERVICE : 0)));
00265 break;
00266
00267 case OT_GOTO_STATION:
00268 order.MakeGoToStation(::GetStationIndex(destination));
00269 order.SetLoadType((OrderLoadFlags)GB(order_flags, 5, 3));
00270 order.SetUnloadType((OrderUnloadFlags)GB(order_flags, 2, 3));
00271 break;
00272
00273 case OT_GOTO_WAYPOINT:
00274 order.MakeGoToWaypoint(::GetWaypointIndex(destination));
00275 break;
00276
00277 default:
00278 return false;
00279 }
00280
00281 order.SetNonStopType((OrderNonStopFlags)GB(order_flags, 0, 2));
00282
00283 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), order.Pack(), CMD_INSERT_ORDER);
00284 }
00285
00286 bool AIOrder::InsertConditionalOrder(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to)
00287 {
00288
00289 if (order_position == ORDER_CURRENT) order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
00290
00291 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00292 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to));
00293
00294 Order order;
00295 order.MakeConditional(jump_to);
00296
00297 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), order.Pack(), CMD_INSERT_ORDER);
00298 }
00299
00300 bool AIOrder::RemoveOrder(VehicleID vehicle_id, OrderPosition order_position)
00301 {
00302 order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
00303
00304 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
00305
00306 return AIObject::DoCommand(0, vehicle_id, order_position, CMD_DELETE_ORDER);
00307 }
00308
00317 static void _DoCommandReturnSetOrderFlags(class AIInstance *instance)
00318 {
00319 AIObject::SetLastCommandRes(AIOrder::_SetOrderFlags());
00320 AIInstance::DoCommandReturn(instance);
00321 }
00322
00323 bool AIOrder::_SetOrderFlags()
00324 {
00325
00326 int retry = AIObject::GetCallbackVariable(3) - 1;
00327 if (retry < 0) {
00328 DEBUG(ai, 0, "Possible infinite loop in SetOrderFlags() detected");
00329 return false;
00330 }
00331 AIObject::SetCallbackVariable(3, retry);
00332
00333 VehicleID vehicle_id = (VehicleID)AIObject::GetCallbackVariable(0);
00334 OrderPosition order_position = (OrderPosition)AIObject::GetCallbackVariable(1);
00335 AIOrderFlags order_flags = (AIOrderFlags)AIObject::GetCallbackVariable(2);
00336
00337 order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
00338
00339 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
00340 EnforcePrecondition(false, AreOrderFlagsValid(GetOrderDestination(vehicle_id, order_position), order_flags));
00341
00342 const Order *order = ::GetVehicleOrder(GetVehicle(vehicle_id), order_position);
00343
00344 AIOrderFlags current = GetOrderFlags(vehicle_id, order_position);
00345
00346 if ((current & AIOF_NON_STOP_FLAGS) != (order_flags & AIOF_NON_STOP_FLAGS)) {
00347 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), (order_flags & AIOF_NON_STOP_FLAGS) << 4 | MOF_NON_STOP, CMD_MODIFY_ORDER, NULL, &_DoCommandReturnSetOrderFlags);
00348 }
00349
00350 switch (order->GetType()) {
00351 case OT_GOTO_DEPOT:
00352 if ((current & AIOF_SERVICE_IF_NEEDED) != (order_flags & AIOF_SERVICE_IF_NEEDED)) {
00353 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), MOF_DEPOT_ACTION, CMD_MODIFY_ORDER, NULL, &_DoCommandReturnSetOrderFlags);
00354 }
00355 break;
00356
00357 case OT_GOTO_STATION:
00358 if ((current & AIOF_UNLOAD_FLAGS) != (order_flags & AIOF_UNLOAD_FLAGS)) {
00359 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), (order_flags & AIOF_UNLOAD_FLAGS) << 2 | MOF_UNLOAD, CMD_MODIFY_ORDER, NULL, &_DoCommandReturnSetOrderFlags);
00360 }
00361 if ((current & AIOF_LOAD_FLAGS) != (order_flags & AIOF_LOAD_FLAGS)) {
00362 return AIObject::DoCommand(0, vehicle_id | (order_position << 16), (order_flags & AIOF_LOAD_FLAGS) >> 1 | MOF_LOAD, CMD_MODIFY_ORDER, NULL, &_DoCommandReturnSetOrderFlags);
00363 }
00364 break;
00365
00366 default: break;
00367 }
00368
00369 assert(GetOrderFlags(vehicle_id, order_position) == order_flags);
00370
00371 return true;
00372 }
00373
00374 bool AIOrder::SetOrderFlags(VehicleID vehicle_id, OrderPosition order_position, AIOrder::AIOrderFlags order_flags)
00375 {
00376 AIObject::SetCallbackVariable(0, vehicle_id);
00377 AIObject::SetCallbackVariable(1, order_position);
00378 AIObject::SetCallbackVariable(2, order_flags);
00379
00380
00381 AIObject::SetCallbackVariable(3, 8);
00382 return AIOrder::_SetOrderFlags();
00383 }
00384
00385 bool AIOrder::ChangeOrder(VehicleID vehicle_id, OrderPosition order_position, AIOrder::AIOrderFlags order_flags)
00386 {
00387 AILog::Warning("AIOrder::ChangeOrder is deprecated and will be removed soon, please use AIOrder::SetOrderFlags instead.");
00388 return SetOrderFlags(vehicle_id, order_position, order_flags);
00389 }
00390
00391 bool AIOrder::MoveOrder(VehicleID vehicle_id, OrderPosition order_position_move, OrderPosition order_position_target)
00392 {
00393 order_position_move = AIOrder::ResolveOrderPosition(vehicle_id, order_position_move);
00394 order_position_target = AIOrder::ResolveOrderPosition(vehicle_id, order_position_target);
00395
00396 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_move));
00397 EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_target));
00398
00399 return AIObject::DoCommand(0, vehicle_id, order_position_move | (order_position_target << 16), CMD_MOVE_ORDER);
00400 }
00401
00402 bool AIOrder::CopyOrders(VehicleID vehicle_id, VehicleID main_vehicle_id)
00403 {
00404 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00405 EnforcePrecondition(false, AIVehicle::IsValidVehicle(main_vehicle_id));
00406
00407 return AIObject::DoCommand(0, vehicle_id | (main_vehicle_id << 16), CO_COPY, CMD_CLONE_ORDER);
00408 }
00409
00410 bool AIOrder::ShareOrders(VehicleID vehicle_id, VehicleID main_vehicle_id)
00411 {
00412 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00413 EnforcePrecondition(false, AIVehicle::IsValidVehicle(main_vehicle_id));
00414
00415 return AIObject::DoCommand(0, vehicle_id | (main_vehicle_id << 16), CO_SHARE, CMD_CLONE_ORDER);
00416 }
00417
00418 bool AIOrder::UnshareOrders(VehicleID vehicle_id)
00419 {
00420 EnforcePrecondition(false, AIVehicle::IsValidVehicle(vehicle_id));
00421
00422 return AIObject::DoCommand(0, vehicle_id, CO_UNSHARE, CMD_CLONE_ORDER);
00423 }