OpenTTD Source: src/ground_vehicle.hpp Source File

OpenTTD Source 15.3

ground_vehicle.hpp
Go to the documentation of this file.
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
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
18#include "widgets/vehicle_widget.h"
19
21 enum AccelStatus : uint8_t {
22 AS_ACCEL,
23 AS_BRAKE,
24};
25
30 struct GroundVehicleCache {
31 /* Cached acceleration values, recalculated when the cargo on a vehicle changes (in addition to the conditions below) */
32 uint32_t cached_weight = 0;
33 uint32_t cached_slope_resistance = 0;
34 uint32_t cached_max_te = 0;
35 uint16_t cached_axle_resistance = 0;
36
37 /* Cached acceleration values, recalculated on load and each time a vehicle is added to/removed from the consist. */
38 uint16_t cached_max_track_speed = 0;
39 uint32_t cached_power = 0;
40 uint32_t cached_air_drag = 0;
41
42 /* Cached NewGRF values, recalculated on load and each time a vehicle is added to/removed from the consist. */
43 uint16_t cached_total_length = 0;
44 EngineID first_engine = EngineID::Invalid();
45 uint8_t cached_veh_length = 0;
46
47 /* Cached UI information. */
48 uint16_t last_speed = 0;
49
50 auto operator<=>(const GroundVehicleCache &) const = default;
51};
52
54 enum GroundVehicleFlags : uint8_t {
55 GVF_GOINGUP_BIT = 0,
56 GVF_GOINGDOWN_BIT = 1,
57 GVF_SUPPRESS_IMPLICIT_ORDERS = 2,
58};
59
81template <class T, VehicleType Type>
82 struct GroundVehicle : public SpecializedVehicle<T, Type> {
83 GroundVehicleCache gcache{};
84 uint16_t gv_flags = 0;
85
86 typedef GroundVehicle<T, Type> GroundVehicleBase;
87
91 GroundVehicle() : SpecializedVehicle<T, Type>() {}
92
93 void PowerChanged();
94 void CargoChanged();
95 int GetAcceleration() const;
96 bool IsChainInDepot() const override;
97
103 uint Crash(bool flooded) override
104 {
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);
109 }
110 return this->Vehicle::Crash(flooded);
111 }
112
117 inline int64_t GetSlopeResistance() const
118 {
119 int64_t incl = 0;
120
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;
126 }
127 }
128
129 return incl;
130 }
131
138 inline void UpdateZPositionAndInclination()
139 {
140 this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos, true);
141 ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
142 ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
143
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), true);
150
151 if (middle_z != this->z_pos) {
152 SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
153 }
154 }
155 }
156
163 inline void UpdateZPosition()
164 {
165#if 0
166 /* The following code does this: */
167
168 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) {
169 switch (this->direction) {
170 case DIR_NE:
171 this->z_pos += (this->x_pos & 1) ^ 1; break;
172 case DIR_SW:
173 this->z_pos += (this->x_pos & 1); break;
174 case DIR_NW:
175 this->z_pos += (this->y_pos & 1) ^ 1; break;
176 case DIR_SE:
177 this->z_pos += (this->y_pos & 1); break;
178 default: break;
179 }
180 } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
181 switch (this->direction) {
182 case DIR_NE:
183 this->z_pos -= (this->x_pos & 1) ^ 1; break;
184 case DIR_SW:
185 this->z_pos -= (this->x_pos & 1); break;
186 case DIR_NW:
187 this->z_pos -= (this->y_pos & 1) ^ 1; break;
188 case DIR_SE:
189 this->z_pos -= (this->y_pos & 1); break;
190 default: break;
191 }
192 }
193
194 /* But gcc 4.4.5 isn't able to nicely optimise it, and the resulting
195 * code is full of conditional jumps. */
196#endif
197
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 */
202
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, true);
207 return;
208 }
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_t x_pos = this->x_pos;
213 int8_t y_pos = this->y_pos;
214 /* DiagDirToAxis() is a simple mask */
215 int8_t d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos;
216 /* We need only the least significant bit */
217 d &= 1;
218 d ^= (int8_t)(dir == DIAGDIR_NW || dir == DIAGDIR_NE);
219 /* Subtraction instead of addition because we are testing for GVF_GOINGUP_BIT.
220 * GVF_GOINGUP_BIT is used because it's bit 0, so simple AND can be used,
221 * without any shift */
222 this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d;
223 }
224
225 assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos, true));
226 }
227
234 inline int UpdateInclination(bool new_tile, bool update_delta)
235 {
236 int old_z = this->z_pos;
237
238 if (new_tile) {
239 this->UpdateZPositionAndInclination();
240 } else {
241 this->UpdateZPosition();
242 }
243
244 this->UpdateViewport(true, update_delta);
245 return old_z;
246 }
247
251 inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
252
256 inline void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); }
257
261 inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
262
266 inline void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); }
267
271 inline void SetWagon() { SetBit(this->subtype, GVSF_WAGON); }
272
276 inline void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); }
277
281 inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
282
286 inline void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); }
287
291 inline void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); }
292
296 inline void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); }
297
301 inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); }
302
306 inline void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); }
307
312 inline bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
313
318 inline bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); }
319
324 inline bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); }
325
330 inline bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); }
331
336 inline bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
337
343 inline void SetLastSpeed()
344 {
345 if (this->cur_speed != this->gcache.last_speed) {
346 SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
347 this->gcache.last_speed = this->cur_speed;
348 }
349 }
350
351protected:
365 inline uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
366 {
367 uint spd = this->subspeed + accel;
368 this->subspeed = (uint8_t)spd;
369
370 /* When we are going faster than the maximum speed, reduce the speed
371 * somewhat gradually. But never lower than the maximum speed. */
372 int tempmax = max_speed;
373 if (this->cur_speed > max_speed) {
374 tempmax = std::max(this->cur_speed - (this->cur_speed / 10) - 1, max_speed);
375 }
376
377 /* Enforce a maximum and minimum speed. Normally we would use something like
378 * Clamp for this, but in this case min_speed might be below the maximum speed
379 * threshold for some reason. That makes acceleration fail and assertions
380 * happen in Clamp. So make it explicit that min_speed overrules the maximum
381 * speed by explicit ordering of min and max. */
382 this->cur_speed = spd = std::max(std::min(this->cur_speed + ((int)spd >> 8), tempmax), min_speed);
383
384 int scaled_spd = this->GetAdvanceSpeed(spd);
385
386 scaled_spd += this->progress;
387 this->progress = 0; // set later in *Handler or *Controller
388 return scaled_spd;
389 }
390};
391
392#endif /* GROUND_VEHICLE_HPP */
SetBit
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
Definition bitmath_func.hpp:121
HasBit
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
Definition bitmath_func.hpp:103
ClrBit
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Definition bitmath_func.hpp:139
DiagDirToAxis
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
Definition direction_func.h:214
DirToDiagDir
DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
Definition direction_func.h:166
DIR_SW
@ DIR_SW
Southwest.
Definition direction_type.h:31
DIR_NW
@ DIR_NW
Northwest.
Definition direction_type.h:33
DIR_SE
@ DIR_SE
Southeast.
Definition direction_type.h:29
DIR_NE
@ DIR_NE
Northeast.
Definition direction_type.h:27
AXIS_X
@ AXIS_X
The X axis.
Definition direction_type.h:124
DiagDirection
DiagDirection
Enumeration for diagonal directions.
Definition direction_type.h:78
DIAGDIR_NE
@ DIAGDIR_NE
Northeast, upper right on your monitor.
Definition direction_type.h:80
DIAGDIR_NW
@ DIAGDIR_NW
Northwest.
Definition direction_type.h:83
AccelStatus
AccelStatus
What is the status of our acceleration?
Definition ground_vehicle.hpp:21
AS_BRAKE
@ AS_BRAKE
We want to stop.
Definition ground_vehicle.hpp:23
AS_ACCEL
@ AS_ACCEL
We want to go faster, if possible of course.
Definition ground_vehicle.hpp:22
GroundVehicleFlags
GroundVehicleFlags
Ground vehicle flags.
Definition ground_vehicle.hpp:54
GVF_SUPPRESS_IMPLICIT_ORDERS
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
Definition ground_vehicle.hpp:57
GVF_GOINGDOWN_BIT
@ GVF_GOINGDOWN_BIT
Vehicle is currently going downhill. (Cached track information for acceleration)
Definition ground_vehicle.hpp:56
GVF_GOINGUP_BIT
@ GVF_GOINGUP_BIT
Vehicle is currently going uphill. (Cached track information for acceleration)
Definition ground_vehicle.hpp:55
GetSlopePixelZ
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Definition landscape.cpp:307
landscape.h
Functions related to OTTD's landscape.
GroundVehicleCache
Cached, frequently calculated values.
Definition ground_vehicle.hpp:30
GroundVehicleCache::cached_weight
uint32_t cached_weight
Total weight of the consist (valid only for the first engine).
Definition ground_vehicle.hpp:32
GroundVehicleCache::cached_air_drag
uint32_t cached_air_drag
Air drag coefficient of the vehicle (valid only for the first engine).
Definition ground_vehicle.hpp:40
GroundVehicleCache::cached_axle_resistance
uint16_t cached_axle_resistance
Resistance caused by the axles of the vehicle (valid only for the first engine).
Definition ground_vehicle.hpp:35
GroundVehicleCache::first_engine
EngineID first_engine
Cached EngineID of the front vehicle. EngineID::Invalid() for the front vehicle itself.
Definition ground_vehicle.hpp:44
GroundVehicleCache::last_speed
uint16_t last_speed
The last speed we did display, so we only have to redraw when this changes.
Definition ground_vehicle.hpp:48
GroundVehicleCache::cached_power
uint32_t cached_power
Total power of the consist (valid only for the first engine).
Definition ground_vehicle.hpp:39
GroundVehicleCache::cached_total_length
uint16_t cached_total_length
Length of the whole vehicle (valid only for the first engine).
Definition ground_vehicle.hpp:43
GroundVehicleCache::cached_veh_length
uint8_t cached_veh_length
Length of this vehicle in units of 1/VEHICLE_LENGTH of normal length. It is cached because this can b...
Definition ground_vehicle.hpp:45
GroundVehicleCache::cached_max_te
uint32_t cached_max_te
Maximum tractive effort of consist (valid only for the first engine).
Definition ground_vehicle.hpp:34
GroundVehicleCache::cached_max_track_speed
uint16_t cached_max_track_speed
Maximum consist speed (in internal units) limited by track type (valid only for the first engine).
Definition ground_vehicle.hpp:38
GroundVehicleCache::cached_slope_resistance
uint32_t cached_slope_resistance
Resistance caused by weight when this vehicle part is at a slope.
Definition ground_vehicle.hpp:33
GroundVehicle
Base class for all vehicles that move through ground.
Definition ground_vehicle.hpp:82
GroundVehicle::IsChainInDepot
bool IsChainInDepot() const override
Check whether the whole vehicle chain is in the depot.
Definition ground_vehicle.cpp:190
GroundVehicle::SetFreeWagon
void SetFreeWagon()
Set a vehicle as a free wagon.
Definition ground_vehicle.hpp:291
GroundVehicle::UpdateInclination
int UpdateInclination(bool new_tile, bool update_delta)
Checks if the vehicle is in a slope and sets the required flags in that case.
Definition ground_vehicle.hpp:234
GroundVehicle::ClearWagon
void ClearWagon()
Clear wagon property.
Definition ground_vehicle.hpp:276
GroundVehicle::GroundVehicleBase
GroundVehicle< T, Type > GroundVehicleBase
Our type.
Definition ground_vehicle.hpp:86
GroundVehicle::gcache
GroundVehicleCache gcache
Cache of often calculated values.
Definition ground_vehicle.hpp:83
GroundVehicle::CargoChanged
void CargoChanged()
Recalculates the cached weight of a vehicle and its parts.
Definition ground_vehicle.cpp:79
GroundVehicle::SetMultiheaded
void SetMultiheaded()
Set a vehicle as a multiheaded engine.
Definition ground_vehicle.hpp:301
GroundVehicle::IsEngine
bool IsEngine() const
Check if a vehicle is an engine (can be first in a consist).
Definition ground_vehicle.hpp:318
GroundVehicle::IsRearDualheaded
bool IsRearDualheaded() const
Tell if we are dealing with the rear end of a multiheaded engine.
Definition ground_vehicle.hpp:336
GroundVehicle::IsMultiheaded
bool IsMultiheaded() const
Check if the vehicle is a multiheaded engine.
Definition ground_vehicle.hpp:330
GroundVehicle::SetEngine
void SetEngine()
Set engine status.
Definition ground_vehicle.hpp:281
GroundVehicle::SetWagon
void SetWagon()
Set a vehicle to be a wagon.
Definition ground_vehicle.hpp:271
GroundVehicle::UpdateZPositionAndInclination
void UpdateZPositionAndInclination()
Updates vehicle's Z position and inclination.
Definition ground_vehicle.hpp:138
GroundVehicle::SetFrontEngine
void SetFrontEngine()
Set front engine state.
Definition ground_vehicle.hpp:251
GroundVehicle::gv_flags
uint16_t gv_flags
Definition ground_vehicle.hpp:84
GroundVehicle::ClearFreeWagon
void ClearFreeWagon()
Clear a vehicle from being a free wagon.
Definition ground_vehicle.hpp:296
GroundVehicle::IsWagon
bool IsWagon() const
Check if a vehicle is a wagon.
Definition ground_vehicle.hpp:324
GroundVehicle::GetSlopeResistance
int64_t GetSlopeResistance() const
Calculates the total slope resistance for this vehicle.
Definition ground_vehicle.hpp:117
GroundVehicle::PowerChanged
void PowerChanged()
Recalculates the cached total power of a vehicle.
Definition ground_vehicle.cpp:21
GroundVehicle::ClearArticulatedPart
void ClearArticulatedPart()
Clear a vehicle from being an articulated part.
Definition ground_vehicle.hpp:266
GroundVehicle::SetArticulatedPart
void SetArticulatedPart()
Set a vehicle to be an articulated part.
Definition ground_vehicle.hpp:261
GroundVehicle::Crash
uint Crash(bool flooded) override
Common code executed for crashed ground vehicles.
Definition ground_vehicle.hpp:103
GroundVehicle::IsFreeWagon
bool IsFreeWagon() const
Check if the vehicle is a free wagon (got no engine in front of it).
Definition ground_vehicle.hpp:312
GroundVehicle::ClearEngine
void ClearEngine()
Clear engine status.
Definition ground_vehicle.hpp:286
GroundVehicle::ClearMultiheaded
void ClearMultiheaded()
Clear multiheaded engine property.
Definition ground_vehicle.hpp:306
GroundVehicle::DoUpdateSpeed
uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
Update the speed of the vehicle.
Definition ground_vehicle.hpp:365
GroundVehicle::GroundVehicle
GroundVehicle()
The constructor at SpecializedVehicle must be called.
Definition ground_vehicle.hpp:91
GroundVehicle::GetAcceleration
int GetAcceleration() const
Calculates the acceleration of the vehicle under its current conditions.
Definition ground_vehicle.cpp:105
GroundVehicle::ClearFrontEngine
void ClearFrontEngine()
Remove the front engine state.
Definition ground_vehicle.hpp:256
GroundVehicle::UpdateZPosition
void UpdateZPosition()
Updates vehicle's Z position.
Definition ground_vehicle.hpp:163
GroundVehicle::SetLastSpeed
void SetLastSpeed()
Update the GUI variant of the current speed of the vehicle.
Definition ground_vehicle.hpp:343
PoolID< uint16_t, struct EngineIDTag, 64000, 0xFFFF >
Pool::PoolItem<&_vehicle_pool >::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:286
SpecializedVehicle
Class defining several overloaded accessors so we don't have to cast vehicle types that often.
Definition vehicle_base.h:1014
SpecializedVehicle::UpdateViewport
void UpdateViewport(bool force_update, bool update_delta)
Update vehicle sprite- and position caches.
Definition vehicle_base.h:1156
Vehicle::GetAdvanceSpeed
static uint GetAdvanceSpeed(uint speed)
Determines the effective vehicle movement speed.
Definition vehicle_base.h:400
Vehicle::z_pos
int32_t z_pos
z coordinate.
Definition vehicle_base.h:267
Vehicle::direction
Direction direction
facing
Definition vehicle_base.h:268
Vehicle::Crash
virtual uint Crash(bool flooded=false)
Crash the (whole) vehicle chain.
Definition vehicle.cpp:291
Vehicle::subtype
uint8_t subtype
subtype (Filled with values from AircraftSubType/DisasterSubType/EffectVehicleType/GroundVehicleSubty...
Definition vehicle_base.h:310
Vehicle::subspeed
uint8_t subspeed
fractional speed
Definition vehicle_base.h:284
Vehicle::y_pos
int32_t y_pos
y coordinate.
Definition vehicle_base.h:266
Vehicle::x_pos
int32_t x_pos
x coordinate.
Definition vehicle_base.h:265
Vehicle::cur_speed
uint16_t cur_speed
current speed
Definition vehicle_base.h:283
Vehicle::progress
uint8_t progress
The percentage (if divided by 256) this vehicle already crossed the tile unit.
Definition vehicle_base.h:287
TILE_UNIT_MASK
static constexpr uint TILE_UNIT_MASK
For masking in/out the inner-tile world coordinate units.
Definition tile_type.h:16
TILE_SIZE
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
vehicle_base.h
Base class for all vehicles.
GVSF_ARTICULATED_PART
@ GVSF_ARTICULATED_PART
Articulated part of an engine.
Definition vehicle_base.h:84
GVSF_FRONT
@ GVSF_FRONT
Leading engine of a consist.
Definition vehicle_base.h:83
GVSF_MULTIHEADED
@ GVSF_MULTIHEADED
Engine is multiheaded (not used for road vehicles).
Definition vehicle_base.h:88
GVSF_FREE_WAGON
@ GVSF_FREE_WAGON
First in a wagon chain (in depot) (not used for road vehicles).
Definition vehicle_base.h:87
GVSF_WAGON
@ GVSF_WAGON
Wagon (not used for road vehicles).
Definition vehicle_base.h:85
GVSF_ENGINE
@ GVSF_ENGINE
Engine that can be front engine, but might be placed behind another engine (not used for road vehicle...
Definition vehicle_base.h:86
vehicle_gui.h
Functions related to the vehicle's GUIs.
vehicle_widget.h
Types related to the vehicle widgets.
WID_VV_START_STOP
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
Definition vehicle_widget.h:17
SetWindowWidgetDirty
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, WidgetID widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition window.cpp:3192
window_func.h
Window functions not directly related to making/drawing windows.
WC_VEHICLE_VIEW
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
Definition window_type.h:344