00001
00002
00003
00004
00005
00006
00007
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 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 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 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 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
00065 return 0;
00066 }
00067
00068 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
00075 return 0;
00076 }
00077
00078 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 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 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 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 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 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 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 bool AIVehicle::SellWagon(VehicleID vehicle_id, int wagon)
00143 {
00144 return _SellWagonInternal(vehicle_id, wagon, false);
00145 }
00146
00147 bool AIVehicle::SellWagonChain(VehicleID vehicle_id, int wagon)
00148 {
00149 return _SellWagonInternal(vehicle_id, wagon, true);
00150 }
00151
00152 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 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 bool AIVehicle::IsInDepot(VehicleID vehicle_id)
00167 {
00168 if (!IsValidVehicle(vehicle_id)) return false;
00169 return ::Vehicle::Get(vehicle_id)->IsInDepot();
00170 }
00171
00172 bool AIVehicle::IsStoppedInDepot(VehicleID vehicle_id)
00173 {
00174 if (!IsValidVehicle(vehicle_id)) return false;
00175 return ::Vehicle::Get(vehicle_id)->IsStoppedInDepot();
00176 }
00177
00178 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 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 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 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 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 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 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 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 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 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 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 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 int32 AIVehicle::GetCurrentSpeed(VehicleID vehicle_id)
00292 {
00293 if (!IsValidVehicle(vehicle_id)) return -1;
00294
00295 return ::Vehicle::Get(vehicle_id)->GetDisplaySpeed();
00296 }
00297
00298 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 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 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 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 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 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 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 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 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 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 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 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 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 }