00001
00002
00003
00004
00005
00006
00007
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
00028 VRF_GOINGUP = 1,
00029 VRF_GOINGDOWN = 2,
00030
00031
00032 VRF_POWEREDWAGON = 3,
00033
00034
00035 VRF_REVERSE_DIRECTION = 4,
00036
00037
00038 VRF_NO_PATH_TO_DESTINATION = 5,
00039
00040
00041 VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6,
00042
00043
00044 VRF_TOGGLE_REVERSE = 7,
00045
00046
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
00060 struct TrainCache {
00061
00062 const struct SpriteGroup *cached_override;
00063
00064 uint16 last_speed;
00065
00066
00067 uint32 cached_power;
00068 uint16 cached_axle_resistance;
00069 uint32 cached_air_drag;
00070 uint16 cached_total_length;
00071 uint8 cached_veh_length;
00072 bool cached_tilt;
00073
00074
00075 uint32 cached_weight;
00076 uint32 cached_slope_resistance;
00077 uint32 cached_max_te;
00078
00079
00080 uint16 cached_max_speed;
00081 int cached_max_curve_speed;
00082
00090 byte cached_vis_effect;
00091 byte user_def_data;
00092
00093 EngineID first_engine;
00094 };
00095
00097 enum AccelStatus {
00098 AS_ACCEL,
00099 AS_BRAKE
00100 };
00101
00105 struct Train : public SpecializedVehicle<Train, VEH_TRAIN> {
00106 TrainCache tcache;
00107
00108
00109 Train *other_multiheaded_part;
00110
00111 uint16 crash_anim_pos;
00112
00113 uint16 flags;
00114 TrackBitsByte track;
00115 byte force_proceed;
00116 RailTypeByte railtype;
00117 RailTypes compatible_railtypes;
00118
00120 uint16 wait_counter;
00121
00123 Train() : SpecializedVehicle<Train, VEH_TRAIN>() {}
00125 virtual ~Train() { this->PreDestructor(); }
00126
00127 const char *GetTypeString() const { return "train"; }
00128 void MarkDirty();
00129 void UpdateDeltaXY(Direction direction);
00130 ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; }
00131 void PlayLeaveStationSound() const;
00132 bool IsPrimaryVehicle() const { return this->IsFrontEngine(); }
00133 SpriteID GetImage(Direction direction) const;
00134 int GetDisplaySpeed() const { return this->tcache.last_speed; }
00135 int GetDisplayMaxSpeed() const { return this->tcache.cached_max_speed; }
00136 Money GetRunningCost() const;
00137 int GetDisplayImageWidth(Point *offset = NULL) const;
00138 bool IsInDepot() const;
00139 bool IsStoppedInDepot() const;
00140 bool Tick();
00141 void OnNewDay();
00142 uint Crash(bool flooded = false);
00143 Trackdir GetVehicleTrackdir() const;
00144 TileIndex GetOrderStationLocation(StationID station);
00145 bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
00146
00147 void ReserveTrackUnderConsist() const;
00148
00149 int GetCurveSpeedLimit() const;
00150
00151 void ConsistChanged(bool same_length);
00152 void CargoChanged();
00153 void PowerChanged();
00154
00155 int UpdateSpeed();
00156
00157 void UpdateAcceleration();
00158
00159 int GetCurrentMaxSpeed() const;
00160 int GetAcceleration() const;
00161
00167 enum TrainSubtype {
00168 TS_FRONT = 0,
00169 TS_ARTICULATED_PART = 1,
00170 TS_WAGON = 2,
00171 TS_ENGINE = 3,
00172 TS_FREE_WAGON = 4,
00173 TS_MULTIHEADED = 5,
00174 };
00175
00179 FORCEINLINE void SetFrontEngine() { SetBit(this->subtype, TS_FRONT); }
00180
00184 FORCEINLINE void ClearFrontEngine() { ClrBit(this->subtype, TS_FRONT); }
00185
00189 FORCEINLINE void SetArticulatedPart() { SetBit(this->subtype, TS_ARTICULATED_PART); }
00190
00194 FORCEINLINE void ClearArticulatedPart() { ClrBit(this->subtype, TS_ARTICULATED_PART); }
00195
00199 FORCEINLINE void SetWagon() { SetBit(this->subtype, TS_WAGON); }
00200
00204 FORCEINLINE void ClearWagon() { ClrBit(this->subtype, TS_WAGON); }
00205
00209 FORCEINLINE void SetEngine() { SetBit(this->subtype, TS_ENGINE); }
00210
00214 FORCEINLINE void ClearEngine() { ClrBit(this->subtype, TS_ENGINE); }
00215
00219 FORCEINLINE void SetFreeWagon() { SetBit(this->subtype, TS_FREE_WAGON); }
00220
00224 FORCEINLINE void ClearFreeWagon() { ClrBit(this->subtype, TS_FREE_WAGON); }
00225
00229 FORCEINLINE void SetMultiheaded() { SetBit(this->subtype, TS_MULTIHEADED); }
00230
00234 FORCEINLINE void ClearMultiheaded() { ClrBit(this->subtype, TS_MULTIHEADED); }
00235
00236
00241 FORCEINLINE bool IsFrontEngine() const { return HasBit(this->subtype, TS_FRONT); }
00242
00247 FORCEINLINE bool IsFreeWagon() const { return HasBit(this->subtype, TS_FREE_WAGON); }
00248
00253 FORCEINLINE bool IsEngine() const { return HasBit(this->subtype, TS_ENGINE); }
00254
00259 FORCEINLINE bool IsWagon() const { return HasBit(this->subtype, TS_WAGON); }
00260
00265 FORCEINLINE bool IsMultiheaded() const { return HasBit(this->subtype, TS_MULTIHEADED); }
00266
00271 FORCEINLINE bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00272
00277 FORCEINLINE bool IsArticulatedPart() const { return HasBit(this->subtype, TS_ARTICULATED_PART); }
00278
00283 FORCEINLINE bool HasArticulatedPart() const { return this->Next() != NULL && this->Next()->IsArticulatedPart(); }
00284
00285
00292 FORCEINLINE Train *GetNextArticPart() const
00293 {
00294 assert(this->HasArticulatedPart());
00295 return this->Next();
00296 }
00297
00302 FORCEINLINE Train *GetFirstEnginePart()
00303 {
00304 Train *v = this;
00305 while (v->IsArticulatedPart()) v = v->Previous();
00306 return v;
00307 }
00308
00313 FORCEINLINE const Train *GetFirstEnginePart() const
00314 {
00315 const Train *v = this;
00316 while (v->IsArticulatedPart()) v = v->Previous();
00317 return v;
00318 }
00319
00324 FORCEINLINE Train *GetLastEnginePart()
00325 {
00326 Train *v = this;
00327 while (v->HasArticulatedPart()) v = v->GetNextArticPart();
00328 return v;
00329 }
00330
00335 FORCEINLINE Train *GetNextVehicle() const
00336 {
00337 const Train *v = this;
00338 while (v->HasArticulatedPart()) v = v->GetNextArticPart();
00339
00340
00341 return v->Next();
00342 }
00343
00348 FORCEINLINE Train *GetPrevVehicle() const
00349 {
00350 Train *v = this->Previous();
00351 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00352
00353 return v;
00354 }
00355
00360 FORCEINLINE Train *GetNextUnit() const
00361 {
00362 Train *v = this->GetNextVehicle();
00363 if (v != NULL && v->IsRearDualheaded()) v = v->GetNextVehicle();
00364
00365 return v;
00366 }
00367
00372 FORCEINLINE Train *GetPrevUnit()
00373 {
00374 Train *v = this->GetPrevVehicle();
00375 if (v != NULL && v->IsRearDualheaded()) v = v->GetPrevVehicle();
00376
00377 return v;
00378 }
00379
00380
00381 protected:
00382
00387 FORCEINLINE uint16 GetPower() const
00388 {
00389
00390 if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) {
00391 uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power);
00392
00393 if (this->IsMultiheaded()) power /= 2;
00394 return power;
00395 }
00396
00397 return 0;
00398 }
00399
00404 FORCEINLINE uint16 GetPoweredPartPower(const Train *head) const
00405 {
00406 if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(head->tile))) {
00407 return RailVehInfo(this->tcache.first_engine)->pow_wag_power;
00408 }
00409
00410 return 0;
00411 }
00412
00417 FORCEINLINE uint16 GetWeight() const
00418 {
00419 uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.Count() * FreightWagonMult(this->cargo_type)) / 16;
00420
00421
00422 if (!this->IsArticulatedPart()) {
00423 weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight);
00424 }
00425
00426
00427 if (HasBit(this->flags, VRF_POWEREDWAGON)) {
00428 weight += RailVehInfo(this->tcache.first_engine)->pow_wag_weight;
00429 }
00430
00431 return weight;
00432 }
00433
00438 FORCEINLINE byte GetTractiveEffort() const
00439 {
00440 return GetVehicleProperty(this, PROP_TRAIN_TRACTIVE_EFFORT, RailVehInfo(this->engine_type)->tractive_effort);
00441 }
00442
00447 FORCEINLINE AccelStatus GetAccelerationStatus() const
00448 {
00449 return (this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK) ? AS_BRAKE : AS_ACCEL;
00450 }
00451
00456 FORCEINLINE uint16 GetCurrentSpeed() const
00457 {
00458 return this->cur_speed * 10 / 16;
00459 }
00460
00465 FORCEINLINE uint32 GetRollingFriction() const
00466 {
00467 return 35;
00468 }
00469
00474 FORCEINLINE int32 GetSlopeResistance() const
00475 {
00476 int32 incl = 0;
00477
00478 for (const Train *u = this; u != NULL; u = u->Next()) {
00479 if (HasBit(u->flags, VRF_GOINGUP)) {
00480 incl += u->tcache.cached_slope_resistance;
00481 } else if (HasBit(u->flags, VRF_GOINGDOWN)) {
00482 incl -= u->tcache.cached_slope_resistance;
00483 }
00484 }
00485
00486 return incl;
00487 }
00488
00493 FORCEINLINE int GetAccelerationType() const
00494 {
00495 return GetRailTypeInfo(this->railtype)->acceleration_type;
00496 }
00497 };
00498
00499 #define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
00500
00501 #endif