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::IsInDepot(VehicleID vehicle_id)
00164 {
00165 if (!IsValidVehicle(vehicle_id)) return false;
00166 return ::GetVehicle(vehicle_id)->IsInDepot();
00167 }
00168
00169 bool AIVehicle::IsStoppedInDepot(VehicleID vehicle_id)
00170 {
00171 if (!IsValidVehicle(vehicle_id)) return false;
00172 return ::GetVehicle(vehicle_id)->IsStoppedInDepot();
00173 }
00174
00175 bool AIVehicle::StartStopVehicle(VehicleID vehicle_id)
00176 {
00177 EnforcePrecondition(false, IsValidVehicle(vehicle_id));
00178
00179 return AIObject::DoCommand(0, vehicle_id, 0, CMD_START_STOP_VEHICLE);
00180 }
00181
00182 bool AIVehicle::SkipToVehicleOrder(VehicleID vehicle_id, AIOrder::OrderPosition order_position)
00183 {
00184 order_position = AIOrder::ResolveOrderPosition(vehicle_id, order_position);
00185
00186 EnforcePrecondition(false, AIOrder::IsValidVehicleOrder(vehicle_id, order_position));
00187
00188 return AIObject::DoCommand(0, vehicle_id, order_position, CMD_SKIP_TO_ORDER);
00189 }
00190
00191 bool AIVehicle::ReverseVehicle(VehicleID vehicle_id)
00192 {
00193 EnforcePrecondition(false, IsValidVehicle(vehicle_id));
00194 EnforcePrecondition(false, ::GetVehicle(vehicle_id)->type == VEH_ROAD || ::GetVehicle(vehicle_id)->type == VEH_TRAIN);
00195
00196 switch (::GetVehicle(vehicle_id)->type) {
00197 case VEH_ROAD: return AIObject::DoCommand(0, vehicle_id, 0, CMD_TURN_ROADVEH);
00198 case VEH_TRAIN: return AIObject::DoCommand(0, vehicle_id, 0, CMD_REVERSE_TRAIN_DIRECTION);
00199 default: NOT_REACHED();
00200 }
00201 }
00202
00203 bool AIVehicle::SetName(VehicleID vehicle_id, const char *name)
00204 {
00205 EnforcePrecondition(false, IsValidVehicle(vehicle_id));
00206 EnforcePrecondition(false, !::StrEmpty(name));
00207 EnforcePreconditionCustomError(false, ::strlen(name) < MAX_LENGTH_VEHICLE_NAME_BYTES, AIError::ERR_PRECONDITION_STRING_TOO_LONG);
00208
00209 return AIObject::DoCommand(0, vehicle_id, 0, CMD_RENAME_VEHICLE, name);
00210 }
00211
00212 TileIndex AIVehicle::GetLocation(VehicleID vehicle_id)
00213 {
00214 if (!IsValidVehicle(vehicle_id)) return INVALID_TILE;
00215
00216 const Vehicle *v = ::GetVehicle(vehicle_id);
00217 if (v->type == VEH_AIRCRAFT) {
00218 uint x = Clamp(v->x_pos / TILE_SIZE, 0, ::MapSizeX() - 2);
00219 uint y = Clamp(v->y_pos / TILE_SIZE, 0, ::MapSizeY() - 2);
00220 return ::TileXY(x, y);
00221 }
00222
00223 return v->tile;
00224 }
00225
00226 EngineID AIVehicle::GetEngineType(VehicleID vehicle_id)
00227 {
00228 if (!IsValidVehicle(vehicle_id)) return INVALID_ENGINE;
00229
00230 return ::GetVehicle(vehicle_id)->engine_type;
00231 }
00232
00233 EngineID AIVehicle::GetWagonEngineType(VehicleID vehicle_id, int wagon)
00234 {
00235 if (!IsValidVehicle(vehicle_id)) return INVALID_ENGINE;
00236 if (wagon >= GetNumWagons(vehicle_id)) return INVALID_ENGINE;
00237
00238 const Vehicle *v = ::GetVehicle(vehicle_id);
00239 if (v->type == VEH_TRAIN) {
00240 while (wagon-- > 0) v = GetNextUnit(v);
00241 }
00242 return v->engine_type;
00243 }
00244
00245 int32 AIVehicle::GetUnitNumber(VehicleID vehicle_id)
00246 {
00247 if (!IsValidVehicle(vehicle_id)) return -1;
00248
00249 return ::GetVehicle(vehicle_id)->unitnumber;
00250 }
00251
00252 char *AIVehicle::GetName(VehicleID vehicle_id)
00253 {
00254 if (!IsValidVehicle(vehicle_id)) return NULL;
00255
00256 static const int len = 64;
00257 char *vehicle_name = MallocT<char>(len);
00258
00259 ::SetDParam(0, vehicle_id);
00260 ::GetString(vehicle_name, STR_VEHICLE_NAME, &vehicle_name[len - 1]);
00261 return vehicle_name;
00262 }
00263
00264 int32 AIVehicle::GetAge(VehicleID vehicle_id)
00265 {
00266 if (!IsValidVehicle(vehicle_id)) return -1;
00267
00268 return ::GetVehicle(vehicle_id)->age;
00269 }
00270
00271 int32 AIVehicle::GetWagonAge(VehicleID vehicle_id, int wagon)
00272 {
00273 if (!IsValidVehicle(vehicle_id)) return -1;
00274 if (wagon >= GetNumWagons(vehicle_id)) return -1;
00275
00276 const Vehicle *v = ::GetVehicle(vehicle_id);
00277 if (v->type == VEH_TRAIN) {
00278 while (wagon-- > 0) v = GetNextUnit(v);
00279 }
00280 return v->age;
00281 }
00282
00283 int32 AIVehicle::GetMaxAge(VehicleID vehicle_id)
00284 {
00285 if (!IsValidVehicle(vehicle_id)) return -1;
00286
00287 return ::GetVehicle(vehicle_id)->max_age;
00288 }
00289
00290 int32 AIVehicle::GetAgeLeft(VehicleID vehicle_id)
00291 {
00292 if (!IsValidVehicle(vehicle_id)) return -1;
00293
00294 return ::GetVehicle(vehicle_id)->max_age - ::GetVehicle(vehicle_id)->age;
00295 }
00296
00297 int32 AIVehicle::GetCurrentSpeed(VehicleID vehicle_id)
00298 {
00299 if (!IsValidVehicle(vehicle_id)) return -1;
00300
00301 return ::GetVehicle(vehicle_id)->GetDisplaySpeed();
00302 }
00303
00304 AIVehicle::VehicleState AIVehicle::GetState(VehicleID vehicle_id)
00305 {
00306 if (!IsValidVehicle(vehicle_id)) return AIVehicle::VS_INVALID;
00307
00308 const Vehicle *v = ::GetVehicle(vehicle_id);
00309 byte vehstatus = v->vehstatus;
00310
00311 if (vehstatus & ::VS_CRASHED) return AIVehicle::VS_CRASHED;
00312 if (v->breakdown_ctr != 0) return AIVehicle::VS_BROKEN;
00313 if (v->IsStoppedInDepot()) return AIVehicle::VS_IN_DEPOT;
00314 if (vehstatus & ::VS_STOPPED) return AIVehicle::VS_STOPPED;
00315 if (v->current_order.IsType(OT_LOADING)) return AIVehicle::VS_AT_STATION;
00316 return AIVehicle::VS_RUNNING;
00317 }
00318
00319 Money AIVehicle::GetRunningCost(VehicleID vehicle_id)
00320 {
00321 if (!IsValidVehicle(vehicle_id)) return -1;
00322
00323 return ::GetVehicle(vehicle_id)->GetRunningCost() >> 8;
00324 }
00325
00326 Money AIVehicle::GetProfitThisYear(VehicleID vehicle_id)
00327 {
00328 if (!IsValidVehicle(vehicle_id)) return -1;
00329
00330 return ::GetVehicle(vehicle_id)->GetDisplayProfitThisYear();
00331 }
00332
00333 Money AIVehicle::GetProfitLastYear(VehicleID vehicle_id)
00334 {
00335 if (!IsValidVehicle(vehicle_id)) return -1;
00336
00337 return ::GetVehicle(vehicle_id)->GetDisplayProfitLastYear();
00338 }
00339
00340 Money AIVehicle::GetCurrentValue(VehicleID vehicle_id)
00341 {
00342 if (!IsValidVehicle(vehicle_id)) return -1;
00343
00344 return ::GetVehicle(vehicle_id)->value;
00345 }
00346
00347 AIVehicle::VehicleType AIVehicle::GetVehicleType(VehicleID vehicle_id)
00348 {
00349 if (!IsValidVehicle(vehicle_id)) return VT_INVALID;
00350
00351 switch (::GetVehicle(vehicle_id)->type) {
00352 case VEH_ROAD: return VT_ROAD;
00353 case VEH_TRAIN: return VT_RAIL;
00354 case VEH_SHIP: return VT_WATER;
00355 case VEH_AIRCRAFT: return VT_AIR;
00356 default: return VT_INVALID;
00357 }
00358 }
00359
00360 AIRoad::RoadType AIVehicle::GetRoadType(VehicleID vehicle_id)
00361 {
00362 if (!IsValidVehicle(vehicle_id)) return AIRoad::ROADTYPE_INVALID;
00363 if (GetVehicleType(vehicle_id) != VT_ROAD) return AIRoad::ROADTYPE_INVALID;
00364
00365 return (AIRoad::RoadType)::GetVehicle(vehicle_id)->u.road.roadtype;
00366 }
00367
00368 int32 AIVehicle::GetCapacity(VehicleID vehicle_id, CargoID cargo)
00369 {
00370 if (!IsValidVehicle(vehicle_id)) return -1;
00371 if (!AICargo::IsValidCargo(cargo)) return -1;
00372
00373 uint32 amount = 0;
00374 for (const Vehicle *v = ::GetVehicle(vehicle_id); v != NULL; v = v->Next()) {
00375 if (v->cargo_type == cargo) amount += v->cargo_cap;
00376 }
00377
00378 return amount;
00379 }
00380
00381 int32 AIVehicle::GetCargoLoad(VehicleID vehicle_id, CargoID cargo)
00382 {
00383 if (!IsValidVehicle(vehicle_id)) return -1;
00384 if (!AICargo::IsValidCargo(cargo)) return -1;
00385
00386 uint32 amount = 0;
00387 for (const Vehicle *v = ::GetVehicle(vehicle_id); v != NULL; v = v->Next()) {
00388 if (v->cargo_type == cargo) amount += v->cargo.Count();
00389 }
00390
00391 return amount;
00392 }
00393
00394 GroupID AIVehicle::GetGroupID(VehicleID vehicle_id)
00395 {
00396 if (!IsValidVehicle(vehicle_id)) return AIGroup::GROUP_INVALID;
00397
00398 return ::GetVehicle(vehicle_id)->group_id;
00399 }
00400
00401 bool AIVehicle::IsArticulated(VehicleID vehicle_id)
00402 {
00403 if (!IsValidVehicle(vehicle_id)) return false;
00404 if (GetVehicleType(vehicle_id) != VT_ROAD && GetVehicleType(vehicle_id) != VT_RAIL) return false;
00405
00406 const Vehicle *v = ::GetVehicle(vehicle_id);
00407 switch (v->type) {
00408 case VEH_ROAD: return RoadVehHasArticPart(v);
00409 case VEH_TRAIN: return EngineHasArticPart(v);
00410 default: NOT_REACHED();
00411 }
00412 }
00413
00414 bool AIVehicle::HasSharedOrders(VehicleID vehicle_id)
00415 {
00416 if (!IsValidVehicle(vehicle_id)) return false;
00417
00418 Vehicle *v = ::GetVehicle(vehicle_id);
00419 return v->orders.list != NULL && v->orders.list->GetNumVehicles() > 1;
00420 }