script_vehicle.cpp

Go to the documentation of this file.
00001 /* $Id: script_vehicle.cpp 23636 2011-12-19 21:06:06Z truebrain $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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   /* In case of test-mode, we return VehicleID 0 */
00074   return 0;
00075 }
00076 
00077 /* static */ 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   /* In case of test-mode, we return VehicleID 0 */
00085   return 0;
00086 }
00087 
00088 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ bool ScriptVehicle::SellWagon(VehicleID vehicle_id, int wagon)
00157 {
00158   return _SellWagonInternal(vehicle_id, wagon, false);
00159 }
00160 
00161 /* static */ bool ScriptVehicle::SellWagonChain(VehicleID vehicle_id, int wagon)
00162 {
00163   return _SellWagonInternal(vehicle_id, wagon, true);
00164 }
00165 
00166 /* static */ 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 /* static */ 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 /* static */ bool ScriptVehicle::IsInDepot(VehicleID vehicle_id)
00183 {
00184   if (!IsValidVehicle(vehicle_id)) return false;
00185   return ::Vehicle::Get(vehicle_id)->IsInDepot();
00186 }
00187 
00188 /* static */ bool ScriptVehicle::IsStoppedInDepot(VehicleID vehicle_id)
00189 {
00190   if (!IsValidVehicle(vehicle_id)) return false;
00191   return ::Vehicle::Get(vehicle_id)->IsStoppedInDepot();
00192 }
00193 
00194 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ int32 ScriptVehicle::GetCurrentSpeed(VehicleID vehicle_id)
00315 {
00316   if (!IsValidVehicle(vehicle_id)) return -1;
00317 
00318   return ::Vehicle::Get(vehicle_id)->GetDisplaySpeed(); // km-ish/h
00319 }
00320 
00321 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 /* static */ 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 }