Change: Let AI developers edit non-editable AI/Game Script Parameters (#8895)
[openttd-github.git] / src / ground_vehicle.hpp
blob15aac1f369542f7c13a6b489f9275e8f5a82ba9f
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 */
8 /** @file ground_vehicle.hpp Base class and functions for all vehicles that move through ground. */
10 #ifndef GROUND_VEHICLE_HPP
11 #define GROUND_VEHICLE_HPP
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"
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.
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.
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).
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).
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.
46 /* Cached UI information. */
47 uint16 last_speed; ///< The last speed we did display, so we only have to redraw when this changes.
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.
57 /**
58 * Base class for all vehicles that move through ground.
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.
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;
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.
83 typedef GroundVehicle<T, Type> GroundVehicleBase; ///< Our type
85 /**
86 * The constructor at SpecializedVehicle must be called.
88 GroundVehicle() : SpecializedVehicle<T, Type>() {}
90 void PowerChanged();
91 void CargoChanged();
92 int GetAcceleration() const;
93 bool IsChainInDepot() const override;
95 /**
96 * Common code executed for crashed ground vehicles
97 * @param flooded was this vehicle flooded?
98 * @return number of victims
100 uint Crash(bool flooded) override
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);
107 return this->Vehicle::Crash(flooded);
111 * Calculates the total slope resistance for this vehicle.
112 * @return Slope resistance.
114 inline int64 GetSlopeResistance() const
116 int64 incl = 0;
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;
126 return incl;
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
135 inline void UpdateZPositionAndInclination()
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);
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));
148 if (middle_z != this->z_pos) {
149 SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
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.
160 inline void UpdateZPosition()
162 #if 0
163 /* The following code does this: */
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;
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;
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
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 */
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;
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;
223 assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos));
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.
232 inline int UpdateInclination(bool new_tile, bool update_delta)
234 int old_z = this->z_pos;
236 if (new_tile) {
237 this->UpdateZPositionAndInclination();
238 } else {
239 this->UpdateZPosition();
242 this->UpdateViewport(true, update_delta);
243 return old_z;
247 * Set front engine state.
249 inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
252 * Remove the front engine state.
254 inline void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); }
257 * Set a vehicle to be an articulated part.
259 inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
262 * Clear a vehicle from being an articulated part.
264 inline void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); }
267 * Set a vehicle to be a wagon.
269 inline void SetWagon() { SetBit(this->subtype, GVSF_WAGON); }
272 * Clear wagon property.
274 inline void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); }
277 * Set engine status.
279 inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
282 * Clear engine status.
284 inline void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); }
287 * Set a vehicle as a free wagon.
289 inline void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); }
292 * Clear a vehicle from being a free wagon.
294 inline void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); }
297 * Set a vehicle as a multiheaded engine.
299 inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); }
302 * Clear multiheaded engine property.
304 inline void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); }
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.
310 inline bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
313 * Check if a vehicle is an engine (can be first in a consist).
314 * @return Returns true if vehicle is an engine.
316 inline bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); }
319 * Check if a vehicle is a wagon.
320 * @return Returns true if vehicle is a wagon.
322 inline bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); }
325 * Check if the vehicle is a multiheaded engine.
326 * @return Returns true if the vehicle is a multiheaded engine.
328 inline bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); }
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.
334 inline bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
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.
341 inline void SetLastSpeed()
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;
349 protected:
351 * Update the speed of the vehicle.
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.
363 inline uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
365 uint spd = this->subspeed + accel;
366 this->subspeed = (byte)spd;
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);
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);
382 int scaled_spd = this->GetAdvanceSpeed(spd);
384 scaled_spd += this->progress;
385 this->progress = 0; // set later in *Handler or *Controller
386 return scaled_spd;
390 #endif /* GROUND_VEHICLE_HPP */