summaryrefslogtreecommitdiff
path: root/src/train.h
blob: b38139e0102a3af30540b7128ae3d1b4385daa8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
/* $Id$ */

/** @file train.h Base for the train class. */

#ifndef TRAIN_H
#define TRAIN_H

#include "stdafx.h"
#include "core/bitmath_func.hpp"
#include "vehicle_base.h"

struct Train;

enum VehicleRailFlags {
	VRF_REVERSING         = 0,

	/* used to calculate if train is going up or down */
	VRF_GOINGUP           = 1,
	VRF_GOINGDOWN         = 2,

	/* used to store if a wagon is powered or not */
	VRF_POWEREDWAGON      = 3,

	/* used to reverse the visible direction of the vehicle */
	VRF_REVERSE_DIRECTION = 4,

	/* used to mark train as lost because PF can't find the route */
	VRF_NO_PATH_TO_DESTINATION = 5,

	/* used to mark that electric train engine is allowed to run on normal rail */
	VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6,

	/* used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle only) */
	VRF_TOGGLE_REVERSE = 7,

	/* used to mark a train that can't get a path reservation */
	VRF_TRAIN_STUCK    = 8,
};


/** enum to handle train subtypes
 * Do not access it directly unless you have to. Use the access functions below
 * This is an enum to tell what bit to access as it is a bitmask
 */
enum TrainSubtype {
	TS_FRONT             = 0, ///< Leading engine of a train
	TS_ARTICULATED_PART  = 1, ///< Articulated part of an engine
	TS_WAGON             = 2, ///< Wagon
	TS_ENGINE            = 3, ///< Engine, that can be front engines, but might be placed behind another engine
	TS_FREE_WAGON        = 4, ///< First in a wagon chain (in depot)
	TS_MULTIHEADED       = 5, ///< Engine is a multiheaded
};


/** Check if a vehicle is front engine
 * @param v vehicle to check
 * @return Returns true if vehicle is a front engine
 */
static inline bool IsFrontEngine(const Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	return HasBit(v->subtype, TS_FRONT);
}

/** Set front engine state
 * @param v vehicle to change
 */
static inline void SetFrontEngine(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	SetBit(v->subtype, TS_FRONT);
}

/** Remove the front engine state
 * @param v vehicle to change
 */
static inline void ClearFrontEngine(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	ClrBit(v->subtype, TS_FRONT);
}

/** Check if a vehicle is an articulated part of an engine
 * @param v vehicle to check
 * @return Returns true if vehicle is an articulated part
 */
static inline bool IsArticulatedPart(const Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	return HasBit(v->subtype, TS_ARTICULATED_PART);
}

/** Set a vehicle to be an articulated part
 * @param v vehicle to change
 */
static inline void SetArticulatedPart(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	SetBit(v->subtype, TS_ARTICULATED_PART);
}

/** Clear a vehicle from being an articulated part
 * @param v vehicle to change
 */
static inline void ClearArticulatedPart(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	ClrBit(v->subtype, TS_ARTICULATED_PART);
}

/** Check if a vehicle is a wagon
 * @param v vehicle to check
 * @return Returns true if vehicle is a wagon
 */
static inline bool IsTrainWagon(const Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	return HasBit(v->subtype, TS_WAGON);
}

/** Set a vehicle to be a wagon
 * @param v vehicle to change
 */
static inline void SetTrainWagon(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	SetBit(v->subtype, TS_WAGON);
}

/** Clear wagon property
 * @param v vehicle to change
 */
static inline void ClearTrainWagon(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	ClrBit(v->subtype, TS_WAGON);
}

/** Check if a vehicle is an engine (can be first in a train)
 * @param v vehicle to check
 * @return Returns true if vehicle is an engine
 */
static inline bool IsTrainEngine(const Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	return HasBit(v->subtype, TS_ENGINE);
}

/** Set engine status
 * @param v vehicle to change
 */
static inline void SetTrainEngine(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	SetBit(v->subtype, TS_ENGINE);
}

