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