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
00063 struct AccelerationCache {
00064
00065 uint32 cached_weight;
00066 uint32 cached_slope_resistance;
00067 uint32 cached_max_te;
00068
00069
00070 uint32 cached_power;
00071 uint32 cached_air_drag;
00072 uint16 cached_axle_resistance;
00073 };
00074
00076 struct TrainCache : public AccelerationCache {
00077
00078 const struct SpriteGroup *cached_override;
00079
00080 uint16 last_speed;
00081
00082
00083 uint16 cached_total_length;
00084 uint8 cached_veh_length;
00085 bool cached_tilt;
00086
00087
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
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
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:
00393
00394 void UpdateVisualEffect(bool allow_power_change);
00395
00400 FORCEINLINE uint16 GetPower() const
00401 {
00402
00403 if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) {
00404 uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power);
00405
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
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
00436 if (!this->IsArticulatedPart()) {
00437 weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight);
00438 }
00439
00440
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;
00519 }
00520 };
00521
00522 #define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
00523
00524 #endif