/** Clear engine status
 * @param v vehicle to change
 */
static inline void ClearTrainEngine(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	ClrBit(v->subtype, TS_ENGINE);
}

/** Check if a vehicle is a free wagon (got no engine in front of it)
 * @param v vehicle to check
 * @return Returns true if vehicle is a free wagon
 */
static inline bool IsFreeWagon(const Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	return HasBit(v->subtype, TS_FREE_WAGON);
}

/** Set if a vehicle is a free wagon
 * @param v vehicle to change
 */
static inline void SetFreeWagon(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	SetBit(v->subtype, TS_FREE_WAGON);
}

/** Clear a vehicle from being a free wagon
 * @param v vehicle to change
 */
static inline void ClearFreeWagon(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	ClrBit(v->subtype, TS_FREE_WAGON);
}

/** Check if a vehicle is a multiheaded engine
 * @param v vehicle to check
 * @return Returns true if vehicle is a multiheaded engine
 */
static inline bool IsMultiheaded(const Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	return HasBit(v->subtype, TS_MULTIHEADED);
}

/** Set if a vehicle is a multiheaded engine
 * @param v vehicle to change
 */
static inline void SetMultiheaded(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	SetBit(v->subtype, TS_MULTIHEADED);
}

/** Clear multiheaded engine property
 * @param v vehicle to change
 */
static inline void ClearMultiheaded(Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	ClrBit(v->subtype, TS_MULTIHEADED);
}

/** Check if an engine has an articulated part.
 * @param v Vehicle.
 * @return True if the engine has an articulated part.
 */
static inline bool EngineHasArticPart(const Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	return (v->Next() != NULL && IsArticulatedPart(v->Next()));
}

/** Tell if we are dealing with the rear end of a multiheaded engine.
 * @param v Vehicle.
 * @return True if the engine is the rear part of a dualheaded engine.
 */
static inline bool IsRearDualheaded(const Vehicle *v)
{
	assert(v->type == VEH_TRAIN);
	return (IsMultiheaded(v) && !IsTrainEngine(v));
}

void CcBuildLoco(bool success, TileIndex tile, uint32 p1, uint32 p2);
void CcBuildWagon(bool success, TileIndex tile, uint32 p1, uint32 p2);

byte FreightWagonMult(CargoID cargo);

int CheckTrainInDepot(const Train *v, bool needs_to_be_stopped);
int CheckTrainStoppedInDepot(const Train *v);
void UpdateTrainAcceleration(Train *v);
void CheckTrainsLengths();

void FreeTrainTrackReservation(const Train *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR);
bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay = false);

int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length);

void TrainConsistChanged(Train *v, bool same_length);
void TrainPowerChanged(Train *v);
Money GetTrainRunningCost(const Train *v);

/** Variables that are cached to improve performance and such */
struct TrainCache {
	/* Cached wagon override spritegroup */
	const struct SpriteGroup *cached_override;

	uint16 last_speed; // NOSAVE: only used in UI

	/* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */
	uint32 cached_power;        ///< total power of the consist.
	uint16 cached_max_speed;    ///< max speed of the consist. (minimum of the max speed of all vehicles in the consist)
	uint16 cached_total_length; ///< Length of the whole train, valid only for first engine.
	uint8 cached_veh_length;    ///< length of this vehicle in units of 1/8 of normal length, cached because this can be set by a callback
	bool cached_tilt;           ///< train can tilt; feature provides a bonus in curves

	/* cached values, recalculated when the cargo on a train changes (in addition to the conditions above) */
	uint32 cached_weight;     ///< total weight of the consist.
	uint32 cached_veh_weight; ///< weight of the vehicle.
	uint32 cached_max_te;     ///< max tractive effort of consist

	/**
	 * Position/type of visual effect.
	 * bit 0 - 3 = position of effect relative to vehicle. (0 = front, 8 = centre, 15 = rear)
	 * bit 4 - 5 = type of effect. (0 = default for engine class, 1 = steam, 2 = diesel, 3 = electric)
	 * bit     6 = disable visual effect.
	 * bit     7 = disable powered wagons.
	 */
	byte cached_vis_effect;
	byte user_def_data;

