00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifndef TRAIN_H
00013 #define TRAIN_H
00014
00015 #include "newgrf_engine.h"
00016 #include "cargotype.h"
00017 #include "rail.h"
00018 #include "engine_base.h"
00019 #include "rail_map.h"
00020 #include "ground_vehicle.hpp"
00021
00022 struct Train;
00023
00024 enum VehicleRailFlags {
00025 VRF_REVERSING = 0,
00026
00027
00028 VRF_POWEREDWAGON = 3,
00029
00030
00031 VRF_REVERSE_DIRECTION = 4,
00032
00033
00034 VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6,
00035
00036
00037 VRF_TOGGLE_REVERSE = 7,
00038
00039
00040 VRF_TRAIN_STUCK = 8,
00041
00042
00043 VRF_LEAVING_STATION = 9,
00044 };
00045
00047 enum TrainForceProceeding {
00048 TFP_NONE = 0,
00049 TFP_STUCK = 1,
00050 TFP_SIGNAL = 2,
00051 };
00052 typedef SimpleTinyEnumT<TrainForceProceeding, byte> TrainForceProceedingByte;
00053
00054 byte FreightWagonMult(CargoID cargo);
00055
00056 void CheckTrainsLengths();
00057
00058 void FreeTrainTrackReservation(const Train *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR);
00059 bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay = false);
00060
00061 int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length);
00062
00064 struct TrainCache {
00065
00066 const struct SpriteGroup *cached_override;
00067
00068 uint16 last_speed;
00069
00070
00071 bool cached_tilt;
00072
00073 byte user_def_data;
00074
00075
00076 int cached_max_curve_speed;
00077 };
00078
00082 struct Train : public GroundVehicle<Train, VEH_TRAIN> {
00083 TrainCache tcache;
00084
00085
00086 Train *other_multiheaded_part;
00087
00088 uint16 crash_anim_pos;
00089
00090 uint16 flags;
00091 TrackBitsByte track;
00092 TrainForceProceedingByte force_proceed;
00093 RailTypeByte railtype;
00094 RailTypes compatible_railtypes;
00095
00097 uint16 wait_counter;
00098
00100 Train() : GroundVehicle<Train, VEH_TRAIN>() {}
00102 virtual ~Train() { this->PreDestructor(); }
00103
00104 friend struct GroundVehicle<Train, VEH_TRAIN>;
00105
00106 const char *GetTypeString() const { return "train"; }
00107 void MarkDirty();
00108 void UpdateDeltaXY(Direction direction);
00109 ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; }
00110 void PlayLeaveStationSound() const;
00111 bool IsPrimaryVehicle() const { return this->IsFrontEngine(); }
00112 SpriteID GetImage(Direction direction) const;
00113 int GetDisplaySpeed() const { return this->tcache.last_speed; }
00114 int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; }
00115 Money GetRunningCost() const;
00116 int GetDisplayImageWidth(Point *offset = NULL) const;
00117 bool IsInDepot() const;
00118 bool IsStoppedInDepot() const;
00119 bool Tick();
00120 void OnNewDay();
00121 uint Crash(bool flooded = false);
00122 Trackdir GetVehicleTrackdir() const;
00123 TileIndex GetOrderStationLocation(StationID station);
00124 bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
00125
00126 void ReserveTrackUnderConsist() const;
00127
00128 int GetCurveSpeedLimit() const;
00129
00130 void ConsistChanged(bool same_length);
00131
00132 void RailtypeChanged();
00133
00134 int UpdateSpeed();
00135
00136 void UpdateAcceleration();
00137
00138 int GetCurrentMaxSpeed() const;
00139
00145 enum TrainSubtype {
00146 TS_FRONT = 0,
00147 TS_ARTICULATED_PART = 1,
00148 TS_WAGON = 2,
00149 TS_ENGINE = 3,
00150 TS_FREE_WAGON = 4,
00151 TS_MULTIHEADED = 5,
00152 };
00153
00157 FORCEINLINE void SetFrontEngine() { SetBit(this->subtype, TS_FRONT); }
00158
00162 FORCEINLINE void ClearFrontEngine() { ClrBit(this->subtype, TS_FRONT); }
00163
00167 FORCEINLINE void SetArticulatedPart() { SetBit(this->subtype, TS_ARTICULATED_PART); }
00168
00172 FORCEINLINE void ClearArticulatedPart() { ClrBit(this->subtype, TS_ARTICULATED_PART); }
00173
00177 FORCEINLINE void SetWagon() { SetBit(this->subtype, TS_WAGON); }
00178
00182 FORCEINLINE void ClearWagon() { ClrBit(this->subtype, TS_WAGON); }
00183
00187 FORCEINLINE void SetEngine() { SetBit(this->subtype, TS_ENGINE); }
00188
00192 FORCEINLINE void ClearEngine() { ClrBit(this->subtype, TS_ENGINE); }
00193
00197 FORCEINLINE void SetFreeWagon() { SetBit(this->subtype, TS_FREE_WAGON); }
00198
00202 FORCEINLINE void ClearFreeWagon() { ClrBit(this->subtype, TS_FREE_WAGON); }
00203
00207 FORCEINLINE void SetMultiheaded() { SetBit(this->subtype, TS_MULTIHEADED); }
00208
00212 FORCEINLINE void ClearMultiheaded() { ClrBit(this->subtype, TS_MULTIHEADED); }
00213
00214
00219 FORCEINLINE bool IsFrontEngine() const { return HasBit(this->subtype, TS_FRONT); }
00220
00225 FORCEINLINE bool IsFreeWagon() const { return HasBit(this->subtype, TS_FREE_WAGON); }
00226
00231 FORCEINLINE bool IsEngine() const { return HasBit(this->subtype, TS_ENGINE); }
00232
00237 FORCEINLINE bool IsWagon() const { return HasBit(this->subtype, TS_WAGON); }
00238
00243 FORCEINLINE bool IsMultiheaded() const { return HasBit(this->subtype, TS_MULTIHEADED); }
00244
00249 FORCEINLINE bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00250
00255 FORCEINLINE bool IsArticulatedPart() const { return HasBit(this->subtype, TS_ARTICULATED_PART); }
00256
00261 FORCEINLINE bool HasArticulatedPart() const { return this->Next() != NULL && this->Next()->IsArticulatedPart(); }
00262
00263
00270 FORCEINLINE Train *GetNextArticPart() const
00271 {
00272 assert(this->HasArticulatedPart());
00273 return this->Next();
00274 }
00275
00280 FORCEINLINE Train *GetFirstEnginePart()
00281 {
00282 Train *v = this;
00283 while (v->IsArticulatedPart()) v = v->Previous();
00284 return v;
00285 }
00286
00291 FORCEINLINE const Train *GetFirstEnginePart() const
00292 {
00293 const Train *v = this;
00294 while (v->IsArticulatedPart()) v = v->Previous();
00295 return v;
00296 }
00297
00302 FORCEINLINE Train *GetLastEnginePart()
00303 {
00304 Train *v = this;
00305 while (v->HasArticulatedPart()) v = v->GetNextArticPart();
00306 return v;
00307 }
00308
00313 FORCEINLINE Train *GetNextVehicle() const
00314 {
00315 const Train *v = this;
00316 while (v->HasArticulatedPart()) v = v->GetNextArticPart();
00317
00318
00319 return v->Next();
00320 }
00321
00326 FORCEINLINE Train *GetPrevVehicle() const
00327 {
00328 Train *v = this->Previous();
00329 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00330
00331 return v;
00332 }
00333
00338 FORCEINLINE Train *GetNextUnit() const
00339 {
00340 Train *v = this->GetNextVehicle();
00341 if (v != NULL && v->IsRearDualheaded()) v = v->GetNextVehicle();
00342
00343 return v;
00344 }
00345
00350 FORCEINLINE Train *GetPrevUnit()
00351 {
00352 Train *v = this->GetPrevVehicle();
00353 if (v != NULL && v->IsRearDualheaded()) v = v->GetPrevVehicle();
00354
00355 return v;
00356 }
00357
00358
00359 protected:
00360
00365 FORCEINLINE uint16 GetPower() const
00366 {
00367
00368 if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) {
00369 uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power);
00370
00371 if (this->IsMultiheaded()) power /= 2;
00372 return power;
00373 }
00374
00375 return 0;
00376 }
00377
00382 FORCEINLINE uint16 GetPoweredPartPower(const Train *head) const
00383 {
00384
00385 if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(this->tile))) {
00386 return RailVehInfo(this->gcache.first_engine)->pow_wag_power;
00387 }
00388
00389 return 0;
00390 }
00391
00396 FORCEINLINE uint16 GetWeight() const
00397 {
00398 uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.Count() * FreightWagonMult(this->cargo_type)) / 16;
00399
00400
00401 if (!this->IsArticulatedPart()) {
00402 weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight);
00403 }
00404
00405
00406 if (HasBit(this->flags, VRF_POWEREDWAGON)) {
00407 weight += RailVehInfo(this->gcache.first_engine)->pow_wag_weight;
00408 }
00409
00410 return weight;
00411 }
00412
00417 FORCEINLINE byte GetTractiveEffort() const
00418 {
00419 return GetVehicleProperty(this, PROP_TRAIN_TRACTIVE_EFFORT, RailVehInfo(this->engine_type)->tractive_effort);
00420 }
00421
00426 FORCEINLINE byte GetAirDragArea() const
00427 {
00428
00429 return (this->track == TRACK_BIT_WORMHOLE && this->vehstatus & VS_HIDDEN) ? 28 : 14;
00430 }
00431
00436 FORCEINLINE byte GetAirDrag() const
00437 {
00438 return RailVehInfo(this->engine_type)->air_drag;
00439 }
00440
00445 FORCEINLINE AccelStatus GetAccelerationStatus() const
00446 {
00447 return (this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK) ? AS_BRAKE : AS_ACCEL;
00448 }
00449
00454 FORCEINLINE uint16 GetCurrentSpeed() const
00455 {
00456 return this->cur_speed;
00457 }
00458
00463 FORCEINLINE uint32 GetRollingFriction() const
00464 {
00465
00466
00467
00468 return 15 * (512 + this->GetCurrentSpeed()) / 512;
00469 }
00470
00475 FORCEINLINE int GetAccelerationType() const
00476 {
00477 return GetRailTypeInfo(this->railtype)->acceleration_type;
00478 }
00479
00484 FORCEINLINE uint32 GetSlopeSteepness() const
00485 {
00486 return _settings_game.vehicle.train_slope_steepness;
00487 }
00488
00493 FORCEINLINE uint16 GetMaxTrackSpeed() const
00494 {
00495 return GetRailTypeInfo(GetRailType(this->tile))->max_speed;
00496 }
00497
00502 FORCEINLINE bool TileMayHaveSlopedTrack() const
00503 {
00504
00505 return this->track == TRACK_BIT_X || this->track == TRACK_BIT_Y;
00506 }
00507 };
00508
00509 #define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
00510
00511 #endif