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 int UpdateSpeed();
00165
00166 void UpdateAcceleration();
00167
00168 int GetCurrentMaxSpeed() const;
00169 int GetAcceleration() const;
00170
00176 enum TrainSubtype {
00177 TS_FRONT = 0,
00178 TS_ARTICULATED_PART = 1,
00179 TS_WAGON = 2,
00180 TS_ENGINE = 3,
00181 TS_FREE_WAGON = 4,
00182 TS_MULTIHEADED = 5,
00183 };
00184
00188 FORCEINLINE void SetFrontEngine() { SetBit(this->subtype, TS_FRONT); }
00189
00193 FORCEINLINE void ClearFrontEngine() { ClrBit(this->subtype, TS_FRONT); }
00194
00198 FORCEINLINE void SetArticulatedPart() { SetBit(this->subtype, TS_ARTICULATED_PART); }
00199
00203 FORCEINLINE void ClearArticulatedPart() { ClrBit(this->subtype, TS_ARTICULATED_PART); }
00204
00208 FORCEINLINE void SetWagon() { SetBit(this->subtype, TS_WAGON); }
00209
00213 FORCEINLINE void ClearWagon() { ClrBit(this->subtype, TS_WAGON); }
00214
00218 FORCEINLINE void SetEngine() { SetBit(this->subtype, TS_ENGINE); }
00219
00223 FORCEINLINE void ClearEngine() { ClrBit(this->subtype, TS_ENGINE); }
00224
00228 FORCEINLINE void SetFreeWagon() { SetBit(this->subtype, TS_FREE_WAGON); }
00229
00233 FORCEINLINE void ClearFreeWagon() { ClrBit(this->subtype, TS_FREE_WAGON); }
00234
00238 FORCEINLINE void SetMultiheaded() { SetBit(this->subtype, TS_MULTIHEADED); }
00239
00243 FORCEINLINE void ClearMultiheaded() { ClrBit(this->subtype, TS_MULTIHEADED); }
00244
00245
00250 FORCEINLINE bool IsFrontEngine() const { return HasBit(this->subtype, TS_FRONT); }
00251
00256 FORCEINLINE bool IsFreeWagon() const { return HasBit(this->subtype, TS_FREE_WAGON); }
00257
00262 FORCEINLINE bool IsEngine() const { return HasBit(this->subtype, TS_ENGINE); }
00263
00268 FORCEINLINE bool IsWagon() const { return HasBit(this->subtype, TS_WAGON); }
00269
00274 FORCEINLINE bool IsMultiheaded() const { return HasBit(this->subtype, TS_MULTIHEADED); }
00275
00280 FORCEINLINE bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00281
00286 FORCEINLINE bool IsArticulatedPart() const { return HasBit(this->subtype, TS_ARTICULATED_PART); }
00287
00292 FORCEINLINE bool HasArticulatedPart() const { return this->Next() != NULL && this->Next()->IsArticulatedPart(); }
00293
00294
00301 FORCEINLINE Train *GetNextArticPart() const
00302 {
00303 assert(this->HasArticulatedPart());
00304 return this->Next();
00305 }
00306
00311 FORCEINLINE Train *GetFirstEnginePart()
00312 {
00313 Train *v = this;
00314 while (v->IsArticulatedPart()) v = v->Previous();
00315 return v;
00316 }
00317
00322 FORCEINLINE const Train *GetFirstEnginePart() const
00323 {
00324 const Train *v = this;
00325 while (v->IsArticulatedPart()) v = v->Previous();
00326 return v;
00327 }
00328
00333 FORCEINLINE Train *GetLastEnginePart()
00334 {
00335 Train *v = this;
00336 while (v->HasArticulatedPart()) v = v->GetNextArticPart();
00337 return v;
00338 }
00339
00344 FORCEINLINE Train *GetNextVehicle() const
00345 {
00346 const Train *v = this;
00347 while (v->HasArticulatedPart()) v = v->GetNextArticPart();
00348
00349
00350 return v->Next();
00351 }
00352
00357 FORCEINLINE Train *GetPrevVehicle() const
00358 {
00359 Train *v = this->Previous();
00360 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00361
00362 return v;
00363 }
00364
00369 FORCEINLINE Train *GetNextUnit() const
00370 {
00371 Train *v = this->GetNextVehicle();
00372 if (v != NULL && v->IsRearDualheaded()) v = v->GetNextVehicle();
00373
00374 return v;
00375 }
00376
00381 FORCEINLINE Train *GetPrevUnit()
00382 {
00383 Train *v = this->GetPrevVehicle();
00384 if (v != NULL && v->IsRearDualheaded()) v = v->GetPrevVehicle();
00385
00386 return v;
00387 }
00388
00389
00390 protected:
00391
00396 FORCEINLINE uint16 GetPower() const
00397 {
00398
00399 if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) {
00400 uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power);
00401
00402 if (this->IsMultiheaded()) power /= 2;
00403 return power;
00404 }
00405
00406 return 0;
00407 }
00408
00413 FORCEINLINE uint16 GetPoweredPartPower(const Train *head) const
00414 {
00415 if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(head->tile))) {
00416 return RailVehInfo(this->tcache.first_engine)->pow_wag_power;
00417 }
00418
00419 return 0;
00420 }
00421
00426 FORCEINLINE uint16 GetWeight() const
00427 {
00428 uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.Count() * FreightWagonMult(this->cargo_type)) / 16;
00429
00430
00431 if (!this->IsArticulatedPart()) {
00432 weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight);
00433 }
00434
00435
00436 if (HasBit(this->flags, VRF_POWEREDWAGON)) {
00437 weight += RailVehInfo(this->tcache.first_engine)->pow_wag_weight;
00438 }
00439
00440 return weight;
00441 }
00442
00447 FORCEINLINE byte GetTractiveEffort() const
00448 {
00449 return GetVehicleProperty(this, PROP_TRAIN_TRACTIVE_EFFORT, RailVehInfo(this->engine_type)->tractive_effort);
00450 }
00451
00456 FORCEINLINE AccelStatus GetAccelerationStatus() const
00457 {
00458 return (this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK) ? AS_BRAKE : AS_ACCEL;
00459 }
00460
00465 FORCEINLINE uint16 GetCurrentSpeed() const
00466 {
00467 return this->cur_speed * 10 / 16;
00468 }
00469
00474 FORCEINLINE uint32 GetRollingFriction() const
00475 {
00476 return 35;
00477 }
00478
00483 FORCEINLINE int32 GetSlopeResistance() const
00484 {
00485 int32 incl = 0;
00486
00487 for (const Train *u = this; u != NULL; u = u->Next()) {
00488 if (HasBit(u->flags, VRF_GOINGUP)) {
00489 incl += u->tcache.cached_slope_resistance;
00490 } else if (HasBit(u->flags, VRF_GOINGDOWN)) {
00491 incl -= u->tcache.cached_slope_resistance;
00492 }
00493 }
00494
00495 return incl;
00496 }
00497
00502 FORCEINLINE int GetAccelerationType() const
00503 {
00504 return GetRailTypeInfo(this->railtype)->acceleration_type;
00505 }
00506
00511 FORCEINLINE uint32 GetSlopeSteepness() const
00512 {
00513 return 20 * _settings_game.vehicle.train_slope_steepness;
00514 }
00515 };
00516
00517 #define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
00518
00519 #endif