# ai_vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id: ai_vehicle.cpp 16803 2009-07-13 09:57:37Z rubidium $ */
    00002
    00005 #include "ai_engine.hpp"
    00006 #include "ai_cargo.hpp"
    00007 #include "ai_gamesettings.hpp"
    00008 #include "ai_group.hpp"
    00009 #include "../ai_instance.hpp"
    00010 #include "../../company_func.h"
    00011 #include "../../aircraft.h"
    00012 #include "../../string_func.h"
    00013 #include "../../strings_func.h"
    00014 #include "../../command_func.h"
    00015 #include "../../roadveh.h"
    00016 #include "../../train.h"
    00017 #include "../../vehicle_func.h"
    00018 #include "table/strings.h"
    00019
    00020 /* static */ bool AIVehicle::IsValidVehicle(VehicleID vehicle_id)
    00021 {
    00022   if (!::IsValidVehicleID(vehicle_id)) return false;
    00023   const Vehicle *v = ::GetVehicle(vehicle_id);
    00024   return v->owner == _current_company && (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && ::IsFreeWagon(v)));
    00025 }
    00026
    00027 /* static */ int32 AIVehicle::GetNumWagons(VehicleID vehicle_id)
    00028 {
    00029   if (!IsValidVehicle(vehicle_id)) return -1;
    00030
    00031   int num = 1;
    00032   if (::GetVehicle(vehicle_id)->type == VEH_TRAIN) {
    00033     const Vehicle *v = ::GetVehicle(vehicle_id);
    00034     while ((v = GetNextUnit(v)) != NULL) num++;
    00035   }
    00036
    00037   return num;
    00038 }
    00039
    00040 /* static */ int AIVehicle::GetLength(VehicleID vehicle_id)
    00041 {
    00042   if (!IsValidVehicle(vehicle_id)) return -1;
    00043
    00044   const Vehicle *v = ::GetVehicle(vehicle_id);
    00045   switch (v->type) {
    00046     case VEH_ROAD: {
    00047       uint total_length = 0;
    00048       for (const Vehicle *u = v; u != NULL; u = u->Next()) {
    00049         total_length += u->u.road.cached_veh_length;
    00050       }
    00051       return total_length;
    00052     }
    00053     case VEH_TRAIN: return v->u.rail.cached_total_length;
    00054     default: return -1;
    00055   }
    00056 }
    00057
    00058 /* static */ VehicleID AIVehicle::BuildVehicle(TileIndex depot, EngineID engine_id)
    00059 {
    00060   EnforcePrecondition(INVALID_VEHICLE, AIEngine::IsValidEngine(engine_id));
    00061
    00062 	::VehicleType type = ::GetEngine(engine_id)->type;
    00063
    00064   EnforcePreconditionCustomError(INVALID_VEHICLE, !AIGameSettings::IsDisabledVehicleType((AIVehicle::VehicleType)type), AIVehicle::ERR_VEHICLE_BUILD_DISABLED);
    00065
    00066   if (!AIObject::DoCommand(depot, engine_id, 0, ::GetCmdBuildVeh(type), NULL, &AIInstance::DoCommandReturnVehicleID)) return INVALID_VEHICLE;
    00067
    00068   /* In case of test-mode, we return VehicleID 0 */
    00069   return 0;
    00070 }
    00071
    00072 /* static */ VehicleID AIVehicle::CloneVehicle(TileIndex depot, VehicleID vehicle_id, bool share_orders)
    00073 {
    00074   EnforcePrecondition(false, IsValidVehicle(vehicle_id));
    00075
    00076   if (!AIObject::DoCommand(depot, vehicle_id, share_orders, CMD_CLONE_VEHICLE, NULL, &AIInstance::DoCommandReturnVehicleID)) return INVALID_VEHICLE;
    00077
    00078   /* In case of test-mode, we return VehicleID 0 */
    00079   return 0;
    00080 }
    00081
    00082 /* static */ bool AIVehicle::_MoveWagonInternal(VehicleID source_vehicle_id, int source_wagon, bool move_attached_wagons, int dest_vehicle_id, int dest_wagon)
    00083 {
    00084   EnforcePrecondition(false, IsValidVehicle(source_vehicle_id) && source_wagon < GetNumWagons(source_vehicle_id));
    00085   EnforcePrecondition(false, dest_vehicle_id == -1 || (IsValidVehicle(dest_vehicle_id) && dest_wagon < GetNumWagons(dest_vehicle_id)));
    00086   EnforcePrecondition(false, ::GetVehicle(source_vehicle_id)->type == VEH_TRAIN);
    00087   EnforcePrecondition(false, dest_vehicle_id == -1 || ::GetVehicle(dest_vehicle_id)->type == VEH_TRAIN);
    00088
    00089   const Vehicle *v = ::GetVehicle(source_vehicle_id);
    00090   while (source_wagon-- > 0) v = GetNextUnit(v);
    00091   const Vehicle *w = NULL;
    00092   if (dest_vehicle_id != -1) {
    00093     w = ::GetVehicle(dest_vehicle_id);
    00094     while (dest_wagon-- > 0) w = GetNextUnit(w);
    00095   }
    00096
    00097   return AIObject::DoCommand(0, v->index | ((w == NULL ? INVALID_VEHICLE : w->index) << 16), move_attached_wagons ? 1 : 0, CMD_MOVE_RAIL_VEHICLE);
    00098 }
    00099
    00100 /* static */ bool AIVehicle::MoveWagon(VehicleID source_vehicle_id, int source_wagon, int dest_vehicle_id, int dest_wagon)
    00101 {
    00102   return _MoveWagonInternal(source_vehicle_id, source_wagon, false, dest_vehicle_id, dest_wagon);
    00103 }
    00104
    00105 /* static */ bool AIVehicle::MoveWagonChain(VehicleID source_vehicle_id, int source_wagon, int dest_vehicle_id, int dest_wagon)
    00106 {
    00107   return _MoveWagonInternal(source_vehicle_id, source_wagon, true, dest_vehicle_id, dest_wagon);
    00108 }
    00109
    00110 /* static */ int AIVehicle::GetRefitCapacity(VehicleID vehicle_id, CargoID cargo)
    00111 {
    00112   if (!IsValidVehicle(vehicle_id)) return -1;
    00113   if (!AICargo::IsValidCargo(cargo)) return -1;
    00114
    00115   CommandCost res = ::DoCommand(0, vehicle_id, cargo, DC_QUERY_COST, GetCmdRefitVeh(::GetVehicle(vehicle_id)));
    00116   return CmdSucceeded(res) ? _returned_refit_capacity : -1;
    00117 }
    00118
    00119 /* static */ bool AIVehicle::RefitVehicle(VehicleID vehicle_id, CargoID cargo)
    00120 {
    00121   EnforcePrecondition(false, IsValidVehicle(vehicle_id) && AICargo::IsValidCargo(cargo));
    00122
    00123   return AIObject::DoCommand(0, vehicle_id, cargo, GetCmdRefitVeh(::GetVehicle(vehicle_id)));
    00124 }
    00125
    00126
    00127 /* static */ bool AIVehicle::SellVehicle(VehicleID vehicle_id)
    00128 {
    00129   EnforcePrecondition(false, IsValidVehicle(vehicle_id));
    00130
    00131   const Vehicle *v = ::GetVehicle(vehicle_id);
    00132   return AIObject::DoCommand(0, vehicle_id, v->type == VEH_TRAIN ? 1 : 0, GetCmdSellVeh(v));
    00133 }
    00134
    00135 /* static */ bool AIVehicle::_SellWagonInternal(VehicleID vehicle_id, int wagon, bool sell_attached_wagons)
    00136 {
    00137   EnforcePrecondition(false, IsValidVehicle(vehicle_id) && wagon < GetNumWagons(vehicle_id));
    00138   EnforcePrecondition(false, ::GetVehicle(vehicle_id)->type == VEH_TRAIN);
    00139
    00140   const Vehicle *v = ::GetVehicle(vehicle_id);
    00141   while (wagon-- > 0) v = GetNextUnit(v);
    00142
    00143   return AIObject::DoCommand(0, v->index, sell_attached_wagons ? 1 : 0, CMD_SELL_RAIL_WAGON);
    00144 }
    00145
    00146 /* static */ bool AIVehicle::SellWagon(VehicleID vehicle_id, int wagon)
    00147 {
    00148   return _SellWagonInternal(vehicle_id, wagon, false);
    00149 }
    00150
    00151 /* static */ bool AIVehicle::SellWagonChain(VehicleID vehicle_id, int wagon)
    00152 {
    00153   return _SellWagonInternal(vehicle_id, wagon, true);
    00154 }
    00155
    00156 /* static */ bool AIVehicle::SendVehicleToDepot(VehicleID vehicle_id)
    00157 {
    00158   EnforcePrecondition(false, IsValidVehicle(vehicle_id));
    00159
    00160   return AIObject::DoCommand(0, vehicle_id, 0, GetCmdSendToDepot(::GetVehicle(vehicle_id)));
    00161 }
    00162
    00163 /* static */ bool AIVehicle::SendVehicleToDepotForServicing(VehicleID vehicle_id)
    00164 {
    00165   EnforcePrecondition(false, IsValidVehicle(vehicle_id));
    00166
    00167   return AIObject::DoCommand(0, vehicle_id, DEPOT_SERVICE, GetCmdSendToDepot(::GetVehicle(vehicle_id)));
    00168 }
    00169
    00170 /* static */ bool AIVehicle::IsInDepot(VehicleID vehicle_id)
    00171 {
    00172   if (!IsValidVehicle(vehicle_id)) return false;
    00173   return ::GetVehicle(vehicle_id)->IsInDepot();
    00174 }
    00175
    00176 /* static */ bool AIVehicle::IsStoppedInDepot(VehicleID vehicle_id)
    00177 {
    00178   if (!IsValidVehicle(vehicle_id)) return false;
    00179   return ::GetVehicle(vehicle_id)->IsStoppedInDepot();
    00180 }
    00181
    00182 /* static */ bool AIVehicle::StartStopVehicle(VehicleID vehicle_id)
    00183 {
    00184   EnforcePrecondition(false, IsValidVehicle(vehicle_id));
    00185
    00186   return AIObject::DoCommand(0, vehicle_id, 0, CMD_START_STOP_VEHICLE);
    00187 }
    00188
    00189 /* static */ bool AIVehicle::SkipToVehicleOrder(VehicleID vehicle_id, AIOrder::OrderPosition order_position)
    00190 {
    00191   order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
    00192
    00193   EnforcePrecondition(false, AIOrder::IsValidVehicleOrder(vehicle_id, order_position));
    00194
    00195   return AIObject::DoCommand(0, vehicle_id, order_position, CMD_SKIP_TO_ORDER);
    00196 }
    00197
    00198 /* static */ bool AIVehicle::ReverseVehicle(VehicleID vehicle_id)
    00199 {
    00200   EnforcePrecondition(false, IsValidVehicle(vehicle_id));
    00201   EnforcePrecondition(false, ::GetVehicle(vehicle_id)->type == VEH_ROAD || ::GetVehicle(vehicle_id)->type == VEH_TRAIN);
    00202
    00203   switch (::GetVehicle(vehicle_id)->type) {
    00204     case VEH_ROAD: return AIObject::DoCommand(0, vehicle_id, 0, CMD_TURN_ROADVEH);
    00205     case VEH_TRAIN: return AIObject::DoCommand(0, vehicle_id, 0, CMD_REVERSE_TRAIN_DIRECTION);
    00206     default: NOT_REACHED();
    00207   }
    00208 }
    00209
    00210 /* static */ bool AIVehicle::SetName(VehicleID vehicle_id, const char *name)
    00211 {
    00212   EnforcePrecondition(false, IsValidVehicle(vehicle_id));
    00213   EnforcePrecondition(false, !::StrEmpty(name));
    00214   EnforcePreconditionCustomError(false, ::strlen(name) < MAX_LENGTH_VEHICLE_NAME_BYTES, AIError::ERR_PRECONDITION_STRING_TOO_LONG);
    00215
    00216   return AIObject::DoCommand(0, vehicle_id, 0, CMD_RENAME_VEHICLE, name);
    00217 }
    00218
    00219 /* static */ TileIndex AIVehicle::GetLocation(VehicleID vehicle_id)
    00220 {
    00221   if (!IsValidVehicle(vehicle_id)) return INVALID_TILE;
    00222
    00223   const Vehicle *v = ::GetVehicle(vehicle_id);
    00224   if (v->type == VEH_AIRCRAFT) {
    00225     uint x = Clamp(v->x_pos / TILE_SIZE, 0, ::MapSizeX() - 2);
    00226     uint y = Clamp(v->y_pos / TILE_SIZE, 0, ::MapSizeY() - 2);
    00227     return ::TileXY(x, y);
    00228   }
    00229
    00230   return v->tile;
    00231 }
    00232
    00233 /* static */ EngineID AIVehicle::GetEngineType(VehicleID vehicle_id)
    00234 {
    00235   if (!IsValidVehicle(vehicle_id)) return INVALID_ENGINE;
    00236
    00237   return ::GetVehicle(vehicle_id)->engine_type;
    00238 }
    00239
    00240 /* static */ EngineID AIVehicle::GetWagonEngineType(VehicleID vehicle_id, int wagon)
    00241 {
    00242   if (!IsValidVehicle(vehicle_id)) return INVALID_ENGINE;
    00243   if (wagon >= GetNumWagons(vehicle_id)) return INVALID_ENGINE;
    00244
    00245   const Vehicle *v = ::GetVehicle(vehicle_id);
    00246   if (v->type == VEH_TRAIN) {
    00247     while (wagon-- > 0) v = GetNextUnit(v);
    00248   }
    00249   return v->engine_type;
    00250 }
    00251
    00252 /* static */ int32 AIVehicle::GetUnitNumber(VehicleID vehicle_id)
    00253 {
    00254   if (!IsValidVehicle(vehicle_id)) return -1;
    00255
    00256   return ::GetVehicle(vehicle_id)->unitnumber;
    00257 }
    00258
    00259 /* static */ char *AIVehicle::GetName(VehicleID vehicle_id)
    00260 {
    00261   if (!IsValidVehicle(vehicle_id)) return NULL;
    00262
    00263   static const int len = 64;
    00264   char *vehicle_name = MallocT<char>(len);
    00265
    00266   ::SetDParam(0, vehicle_id);
    00267   ::GetString(vehicle_name, STR_VEHICLE_NAME, &vehicle_name[len - 1]);
    00268   return vehicle_name;
    00269 }
    00270
    00271 /* static */ int32 AIVehicle::GetAge(VehicleID vehicle_id)
    00272 {
    00273   if (!IsValidVehicle(vehicle_id)) return -1;
    00274
    00275   return ::GetVehicle(vehicle_id)->age;
    00276 }
    00277
    00278 /* static */ int32 AIVehicle::GetWagonAge(VehicleID vehicle_id, int wagon)
    00279 {
    00280   if (!IsValidVehicle(vehicle_id)) return -1;
    00281   if (wagon >= GetNumWagons(vehicle_id)) return -1;
    00282
    00283   const Vehicle *v = ::GetVehicle(vehicle_id);
    00284   if (v->type == VEH_TRAIN) {
    00285     while (wagon-- > 0) v = GetNextUnit(v);
    00286   }
    00287   return v->age;
    00288 }
    00289
    00290 /* static */ int32 AIVehicle::GetMaxAge(VehicleID vehicle_id)
    00291 {
    00292   if (!IsValidVehicle(vehicle_id)) return -1;
    00293
    00294   return ::GetVehicle(vehicle_id)->max_age;
    00295 }
    00296
    00297 /* static */ int32 AIVehicle::GetAgeLeft(VehicleID vehicle_id)
    00298 {
    00299   if (!IsValidVehicle(vehicle_id)) return -1;
    00300
    00301   return ::GetVehicle(vehicle_id)->max_age - ::GetVehicle(vehicle_id)->age;
    00302 }
    00303
    00304 /* static */ int32 AIVehicle::GetCurrentSpeed(VehicleID vehicle_id)
    00305 {
    00306   if (!IsValidVehicle(vehicle_id)) return -1;
    00307
    00308   return ::GetVehicle(vehicle_id)->GetDisplaySpeed(); // km-ish/h
    00309 }
    00310
    00311 /* static */ AIVehicle::VehicleState AIVehicle::GetState(VehicleID vehicle_id)
    00312 {
    00313   if (!IsValidVehicle(vehicle_id)) return AIVehicle::VS_INVALID;
    00314
    00315   const Vehicle *v = ::GetVehicle(vehicle_id);
    00316   byte vehstatus = v->vehstatus;
    00317
    00318   if (vehstatus & ::VS_CRASHED) return AIVehicle::VS_CRASHED;
    00319   if (v->breakdown_ctr != 0) return AIVehicle::VS_BROKEN;
    00320   if (v->IsStoppedInDepot()) return AIVehicle::VS_IN_DEPOT;
    00321   if (vehstatus & ::VS_STOPPED) return AIVehicle::VS_STOPPED;
    00322   if (v->current_order.IsType(OT_LOADING)) return AIVehicle::VS_AT_STATION;
    00323   return AIVehicle::VS_RUNNING;
    00324 }
    00325
    00326 /* static */ Money AIVehicle::GetRunningCost(VehicleID vehicle_id)
    00327 {
    00328   if (!IsValidVehicle(vehicle_id)) return -1;
    00329
    00330   return ::GetVehicle(vehicle_id)->GetRunningCost() >> 8;
    00331 }
    00332
    00333 /* static */ Money AIVehicle::GetProfitThisYear(VehicleID vehicle_id)
    00334 {
    00335   if (!IsValidVehicle(vehicle_id)) return -1;
    00336
    00337   return ::GetVehicle(vehicle_id)->GetDisplayProfitThisYear();
    00338 }
    00339
    00340 /* static */ Money AIVehicle::GetProfitLastYear(VehicleID vehicle_id)
    00341 {
    00342   if (!IsValidVehicle(vehicle_id)) return -1;
    00343
    00344   return ::GetVehicle(vehicle_id)->GetDisplayProfitLastYear();
    00345 }
    00346
    00347 /* static */ Money AIVehicle::GetCurrentValue(VehicleID vehicle_id)
    00348 {
    00349   if (!IsValidVehicle(vehicle_id)) return -1;
    00350
    00351   return ::GetVehicle(vehicle_id)->value;
    00352 }
    00353
    00354 /* static */ AIVehicle::VehicleType AIVehicle::GetVehicleType(VehicleID vehicle_id)
    00355 {
    00356   if (!IsValidVehicle(vehicle_id)) return VT_INVALID;
    00357
    00358   switch (::GetVehicle(vehicle_id)->type) {
    00359     case VEH_ROAD:     return VT_ROAD;
    00360     case VEH_TRAIN:    return VT_RAIL;
    00361     case VEH_SHIP:     return VT_WATER;
    00362     case VEH_AIRCRAFT: return VT_AIR;
    00363     default:           return VT_INVALID;
    00364   }
    00365 }
    00366
    00367 /* static */ AIRoad::RoadType AIVehicle::GetRoadType(VehicleID vehicle_id)
    00368 {
    00369   if (!IsValidVehicle(vehicle_id)) return AIRoad::ROADTYPE_INVALID;
    00370   if (GetVehicleType(vehicle_id) != VT_ROAD) return AIRoad::ROADTYPE_INVALID;
    00371
    00372   return (AIRoad::RoadType)::GetVehicle(vehicle_id)->u.road.roadtype;
    00373 }
    00374
    00375 /* static */ int32 AIVehicle::GetCapacity(VehicleID vehicle_id, CargoID cargo)
    00376 {
    00377   if (!IsValidVehicle(vehicle_id)) return -1;
    00378   if (!AICargo::IsValidCargo(cargo)) return -1;
    00379
    00380   uint32 amount = 0;
    00381   for (const Vehicle *v = ::GetVehicle(vehicle_id); v != NULL; v = v->Next()) {
    00382     if (v->cargo_type == cargo) amount += v->cargo_cap;
    00383   }
    00384
    00385   return amount;
    00386 }
    00387
    00388 /* static */ int32 AIVehicle::GetCargoLoad(VehicleID vehicle_id, CargoID cargo)
    00389 {
    00390   if (!IsValidVehicle(vehicle_id)) return -1;
    00391   if (!AICargo::IsValidCargo(cargo)) return -1;
    00392
    00393   uint32 amount = 0;
    00394   for (const Vehicle *v = ::GetVehicle(vehicle_id); v != NULL; v = v->Next()) {
    00395     if (v->cargo_type == cargo) amount += v->cargo.Count();
    00396   }
    00397
    00398   return amount;
    00399 }
    00400
    00401 /* static */ GroupID AIVehicle::GetGroupID(VehicleID vehicle_id)
    00402 {
    00403   if (!IsValidVehicle(vehicle_id)) return AIGroup::GROUP_INVALID;
    00404
    00405   return ::GetVehicle(vehicle_id)->group_id;
    00406 }
    00407
    00408 /* static */ bool AIVehicle::IsArticulated(VehicleID vehicle_id)
    00409 {
    00410   if (!IsValidVehicle(vehicle_id)) return false;
    00411   if (GetVehicleType(vehicle_id) != VT_ROAD && GetVehicleType(vehicle_id) != VT_RAIL) return false;
    00412
    00413   const Vehicle *v = ::GetVehicle(vehicle_id);
    00414   switch (v->type) {
    00415     case VEH_ROAD: return RoadVehHasArticPart(v);
    00416     case VEH_TRAIN: return EngineHasArticPart(v);
    00417     default: NOT_REACHED();
    00418   }
    00419 }
    00420
    00421 /* static */ bool AIVehicle::HasSharedOrders(VehicleID vehicle_id)
    00422 {
    00423   if (!IsValidVehicle(vehicle_id)) return false;
    00424
    00425   Vehicle *v = ::GetVehicle(vehicle_id);
    00426   return v->orders.list != NULL && v->orders.list->GetNumVehicles() > 1;
    00427 }
    00428
    00429 /* static */ int AIVehicle::GetReliability(VehicleID vehicle_id)
    00430 {
    00431   if (!IsValidVehicle(vehicle_id)) return -1;
    00432
    00433   const Vehicle *v = ::GetVehicle(vehicle_id);
    00434   return v->reliability * 100 >> 16;
    00435 }