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