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 ground_vehicle.hpp Base class and functions for all vehicles that move through ground. */ 9 10 #ifndef GROUND_VEHICLE_HPP 11 #define GROUND_VEHICLE_HPP 12 13 #include "vehicle_base.h" 14 #include "vehicle_gui.h" 15 #include "landscape.h" 16 #include "window_func.h" 17 #include "widgets/vehicle_widget.h" 18 19 /** What is the status of our acceleration? */ 20 enum AccelStatus { 21 AS_ACCEL, ///< We want to go faster, if possible of course. 22 AS_BRAKE, ///< We want to stop. 23 }; 24 25 /** 26 * Cached, frequently calculated values. 27 * All of these values except cached_slope_resistance are set only for the first part of a vehicle. 28 */ 29 struct GroundVehicleCache { 30 /* Cached acceleration values, recalculated when the cargo on a vehicle changes (in addition to the conditions below) */ 31 uint32 cached_weight; ///< Total weight of the consist (valid only for the first engine). 32 uint32 cached_slope_resistance; ///< Resistance caused by weight when this vehicle part is at a slope. 33 uint32 cached_max_te; ///< Maximum tractive effort of consist (valid only for the first engine). 34 uint16 cached_axle_resistance; ///< Resistance caused by the axles of the vehicle (valid only for the first engine). 35 36 /* Cached acceleration values, recalculated on load and each time a vehicle is added to/removed from the consist. */ 37 uint16 cached_max_track_speed; ///< Maximum consist speed (in internal units) limited by track type (valid only for the first engine). 38 uint32 cached_power; ///< Total power of the consist (valid only for the first engine). 39 uint32 cached_air_drag; ///< Air drag coefficient of the vehicle (valid only for the first engine). 40 41 /* Cached NewGRF values, recalculated on load and each time a vehicle is added to/removed from the consist. */ 42 uint16 cached_total_length; ///< Length of the whole vehicle (valid only for the first engine). 43 EngineID first_engine; ///< Cached EngineID of the front vehicle. INVALID_ENGINE for the front vehicle itself. 44 uint8 cached_veh_length; ///< Length of this vehicle in units of 1/VEHICLE_LENGTH of normal length. It is cached because this can be set by a callback. 45 46 /* Cached UI information. */ 47 uint16 last_speed; ///< The last speed we did display, so we only have to redraw when this changes. 48 }; 49 50 /** Ground vehicle flags. */ 51 enum GroundVehicleFlags { 52 GVF_GOINGUP_BIT = 0, ///< Vehicle is currently going uphill. (Cached track information for acceleration) 53 GVF_GOINGDOWN_BIT = 1, ///< Vehicle is currently going downhill. (Cached track information for acceleration) 54 GVF_SUPPRESS_IMPLICIT_ORDERS = 2, ///< Disable insertion and removal of automatic orders until the vehicle completes the real order. 55 }; 56 57 /** 58 * Base class for all vehicles that move through ground. 59 * 60 * Child classes must define all of the following functions. 61 * These functions are not defined as pure virtual functions at this class to improve performance. 62 * 63 * virtual uint16 GetPower() const = 0; 64 * virtual uint16 GetPoweredPartPower(const T *head) const = 0; 65 * virtual uint16 GetWeight() const = 0; 66 * virtual byte GetTractiveEffort() const = 0; 67 * virtual byte GetAirDrag() const = 0; 68 * virtual byte GetAirDragArea() const = 0; 69 * virtual AccelStatus GetAccelerationStatus() const = 0; 70 * virtual uint16 GetCurrentSpeed() const = 0; 71 * virtual uint32 GetRollingFriction() const = 0; 72 * virtual int GetAccelerationType() const = 0; 73 * virtual int32 GetSlopeSteepness() const = 0; 74 * virtual int GetDisplayMaxSpeed() const = 0; 75 * virtual uint16 GetMaxTrackSpeed() const = 0; 76 * virtual bool TileMayHaveSlopedTrack() const = 0; 77 */ 78 template <class T, VehicleType Type> 79 struct GroundVehicle : public SpecializedVehicle<T, Type> { 80 GroundVehicleCache gcache; ///< Cache of often calculated values. 81 uint16 gv_flags; ///< @see GroundVehicleFlags. 82 83 typedef GroundVehicle<T, Type> GroundVehicleBase; ///< Our type 84 85 /** 86 * The constructor at SpecializedVehicle must be called. 87 */ GroundVehicleGroundVehicle88 GroundVehicle() : SpecializedVehicle<T, Type>() {} 89 90 void PowerChanged(); 91 void CargoChanged(); 92 int GetAcceleration() const; 93 bool IsChainInDepot() const override; 94 95 /** 96 * Common code executed for crashed ground vehicles 97 * @param flooded was this vehicle flooded? 98 * @return number of victims 99 */ CrashGroundVehicle100 uint Crash(bool flooded) override 101 { 102 /* Crashed vehicles aren't going up or down */ 103 for (T *v = T::From(this); v != nullptr; v = v->Next()) { 104 ClrBit(v->gv_flags, GVF_GOINGUP_BIT); 105 ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT); 106 } 107 return this->Vehicle::Crash(flooded); 108 } 109 110 /** 111 * Calculates the total slope resistance for this vehicle. 112 * @return Slope resistance. 113 */ GetSlopeResistanceGroundVehicle114 inline int64 GetSlopeResistance() const 115 { 116 int64 incl = 0; 117 118 for (const T *u = T::From(this); u != nullptr; u = u->Next()) { 119 if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) { 120 incl += u->gcache.cached_slope_resistance; 121 } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) { 122 incl -= u->gcache.cached_slope_resistance; 123 } 124 } 125 126 return incl; 127 } 128 129 /** 130 * Updates vehicle's Z position and inclination. 131 * Used when the vehicle entered given tile. 132 * @pre The vehicle has to be at (or near to) a border of the tile, 133 * directed towards tile centre 134 */ UpdateZPositionAndInclinationGroundVehicle135 inline void UpdateZPositionAndInclination() 136 { 137 this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos); 138 ClrBit(this->gv_flags, GVF_GOINGUP_BIT); 139 ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT); 140 141 if (T::From(this)->TileMayHaveSlopedTrack()) { 142 /* To check whether the current tile is sloped, and in which 143 * direction it is sloped, we get the 'z' at the center of 144 * the tile (middle_z) and the edge of the tile (old_z), 145 * which we then can compare. */ 146 int middle_z = GetSlopePixelZ((this->x_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2), (this->y_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2)); 147 148 if (middle_z != this->z_pos) { 149 SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT); 150 } 151 } 152 } 153 154 /** 155 * Updates vehicle's Z position. 156 * Inclination can't change in the middle of a tile. 157 * The faster code is used for trains and road vehicles unless they are 158 * reversing on a sloped tile. 159 */ UpdateZPositionGroundVehicle160 inline void UpdateZPosition() 161 { 162 #if 0 163 /* The following code does this: */ 164 165 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) { 166 switch (this->direction) { 167 case DIR_NE: 168 this->z_pos += (this->x_pos & 1); break; 169 case DIR_SW: 170 this->z_pos += (this->x_pos & 1) ^ 1; break; 171 case DIR_NW: 172 this->z_pos += (this->y_pos & 1); break; 173 case DIR_SE: 174 this->z_pos += (this->y_pos & 1) ^ 1; break; 175 default: break; 176 } 177 } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) { 178 switch (this->direction) { 179 case DIR_NE: 180 this->z_pos -= (this->x_pos & 1); break; 181 case DIR_SW: 182 this->z_pos -= (this->x_pos & 1) ^ 1; break; 183 case DIR_NW: 184 this->z_pos -= (this->y_pos & 1); break; 185 case DIR_SE: 186 this->z_pos -= (this->y_pos & 1) ^ 1; break; 187 default: break; 188 } 189 } 190 191 /* But gcc 4.4.5 isn't able to nicely optimise it, and the resulting 192 * code is full of conditional jumps. */ 193 #endif 194 195 /* Vehicle's Z position can change only if it has GVF_GOINGUP_BIT or GVF_GOINGDOWN_BIT set. 196 * Furthermore, if this function is called once every time the vehicle's position changes, 197 * we know the Z position changes by +/-1 at certain moments - when x_pos, y_pos is odd/even, 198 * depending on orientation of the slope and vehicle's direction */ 199 200 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) { 201 if (T::From(this)->HasToUseGetSlopePixelZ()) { 202 /* In some cases, we have to use GetSlopePixelZ() */ 203 this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos); 204 return; 205 } 206 /* DirToDiagDir() is a simple right shift */ 207 DiagDirection dir = DirToDiagDir(this->direction); 208 /* Read variables, so the compiler knows the access doesn't trap */ 209 int8 x_pos = this->x_pos; 210 int8 y_pos = this->y_pos; 211 /* DiagDirToAxis() is a simple mask */ 212 int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos; 213 /* We need only the least significant bit */ 214 d &= 1; 215 /* Conditional "^ 1". Optimised to "(dir - 1) <= 1". */ 216 d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE); 217 /* Subtraction instead of addition because we are testing for GVF_GOINGUP_BIT. 218 * GVF_GOINGUP_BIT is used because it's bit 0, so simple AND can be used, 219 * without any shift */ 220 this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d; 221 } 222 223 assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos)); 224 } 225 226 /** 227 * Checks if the vehicle is in a slope and sets the required flags in that case. 228 * @param new_tile True if the vehicle reached a new tile. 229 * @param update_delta Indicates to also update the delta. 230 * @return Old height of the vehicle. 231 */ UpdateInclinationGroundVehicle232 inline int UpdateInclination(bool new_tile, bool update_delta) 233 { 234 int old_z = this->z_pos; 235 236 if (new_tile) { 237 this->UpdateZPositionAndInclination(); 238 } else { 239 this->UpdateZPosition(); 240 } 241 242 this->UpdateViewport(true, update_delta); 243 return old_z; 244 } 245 246 /** 247 * Set front engine state. 248 */ SetFrontEngineGroundVehicle249 inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); } 250 251 /** 252 * Remove the front engine state. 253 */ ClearFrontEngineGroundVehicle254 inline void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); } 255 256 /** 257 * Set a vehicle to be an articulated part. 258 */ SetArticulatedPartGroundVehicle259 inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); } 260 261 /** 262 * Clear a vehicle from being an articulated part. 263 */ ClearArticulatedPartGroundVehicle264 inline void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); } 265 266 /** 267 * Set a vehicle to be a wagon. 268 */ SetWagonGroundVehicle269 inline void SetWagon() { SetBit(this->subtype, GVSF_WAGON); } 270 271 /** 272 * Clear wagon property. 273 */ ClearWagonGroundVehicle274 inline void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); } 275 276 /** 277 * Set engine status. 278 */ SetEngineGroundVehicle279 inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); } 280 281 /** 282 * Clear engine status. 283 */ ClearEngineGroundVehicle284 inline void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); } 285 286 /** 287 * Set a vehicle as a free wagon. 288 */ SetFreeWagonGroundVehicle289 inline void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); } 290 291 /** 292 * Clear a vehicle from being a free wagon. 293 */ ClearFreeWagonGroundVehicle294 inline void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); } 295 296 /** 297 * Set a vehicle as a multiheaded engine. 298 */ SetMultiheadedGroundVehicle299 inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); } 300 301 /** 302 * Clear multiheaded engine property. 303 */ ClearMultiheadedGroundVehicle304 inline void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); } 305 306 /** 307 * Check if the vehicle is a free wagon (got no engine in front of it). 308 * @return Returns true if the vehicle is a free wagon. 309 */ IsFreeWagonGroundVehicle310 inline bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); } 311 312 /** 313 * Check if a vehicle is an engine (can be first in a consist). 314 * @return Returns true if vehicle is an engine. 315 */ IsEngineGroundVehicle316 inline bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); } 317 318 /** 319 * Check if a vehicle is a wagon. 320 * @return Returns true if vehicle is a wagon. 321 */ IsWagonGroundVehicle322 inline bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); } 323 324 /** 325 * Check if the vehicle is a multiheaded engine. 326 * @return Returns true if the vehicle is a multiheaded engine. 327 */ IsMultiheadedGroundVehicle328 inline bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); } 329 330 /** 331 * Tell if we are dealing with the rear end of a multiheaded engine. 332 * @return True if the engine is the rear part of a dualheaded engine. 333 */ IsRearDualheadedGroundVehicle334 inline bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); } 335 336 /** 337 * Update the GUI variant of the current speed of the vehicle. 338 * Also mark the widget dirty when that is needed, i.e. when 339 * the speed of this vehicle has changed. 340 */ SetLastSpeedGroundVehicle341 inline void SetLastSpeed() 342 { 343 if (this->cur_speed != this->gcache.last_speed) { 344 SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); 345 this->gcache.last_speed = this->cur_speed; 346 } 347 } 348 349 protected: 350 /** 351 * Update the speed of the vehicle. 352 * 353 * It updates the cur_speed and subspeed variables depending on the state 354 * of the vehicle; in this case the current acceleration, minimum and 355 * maximum speeds of the vehicle. It returns the distance that that the 356 * vehicle can drive this tick. #Vehicle::GetAdvanceDistance() determines 357 * the distance to drive before moving a step on the map. 358 * @param accel The acceleration we would like to give this vehicle. 359 * @param min_speed The minimum speed here, in vehicle specific units. 360 * @param max_speed The maximum speed here, in vehicle specific units. 361 * @return Distance to drive. 362 */ DoUpdateSpeedGroundVehicle363 inline uint DoUpdateSpeed(uint accel, int min_speed, int max_speed) 364 { 365 uint spd = this->subspeed + accel; 366 this->subspeed = (byte)spd; 367 368 /* When we are going faster than the maximum speed, reduce the speed 369 * somewhat gradually. But never lower than the maximum speed. */ 370 int tempmax = max_speed; 371 if (this->cur_speed > max_speed) { 372 tempmax = std::max(this->cur_speed - (this->cur_speed / 10) - 1, max_speed); 373 } 374 375 /* Enforce a maximum and minimum speed. Normally we would use something like 376 * Clamp for this, but in this case min_speed might be below the maximum speed 377 * threshold for some reason. That makes acceleration fail and assertions 378 * happen in Clamp. So make it explicit that min_speed overrules the maximum 379 * speed by explicit ordering of min and max. */ 380 this->cur_speed = spd = std::max(std::min(this->cur_speed + ((int)spd >> 8), tempmax), min_speed); 381 382 int scaled_spd = this->GetAdvanceSpeed(spd); 383 384 scaled_spd += this->progress; 385 this->progress = 0; // set later in *Handler or *Controller 386 return scaled_spd; 387 } 388 }; 389 390 #endif /* GROUND_VEHICLE_HPP */ 391