ai_vehicle.cpp

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

Generated on Fri Dec 31 17:15:29 2010 for OpenTTD by  doxygen 1.6.1