00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifndef TRAIN_H
00013 #define TRAIN_H
00014
00015 #include "core/enum_type.hpp"
00016
00017 #include "newgrf_engine.h"
00018 #include "cargotype.h"
00019 #include "rail.h"
00020 #include "engine_base.h"
00021 #include "rail_map.h"
00022 #include "ground_vehicle.hpp"
00023
00024 struct Train;
00025
00027 enum VehicleRailFlags {
00028 VRF_REVERSING = 0,
00029 VRF_POWEREDWAGON = 3,
00030 VRF_REVERSE_DIRECTION = 4,
00031
00032 VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6,
00033 VRF_TOGGLE_REVERSE = 7,
00034 VRF_TRAIN_STUCK = 8,
00035 VRF_LEAVING_STATION = 9,
00036 };
00037
00039 enum TrainForceProceeding {
00040 TFP_NONE = 0,
00041 TFP_STUCK = 1,
00042 TFP_SIGNAL = 2,
00043 };
00044 typedef SimpleTinyEnumT<TrainForceProceeding, byte> TrainForceProceedingByte;
00045
00047 enum ConsistChangeFlags {
00048 CCF_LENGTH = 0x01,
00049 CCF_CAPACITY = 0x02,
00050
00051 CCF_TRACK = 0,
00052 CCF_LOADUNLOAD = 0,
00053 CCF_AUTOREFIT = CCF_CAPACITY,
00054 CCF_REFIT = CCF_LENGTH | CCF_CAPACITY,
00055 CCF_ARRANGE = CCF_LENGTH | CCF_CAPACITY,
00056 CCF_SAVELOAD = CCF_LENGTH,
00057 };
00058 DECLARE_ENUM_AS_BIT_SET(ConsistChangeFlags)
00059
00060 byte FreightWagonMult(CargoID cargo);
00061
00062 void CheckTrainsLengths();
00063
00064 void FreeTrainTrackReservation(const Train *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR);
00065 bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay = false);
00066
00067 int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length);
00068
00069 void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type);
00070
00072 struct TrainCache {
00073
00074 const struct SpriteGroup *cached_override;
00075
00076
00077 bool cached_tilt;
00078
00079 byte user_def_data;
00080
00081
00082 int cached_max_curve_speed;
00083 };
00084
00088 struct Train FINAL : public GroundVehicle<Train, VEH_TRAIN> {
00089 TrainCache tcache;
00090
00091
00092 Train *other_multiheaded_part;
00093
00094 uint16 crash_anim_pos;
00095
00096 uint16 flags;
00097 TrackBitsByte track;
00098 TrainForceProceedingByte force_proceed;
00099 RailTypeByte railtype;
00100 RailTypes compatible_railtypes;
00101
00103 uint16 wait_counter;
00104
00106 Train() : GroundVehicleBase() {}
00108 virtual ~Train() { this->PreDestructor(); }
00109
00110 friend struct GroundVehicle<Train, VEH_TRAIN>;
00111
00112 void MarkDirty();
00113 void UpdateDeltaXY(Direction direction);
00114 ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; }
00115 void PlayLeaveStationSound() const;
00116 bool IsPrimaryVehicle() const { return this->IsFrontEngine(); }
00117 SpriteID GetImage(Direction direction, EngineImageType image_type) const;
00118 int GetDisplaySpeed() const { return this->gcache.last_speed; }
00119 int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; }
00120 Money GetRunningCost() const;
00121 int GetDisplayImageWidth(Point *offset = NULL) const;
00122 bool IsInDepot() const { return this->track == TRACK_BIT_DEPOT; }
00123 bool Tick();
00124 void OnNewDay();
00125 uint Crash(bool flooded = false);
00126 Trackdir GetVehicleTrackdir() const;
00127 TileIndex GetOrderStationLocation(StationID station);
00128 bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
00129
00130 void ReserveTrackUnderConsist() const;
00131
00132 int GetCurveSpeedLimit() const;
00133
00134 void ConsistChanged(ConsistChangeFlags allowed_changes);
00135
00136 int UpdateSpeed();
00137
00138 void UpdateAcceleration();
00139
00140 int GetCurrentMaxSpeed() const;
00141
00146 inline Train *GetNextUnit() const
00147 {
00148 Train *v = this->GetNextVehicle();
00149 if (v != NULL && v->IsRearDualheaded()) v = v->GetNextVehicle();
00150
00151 return v;
00152 }
00153
00158 inline Train *GetPrevUnit()
00159 {
00160 Train *v = this->GetPrevVehicle();
00161 if (v != NULL && v->IsRearDualheaded()) v = v->GetPrevVehicle();
00162
00163 return v;
00164 }
00165
00170 int CalcNextVehicleOffset() const
00171 {
00172
00173
00174
00175
00176 return this->gcache.cached_veh_length / 2 + (this->Next() != NULL ? this->Next()->gcache.cached_veh_length + 1 : 0) / 2;
00177 }
00178
00179 protected:
00180
00185 inline uint16 GetPower() const
00186 {
00187
00188 if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) {
00189 uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power);
00190
00191 if (this->IsMultiheaded()) power /= 2;
00192 return power;
00193 }
00194
00195 return 0;
00196 }
00197
00202 inline uint16 GetPoweredPartPower(const Train *head) const
00203 {
00204
00205 if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(this->tile))) {
00206 return RailVehInfo(this->gcache.first_engine)->pow_wag_power;
00207 }
00208
00209 return 0;
00210 }
00211
00216 inline uint16 GetWeight() const
00217 {
00218 uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.StoredCount() * FreightWagonMult(this->cargo_type)) / 16;
00219
00220
00221 if (!this->IsArticulatedPart()) {
00222 weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight);
00223 }
00224
00225
00226 if (HasBit(this->flags, VRF_POWEREDWAGON)) {
00227 weight += RailVehInfo(this->gcache.first_engine)->pow_wag_weight;
00228 }
00229
00230 return weight;
00231 }
00232
00237 inline byte GetTractiveEffort() const
00238 {
00239 return GetVehicleProperty(this, PROP_TRAIN_TRACTIVE_EFFORT, RailVehInfo(this->engine_type)->tractive_effort);
00240 }
00241
00246 inline byte GetAirDragArea() const
00247 {
00248
00249 return (this->track == TRACK_BIT_WORMHOLE && this->vehstatus & VS_HIDDEN) ? 28 : 14;
00250 }
00251
00256 inline byte GetAirDrag() const
00257 {
00258 return RailVehInfo(this->engine_type)->air_drag;
00259 }
00260
00265 inline AccelStatus GetAccelerationStatus() const
00266 {
00267 return (this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK) ? AS_BRAKE : AS_ACCEL;
00268 }
00269
00274 inline uint16 GetCurrentSpeed() const
00275 {
00276 return this->cur_speed;
00277 }
00278
00283 inline uint32 GetRollingFriction() const
00284 {
00285
00286
00287
00288 return 15 * (512 + this->GetCurrentSpeed()) / 512;
00289 }
00290
00295 inline int GetAccelerationType() const
00296 {
00297 return GetRailTypeInfo(this->railtype)->acceleration_type;
00298 }
00299
00304 inline uint32 GetSlopeSteepness() const
00305 {
00306 return _settings_game.vehicle.train_slope_steepness;
00307 }
00308
00313 inline uint16 GetMaxTrackSpeed() const
00314 {
00315 return GetRailTypeInfo(GetRailType(this->tile))->max_speed;
00316 }
00317
00322 inline bool TileMayHaveSlopedTrack() const
00323 {
00324
00325 return this->track == TRACK_BIT_X || this->track == TRACK_BIT_Y;
00326 }
00327
00333 inline bool HasToUseGetSlopePixelZ()
00334 {
00335 return false;
00336 }
00337 };
00338
00339 #define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
00340
00341 #endif