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 "../../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 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 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 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 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
00077 return 0;
00078 }
00079
00080 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
00087 return 0;
00088 }
00089
00090 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 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 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 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 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 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 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 bool AIVehicle::SellWagon(VehicleID vehicle_id, int wagon)
00155 {
00156 return _SellWagonInternal(vehicle_id, wagon, false);
00157 }
00158
00159 bool AIVehicle::SellWagonChain(VehicleID vehicle_id, int wagon)
00160 {
00161 return _SellWagonInternal(vehicle_id, wagon, true);
00162 }
00163
00164 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 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 bool AIVehicle::IsInDepot(VehicleID vehicle_id)
00179 {
00180 if (!IsValidVehicle(vehicle_id)) return false;
00181 return ::Vehicle::Get(vehicle_id)->IsInDepot();
00182 }
00183
00184 bool AIVehicle::IsStoppedInDepot(VehicleID vehicle_id)
00185 {
00186 if (!IsValidVehicle(vehicle_id)) return false;
00187 return ::Vehicle::Get(vehicle_id)->IsStoppedInDepot();
00188 }
00189
00190 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 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 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 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 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 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 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 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 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 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 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 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 int32 AIVehicle::GetCurrentSpeed(VehicleID vehicle_id)
00304 {
00305 if (!IsValidVehicle(vehicle_id)) return -1;
00306
00307 return ::Vehicle::Get(vehicle_id)->GetDisplaySpeed();
00308 }
00309
00310 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 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 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 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 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 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 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 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 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 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 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 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 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 }