ai_vehicle.cpp

Go to the documentation of this file.
00001 /* $Id: ai_vehicle.cpp 18504 2009-12-14 22:17:15Z yexo $ */
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 }

Generated on Wed Dec 23 23:27:48 2009 for OpenTTD by  doxygen 1.5.6