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 "table/strings.h"
00026
00027 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 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 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 VehicleID AIVehicle::BuildVehicle(TileIndex depot, EngineID engine_id)
00066 {
00067 EnforcePrecondition(INVALID_VEHICLE, AIEngine::IsBuildable(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
00076 return 0;
00077 }
00078
00079 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
00086 return 0;
00087 }
00088
00089 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 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 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 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 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 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 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 bool AIVehicle::SellWagon(VehicleID vehicle_id, int wagon)
00154 {
00155 return _SellWagonInternal(vehicle_id, wagon, false);
00156 }
00157
00158 bool AIVehicle::SellWagonChain(VehicleID vehicle_id, int wagon)
00159 {
00160 return _SellWagonInternal(vehicle_id, wagon, true);
00161 }
00162
00163 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 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 bool AIVehicle::IsInDepot(VehicleID vehicle_id)
00178 {
00179 if (!IsValidVehicle(vehicle_id)) return false;
00180 return ::Vehicle::Get(vehicle_id)->IsInDepot();
00181 }
00182
00183 bool AIVehicle::IsStoppedInDepot(VehicleID vehicle_id)
00184 {
00185 if (!IsValidVehicle(vehicle_id)) return false;
00186 return ::Vehicle::Get(vehicle_id)->IsStoppedInDepot();
00187 }
00188
00189 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 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 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 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 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 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 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 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 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 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 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 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 int32 AIVehicle::GetCurrentSpeed(VehicleID vehicle_id)
00303 {
00304 if (!IsValidVehicle(vehicle_id)) return -1;
00305
00306 return ::Vehicle::Get(vehicle_id)->GetDisplaySpeed();
00307 }
00308
00309 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 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 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 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 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 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 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 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 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 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 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 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 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 }