1 /* 2 * This file is part of OpenTTD. 3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. 4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. 6 */ 7 8 /** @file train.h Base for the train class. */ 9 10 #ifndef TRAIN_H 11 #define TRAIN_H 12 13 #include "core/enum_type.hpp" 14 15 #include "newgrf_engine.h" 16 #include "cargotype.h" 17 #include "rail.h" 18 #include "engine_base.h" 19 #include "rail_map.h" 20 #include "ground_vehicle.hpp" 21 22 struct Train; 23 24 /** Rail vehicle flags. */ 25 enum VehicleRailFlags { 26 VRF_REVERSING = 0, 27 VRF_POWEREDWAGON = 3, ///< Wagon is powered. 28 VRF_REVERSE_DIRECTION = 4, ///< Reverse the visible direction of the vehicle. 29 30 VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6, ///< Electric train engine is allowed to run on normal rail. */ 31 VRF_TOGGLE_REVERSE = 7, ///< Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle only). 32 VRF_TRAIN_STUCK = 8, ///< Train can't get a path reservation. 33 VRF_LEAVING_STATION = 9, ///< Train is just leaving a station. 34 }; 35 36 /** Modes for ignoring signals. */ 37 enum TrainForceProceeding : byte { 38 TFP_NONE = 0, ///< Normal operation. 39 TFP_STUCK = 1, ///< Proceed till next signal, but ignore being stuck till then. This includes force leaving depots. 40 TFP_SIGNAL = 2, ///< Ignore next signal, after the signal ignore being stuck. 41 }; 42 43 /** Flags for Train::ConsistChanged */ 44 enum ConsistChangeFlags { 45 CCF_LENGTH = 0x01, ///< Allow vehicles to change length. 46 CCF_CAPACITY = 0x02, ///< Allow vehicles to change capacity. 47 48 CCF_TRACK = 0, ///< Valid changes while vehicle is driving, and possibly changing tracks. 49 CCF_LOADUNLOAD = 0, ///< Valid changes while vehicle is loading/unloading. 50 CCF_AUTOREFIT = CCF_CAPACITY, ///< Valid changes for autorefitting in stations. 51 CCF_REFIT = CCF_LENGTH | CCF_CAPACITY, ///< Valid changes for refitting in a depot. 52 CCF_ARRANGE = CCF_LENGTH | CCF_CAPACITY, ///< Valid changes for arranging the consist in a depot. 53 CCF_SAVELOAD = CCF_LENGTH, ///< Valid changes when loading a savegame. (Everything that is not stored in the save.) 54 }; 55 DECLARE_ENUM_AS_BIT_SET(ConsistChangeFlags) 56 57 byte FreightWagonMult(CargoID cargo); 58 59 void CheckTrainsLengths(); 60 61 void FreeTrainTrackReservation(const Train *v); 62 bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay = false); 63 64 int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length); 65 66 void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type); 67 68 /** Variables that are cached to improve performance and such */ 69 struct TrainCache { 70 /* Cached wagon override spritegroup */ 71 const struct SpriteGroup *cached_override; 72 73 /* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */ 74 bool cached_tilt; ///< train can tilt; feature provides a bonus in curves 75 int cached_curve_speed_mod; ///< curve speed modifier of the entire train 76 77 byte user_def_data; ///< Cached property 0x25. Can be set by Callback 0x36. 78 79 /* cached max. speed / acceleration data */ 80 int cached_max_curve_speed; ///< max consist speed limited by curves 81 }; 82 83 /** 84 * 'Train' is either a loco or a wagon. 85 */ 86 struct Train FINAL : public GroundVehicle<Train, VEH_TRAIN> { 87 TrainCache tcache; 88 89 /* Link between the two ends of a multiheaded engine */ 90 Train *other_multiheaded_part; 91 92 uint16 crash_anim_pos; ///< Crash animation counter. 93 94 uint16 flags; 95 TrackBits track; 96 TrainForceProceeding force_proceed; 97 RailType railtype; 98 RailTypes compatible_railtypes; 99 100 /** Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through signals. */ 101 uint16 wait_counter; 102 103 /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ TrainFINAL104 Train() : GroundVehicleBase() {} 105 /** We want to 'destruct' the right class. */ ~TrainFINAL106 virtual ~Train() { this->PreDestructor(); } 107 108 friend struct GroundVehicle<Train, VEH_TRAIN>; // GroundVehicle needs to use the acceleration functions defined at Train. 109 110 void MarkDirty(); 111 void UpdateDeltaXY(); 112 ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; } 113 void PlayLeaveStationSound() const; 114 bool IsPrimaryVehicle() const { return this->IsFrontEngine(); } 115 void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const; 116 int GetDisplaySpeed() const { return this->gcache.last_speed; } 117 int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } 118 Money GetRunningCost() const; 119 int GetDisplayImageWidth(Point *offset = nullptr) const; 120 bool IsInDepot() const { return this->track == TRACK_BIT_DEPOT; } 121 bool Tick(); 122 void OnNewDay(); 123 uint Crash(bool flooded = false); 124 Trackdir GetVehicleTrackdir() const; 125 TileIndex GetOrderStationLocation(StationID station); 126 bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); 127 128 void ReserveTrackUnderConsist() const; 129 130 int GetCurveSpeedLimit() const; 131 132 void ConsistChanged(ConsistChangeFlags allowed_changes); 133 134 int UpdateSpeed(); 135 136 void UpdateAcceleration(); 137 138 int GetCurrentMaxSpeed() const; 139 140 /** 141 * Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist. 142 * @return Next vehicle in the consist. 143 */ 144 inline Train *GetNextUnit() const 145 { 146 Train *v = this->GetNextVehicle(); 147 if (v != nullptr && v->IsRearDualheaded()) v = v->GetNextVehicle(); 148 149 return v; 150 } 151 152 /** 153 * Get the previous real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist. 154 * @return Previous vehicle in the consist. 155 */ 156 inline Train *GetPrevUnit() 157 { 158 Train *v = this->GetPrevVehicle(); 159 if (v != nullptr && v->IsRearDualheaded()) v = v->GetPrevVehicle(); 160 161 return v; 162 } 163 164 /** 165 * Calculate the offset from this vehicle's center to the following center taking the vehicle lengths into account. 166 * @return Offset from center to center. 167 */ 168 int CalcNextVehicleOffset() const 169 { 170 /* For vehicles with odd lengths the part before the center will be one unit 171 * longer than the part after the center. This means we have to round up the 172 * length of the next vehicle but may not round the length of the current 173 * vehicle. */ 174 return this->gcache.cached_veh_length / 2 + (this->Next() != nullptr ? this->Next()->gcache.cached_veh_length + 1 : 0) / 2; 175 } 176 177 protected: // These functions should not be called outside acceleration code. 178 179 /** 180 * Allows to know the power value that this vehicle will use. 181 * @return Power value from the engine in HP, or zero if the vehicle is not powered. 182 */ 183 inline uint16 GetPower() const 184 { 185 /* Power is not added for articulated parts */ 186 if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) { 187 uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power); 188 /* Halve power for multiheaded parts */ 189 if (this->IsMultiheaded()) power /= 2; 190 return power; 191 } 192 193 return 0; 194 } 195 196 /** 197 * Returns a value if this articulated part is powered. 198 * @return Power value from the articulated part in HP, or zero if it is not powered. 199 */ 200 inline uint16 GetPoweredPartPower(const Train *head) const 201 { 202 /* For powered wagons the engine defines the type of engine (i.e. railtype) */ 203 if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(this->tile))) { 204 return RailVehInfo(this->gcache.first_engine)->pow_wag_power; 205 } 206 207 return 0; 208 } 209 210 /** 211 * Allows to know the weight value that this vehicle will use. 212 * @return Weight value from the engine in tonnes. 213 */ 214 inline uint16 GetWeight() const 215 { 216 uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.StoredCount() * FreightWagonMult(this->cargo_type)) / 16; 217 218 /* Vehicle weight is not added for articulated parts. */ 219 if (!this->IsArticulatedPart()) { 220 weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight); 221 } 222 223 /* Powered wagons have extra weight added. */ 224 if (HasBit(this->flags, VRF_POWEREDWAGON)) { 225 weight += RailVehInfo(this->gcache.first_engine)->pow_wag_weight; 226 } 227 228 return weight; 229 } 230 231 /** 232 * Allows to know the tractive effort value that this vehicle will use. 233 * @return Tractive effort value from the engine. 234 */ 235 inline byte GetTractiveEffort() const 236 { 237 return GetVehicleProperty(this, PROP_TRAIN_TRACTIVE_EFFORT, RailVehInfo(this->engine_type)->tractive_effort); 238 } 239 240 /** 241 * Gets the area used for calculating air drag. 242 * @return Area of the engine in m^2. 243 */ 244 inline byte GetAirDragArea() const 245 { 246 /* Air drag is higher in tunnels due to the limited cross-section. */ 247 return (this->track == TRACK_BIT_WORMHOLE && this->vehstatus & VS_HIDDEN) ? 28 : 14; 248 } 249 250 /** 251 * Gets the air drag coefficient of this vehicle. 252 * @return Air drag value from the engine. 253 */ 254 inline byte GetAirDrag() const 255 { 256 return RailVehInfo(this->engine_type)->air_drag; 257 } 258 259 /** 260 * Checks the current acceleration status of this vehicle. 261 * @return Acceleration status. 262 */ 263 inline AccelStatus GetAccelerationStatus() const 264 { 265 return (this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK) ? AS_BRAKE : AS_ACCEL; 266 } 267 268 /** 269 * Calculates the current speed of this vehicle. 270 * @return Current speed in km/h-ish. 271 */ 272 inline uint16 GetCurrentSpeed() const 273 { 274 return this->cur_speed; 275 } 276 277 /** 278 * Returns the rolling friction coefficient of this vehicle. 279 * @return Rolling friction coefficient in [1e-4]. 280 */ 281 inline uint32 GetRollingFriction() const 282 { 283 /* Rolling friction for steel on steel is between 0.1% and 0.2%. 284 * The friction coefficient increases with speed in a way that 285 * it doubles at 512 km/h, triples at 1024 km/h and so on. */ 286 return 15 * (512 + this->GetCurrentSpeed()) / 512; 287 } 288 289 /** 290 * Allows to know the acceleration type of a vehicle. 291 * @return Acceleration type of the vehicle. 292 */ 293 inline int GetAccelerationType() const 294 { 295 return GetRailTypeInfo(this->railtype)->acceleration_type; 296 } 297 298 /** 299 * Returns the slope steepness used by this vehicle. 300 * @return Slope steepness used by the vehicle. 301 */ 302 inline uint32 GetSlopeSteepness() const 303 { 304 return _settings_game.vehicle.train_slope_steepness; 305 } 306 307 /** 308 * Gets the maximum speed allowed by the track for this vehicle. 309 * @return Maximum speed allowed. 310 */ 311 inline uint16 GetMaxTrackSpeed() const 312 { 313 return GetRailTypeInfo(GetRailType(this->tile))->max_speed; 314 } 315 316 /** 317 * Returns the curve speed modifier of this vehicle. 318 * @return Current curve speed modifier, in fixed-point binary representation with 8 fractional bits. 319 */ 320 inline int GetCurveSpeedModifier() const 321 { 322 return GetVehicleProperty(this, PROP_TRAIN_CURVE_SPEED_MOD, RailVehInfo(this->engine_type)->curve_speed_mod, true); 323 } 324 325 /** 326 * Checks if the vehicle is at a tile that can be sloped. 327 * @return True if the tile can be sloped. 328 */ 329 inline bool TileMayHaveSlopedTrack() const 330 { 331 /* Any track that isn't TRACK_BIT_X or TRACK_BIT_Y cannot be sloped. */ 332 return this->track == TRACK_BIT_X || this->track == TRACK_BIT_Y; 333 } 334 335 /** 336 * Trains can always use the faster algorithm because they 337 * have always the same direction as the track under them. 338 * @return false 339 */ 340 inline bool HasToUseGetSlopePixelZ() 341 { 342 return false; 343 } 344 }; 345 346 #endif /* TRAIN_H */ 347