OpenTTD
ground_vehicle.hpp
Go to the documentation of this file.
1 /* $Id: ground_vehicle.hpp 26888 2014-09-21 12:44:38Z rubidium $ */
2 
3 /*
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/>.
8  */
9 
12 #ifndef GROUND_VEHICLE_HPP
13 #define GROUND_VEHICLE_HPP
14 
15 #include "vehicle_base.h"
16 #include "vehicle_gui.h"
17 #include "landscape.h"
18 #include "window_func.h"
19 #include "widgets/vehicle_widget.h"
20 
25 };
26 
32  /* Cached acceleration values, recalculated when the cargo on a vehicle changes (in addition to the conditions below) */
33  uint32 cached_weight;
35  uint32 cached_max_te;
37 
38  /* Cached acceleration values, recalculated on load and each time a vehicle is added to/removed from the consist. */
40  uint32 cached_power;
41  uint32 cached_air_drag;
42 
43  /* Cached NewGRF values, recalculated on load and each time a vehicle is added to/removed from the consist. */
47 
48  /* Cached UI information. */
49  uint16 last_speed;
50 };
51 
57 };
58 
80 template <class T, VehicleType Type>
81 struct GroundVehicle : public SpecializedVehicle<T, Type> {
83  uint16 gv_flags;
84 
86 
91 
92  void PowerChanged();
93  void CargoChanged();
94  int GetAcceleration() const;
95  bool IsChainInDepot() const;
96 
102  /* virtual */ uint Crash(bool flooded)
103  {
104  /* Crashed vehicles aren't going up or down */
105  for (T *v = T::From(this); v != NULL; v = v->Next()) {
106  ClrBit(v->gv_flags, GVF_GOINGUP_BIT);
107  ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT);
108  }
109  return this->Vehicle::Crash(flooded);
110  }
111 
116  inline int64 GetSlopeResistance() const
117  {
118  int64 incl = 0;
119 
120  for (const T *u = T::From(this); u != NULL; u = u->Next()) {
121  if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) {
122  incl += u->gcache.cached_slope_resistance;
123  } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) {
124  incl -= u->gcache.cached_slope_resistance;
125  }
126  }
127 
128  return incl;
129  }
130 
138  {
139  this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos);
140  ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
141  ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
142 
143  if (T::From(this)->TileMayHaveSlopedTrack()) {
144  /* To check whether the current tile is sloped, and in which
145  * direction it is sloped, we get the 'z' at the center of
146  * the tile (middle_z) and the edge of the tile (old_z),
147  * which we then can compare. */
148  int middle_z = GetSlopePixelZ((this->x_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2), (this->y_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2));
149 
150  if (middle_z != this->z_pos) {
151  SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
152  }
153  }
154  }
155 
162  inline void UpdateZPosition()
163  {
164 #if 0
165  /* The following code does this: */
166 
167  if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) {
168  switch (this->direction) {
169  case DIR_NE:
170  this->z_pos += (this->x_pos & 1); break;
171  case DIR_SW:
172  this->z_pos += (this->x_pos & 1) ^ 1; break;
173  case DIR_NW:
174  this->z_pos += (this->y_pos & 1); break;
175  case DIR_SE:
176  this->z_pos += (this->y_pos & 1) ^ 1; break;
177  default: break;
178  }
179  } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
180  switch (this->direction) {
181  case DIR_NE:
182  this->z_pos -= (this->x_pos & 1); break;
183  case DIR_SW:
184  this->z_pos -= (this->x_pos & 1) ^ 1; break;
185  case DIR_NW:
186  this->z_pos -= (this->y_pos & 1); break;
187  case DIR_SE:
188  this->z_pos -= (this->y_pos & 1) ^ 1; break;
189  default: break;
190  }
191  }
192 
193  /* But gcc 4.4.5 isn't able to nicely optimise it, and the resulting
194  * code is full of conditional jumps. */
195 #endif
196 
197  /* Vehicle's Z position can change only if it has GVF_GOINGUP_BIT or GVF_GOINGDOWN_BIT set.
198  * Furthermore, if this function is called once every time the vehicle's position changes,
199  * we know the Z position changes by +/-1 at certain moments - when x_pos, y_pos is odd/even,
200  * depending on orientation of the slope and vehicle's direction */
201 
202  if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
203  if (T::From(this)->HasToUseGetSlopePixelZ()) {
204  /* In some cases, we have to use GetSlopePixelZ() */
205  this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos);
206  return;
207  }
208  /* DirToDiagDir() is a simple right shift */
209  DiagDirection dir = DirToDiagDir(this->direction);
210  /* Read variables, so the compiler knows the access doesn't trap */
211  int8 x_pos = this->x_pos;
212  int8 y_pos = this->y_pos;
213  /* DiagDirToAxis() is a simple mask */
214  int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos;
215  /* We need only the least significant bit */
216  d &= 1;
217  /* Conditional "^ 1". Optimised to "(dir - 1) <= 1". */
218  d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE);
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));
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) {
347  this->gcache.last_speed = this->cur_speed;
348  }
349  }
350 
351 protected:
365  inline uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
366  {
367  uint spd = this->subspeed + accel;
368  this->subspeed = (byte)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 = 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 = max(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 */
void ClearEngine()
Clear engine status.
AccelStatus
What is the status of our acceleration?
GroundVehicleFlags
Ground vehicle flags.
static DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
void SetFrontEngine()
Set front engine state.
virtual uint Crash(bool flooded=false)
Crash the (whole) vehicle chain.
Definition: vehicle.cpp:260
uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
Update the speed of the vehicle.
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
void ClearArticulatedPart()
Clear a vehicle from being an articulated part.
Leading engine of a consist.
Definition: vehicle_base.h:113
void UpdateZPositionAndInclination()
Updates vehicle&#39;s Z position and inclination.
Start or stop this vehicle, and show information about the current state.
bool IsMultiheaded() const
Check if the vehicle is a multiheaded engine.
Engine that can be front engine, but might be placed behind another engine (not used for road vehicle...
Definition: vehicle_base.h:116
uint32 cached_power
Total power of the consist (valid only for the first engine).
GroundVehicle()
The constructor at SpecializedVehicle must be called.
uint16 cached_axle_resistance
Resistance caused by the axles of the vehicle (valid only for the first engine).
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:26
Wagon (not used for road vehicles).
Definition: vehicle_base.h:115
Cached, frequently calculated values.
Functions related to the vehicle&#39;s GUIs.
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:15
Southeast.
EngineID first_engine
Cached EngineID of the front vehicle. INVALID_ENGINE for the front vehicle itself.
Northeast.
Class defining several overloaded accessors so we don&#39;t have to cast vehicle types that often...
Definition: vehicle_base.h:993
uint32 cached_air_drag
Air drag coefficient of the vehicle (valid only for the first engine).
GroundVehicle< T, Type > GroundVehicleBase
Our type.
bool IsWagon() const
Check if a vehicle is a wagon.
void SetEngine()
Set engine status.
int64 GetSlopeResistance() const
Calculates the total slope resistance for this vehicle.
We want to stop.
Southeast.
Southwest.
void ClearFrontEngine()
Remove the front engine state.
void ClearFreeWagon()
Clear a vehicle from being a free wagon.
Vehicle view; Window numbers:
Definition: window_type.h:334
uint32 cached_slope_resistance
Resistance caused by weight when this vehicle part is at a slope.
bool IsRearDualheaded() const
Tell if we are dealing with the rear end of a multiheaded engine.
DiagDirection
Enumeration for diagonal directions.
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:42
Vehicle is currently going uphill. (Cached track information for acceleration)
We want to go faster, if possible of course.
Engine is multiheaded (not used for road vehicles).
Definition: vehicle_base.h:118
uint16 last_speed
The last speed we did display, so we only have to redraw when this changes.
The X axis.
static Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
Vehicle is currently going downhill. (Cached track information for acceleration)
Articulated part of an engine.
Definition: vehicle_base.h:114
void UpdateZPosition()
Updates vehicle&#39;s Z position.
static T ClrBit(T &x, const uint8 y)
Clears a bit in a variable.
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition: window.cpp:3134
Base class for all vehicles.
uint16 EngineID
Unique identification number of an engine.
Definition: engine_type.h:22
uint16 cached_total_length
Length of the whole vehicle (valid only for the first engine).
First in a wagon chain (in depot) (not used for road vehicles).
Definition: vehicle_base.h:117
uint16 cached_max_track_speed
Maximum consist speed limited by track type (valid only for the first engine).
static const uint TILE_UNIT_MASK
For masking in/out the inner-tile world coordinate units.
Definition: tile_type.h:16
Functions related to OTTD&#39;s landscape.
void SetLastSpeed()
Update the GUI variant of the current speed of the vehicle.
bool IsFreeWagon() const
Check if the vehicle is a free wagon (got no engine in front of it).
uint8 cached_veh_length
Length of this vehicle in units of 1/VEHICLE_LENGTH of normal length. It is cached because this can b...
Northwest.
Types related to the vehicle widgets.
void ClearMultiheaded()
Clear multiheaded engine property.
void SetArticulatedPart()
Set a vehicle to be an articulated part.
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
void SetFreeWagon()
Set a vehicle as a free wagon.
uint32 cached_max_te
Maximum tractive effort of consist (valid only for the first engine).
Window functions not directly related to making/drawing windows.
uint Crash(bool flooded)
Common code executed for crashed ground vehicles.
int UpdateInclination(bool new_tile, bool update_delta)
Checks if the vehicle is in a slope and sets the required flags in that case.
Base class for all vehicles that move through ground.
void SetMultiheaded()
Set a vehicle as a multiheaded engine.
void SetWagon()
Set a vehicle to be a wagon.
Southwest.
uint32 cached_weight
Total weight of the consist (valid only for the first engine).
Disable insertion and removal of automatic orders until the vehicle completes the real order...
bool IsEngine() const
Check if a vehicle is an engine (can be first in a consist).
GroundVehicleCache gcache
Cache of often calculated values.
void ClearWagon()
Clear wagon property.