4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file ground_vehicle.hpp Base class and functions for all vehicles that move through ground. */
12 #ifndef GROUND_VEHICLE_HPP
13 #define GROUND_VEHICLE_HPP
15 #include "vehicle_base.h"
16 #include "vehicle_gui.h"
17 #include "landscape.h"
18 #include "window_func.h"
19 #include "tunnel_map.h"
20 #include "widgets/vehicle_widget.h"
22 /** What is the status of our acceleration? */
24 AS_ACCEL
, ///< We want to go faster, if possible of course.
25 AS_BRAKE
, ///< We want to stop.
29 * Cached, frequently calculated values.
30 * All of these values except cached_slope_resistance are set only for the first part of a vehicle.
32 struct GroundVehicleCache
{
33 /* Cached acceleration values, recalculated when the cargo on a vehicle changes (in addition to the conditions below) */
34 uint32 cached_weight
; ///< Total weight of the consist (valid only for the first engine).
35 uint32 cached_slope_resistance
; ///< Resistance caused by weight when this vehicle part is at a slope.
36 uint32 cached_max_te
; ///< Maximum tractive effort of consist (valid only for the first engine).
38 /* Cached acceleration values, recalculated on load and each time a vehicle is added to/removed from the consist. */
39 uint16 cached_max_track_speed
; ///< Maximum consist speed limited by track type (valid only for the first engine).
40 uint32 cached_power
; ///< Total power of the consist (valid only for the first engine).
41 uint32 cached_air_drag
; ///< Air drag coefficient of the vehicle (valid only for the first engine).
43 /* Cached NewGRF values, recalculated on load and each time a vehicle is added to/removed from the consist. */
44 uint16 cached_total_length
; ///< Length of the whole vehicle (valid only for the first engine).
45 EngineID first_engine
; ///< Cached EngineID of the front vehicle. INVALID_ENGINE for the front vehicle itself.
46 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.
48 /* Cached UI information. */
49 uint16 last_speed
; ///< The last speed we did display, so we only have to redraw when this changes.
52 /** Ground vehicle flags. */
53 enum GroundVehicleFlags
{
54 GVF_GOINGUP_BIT
= 0, ///< Vehicle is currently going uphill. (Cached track information for acceleration)
55 GVF_GOINGDOWN_BIT
= 1, ///< Vehicle is currently going downhill. (Cached track information for acceleration)
56 GVF_SUPPRESS_IMPLICIT_ORDERS
= 2, ///< Disable insertion and removal of automatic orders until the vehicle completes the real order.
57 GVF_CHUNNEL_BIT
= 3, ///< Vehicle may currently be in a chunnel. (Cached track information for inclination changes)
61 * Base class for all vehicles that move through ground.
63 * Child classes must define all of the following functions.
64 * These functions are not defined as pure virtual functions at this class to improve performance.
66 * virtual uint16 GetPower() const = 0;
67 * virtual uint16 GetPoweredPartPower(const T *head) const = 0;
68 * virtual uint16 GetWeight() const = 0;
69 * virtual byte GetTractiveEffort() const = 0;
70 * virtual byte GetAirDrag() const = 0;
71 * virtual byte GetAirDragArea() const = 0;
72 * virtual AccelStatus GetAccelerationStatus() const = 0;
73 * virtual uint16 GetCurrentSpeed() const = 0;
74 * virtual uint32 GetRollingFriction() const = 0;
75 * virtual int GetAccelerationType() const = 0;
76 * virtual int32 GetSlopeSteepness() const = 0;
77 * virtual int GetDisplayMaxSpeed() const = 0;
78 * virtual uint16 GetMaxTrackSpeed() const = 0;
79 * virtual bool TileMayHaveSlopedTrack() const = 0;
81 template <class T
, VehicleType Type
>
82 struct GroundVehicle
: public SpecializedVehicle
<T
, Type
> {
83 GroundVehicleCache gcache
; ///< Cache of often calculated values.
84 uint16 gv_flags
; ///< @see GroundVehicleFlags.
86 typedef GroundVehicle
<T
, Type
> GroundVehicleBase
; ///< Our type
89 * The constructor at SpecializedVehicle must be called.
91 GroundVehicle() : SpecializedVehicle
<T
, Type
>() {}
95 int GetAcceleration() const;
96 bool IsChainInDepot() const;
99 * Common code executed for crashed ground vehicles
100 * @param flooded was this vehicle flooded?
101 * @return number of victims
103 /* virtual */ uint
Crash(bool flooded
)
105 /* Crashed vehicles aren't going up or down */
106 for (T
*v
= T::From(this); v
!= nullptr; v
= v
->Next()) {
107 ClrBit(v
->gv_flags
, GVF_GOINGUP_BIT
);
108 ClrBit(v
->gv_flags
, GVF_GOINGDOWN_BIT
);
110 return this->Vehicle::Crash(flooded
);
114 * Calculates the total slope resistance for this vehicle.
115 * @return Slope resistance.
117 inline int64
GetSlopeResistance() const
121 for (const T
*u
= T::From(this); u
!= nullptr; u
= u
->Next()) {
122 if (HasBit(u
->gv_flags
, GVF_GOINGUP_BIT
)) {
123 incl
+= u
->gcache
.cached_slope_resistance
;
124 } else if (HasBit(u
->gv_flags
, GVF_GOINGDOWN_BIT
)) {
125 incl
-= u
->gcache
.cached_slope_resistance
;
133 * Updates vehicle's Z position and inclination.
134 * Used when the vehicle entered given tile.
135 * @pre The vehicle has to be at (or near to) a border of the tile,
136 * directed towards tile centre
138 inline void UpdateZPositionAndInclination()
140 this->z_pos
= GetSlopePixelZ(this->x_pos
, this->y_pos
);
141 ClrBit(this->gv_flags
, GVF_GOINGUP_BIT
);
142 ClrBit(this->gv_flags
, GVF_GOINGDOWN_BIT
);
144 if (T::From(this)->TileMayHaveSlopedTrack()) {
145 /* To check whether the current tile is sloped, and in which
146 * direction it is sloped, we get the 'z' at the center of
147 * the tile (middle_z) and the edge of the tile (old_z),
148 * which we then can compare. */
149 int middle_z
= GetSlopePixelZ((this->x_pos
& ~TILE_UNIT_MASK
) | (TILE_SIZE
/ 2), (this->y_pos
& ~TILE_UNIT_MASK
) | (TILE_SIZE
/ 2));
151 if (middle_z
!= this->z_pos
) {
152 SetBit(this->gv_flags
, (middle_z
> this->z_pos
) ? GVF_GOINGUP_BIT
: GVF_GOINGDOWN_BIT
);
158 * Updates vehicle's Z position.
159 * Inclination can't change in the middle of a tile.
160 * The faster code is used for trains and road vehicles unless they are
161 * reversing on a sloped tile.
163 inline void UpdateZPosition()
166 /* The following code does this: */
168 if (HasBit(this->gv_flags
, GVF_GOINGUP_BIT
)) {
169 switch (this->direction
) {
171 this->z_pos
+= (this->x_pos
& 1); break;
173 this->z_pos
+= (this->x_pos
& 1) ^ 1; break;
175 this->z_pos
+= (this->y_pos
& 1); break;
177 this->z_pos
+= (this->y_pos
& 1) ^ 1; break;
180 } else if (HasBit(this->gv_flags
, GVF_GOINGDOWN_BIT
)) {
181 switch (this->direction
) {
183 this->z_pos
-= (this->x_pos
& 1); break;
185 this->z_pos
-= (this->x_pos
& 1) ^ 1; break;
187 this->z_pos
-= (this->y_pos
& 1); break;
189 this->z_pos
-= (this->y_pos
& 1) ^ 1; break;
194 /* But gcc 4.4.5 isn't able to nicely optimise it, and the resulting
195 * code is full of conditional jumps. */
198 /* Vehicle's Z position can change only if it has GVF_GOINGUP_BIT or GVF_GOINGDOWN_BIT set.
199 * Furthermore, if this function is called once every time the vehicle's position changes,
200 * we know the Z position changes by +/-1 at certain moments - when x_pos, y_pos is odd/even,
201 * depending on orientation of the slope and vehicle's direction */
203 if (HasBit(this->gv_flags
, GVF_GOINGUP_BIT
) || HasBit(this->gv_flags
, GVF_GOINGDOWN_BIT
)) {
204 if (T::From(this)->HasToUseGetSlopePixelZ()) {
205 /* In some cases, we have to use GetSlopePixelZ() */
206 this->z_pos
= GetSlopePixelZ(this->x_pos
, this->y_pos
);
209 /* DirToDiagDir() is a simple right shift */
210 DiagDirection dir
= DirToDiagDir(this->direction
);
211 /* Read variables, so the compiler knows the access doesn't trap */
212 int8 x_pos
= this->x_pos
;
213 int8 y_pos
= this->y_pos
;
214 /* DiagDirToAxis() is a simple mask */
215 int8 d
= DiagDirToAxis(dir
) == AXIS_X
? x_pos
: y_pos
;
216 /* We need only the least significant bit */
218 /* Conditional "^ 1". Optimised to "(dir - 1) <= 1". */
219 d
^= (int8
)(dir
== DIAGDIR_SW
|| dir
== DIAGDIR_SE
);
220 /* Subtraction instead of addition because we are testing for GVF_GOINGUP_BIT.
221 * GVF_GOINGUP_BIT is used because it's bit 0, so simple AND can be used,
222 * without any shift */
223 this->z_pos
+= HasBit(this->gv_flags
, GVF_GOINGUP_BIT
) ? d
: -d
;
226 if (HasBit(this->gv_flags
, GVF_CHUNNEL_BIT
) && !IsTunnelTile(this->tile
)) {
227 ClrBit(this->gv_flags
, GVF_CHUNNEL_BIT
);
231 assert(this->z_pos
== GetSlopePixelZ(this->x_pos
, this->y_pos
));
235 void UpdateZPositionInWormhole();
238 * Checks if the vehicle is in a slope and sets the required flags in that case.
239 * @param new_tile True if the vehicle reached a new tile.
240 * @param update_delta Indicates to also update the delta.
241 * @return Old height of the vehicle.
243 inline int UpdateInclination(bool new_tile
, bool update_delta
, bool in_wormhole
= false)
245 int old_z
= this->z_pos
;
248 if (HasBit(this->gv_flags
, GVF_CHUNNEL_BIT
)) this->UpdateZPositionInWormhole();
249 } else if (new_tile
) {
250 this->UpdateZPositionAndInclination();
252 this->UpdateZPosition();
255 this->UpdateViewport(true, update_delta
);
260 * Set front engine state.
262 inline void SetFrontEngine() { SetBit(this->subtype
, GVSF_FRONT
); }
265 * Remove the front engine state.
267 inline void ClearFrontEngine() { ClrBit(this->subtype
, GVSF_FRONT
); }
270 * Set a vehicle to be an articulated part.
272 inline void SetArticulatedPart() { SetBit(this->subtype
, GVSF_ARTICULATED_PART
); }
275 * Clear a vehicle from being an articulated part.
277 inline void ClearArticulatedPart() { ClrBit(this->subtype
, GVSF_ARTICULATED_PART
); }
280 * Set a vehicle to be a wagon.
282 inline void SetWagon() { SetBit(this->subtype
, GVSF_WAGON
); }
285 * Clear wagon property.
287 inline void ClearWagon() { ClrBit(this->subtype
, GVSF_WAGON
); }
292 inline void SetEngine() { SetBit(this->subtype
, GVSF_ENGINE
); }
295 * Clear engine status.
297 inline void ClearEngine() { ClrBit(this->subtype
, GVSF_ENGINE
); }
300 * Set a vehicle as a free wagon.
302 inline void SetFreeWagon() { SetBit(this->subtype
, GVSF_FREE_WAGON
); }
305 * Clear a vehicle from being a free wagon.
307 inline void ClearFreeWagon() { ClrBit(this->subtype
, GVSF_FREE_WAGON
); }
310 * Set a vehicle as a virtual vehicle.
312 inline void SetVirtual() { SetBit(this->subtype
, GVSF_VIRTUAL
); }
315 * Clear a vehicle from being a virtual vehicle.
317 inline void ClearVirtual() { ClrBit(this->subtype
, GVSF_VIRTUAL
); }
320 * Set a vehicle as a multiheaded engine.
322 inline void SetMultiheaded() { SetBit(this->subtype
, GVSF_MULTIHEADED
); }
325 * Clear multiheaded engine property.
327 inline void ClearMultiheaded() { ClrBit(this->subtype
, GVSF_MULTIHEADED
); }
330 * Check if the vehicle is a free wagon (got no engine in front of it).
331 * @return Returns true if the vehicle is a free wagon.
333 inline bool IsFreeWagon() const { return HasBit(this->subtype
, GVSF_FREE_WAGON
); }
336 * Check if a vehicle is an engine (can be first in a consist).
337 * @return Returns true if vehicle is an engine.
339 inline bool IsEngine() const { return HasBit(this->subtype
, GVSF_ENGINE
); }
342 * Check if a vehicle is a wagon.
343 * @return Returns true if vehicle is a wagon.
345 inline bool IsWagon() const { return HasBit(this->subtype
, GVSF_WAGON
); }
348 * Check if the vehicle is a multiheaded engine.
349 * @return Returns true if the vehicle is a multiheaded engine.
351 inline bool IsMultiheaded() const { return HasBit(this->subtype
, GVSF_MULTIHEADED
); }
354 * Tell if we are dealing with a virtual vehicle (used for templates).
355 * @return True if the vehicle is a virtual vehicle.
357 inline bool IsVirtual() const { return HasBit(this->subtype
, GVSF_VIRTUAL
); }
360 * Tell if we are dealing with the rear end of a multiheaded engine.
361 * @return True if the engine is the rear part of a dualheaded engine.
363 inline bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
366 * Update the GUI variant of the current speed of the vehicle.
367 * Also mark the widget dirty when that is needed, i.e. when
368 * the speed of this vehicle has changed.
370 inline void SetLastSpeed()
372 if (this->cur_speed
!= this->gcache
.last_speed
) {
373 SetWindowWidgetDirty(WC_VEHICLE_VIEW
, this->index
, WID_VV_START_STOP
);
374 this->gcache
.last_speed
= this->cur_speed
;
380 * Update the speed of the vehicle.
382 * It updates the cur_speed and subspeed variables depending on the state
383 * of the vehicle; in this case the current acceleration, minimum and
384 * maximum speeds of the vehicle. It returns the distance that that the
385 * vehicle can drive this tick. #Vehicle::GetAdvanceDistance() determines
386 * the distance to drive before moving a step on the map.
387 * @param accel The acceleration we would like to give this vehicle.
388 * @param min_speed The minimum speed here, in vehicle specific units.
389 * @param max_speed The maximum speed here, in vehicle specific units.
390 * @return Distance to drive.
392 inline uint
DoUpdateSpeed(uint accel
, int min_speed
, int max_speed
)
394 uint spd
= this->subspeed
+ accel
;
395 this->subspeed
= (byte
)spd
;
397 /* When we are going faster than the maximum speed, reduce the speed
398 * somewhat gradually. But never lower than the maximum speed. */
399 int tempmax
= max_speed
;
400 if (this->cur_speed
> max_speed
) {
401 tempmax
= max(this->cur_speed
- (this->cur_speed
/ 10) - 1, max_speed
);
404 /* Enforce a maximum and minimum speed. Normally we would use something like
405 * Clamp for this, but in this case min_speed might be below the maximum speed
406 * threshold for some reason. That makes acceleration fail and assertions
407 * happen in Clamp. So make it explicit that min_speed overrules the maximum
408 * speed by explicit ordering of min and max. */
409 this->cur_speed
= spd
= max(min(this->cur_speed
+ ((int)spd
>> 8), tempmax
), min_speed
);
411 int scaled_spd
= this->GetAdvanceSpeed(spd
);
413 scaled_spd
+= this->progress
;
414 this->progress
= 0; // set later in *Handler or *Controller
419 #endif /* GROUND_VEHICLE_HPP */