script_vehicle.cpp

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