# ai_vehicle.cpp

Go to the documentation of this file.

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