	/* NOSAVE: for wagon override - id of the first engine in train
	 * 0xffff == not in train */
	EngineID first_engine;
};

/**
 * 'Train' is either a loco or a wagon.
 */
struct Train : public SpecializedVehicle<Train, VEH_TRAIN> {
	TrainCache tcache;

	/* Link between the two ends of a multiheaded engine */
	Train *other_multiheaded_part;

	uint16 crash_anim_pos;

	uint16 flags;
	TrackBitsByte track;
	byte force_proceed;
	RailTypeByte railtype;
	RailTypes compatible_railtypes;

	/** Initializes the Vehicle to a train */
	Train() { this->type = VEH_TRAIN; }

	/** We want to 'destruct' the right class. */
	virtual ~Train() { this->PreDestructor(); }

	const char *GetTypeString() const { return "train"; }
	void MarkDirty();
	void UpdateDeltaXY(Direction direction);
	ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; }
	void PlayLeaveStationSound() const;
	bool IsPrimaryVehicle() const { return IsFrontEngine(this); }
	SpriteID GetImage(Direction direction) const;
	int GetDisplaySpeed() const { return this->tcache.last_speed; }
	int GetDisplayMaxSpeed() const { return this->tcache.cached_max_speed; }
	Money GetRunningCost() const;
	bool IsInDepot() const { return CheckTrainInDepot(this, false) != -1; }
	bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; }
	bool Tick();
	void OnNewDay();
	Trackdir GetVehicleTrackdir() const;
	TileIndex GetOrderStationLocation(StationID station);
	bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
};

#define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)

/**
 * Get the next part of a multi-part engine.
 * Will only work on a multi-part engine (EngineHasArticPart(v) == true),
 * Result is undefined for normal engine.
 */
static inline Train *GetNextArticPart(const Train *v)
{
	assert(EngineHasArticPart(v));
	return v->Next();
}

/** Get the last part of a multi-part engine.
 * @param v Vehicle.
 * @return Last part of the engine.
 */
static inline Train *GetLastEnginePart(Train *v)
{
	assert(v->type == VEH_TRAIN);
	while (EngineHasArticPart(v)) v = GetNextArticPart(v);
	return v;
}

/** Get the next real (non-articulated part) vehicle in the consist.
 * @param v Vehicle.
 * @return Next vehicle in the consist.
 */
static inline Train *GetNextVehicle(const Train *v)
{
	assert(v->type == VEH_TRAIN);
	while (EngineHasArticPart(v)) v = GetNextArticPart(v);

	/* v now contains the last artic part in the engine */
	return v->Next();
}

/** Get the previous real (non-articulated part) vehicle in the consist.
 * @param w Vehicle.
 * @return Previous vehicle in the consist.
 */
static inline Train *GetPrevVehicle(const Train *w)
{
	assert(w->type == VEH_TRAIN);

	Train *v = w->Previous();
	while (v != NULL && IsArticulatedPart(v)) v = v->Previous();

	return v;
}

/** Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist.
 * @param v Vehicle.
 * @return Next vehicle in the consist.
 */
static inline Train *GetNextUnit(const Train *v)
{
	assert(v->type == VEH_TRAIN);
	Train *w = GetNextVehicle(v);
	if (w != NULL && IsRearDualheaded(w)) w = GetNextVehicle(w);

	return w;
}

/** Get the previous real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist.
 * @param v Vehicle.
 * @return Previous vehicle in the consist.
 */
static inline Train *GetPrevUnit(const Train *v)
{
	assert(v->type == VEH_TRAIN);
	Train *w = GetPrevVehicle(v);
	if (w != NULL && IsRearDualheaded(w)) w = GetPrevVehicle(w);

	return w;
}

#endif /* TRAIN_H */