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