# ai_vehicle.cpp

Go to the documentation of this file.

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