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

Generated on Sun Jun 5 04:19:53 2011 for OpenTTD by  doxygen 1.6.1