# train.h

Go to the documentation of this file.

    00001 /* $Id: train.h 20521 2010-08-16 23:15:33Z rubidium $ */
    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 #ifndef TRAIN_H
    00013 #define TRAIN_H
    00014
    00015 #include "vehicle_base.h"
    00016 #include "newgrf_engine.h"
    00017 #include "cargotype.h"
    00018 #include "rail.h"
    00019 #include "engine_base.h"
    00020 #include "rail_map.h"
    00021
    00022 struct Train;
    00023
    00024 enum VehicleRailFlags {
    00025   VRF_REVERSING         = 0,
    00026
    00027   /* used to calculate if train is going up or down */
    00028   VRF_GOINGUP           = 1,
    00029   VRF_GOINGDOWN         = 2,
    00030
    00031   /* used to store if a wagon is powered or not */
    00032   VRF_POWEREDWAGON      = 3,
    00033
    00034   /* used to reverse the visible direction of the vehicle */
    00035   VRF_REVERSE_DIRECTION = 4,
    00036
    00037   /* used to mark train as lost because PF can't find the route */
    00038   VRF_NO_PATH_TO_DESTINATION = 5,
    00039
    00040   /* used to mark that electric train engine is allowed to run on normal rail */
    00041   VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6,
    00042
    00043   /* used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle only) */
    00044   VRF_TOGGLE_REVERSE = 7,
    00045
    00046   /* used to mark a train that can't get a path reservation */
    00047   VRF_TRAIN_STUCK    = 8,
    00048 };
    00049
    00050 byte FreightWagonMult(CargoID cargo);
    00051
    00052 void CheckTrainsLengths();
    00053
    00054 void FreeTrainTrackReservation(const Train *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR);
    00055 bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay = false);
    00056
    00057 int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length);
    00058
    00063 struct AccelerationCache {
    00064   /* cached values, recalculated when the cargo on a train changes (in addition to the conditions above) */
    00065   uint32 cached_weight;
    00066   uint32 cached_slope_resistance;
    00067   uint32 cached_max_te;
    00068
    00069   /* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */
    00070   uint32 cached_power;
    00071   uint32 cached_air_drag;
    00072   uint16 cached_axle_resistance;
    00073 };
    00074
    00076 struct TrainCache : public AccelerationCache {
    00077   /* Cached wagon override spritegroup */
    00078   const struct SpriteGroup *cached_override;
    00079
    00080   uint16 last_speed; // NOSAVE: only used in UI
    00081
    00082   /* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */
    00083   uint16 cached_total_length;
    00084   uint8 cached_veh_length;
    00085   bool cached_tilt;
    00086
    00087   /* cached max. speed / acceleration data */
    00088   uint16 cached_max_speed;
    00089   uint16 cached_max_rail_speed;
    00090   int cached_max_curve_speed;
    00091
    00099   byte cached_vis_effect;
    00100   byte user_def_data;
    00101
    00102   EngineID first_engine;
    00103 };
    00104
    00106 enum AccelStatus {
    00107   AS_ACCEL,
    00108   AS_BRAKE
    00109 };
    00110
    00114 struct Train : public SpecializedVehicle<Train, VEH_TRAIN> {
    00115   TrainCache tcache;
    00116
    00117   /* Link between the two ends of a multiheaded engine */
    00118   Train *other_multiheaded_part;
    00119
    00120   uint16 crash_anim_pos;
    00121
    00122   uint16 flags;
    00123   TrackBitsByte track;
    00124   byte force_proceed;
    00125   RailTypeByte railtype;
    00126   RailTypes compatible_railtypes;
    00127
    00129   uint16 wait_counter;
    00130
    00132   Train() : SpecializedVehicle<Train, VEH_TRAIN>() {}
    00134   virtual ~Train() { this->PreDestructor(); }
    00135
    00136   const char *GetTypeString() const { return "train"; }
    00137   void MarkDirty();
    00138   void UpdateDeltaXY(Direction direction);
    00139   ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; }
    00140   void PlayLeaveStationSound() const;
    00141   bool IsPrimaryVehicle() const { return this->IsFrontEngine(); }
    00142   SpriteID GetImage(Direction direction) const;
    00143   int GetDisplaySpeed() const { return this->tcache.last_speed; }
    00144   int GetDisplayMaxSpeed() const { return this->tcache.cached_max_speed; }
    00145   Money GetRunningCost() const;
    00146   int GetDisplayImageWidth(Point *offset = NULL) const;
    00147   bool IsInDepot() const;
    00148   bool IsStoppedInDepot() const;
    00149   bool Tick();
    00150   void OnNewDay();
    00151   uint Crash(bool flooded = false);
    00152   Trackdir GetVehicleTrackdir() const;
    00153   TileIndex GetOrderStationLocation(StationID station);
    00154   bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
    00155
    00156   void ReserveTrackUnderConsist() const;
    00157
    00158   int GetCurveSpeedLimit() const;
    00159
    00160   void ConsistChanged(bool same_length);
    00161   void CargoChanged();
    00162   void PowerChanged();
    00163
    00164   void RailtypeChanged();
    00165
    00166   int UpdateSpeed();
    00167
    00168   void UpdateAcceleration();
    00169
    00170   int GetCurrentMaxSpeed() const;
    00171   int GetAcceleration() const;
    00172
    00178   enum TrainSubtype {
    00179     TS_FRONT             = 0,
    00180     TS_ARTICULATED_PART  = 1,
    00181     TS_WAGON             = 2,
    00182     TS_ENGINE            = 3,
    00183     TS_FREE_WAGON        = 4,
    00184     TS_MULTIHEADED       = 5,
    00185   };
    00186
    00190   FORCEINLINE void SetFrontEngine() { SetBit(this->subtype, TS_FRONT); }
    00191
    00195   FORCEINLINE void ClearFrontEngine() { ClrBit(this->subtype, TS_FRONT); }
    00196
    00200   FORCEINLINE void SetArticulatedPart() { SetBit(this->subtype, TS_ARTICULATED_PART); }
    00201
    00205   FORCEINLINE void ClearArticulatedPart() { ClrBit(this->subtype, TS_ARTICULATED_PART); }
    00206
    00210   FORCEINLINE void SetWagon() { SetBit(this->subtype, TS_WAGON); }
    00211
    00215   FORCEINLINE void ClearWagon() { ClrBit(this->subtype, TS_WAGON); }
    00216
    00220   FORCEINLINE void SetEngine() { SetBit(this->subtype, TS_ENGINE); }
    00221
    00225   FORCEINLINE void ClearEngine() { ClrBit(this->subtype, TS_ENGINE); }
    00226
    00230   FORCEINLINE void SetFreeWagon() { SetBit(this->subtype, TS_FREE_WAGON); }
    00231
    00235   FORCEINLINE void ClearFreeWagon() { ClrBit(this->subtype, TS_FREE_WAGON); }
    00236
    00240   FORCEINLINE void SetMultiheaded() { SetBit(this->subtype, TS_MULTIHEADED); }
    00241
    00245   FORCEINLINE void ClearMultiheaded() { ClrBit(this->subtype, TS_MULTIHEADED); }
    00246
    00247
    00252   FORCEINLINE bool IsFrontEngine() const { return HasBit(this->subtype, TS_FRONT); }
    00253
    00258   FORCEINLINE bool IsFreeWagon() const { return HasBit(this->subtype, TS_FREE_WAGON); }
    00259
    00264   FORCEINLINE bool IsEngine() const { return HasBit(this->subtype, TS_ENGINE); }
    00265
    00270   FORCEINLINE bool IsWagon() const { return HasBit(this->subtype, TS_WAGON); }
    00271
    00276   FORCEINLINE bool IsMultiheaded() const { return HasBit(this->subtype, TS_MULTIHEADED); }
    00277
    00282   FORCEINLINE bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
    00283
    00288   FORCEINLINE bool IsArticulatedPart() const { return HasBit(this->subtype, TS_ARTICULATED_PART); }
    00289
    00294   FORCEINLINE bool HasArticulatedPart() const { return this->Next() != NULL && this->Next()->IsArticulatedPart(); }
    00295
    00296
    00303   FORCEINLINE Train *GetNextArticPart() const
    00304   {
    00305     assert(this->HasArticulatedPart());
    00306     return this->Next();
    00307   }
    00308
    00313   FORCEINLINE Train *GetFirstEnginePart()
    00314   {
    00315     Train *v = this;
    00316     while (v->IsArticulatedPart()) v = v->Previous();
    00317     return v;
    00318   }
    00319
    00324   FORCEINLINE const Train *GetFirstEnginePart() const
    00325   {
    00326     const Train *v = this;
    00327     while (v->IsArticulatedPart()) v = v->Previous();
    00328     return v;
    00329   }
    00330
    00335   FORCEINLINE Train *GetLastEnginePart()
    00336   {
    00337     Train *v = this;
    00338     while (v->HasArticulatedPart()) v = v->GetNextArticPart();
    00339     return v;
    00340   }
    00341
    00346   FORCEINLINE Train *GetNextVehicle() const
    00347   {
    00348     const Train *v = this;
    00349     while (v->HasArticulatedPart()) v = v->GetNextArticPart();
    00350
    00351     /* v now contains the last artic part in the engine */
    00352     return v->Next();
    00353   }
    00354
    00359   FORCEINLINE Train *GetPrevVehicle() const
    00360   {
    00361     Train *v = this->Previous();
    00362     while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
    00363
    00364     return v;
    00365   }
    00366
    00371   FORCEINLINE Train *GetNextUnit() const
    00372   {
    00373     Train *v = this->GetNextVehicle();
    00374     if (v != NULL && v->IsRearDualheaded()) v = v->GetNextVehicle();
    00375
    00376     return v;
    00377   }
    00378
    00383   FORCEINLINE Train *GetPrevUnit()
    00384   {
    00385     Train *v = this->GetPrevVehicle();
    00386     if (v != NULL && v->IsRearDualheaded()) v = v->GetPrevVehicle();
    00387
    00388     return v;
    00389   }
    00390
    00391
    00392 protected: // These functions should not be called outside acceleration code.
    00393
    00394   void UpdateVisualEffect(bool allow_power_change);
    00395
    00400   FORCEINLINE uint16 GetPower() const
    00401   {
    00402     /* Power is not added for articulated parts */
    00403     if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) {
    00404       uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power);
    00405       /* Halve power for multiheaded parts */
    00406       if (this->IsMultiheaded()) power /= 2;
    00407       return power;
    00408     }
    00409
    00410     return 0;
    00411   }
    00412
    00417   FORCEINLINE uint16 GetPoweredPartPower(const Train *head) const
    00418   {
    00419     /* For powered wagons the engine defines the type of engine (i.e. railtype) */
    00420     if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(this->tile))) {
    00421       return RailVehInfo(this->tcache.first_engine)->pow_wag_power;
    00422     }
    00423
    00424     return 0;
    00425   }
    00426
    00431   FORCEINLINE uint16 GetWeight() const
    00432   {
    00433     uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.Count() * FreightWagonMult(this->cargo_type)) / 16;
    00434
    00435     /* Vehicle weight is not added for articulated parts. */
    00436     if (!this->IsArticulatedPart()) {
    00437       weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight);
    00438     }
    00439
    00440     /* Powered wagons have extra weight added. */
    00441     if (HasBit(this->flags, VRF_POWEREDWAGON)) {
    00442       weight += RailVehInfo(this->tcache.first_engine)->pow_wag_weight;
    00443     }
    00444
    00445     return weight;
    00446   }
    00447
    00452   FORCEINLINE byte GetTractiveEffort() const
    00453   {
    00454     return GetVehicleProperty(this, PROP_TRAIN_TRACTIVE_EFFORT, RailVehInfo(this->engine_type)->tractive_effort);
    00455   }
    00456
    00461   FORCEINLINE AccelStatus GetAccelerationStatus() const
    00462   {
    00463     return (this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK) ? AS_BRAKE : AS_ACCEL;
    00464   }
    00465
    00470   FORCEINLINE uint16 GetCurrentSpeed() const
    00471   {
    00472     return this->cur_speed * 10 / 16;
    00473   }
    00474
    00479   FORCEINLINE uint32 GetRollingFriction() const
    00480   {
    00481     return 35;
    00482   }
    00483
    00488   FORCEINLINE int32 GetSlopeResistance() const
    00489   {
    00490     int32 incl = 0;
    00491
    00492     for (const Train *u = this; u != NULL; u = u->Next()) {
    00493       if (HasBit(u->flags, VRF_GOINGUP)) {
    00494         incl += u->tcache.cached_slope_resistance;
    00495       } else if (HasBit(u->flags, VRF_GOINGDOWN)) {
    00496         incl -= u->tcache.cached_slope_resistance;
    00497       }
    00498     }
    00499
    00500     return incl;
    00501   }
    00502
    00507   FORCEINLINE int GetAccelerationType() const
    00508   {
    00509     return GetRailTypeInfo(this->railtype)->acceleration_type;
    00510   }
    00511
    00516   FORCEINLINE uint32 GetSlopeSteepness() const
    00517   {
    00518     return 20 * _settings_game.vehicle.train_slope_steepness; // 1% slope * slope steepness
    00519   }
    00520 };
    00521
    00522 #define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
    00523
    00524 #endif /* TRAIN_H */