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  */
7 
8 /** @file vehicle.cpp Base implementations of all vehicles. */
9 
10 #include "stdafx.h"
11 #include "error.h"
12 #include "roadveh.h"
13 #include "ship.h"
14 #include "spritecache.h"
15 #include "timetable.h"
16 #include "viewport_func.h"
17 #include "news_func.h"
18 #include "command_func.h"
19 #include "company_func.h"
20 #include "train.h"
21 #include "aircraft.h"
22 #include "newgrf_debug.h"
23 #include "newgrf_sound.h"
24 #include "newgrf_station.h"
25 #include "group_gui.h"
26 #include "strings_func.h"
27 #include "zoom_func.h"
28 #include "date_func.h"
29 #include "vehicle_func.h"
30 #include "autoreplace_func.h"
31 #include "autoreplace_gui.h"
32 #include "station_base.h"
33 #include "ai/ai.hpp"
34 #include "depot_func.h"
35 #include "network/network.h"
36 #include "core/pool_func.hpp"
37 #include "economy_base.h"
38 #include "articulated_vehicles.h"
39 #include "roadstop_base.h"
40 #include "core/random_func.hpp"
41 #include "core/backup_type.hpp"
42 #include "order_backup.h"
43 #include "sound_func.h"
44 #include "effectvehicle_func.h"
45 #include "effectvehicle_base.h"
46 #include "vehiclelist.h"
47 #include "bridge_map.h"
48 #include "tunnel_map.h"
49 #include "depot_map.h"
50 #include "gamelog.h"
51 #include "linkgraph/linkgraph.h"
52 #include "linkgraph/refresh.h"
53 #include "framerate_type.h"
54 
55 #include "table/strings.h"
56 
57 #include "safeguards.h"
58 
59 /* Number of bits in the hash to use from each vehicle coord */
60 static const uint GEN_HASHX_BITS = 6;
61 static const uint GEN_HASHY_BITS = 6;
62 
63 /* Size of each hash bucket */
64 static const uint GEN_HASHX_BUCKET_BITS = 7;
65 static const uint GEN_HASHY_BUCKET_BITS = 6;
66 
67 /* Compute hash for vehicle coord */
68 #define GEN_HASHX(x)    GB((x), GEN_HASHX_BUCKET_BITS + ZOOM_LVL_SHIFT, GEN_HASHX_BITS)
69 #define GEN_HASHY(y)   (GB((y), GEN_HASHY_BUCKET_BITS + ZOOM_LVL_SHIFT, GEN_HASHY_BITS) << GEN_HASHX_BITS)
70 #define GEN_HASH(x, y) (GEN_HASHY(y) + GEN_HASHX(x))
71 
72 /* Maximum size until hash repeats */
73 static const int GEN_HASHX_SIZE = 1 << (GEN_HASHX_BUCKET_BITS + GEN_HASHX_BITS + ZOOM_LVL_SHIFT);
74 static const int GEN_HASHY_SIZE = 1 << (GEN_HASHY_BUCKET_BITS + GEN_HASHY_BITS + ZOOM_LVL_SHIFT);
75 
76 /* Increments to reach next bucket in hash table */
77 static const int GEN_HASHX_INC = 1;
78 static const int GEN_HASHY_INC = 1 << GEN_HASHX_BITS;
79 
80 /* Mask to wrap-around buckets */
81 static const uint GEN_HASHX_MASK =  (1 << GEN_HASHX_BITS) - 1;
82 static const uint GEN_HASHY_MASK = ((1 << GEN_HASHY_BITS) - 1) << GEN_HASHX_BITS;
83 
84 VehicleID _new_vehicle_id;
85 uint _returned_refit_capacity;        ///< Stores the capacity after a refit operation.
86 uint16 _returned_mail_refit_capacity; ///< Stores the mail capacity after a refit operation (Aircraft only).
87 
88 
89 /** The pool with all our precious vehicles. */
90 VehiclePool _vehicle_pool("Vehicle");
INSTANTIATE_POOL_METHODS(Vehicle)91 INSTANTIATE_POOL_METHODS(Vehicle)
92 
93 
94 /**
95  * Determine shared bounds of all sprites.
96  * @param[out] bounds Shared bounds.
97  */
98 void VehicleSpriteSeq::GetBounds(Rect *bounds) const
99 {
100 	bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
101 	for (uint i = 0; i < this->count; ++i) {
102 		const Sprite *spr = GetSprite(this->seq[i].sprite, ST_NORMAL);
103 		if (i == 0) {
104 			bounds->left = spr->x_offs;
105 			bounds->top  = spr->y_offs;
106 			bounds->right  = spr->width  + spr->x_offs - 1;
107 			bounds->bottom = spr->height + spr->y_offs - 1;
108 		} else {
109 			if (spr->x_offs < bounds->left) bounds->left = spr->x_offs;
110 			if (spr->y_offs < bounds->top)  bounds->top  = spr->y_offs;
111 			int right  = spr->width  + spr->x_offs - 1;
112 			int bottom = spr->height + spr->y_offs - 1;
113 			if (right  > bounds->right)  bounds->right  = right;
114 			if (bottom > bounds->bottom) bounds->bottom = bottom;
115 		}
116 	}
117 }
118 
119 /**
120  * Draw the sprite sequence.
121  * @param x X position
122  * @param y Y position
123  * @param default_pal Vehicle palette
124  * @param force_pal Whether to ignore individual palettes, and draw everything with \a default_pal.
125  */
Draw(int x,int y,PaletteID default_pal,bool force_pal) const126 void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const
127 {
128 	for (uint i = 0; i < this->count; ++i) {
129 		PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal;
130 		DrawSprite(this->seq[i].sprite, pal, x, y);
131 	}
132 }
133 
134 /**
135  * Function to tell if a vehicle needs to be autorenewed
136  * @param *c The vehicle owner
137  * @param use_renew_setting Should the company renew setting be considered?
138  * @return true if the vehicle is old enough for replacement
139  */
NeedsAutorenewing(const Company * c,bool use_renew_setting) const140 bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
141 {
142 	/* We can always generate the Company pointer when we have the vehicle.
143 	 * However this takes time and since the Company pointer is often present
144 	 * when this function is called then it's faster to pass the pointer as an
145 	 * argument rather than finding it again. */
146 	assert(c == Company::Get(this->owner));
147 
148 	if (use_renew_setting && !c->settings.engine_renew) return false;
149 	if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
150 
151 	/* Only engines need renewing */
152 	if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
153 
154 	return true;
155 }
156 
157 /**
158  * Service a vehicle and all subsequent vehicles in the consist
159  *
160  * @param *v The vehicle or vehicle chain being serviced
161  */
VehicleServiceInDepot(Vehicle * v)162 void VehicleServiceInDepot(Vehicle *v)
163 {
164 	assert(v != nullptr);
165 	SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
166 
167 	do {
168 		v->date_of_last_service = _date;
169 		v->breakdowns_since_last_service = 0;
170 		v->reliability = v->GetEngine()->reliability;
171 		/* Prevent vehicles from breaking down directly after exiting the depot. */
172 		v->breakdown_chance /= 4;
173 		if (_settings_game.difficulty.vehicle_breakdowns == 1) v->breakdown_chance = 0; // on reduced breakdown
174 		v = v->Next();
175 	} while (v != nullptr && v->HasEngineType());
176 }
177 
178 /**
179  * Check if the vehicle needs to go to a depot in near future (if a opportunity presents itself) for service or replacement.
180  *
181  * @see NeedsAutomaticServicing()
182  * @return true if the vehicle should go to a depot if a opportunity presents itself.
183  */
NeedsServicing() const184 bool Vehicle::NeedsServicing() const
185 {
186 	/* Stopped or crashed vehicles will not move, as such making unmovable
187 	 * vehicles to go for service is lame. */
188 	if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
189 
190 	/* Are we ready for the next service cycle? */
191 	const Company *c = Company::Get(this->owner);
192 	if (this->ServiceIntervalIsPercent() ?
193 			(this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) :
194 			(this->date_of_last_service + this->GetServiceInterval() >= _date)) {
195 		return false;
196 	}
197 
198 	/* If we're servicing anyway, because we have not disabled servicing when
199 	 * there are no breakdowns or we are playing with breakdowns, bail out. */
200 	if (!_settings_game.order.no_servicing_if_no_breakdowns ||
201 			_settings_game.difficulty.vehicle_breakdowns != 0) {
202 		return true;
203 	}
204 
205 	/* Test whether there is some pending autoreplace.
206 	 * Note: We do this after the service-interval test.
207 	 * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
208 	bool pending_replace = false;
209 	Money needed_money = c->settings.engine_renew_money;
210 	if (needed_money > c->money) return false;
211 
212 	for (const Vehicle *v = this; v != nullptr; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : nullptr) {
213 		bool replace_when_old = false;
214 		EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
215 
216 		/* Check engine availability */
217 		if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
218 		/* Is the vehicle old if we are not always replacing? */
219 		if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
220 
221 		/* Check refittability */
222 		CargoTypes available_cargo_types, union_mask;
223 		GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
224 		/* Is there anything to refit? */
225 		if (union_mask != 0) {
226 			CargoID cargo_type;
227 			/* We cannot refit to mixed cargoes in an automated way */
228 			if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) continue;
229 
230 			/* Did the old vehicle carry anything? */
231 			if (cargo_type != CT_INVALID) {
232 				/* We can't refit the vehicle to carry the cargo we want */
233 				if (!HasBit(available_cargo_types, cargo_type)) continue;
234 			}
235 		}
236 
237 		/* Check money.
238 		 * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
239 		pending_replace = true;
240 		needed_money += 2 * Engine::Get(new_engine)->GetCost();
241 		if (needed_money > c->money) return false;
242 	}
243 
244 	return pending_replace;
245 }
246 
247 /**
248  * Checks if the current order should be interrupted for a service-in-depot order.
249  * @see NeedsServicing()
250  * @return true if the current order should be interrupted.
251  */
NeedsAutomaticServicing() const252 bool Vehicle::NeedsAutomaticServicing() const
253 {
254 	if (this->HasDepotOrder()) return false;
255 	if (this->current_order.IsType(OT_LOADING)) return false;
256 	if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
257 	return NeedsServicing();
258 }
259 
Crash(bool flooded)260 uint Vehicle::Crash(bool flooded)
261 {
262 	assert((this->vehstatus & VS_CRASHED) == 0);
263 	assert(this->Previous() == nullptr); // IsPrimaryVehicle fails for free-wagon-chains
264 
265 	uint pass = 0;
266 	/* Stop the vehicle. */
267 	if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
268 	/* crash all wagons, and count passengers */
269 	for (Vehicle *v = this; v != nullptr; v = v->Next()) {
270 		/* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */
271 		if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.TotalCount();
272 		v->vehstatus |= VS_CRASHED;
273 		v->MarkAllViewportsDirty();
274 	}
275 
276 	/* Dirty some windows */
277 	InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
278 	SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
279 	SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
280 	SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
281 
282 	delete this->cargo_payment;
283 	assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
284 
285 	return RandomRange(pass + 1); // Randomise deceased passengers.
286 }
287 
288 
289 /**
290  * Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
291  * @param engine The engine that caused the problem
292  * @param part1  Part 1 of the error message, taking the grfname as parameter 1
293  * @param part2  Part 2 of the error message, taking the engine as parameter 2
294  * @param bug_type Flag to check and set in grfconfig
295  * @param critical Shall the "OpenTTD might crash"-message be shown when the player tries to unpause?
296  */
ShowNewGrfVehicleError(EngineID engine,StringID part1,StringID part2,GRFBugs bug_type,bool critical)297 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
298 {
299 	const Engine *e = Engine::Get(engine);
300 	GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
301 
302 	/* Missing GRF. Nothing useful can be done in this situation. */
303 	if (grfconfig == nullptr) return;
304 
305 	if (!HasBit(grfconfig->grf_bugs, bug_type)) {
306 		SetBit(grfconfig->grf_bugs, bug_type);
307 		SetDParamStr(0, grfconfig->GetName());
308 		SetDParam(1, engine);
309 		ShowErrorMessage(part1, part2, WL_CRITICAL);
310 		if (!_networking) DoCommand(0, critical ? PM_PAUSED_ERROR : PM_PAUSED_NORMAL, 1, DC_EXEC, CMD_PAUSE);
311 	}
312 
313 	/* debug output */
314 	char buffer[512];
315 
316 	SetDParamStr(0, grfconfig->GetName());
317 	GetString(buffer, part1, lastof(buffer));
318 	Debug(grf, 0, "{}", buffer + 3);
319 
320 	SetDParam(1, engine);
321 	GetString(buffer, part2, lastof(buffer));
322 	Debug(grf, 0, "{}", buffer + 3);
323 }
324 
325 /**
326  * Logs a bug in GRF and shows a warning message if this
327  * is for the first time this happened.
328  * @param u first vehicle of chain
329  */
VehicleLengthChanged(const Vehicle * u)330 void VehicleLengthChanged(const Vehicle *u)
331 {
332 	/* show a warning once for each engine in whole game and once for each GRF after each game load */
333 	const Engine *engine = u->GetEngine();
334 	uint32 grfid = engine->grf_prop.grffile->grfid;
335 	GRFConfig *grfconfig = GetGRFConfig(grfid);
336 	if (GamelogGRFBugReverse(grfid, engine->grf_prop.local_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
337 		ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true);
338 	}
339 }
340 
341 /**
342  * Vehicle constructor.
343  * @param type Type of the new vehicle.
344  */
Vehicle(VehicleType type)345 Vehicle::Vehicle(VehicleType type)
346 {
347 	this->type               = type;
348 	this->coord.left         = INVALID_COORD;
349 	this->sprite_cache.old_coord.left = INVALID_COORD;
350 	this->group_id           = DEFAULT_GROUP;
351 	this->fill_percent_te_id = INVALID_TE_ID;
352 	this->first              = this;
353 	this->colourmap          = PAL_NONE;
354 	this->cargo_age_counter  = 1;
355 	this->last_station_visited = INVALID_STATION;
356 	this->last_loading_station = INVALID_STATION;
357 }
358 
359 /**
360  * Get a value for a vehicle's random_bits.
361  * @return A random value from 0 to 255.
362  */
VehicleRandomBits()363 byte VehicleRandomBits()
364 {
365 	return GB(Random(), 0, 8);
366 }
367 
368 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
369  * lookup times at the expense of memory usage. */
370 const int HASH_BITS = 7;
371 const int HASH_SIZE = 1 << HASH_BITS;
372 const int HASH_MASK = HASH_SIZE - 1;
373 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
374 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
375 
376 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
377  * Profiling results show that 0 is fastest. */
378 const int HASH_RES = 0;
379 
380 static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
381 
VehicleFromTileHash(int xl,int yl,int xu,int yu,void * data,VehicleFromPosProc * proc,bool find_first)382 static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
383 {
384 	for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
385 		for (int x = xl; ; x = (x + 1) & HASH_MASK) {
386 			Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
387 			for (; v != nullptr; v = v->hash_tile_next) {
388 				Vehicle *a = proc(v, data);
389 				if (find_first && a != nullptr) return a;
390 			}
391 			if (x == xu) break;
392 		}
393 		if (y == yu) break;
394 	}
395 
396 	return nullptr;
397 }
398 
399 
400 /**
401  * Helper function for FindVehicleOnPos/HasVehicleOnPos.
402  * @note Do not call this function directly!
403  * @param x    The X location on the map
404  * @param y    The Y location on the map
405  * @param data Arbitrary data passed to proc
406  * @param proc The proc that determines whether a vehicle will be "found".
407  * @param find_first Whether to return on the first found or iterate over
408  *                   all vehicles
409  * @return the best matching or first vehicle (depending on find_first).
410  */
VehicleFromPosXY(int x,int y,void * data,VehicleFromPosProc * proc,bool find_first)411 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
412 {
413 	const int COLL_DIST = 6;
414 
415 	/* Hash area to scan is from xl,yl to xu,yu */
416 	int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
417 	int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
418 	int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
419 	int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
420 
421 	return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
422 }
423 
424 /**
425  * Find a vehicle from a specific location. It will call proc for ALL vehicles
426  * on the tile and YOU must make SURE that the "best one" is stored in the
427  * data value and is ALWAYS the same regardless of the order of the vehicles
428  * where proc was called on!
429  * When you fail to do this properly you create an almost untraceable DESYNC!
430  * @note The return value of proc will be ignored.
431  * @note Use this when you have the intention that all vehicles
432  *       should be iterated over.
433  * @param x    The X location on the map
434  * @param y    The Y location on the map
435  * @param data Arbitrary data passed to proc
436  * @param proc The proc that determines whether a vehicle will be "found".
437  */
FindVehicleOnPosXY(int x,int y,void * data,VehicleFromPosProc * proc)438 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
439 {
440 	VehicleFromPosXY(x, y, data, proc, false);
441 }
442 
443 /**
444  * Checks whether a vehicle in on a specific location. It will call proc for
445  * vehicles until it returns non-nullptr.
446  * @note Use FindVehicleOnPosXY when you have the intention that all vehicles
447  *       should be iterated over.
448  * @param x    The X location on the map
449  * @param y    The Y location on the map
450  * @param data Arbitrary data passed to proc
451  * @param proc The proc that determines whether a vehicle will be "found".
452  * @return True if proc returned non-nullptr.
453  */
HasVehicleOnPosXY(int x,int y,void * data,VehicleFromPosProc * proc)454 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
455 {
456 	return VehicleFromPosXY(x, y, data, proc, true) != nullptr;
457 }
458 
459 /**
460  * Helper function for FindVehicleOnPos/HasVehicleOnPos.
461  * @note Do not call this function directly!
462  * @param tile The location on the map
463  * @param data Arbitrary data passed to \a proc.
464  * @param proc The proc that determines whether a vehicle will be "found".
465  * @param find_first Whether to return on the first found or iterate over
466  *                   all vehicles
467  * @return the best matching or first vehicle (depending on find_first).
468  */
VehicleFromPos(TileIndex tile,void * data,VehicleFromPosProc * proc,bool find_first)469 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
470 {
471 	int x = GB(TileX(tile), HASH_RES, HASH_BITS);
472 	int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
473 
474 	Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
475 	for (; v != nullptr; v = v->hash_tile_next) {
476 		if (v->tile != tile) continue;
477 
478 		Vehicle *a = proc(v, data);
479 		if (find_first && a != nullptr) return a;
480 	}
481 
482 	return nullptr;
483 }
484 
485 /**
486  * Find a vehicle from a specific location. It will call \a proc for ALL vehicles
487  * on the tile and YOU must make SURE that the "best one" is stored in the
488  * data value and is ALWAYS the same regardless of the order of the vehicles
489  * where proc was called on!
490  * When you fail to do this properly you create an almost untraceable DESYNC!
491  * @note The return value of \a proc will be ignored.
492  * @note Use this function when you have the intention that all vehicles
493  *       should be iterated over.
494  * @param tile The location on the map
495  * @param data Arbitrary data passed to \a proc.
496  * @param proc The proc that determines whether a vehicle will be "found".
497  */
FindVehicleOnPos(TileIndex tile,void * data,VehicleFromPosProc * proc)498 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
499 {
500 	VehicleFromPos(tile, data, proc, false);
501 }
502 
503 /**
504  * Checks whether a vehicle is on a specific location. It will call \a proc for
505  * vehicles until it returns non-nullptr.
506  * @note Use #FindVehicleOnPos when you have the intention that all vehicles
507  *       should be iterated over.
508  * @param tile The location on the map
509  * @param data Arbitrary data passed to \a proc.
510  * @param proc The \a proc that determines whether a vehicle will be "found".
511  * @return True if proc returned non-nullptr.
512  */
HasVehicleOnPos(TileIndex tile,void * data,VehicleFromPosProc * proc)513 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
514 {
515 	return VehicleFromPos(tile, data, proc, true) != nullptr;
516 }
517 
518 /**
519  * Callback that returns 'real' vehicles lower or at height \c *(int*)data .
520  * @param v Vehicle to examine.
521  * @param data Pointer to height data.
522  * @return \a v if conditions are met, else \c nullptr.
523  */
EnsureNoVehicleProcZ(Vehicle * v,void * data)524 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
525 {
526 	int z = *(int*)data;
527 
528 	if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return nullptr;
529 	if (v->z_pos > z) return nullptr;
530 
531 	return v;
532 }
533 
534 /**
535  * Ensure there is no vehicle at the ground at the given position.
536  * @param tile Position to examine.
537  * @return Succeeded command (ground is free) or failed command (a vehicle is found).
538  */
EnsureNoVehicleOnGround(TileIndex tile)539 CommandCost EnsureNoVehicleOnGround(TileIndex tile)
540 {
541 	int z = GetTileMaxPixelZ(tile);
542 
543 	/* Value v is not safe in MP games, however, it is used to generate a local
544 	 * error message only (which may be different for different machines).
545 	 * Such a message does not affect MP synchronisation.
546 	 */
547 	Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
548 	if (v != nullptr) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
549 	return CommandCost();
550 }
551 
552 /** Procedure called for every vehicle found in tunnel/bridge in the hash map */
GetVehicleTunnelBridgeProc(Vehicle * v,void * data)553 static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
554 {
555 	if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return nullptr;
556 	if (v == (const Vehicle *)data) return nullptr;
557 
558 	return v;
559 }
560 
561 /**
562  * Finds vehicle in tunnel / bridge
563  * @param tile first end
564  * @param endtile second end
565  * @param ignore Ignore this vehicle when searching
566  * @return Succeeded command (if tunnel/bridge is free) or failed command (if a vehicle is using the tunnel/bridge).
567  */
TunnelBridgeIsFree(TileIndex tile,TileIndex endtile,const Vehicle * ignore)568 CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
569 {
570 	/* Value v is not safe in MP games, however, it is used to generate a local
571 	 * error message only (which may be different for different machines).
572 	 * Such a message does not affect MP synchronisation.
573 	 */
574 	Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
575 	if (v == nullptr) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
576 
577 	if (v != nullptr) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
578 	return CommandCost();
579 }
580 
EnsureNoTrainOnTrackProc(Vehicle * v,void * data)581 static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
582 {
583 	TrackBits rail_bits = *(TrackBits *)data;
584 
585 	if (v->type != VEH_TRAIN) return nullptr;
586 
587 	Train *t = Train::From(v);
588 	if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return nullptr;
589 
590 	return v;
591 }
592 
593 /**
594  * Tests if a vehicle interacts with the specified track bits.
595  * All track bits interact except parallel #TRACK_BIT_HORZ or #TRACK_BIT_VERT.
596  *
597  * @param tile The tile.
598  * @param track_bits The track bits.
599  * @return \c true if no train that interacts, is found. \c false if a train is found.
600  */
EnsureNoTrainOnTrackBits(TileIndex tile,TrackBits track_bits)601 CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
602 {
603 	/* Value v is not safe in MP games, however, it is used to generate a local
604 	 * error message only (which may be different for different machines).
605 	 * Such a message does not affect MP synchronisation.
606 	 */
607 	Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
608 	if (v != nullptr) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
609 	return CommandCost();
610 }
611 
UpdateVehicleTileHash(Vehicle * v,bool remove)612 static void UpdateVehicleTileHash(Vehicle *v, bool remove)
613 {
614 	Vehicle **old_hash = v->hash_tile_current;
615 	Vehicle **new_hash;
616 
617 	if (remove) {
618 		new_hash = nullptr;
619 	} else {
620 		int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
621 		int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
622 		new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
623 	}
624 
625 	if (old_hash == new_hash) return;
626 
627 	/* Remove from the old position in the hash table */
628 	if (old_hash != nullptr) {
629 		if (v->hash_tile_next != nullptr) v->hash_tile_next->hash_tile_prev = v->hash_tile_prev;
630 		*v->hash_tile_prev = v->hash_tile_next;
631 	}
632 
633 	/* Insert vehicle at beginning of the new position in the hash table */
634 	if (new_hash != nullptr) {
635 		v->hash_tile_next = *new_hash;
636 		if (v->hash_tile_next != nullptr) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next;
637 		v->hash_tile_prev = new_hash;
638 		*new_hash = v;
639 	}
640 
641 	/* Remember current hash position */
642 	v->hash_tile_current = new_hash;
643 }
644 
645 static Vehicle *_vehicle_viewport_hash[1 << (GEN_HASHX_BITS + GEN_HASHY_BITS)];
646 
UpdateVehicleViewportHash(Vehicle * v,int x,int y,int old_x,int old_y)647 static void UpdateVehicleViewportHash(Vehicle *v, int x, int y, int old_x, int old_y)
648 {
649 	Vehicle **old_hash, **new_hash;
650 
651 	new_hash = (x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GEN_HASH(x, y)];
652 	old_hash = (old_x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
653 
654 	if (old_hash == new_hash) return;
655 
656 	/* remove from hash table? */
657 	if (old_hash != nullptr) {
658 		if (v->hash_viewport_next != nullptr) v->hash_viewport_next->hash_viewport_prev = v->hash_viewport_prev;
659 		*v->hash_viewport_prev = v->hash_viewport_next;
660 	}
661 
662 	/* insert into hash table? */
663 	if (new_hash != nullptr) {
664 		v->hash_viewport_next = *new_hash;
665 		if (v->hash_viewport_next != nullptr) v->hash_viewport_next->hash_viewport_prev = &v->hash_viewport_next;
666 		v->hash_viewport_prev = new_hash;
667 		*new_hash = v;
668 	}
669 }
670 
ResetVehicleHash()671 void ResetVehicleHash()
672 {
673 	for (Vehicle *v : Vehicle::Iterate()) { v->hash_tile_current = nullptr; }
674 	memset(_vehicle_viewport_hash, 0, sizeof(_vehicle_viewport_hash));
675 	memset(_vehicle_tile_hash, 0, sizeof(_vehicle_tile_hash));
676 }
677 
ResetVehicleColourMap()678 void ResetVehicleColourMap()
679 {
680 	for (Vehicle *v : Vehicle::Iterate()) { v->colourmap = PAL_NONE; }
681 }
682 
683 /**
684  * List of vehicles that should check for autoreplace this tick.
685  * Mapping of vehicle -> leave depot immediately after autoreplace.
686  */
687 typedef SmallMap<Vehicle *, bool> AutoreplaceMap;
688 static AutoreplaceMap _vehicles_to_autoreplace;
689 
InitializeVehicles()690 void InitializeVehicles()
691 {
692 	_vehicles_to_autoreplace.clear();
693 	_vehicles_to_autoreplace.shrink_to_fit();
694 	ResetVehicleHash();
695 }
696 
CountVehiclesInChain(const Vehicle * v)697 uint CountVehiclesInChain(const Vehicle *v)
698 {
699 	uint count = 0;
700 	do count++; while ((v = v->Next()) != nullptr);
701 	return count;
702 }
703 
704 /**
705  * Check if a vehicle is counted in num_engines in each company struct
706  * @return true if the vehicle is counted in num_engines
707  */
IsEngineCountable() const708 bool Vehicle::IsEngineCountable() const
709 {
710 	switch (this->type) {
711 		case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
712 		case VEH_TRAIN:
713 			return !this->IsArticulatedPart() && // tenders and other articulated parts
714 					!Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
715 		case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
716 		case VEH_SHIP: return true;
717 		default: return false; // Only count company buildable vehicles
718 	}
719 }
720 
721 /**
722  * Check whether Vehicle::engine_type has any meaning.
723  * @return true if the vehicle has a usable engine type.
724  */
HasEngineType() const725 bool Vehicle::HasEngineType() const
726 {
727 	switch (this->type) {
728 		case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft();
729 		case VEH_TRAIN:
730 		case VEH_ROAD:
731 		case VEH_SHIP: return true;
732 		default: return false;
733 	}
734 }
735 
736 /**
737  * Retrieves the engine of the vehicle.
738  * @return Engine of the vehicle.
739  * @pre HasEngineType() == true
740  */
GetEngine() const741 const Engine *Vehicle::GetEngine() const
742 {
743 	return Engine::Get(this->engine_type);
744 }
745 
746 /**
747  * Retrieve the NewGRF the vehicle is tied to.
748  * This is the GRF providing the Action 3 for the engine type.
749  * @return NewGRF associated to the vehicle.
750  */
GetGRF() const751 const GRFFile *Vehicle::GetGRF() const
752 {
753 	return this->GetEngine()->GetGRF();
754 }
755 
756 /**
757  * Retrieve the GRF ID of the NewGRF the vehicle is tied to.
758  * This is the GRF providing the Action 3 for the engine type.
759  * @return GRF ID of the associated NewGRF.
760  */
GetGRFID() const761 uint32 Vehicle::GetGRFID() const
762 {
763 	return this->GetEngine()->GetGRFID();
764 }
765 
766 /**
767  * Handle the pathfinding result, especially the lost status.
768  * If the vehicle is now lost and wasn't previously fire an
769  * event to the AIs and a news message to the user. If the
770  * vehicle is not lost anymore remove the news message.
771  * @param path_found Whether the vehicle has a path to its destination.
772  */
HandlePathfindingResult(bool path_found)773 void Vehicle::HandlePathfindingResult(bool path_found)
774 {
775 	if (path_found) {
776 		/* Route found, is the vehicle marked with "lost" flag? */
777 		if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
778 
779 		/* Clear the flag as the PF's problem was solved. */
780 		ClrBit(this->vehicle_flags, VF_PATHFINDER_LOST);
781 		SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
782 		InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type));
783 		/* Delete the news item. */
784 		DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
785 		return;
786 	}
787 
788 	/* Were we already lost? */
789 	if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
790 
791 	/* It is first time the problem occurred, set the "lost" flag. */
792 	SetBit(this->vehicle_flags, VF_PATHFINDER_LOST);
793 	SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
794 	InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type));
795 	/* Notify user about the event. */
796 	AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
797 	if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
798 		SetDParam(0, this->index);
799 		AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_LOST, this->index);
800 	}
801 }
802 
803 /** Destroy all stuff that (still) needs the virtual functions to work properly */
PreDestructor()804 void Vehicle::PreDestructor()
805 {
806 	if (CleaningPool()) return;
807 
808 	if (Station::IsValidID(this->last_station_visited)) {
809 		Station *st = Station::Get(this->last_station_visited);
810 		st->loading_vehicles.remove(this);
811 
812 		HideFillingPercent(&this->fill_percent_te_id);
813 		this->CancelReservation(INVALID_STATION, st);
814 		delete this->cargo_payment;
815 		assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
816 	}
817 
818 	if (this->IsEngineCountable()) {
819 		GroupStatistics::CountEngine(this, -1);
820 		if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
821 		GroupStatistics::UpdateAutoreplace(this->owner);
822 
823 		if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
824 		DeleteGroupHighlightOfVehicle(this);
825 	}
826 
827 	if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
828 		Aircraft *a = Aircraft::From(this);
829 		Station *st = GetTargetAirportIfValid(a);
830 		if (st != nullptr) {
831 			const AirportFTA *layout = st->airport.GetFTA()->layout;
832 			CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
833 		}
834 	}
835 
836 
837 	if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
838 		RoadVehicle *v = RoadVehicle::From(this);
839 		if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
840 			/* Leave the drive through roadstop, when you have not already left it. */
841 			RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
842 		}
843 	}
844 
845 	if (this->Previous() == nullptr) {
846 		InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
847 	}
848 
849 	if (this->IsPrimaryVehicle()) {
850 		CloseWindowById(WC_VEHICLE_VIEW, this->index);
851 		CloseWindowById(WC_VEHICLE_ORDERS, this->index);
852 		CloseWindowById(WC_VEHICLE_REFIT, this->index);
853 		CloseWindowById(WC_VEHICLE_DETAILS, this->index);
854 		CloseWindowById(WC_VEHICLE_TIMETABLE, this->index);
855 		SetWindowDirty(WC_COMPANY, this->owner);
856 		OrderBackup::ClearVehicle(this);
857 	}
858 	InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
859 
860 	this->cargo.Truncate();
861 	DeleteVehicleOrders(this);
862 	DeleteDepotHighlightOfVehicle(this);
863 
864 	extern void StopGlobalFollowVehicle(const Vehicle *v);
865 	StopGlobalFollowVehicle(this);
866 
867 	ReleaseDisastersTargetingVehicle(this->index);
868 }
869 
~Vehicle()870 Vehicle::~Vehicle()
871 {
872 	if (CleaningPool()) {
873 		this->cargo.OnCleanPool();
874 		return;
875 	}
876 
877 	/* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
878 	 * it may happen that vehicle chain is deleted when visible */
879 	if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty();
880 
881 	Vehicle *v = this->Next();
882 	this->SetNext(nullptr);
883 
884 	delete v;
885 
886 	UpdateVehicleTileHash(this, true);
887 	UpdateVehicleViewportHash(this, INVALID_COORD, 0, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
888 	DeleteVehicleNews(this->index, INVALID_STRING_ID);
889 	DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
890 }
891 
892 /**
893  * Adds a vehicle to the list of vehicles that visited a depot this tick
894  * @param *v vehicle to add
895  */
VehicleEnteredDepotThisTick(Vehicle * v)896 void VehicleEnteredDepotThisTick(Vehicle *v)
897 {
898 	/* Vehicle should stop in the depot if it was in 'stopping' state */
899 	_vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
900 
901 	/* We ALWAYS set the stopped state. Even when the vehicle does not plan on
902 	 * stopping in the depot, so we stop it to ensure that it will not reserve
903 	 * the path out of the depot before we might autoreplace it to a different
904 	 * engine. The new engine would not own the reserved path we store that we
905 	 * stopped the vehicle, so autoreplace can start it again */
906 	v->vehstatus |= VS_STOPPED;
907 }
908 
909 /**
910  * Increases the day counter for all vehicles and calls 1-day and 32-day handlers.
911  * Each tick, it processes vehicles with "index % DAY_TICKS == _date_fract",
912  * so each day, all vehicles are processes in DAY_TICKS steps.
913  */
RunVehicleDayProc()914 static void RunVehicleDayProc()
915 {
916 	if (_game_mode != GM_NORMAL) return;
917 
918 	/* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
919 	for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
920 		Vehicle *v = Vehicle::Get(i);
921 		if (v == nullptr) continue;
922 
923 		/* Call the 32-day callback if needed */
924 		if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
925 			uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
926 			if (callback != CALLBACK_FAILED) {
927 				if (HasBit(callback, 0)) {
928 					TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
929 				}
930 
931 				/* After a vehicle trigger, the graphics and properties of the vehicle could change.
932 				 * Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */
933 				if (callback != 0) v->First()->MarkDirty();
934 
935 				if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
936 			}
937 		}
938 
939 		/* This is called once per day for each vehicle, but not in the first tick of the day */
940 		v->OnNewDay();
941 	}
942 }
943 
CallVehicleTicks()944 void CallVehicleTicks()
945 {
946 	_vehicles_to_autoreplace.clear();
947 
948 	RunVehicleDayProc();
949 
950 	{
951 		PerformanceMeasurer framerate(PFE_GL_ECONOMY);
952 		for (Station *st : Station::Iterate()) LoadUnloadStation(st);
953 	}
954 	PerformanceAccumulator::Reset(PFE_GL_TRAINS);
955 	PerformanceAccumulator::Reset(PFE_GL_ROADVEHS);
956 	PerformanceAccumulator::Reset(PFE_GL_SHIPS);
957 	PerformanceAccumulator::Reset(PFE_GL_AIRCRAFT);
958 
959 	for (Vehicle *v : Vehicle::Iterate()) {
960 		[[maybe_unused]] size_t vehicle_index = v->index;
961 
962 		/* Vehicle could be deleted in this tick */
963 		if (!v->Tick()) {
964 			assert(Vehicle::Get(vehicle_index) == nullptr);
965 			continue;
966 		}
967 
968 		assert(Vehicle::Get(vehicle_index) == v);
969 
970 		switch (v->type) {
971 			default: break;
972 
973 			case VEH_TRAIN:
974 			case VEH_ROAD:
975 			case VEH_AIRCRAFT:
976 			case VEH_SHIP: {
977 				Vehicle *front = v->First();
978 
979 				if (v->vcache.cached_cargo_age_period != 0) {
980 					v->cargo_age_counter = std::min(v->cargo_age_counter, v->vcache.cached_cargo_age_period);
981 					if (--v->cargo_age_counter == 0) {
982 						v->cargo.AgeCargo();
983 						v->cargo_age_counter = v->vcache.cached_cargo_age_period;
984 					}
985 				}
986 
987 				/* Do not play any sound when crashed */
988 				if (front->vehstatus & VS_CRASHED) continue;
989 
990 				/* Do not play any sound when in depot or tunnel */
991 				if (v->vehstatus & VS_HIDDEN) continue;
992 
993 				/* Do not play any sound when stopped */
994 				if ((front->vehstatus & VS_STOPPED) && (front->type != VEH_TRAIN || front->cur_speed == 0)) continue;
995 
996 				/* Check vehicle type specifics */
997 				switch (v->type) {
998 					case VEH_TRAIN:
999 						if (Train::From(v)->IsWagon()) continue;
1000 						break;
1001 
1002 					case VEH_ROAD:
1003 						if (!RoadVehicle::From(v)->IsFrontEngine()) continue;
1004 						break;
1005 
1006 					case VEH_AIRCRAFT:
1007 						if (!Aircraft::From(v)->IsNormalAircraft()) continue;
1008 						break;
1009 
1010 					default:
1011 						break;
1012 				}
1013 
1014 				v->motion_counter += front->cur_speed;
1015 				/* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
1016 				if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
1017 
1018 				/* Play an alternating running sound every 16 ticks */
1019 				if (GB(v->tick_counter, 0, 4) == 0) {
1020 					/* Play running sound when speed > 0 and not braking */
1021 					bool running = (front->cur_speed > 0) && !(front->vehstatus & (VS_STOPPED | VS_TRAIN_SLOWING));
1022 					PlayVehicleSound(v, running ? VSE_RUNNING_16 : VSE_STOPPED_16);
1023 				}
1024 
1025 				break;
1026 			}
1027 		}
1028 	}
1029 
1030 	Backup<CompanyID> cur_company(_current_company, FILE_LINE);
1031 	for (auto &it : _vehicles_to_autoreplace) {
1032 		Vehicle *v = it.first;
1033 		/* Autoreplace needs the current company set as the vehicle owner */
1034 		cur_company.Change(v->owner);
1035 
1036 		/* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
1037 		 * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
1038 		 * they are already leaving the depot again before being replaced. */
1039 		if (it.second) v->vehstatus &= ~VS_STOPPED;
1040 
1041 		/* Store the position of the effect as the vehicle pointer will become invalid later */
1042 		int x = v->x_pos;
1043 		int y = v->y_pos;
1044 		int z = v->z_pos;
1045 
1046 		const Company *c = Company::Get(_current_company);
1047 		SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
1048 		CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
1049 		SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
1050 
1051 		if (!IsLocalCompany()) continue;
1052 
1053 		if (res.Succeeded() && res.GetCost() != 0) {
1054 			ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
1055 			continue;
1056 		}
1057 
1058 		StringID error_message = res.GetErrorMessage();
1059 		if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
1060 
1061 		if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
1062 
1063 		StringID message;
1064 		if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
1065 			message = error_message;
1066 		} else {
1067 			message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
1068 		}
1069 
1070 		SetDParam(0, v->index);
1071 		SetDParam(1, error_message);
1072 		AddVehicleAdviceNewsItem(message, v->index);
1073 	}
1074 
1075 	cur_company.Restore();
1076 }
1077 
1078 /**
1079  * Add vehicle sprite for drawing to the screen.
1080  * @param v Vehicle to draw.
1081  */
DoDrawVehicle(const Vehicle * v)1082 static void DoDrawVehicle(const Vehicle *v)
1083 {
1084 	PaletteID pal = PAL_NONE;
1085 
1086 	if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
1087 
1088 	/* Check whether the vehicle shall be transparent due to the game state */
1089 	bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
1090 
1091 	if (v->type == VEH_EFFECT) {
1092 		/* Check whether the vehicle shall be transparent/invisible due to GUI settings.
1093 		 * However, transparent smoke and bubbles look weird, so always hide them. */
1094 		TransparencyOption to = EffectVehicle::From(v)->GetTransparencyOption();
1095 		if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
1096 	}
1097 
1098 	StartSpriteCombine();
1099 	for (uint i = 0; i < v->sprite_cache.sprite_seq.count; ++i) {
1100 		PaletteID pal2 = v->sprite_cache.sprite_seq.seq[i].pal;
1101 		if (!pal2 || (v->vehstatus & VS_CRASHED)) pal2 = pal;
1102 		AddSortableSpriteToDraw(v->sprite_cache.sprite_seq.seq[i].sprite, pal2, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
1103 			v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
1104 	}
1105 	EndSpriteCombine();
1106 }
1107 
1108 /**
1109  * Add the vehicle sprites that should be drawn at a part of the screen.
1110  * @param dpi Rectangle being drawn.
1111  */
ViewportAddVehicles(DrawPixelInfo * dpi)1112 void ViewportAddVehicles(DrawPixelInfo *dpi)
1113 {
1114 	/* The bounding rectangle */
1115 	const int l = dpi->left;
1116 	const int r = dpi->left + dpi->width;
1117 	const int t = dpi->top;
1118 	const int b = dpi->top + dpi->height;
1119 
1120 	/* Border size of MAX_VEHICLE_PIXEL_xy */
1121 	const int xb = MAX_VEHICLE_PIXEL_X * ZOOM_LVL_BASE;
1122 	const int yb = MAX_VEHICLE_PIXEL_Y * ZOOM_LVL_BASE;
1123 
1124 	/* The hash area to scan */
1125 	int xl, xu, yl, yu;
1126 
1127 	if (dpi->width + xb < GEN_HASHX_SIZE) {
1128 		xl = GEN_HASHX(l - xb);
1129 		xu = GEN_HASHX(r);
1130 	} else {
1131 		/* scan whole hash row */
1132 		xl = 0;
1133 		xu = GEN_HASHX_MASK;
1134 	}
1135 
1136 	if (dpi->height + yb < GEN_HASHY_SIZE) {
1137 		yl = GEN_HASHY(t - yb);
1138 		yu = GEN_HASHY(b);
1139 	} else {
1140 		/* scan whole column */
1141 		yl = 0;
1142 		yu = GEN_HASHY_MASK;
1143 	}
1144 
1145 	for (int y = yl;; y = (y + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1146 		for (int x = xl;; x = (x + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1147 			const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
1148 
1149 			while (v != nullptr) {
1150 
1151 				if (!(v->vehstatus & VS_HIDDEN) &&
1152 					l <= v->coord.right + xb &&
1153 					t <= v->coord.bottom + yb &&
1154 					r >= v->coord.left - xb &&
1155 					b >= v->coord.top - yb)
1156 				{
1157 					/*
1158 					 * This vehicle can potentially be drawn as part of this viewport and
1159 					 * needs to be revalidated, as the sprite may not be correct.
1160 					 */
1161 					if (v->sprite_cache.revalidate_before_draw) {
1162 						VehicleSpriteSeq seq;
1163 						v->GetImage(v->direction, EIT_ON_MAP, &seq);
1164 
1165 						if (seq.IsValid() && v->sprite_cache.sprite_seq != seq) {
1166 							v->sprite_cache.sprite_seq = seq;
1167 							/*
1168 							 * A sprite change may also result in a bounding box change,
1169 							 * so we need to update the bounding box again before we
1170 							 * check to see if the vehicle should be drawn. Note that
1171 							 * we can't interfere with the viewport hash at this point,
1172 							 * so we keep the original hash on the assumption there will
1173 							 * not be a significant change in the top and left coordinates
1174 							 * of the vehicle.
1175 							 */
1176 							v->UpdateBoundingBoxCoordinates(false);
1177 
1178 						}
1179 
1180 						v->sprite_cache.revalidate_before_draw = false;
1181 					}
1182 
1183 					if (l <= v->coord.right &&
1184 						t <= v->coord.bottom &&
1185 						r >= v->coord.left &&
1186 						b >= v->coord.top) DoDrawVehicle(v);
1187 				}
1188 
1189 				v = v->hash_viewport_next;
1190 			}
1191 
1192 			if (x == xu) break;
1193 		}
1194 
1195 		if (y == yu) break;
1196 	}
1197 }
1198 
1199 /**
1200  * Find the vehicle close to the clicked coordinates.
1201  * @param vp Viewport clicked in.
1202  * @param x  X coordinate in the viewport.
1203  * @param y  Y coordinate in the viewport.
1204  * @return Closest vehicle, or \c nullptr if none found.
1205  */
CheckClickOnVehicle(const Viewport * vp,int x,int y)1206 Vehicle *CheckClickOnVehicle(const Viewport *vp, int x, int y)
1207 {
1208 	Vehicle *found = nullptr;
1209 	uint dist, best_dist = UINT_MAX;
1210 
1211 	if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return nullptr;
1212 
1213 	x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
1214 	y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
1215 
1216 	for (Vehicle *v : Vehicle::Iterate()) {
1217 		if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
1218 				x >= v->coord.left && x <= v->coord.right &&
1219 				y >= v->coord.top && y <= v->coord.bottom) {
1220 
1221 			dist = std::max(
1222 				abs(((v->coord.left + v->coord.right) >> 1) - x),
1223 				abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1224 			);
1225 
1226 			if (dist < best_dist) {
1227 				found = v;
1228 				best_dist = dist;
1229 			}
1230 		}
1231 	}
1232 
1233 	return found;
1234 }
1235 
1236 /**
1237  * Decrease the value of a vehicle.
1238  * @param v %Vehicle to devaluate.
1239  */
DecreaseVehicleValue(Vehicle * v)1240 void DecreaseVehicleValue(Vehicle *v)
1241 {
1242 	v->value -= v->value >> 8;
1243 	SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
1244 }
1245 
1246 static const byte _breakdown_chance[64] = {
1247 	  3,   3,   3,   3,   3,   3,   3,   3,
1248 	  4,   4,   5,   5,   6,   6,   7,   7,
1249 	  8,   8,   9,   9,  10,  10,  11,  11,
1250 	 12,  13,  13,  13,  13,  14,  15,  16,
1251 	 17,  19,  21,  25,  28,  31,  34,  37,
1252 	 40,  44,  48,  52,  56,  60,  64,  68,
1253 	 72,  80,  90, 100, 110, 120, 130, 140,
1254 	150, 170, 190, 210, 230, 250, 250, 250,
1255 };
1256 
CheckVehicleBreakdown(Vehicle * v)1257 void CheckVehicleBreakdown(Vehicle *v)
1258 {
1259 	int rel, rel_old;
1260 
1261 	/* decrease reliability */
1262 	if (!_settings_game.order.no_servicing_if_no_breakdowns ||
1263 			_settings_game.difficulty.vehicle_breakdowns != 0) {
1264 		v->reliability = rel = std::max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
1265 		if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
1266 	}
1267 
1268 	if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
1269 			_settings_game.difficulty.vehicle_breakdowns < 1 ||
1270 			v->cur_speed < 5 || _game_mode == GM_MENU) {
1271 		return;
1272 	}
1273 
1274 	uint32 r = Random();
1275 
1276 	/* increase chance of failure */
1277 	int chance = v->breakdown_chance + 1;
1278 	if (Chance16I(1, 25, r)) chance += 25;
1279 	v->breakdown_chance = std::min(255, chance);
1280 
1281 	/* calculate reliability value to use in comparison */
1282 	rel = v->reliability;
1283 	if (v->type == VEH_SHIP) rel += 0x6666;
1284 
1285 	/* reduced breakdowns? */
1286 	if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
1287 
1288 	/* check if to break down */
1289 	if (_breakdown_chance[(uint)std::min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
1290 		v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
1291 		v->breakdown_delay  = GB(r, 24, 7) + 0x80;
1292 		v->breakdown_chance = 0;
1293 	}
1294 }
1295 
1296 /**
1297  * Handle all of the aspects of a vehicle breakdown
1298  * This includes adding smoke and sounds, and ending the breakdown when appropriate.
1299  * @return true iff the vehicle is stopped because of a breakdown
1300  * @note This function always returns false for aircraft, since these never stop for breakdowns
1301  */
HandleBreakdown()1302 bool Vehicle::HandleBreakdown()
1303 {
1304 	/* Possible states for Vehicle::breakdown_ctr
1305 	 * 0  - vehicle is running normally
1306 	 * 1  - vehicle is currently broken down
1307 	 * 2  - vehicle is going to break down now
1308 	 * >2 - vehicle is counting down to the actual breakdown event */
1309 	switch (this->breakdown_ctr) {
1310 		case 0:
1311 			return false;
1312 
1313 		case 2:
1314 			this->breakdown_ctr = 1;
1315 
1316 			if (this->breakdowns_since_last_service != 255) {
1317 				this->breakdowns_since_last_service++;
1318 			}
1319 
1320 			if (this->type == VEH_AIRCRAFT) {
1321 				/* Aircraft just need this flag, the rest is handled elsewhere */
1322 				this->vehstatus |= VS_AIRCRAFT_BROKEN;
1323 			} else {
1324 				this->cur_speed = 0;
1325 
1326 				if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
1327 					bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP;
1328 					SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
1329 						(train_or_ship ? SND_10_BREAKDOWN_TRAIN_SHIP : SND_0F_BREAKDOWN_ROADVEHICLE) :
1330 						(train_or_ship ? SND_3A_BREAKDOWN_TRAIN_SHIP_TOYLAND : SND_35_BREAKDOWN_ROADVEHICLE_TOYLAND), this);
1331 				}
1332 
1333 				if (!(this->vehstatus & VS_HIDDEN) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_NO_BREAKDOWN_SMOKE)) {
1334 					EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
1335 					if (u != nullptr) u->animation_state = this->breakdown_delay * 2;
1336 				}
1337 			}
1338 
1339 			this->MarkDirty(); // Update graphics after speed is zeroed
1340 			SetWindowDirty(WC_VEHICLE_VIEW, this->index);
1341 			SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
1342 
1343 			FALLTHROUGH;
1344 		case 1:
1345 			/* Aircraft breakdowns end only when arriving at the airport */
1346 			if (this->type == VEH_AIRCRAFT) return false;
1347 
1348 			/* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
1349 			if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
1350 				if (--this->breakdown_delay == 0) {
1351 					this->breakdown_ctr = 0;
1352 					this->MarkDirty();
1353 					SetWindowDirty(WC_VEHICLE_VIEW, this->index);
1354 				}
1355 			}
1356 			return true;
1357 
1358 		default:
1359 			if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
1360 			return false;
1361 	}
1362 }
1363 
1364 /**
1365  * Update age of a vehicle.
1366  * @param v Vehicle to update.
1367  */
AgeVehicle(Vehicle * v)1368 void AgeVehicle(Vehicle *v)
1369 {
1370 	if (v->age < MAX_DAY) {
1371 		v->age++;
1372 		if (v->IsPrimaryVehicle() && v->age == VEHICLE_PROFIT_MIN_AGE + 1) GroupStatistics::VehicleReachedProfitAge(v);
1373 	}
1374 
1375 	if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
1376 
1377 	int age = v->age - v->max_age;
1378 	if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
1379 			age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
1380 		v->reliability_spd_dec <<= 1;
1381 	}
1382 
1383 	SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
1384 
1385 	/* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
1386 	if (v->Previous() != nullptr || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
1387 
1388 	const Company *c = Company::Get(v->owner);
1389 	/* Don't warn if a renew is active */
1390 	if (c->settings.engine_renew && v->GetEngine()->company_avail != 0) return;
1391 	/* Don't warn if a replacement is active */
1392 	if (EngineHasReplacementForCompany(c, v->engine_type, v->group_id)) return;
1393 
1394 	StringID str;
1395 	if (age == -DAYS_IN_LEAP_YEAR) {
1396 		str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1397 	} else if (age == 0) {
1398 		str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1399 	} else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
1400 		str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1401 	} else {
1402 		return;
1403 	}
1404 
1405 	SetDParam(0, v->index);
1406 	AddVehicleAdviceNewsItem(str, v->index);
1407 }
1408 
1409 /**
1410  * Calculates how full a vehicle is.
1411  * @param front The front vehicle of the consist to check.
1412  * @param colour The string to show depending on if we are unloading or loading
1413  * @return A percentage of how full the Vehicle is.
1414  *         Percentages are rounded towards 50%, so that 0% and 100% are only returned
1415  *         if the vehicle is completely empty or full.
1416  *         This is useful for both display and conditional orders.
1417  */
CalcPercentVehicleFilled(const Vehicle * front,StringID * colour)1418 uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
1419 {
1420 	int count = 0;
1421 	int max = 0;
1422 	int cars = 0;
1423 	int unloading = 0;
1424 	bool loading = false;
1425 
1426 	bool is_loading = front->current_order.IsType(OT_LOADING);
1427 
1428 	/* The station may be nullptr when the (colour) string does not need to be set. */
1429 	const Station *st = Station::GetIfValid(front->last_station_visited);
1430 	assert(colour == nullptr || (st != nullptr && is_loading));
1431 
1432 	bool order_no_load = is_loading && (front->current_order.GetLoadType() & OLFB_NO_LOAD);
1433 	bool order_full_load = is_loading && (front->current_order.GetLoadType() & OLFB_FULL_LOAD);
1434 
1435 	/* Count up max and used */
1436 	for (const Vehicle *v = front; v != nullptr; v = v->Next()) {
1437 		count += v->cargo.StoredCount();
1438 		max += v->cargo_cap;
1439 		if (v->cargo_cap != 0 && colour != nullptr) {
1440 			unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
1441 			loading |= !order_no_load &&
1442 					(order_full_load || st->goods[v->cargo_type].HasRating()) &&
1443 					!HasBit(v->vehicle_flags, VF_LOADING_FINISHED) && !HasBit(v->vehicle_flags, VF_STOP_LOADING);
1444 			cars++;
1445 		}
1446 	}
1447 
1448 	if (colour != nullptr) {
1449 		if (unloading == 0 && loading) {
1450 			*colour = STR_PERCENT_UP;
1451 		} else if (unloading == 0 && !loading) {
1452 			*colour = STR_PERCENT_NONE;
1453 		} else if (cars == unloading || !loading) {
1454 			*colour = STR_PERCENT_DOWN;
1455 		} else {
1456 			*colour = STR_PERCENT_UP_DOWN;
1457 		}
1458 	}
1459 
1460 	/* Train without capacity */
1461 	if (max == 0) return 100;
1462 
1463 	/* Return the percentage */
1464 	if (count * 2 < max) {
1465 		/* Less than 50%; round up, so that 0% means really empty. */
1466 		return CeilDiv(count * 100, max);
1467 	} else {
1468 		/* More than 50%; round down, so that 100% means really full. */
1469 		return (count * 100) / max;
1470 	}
1471 }
1472 
1473 /**
1474  * Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it, etc.
1475  * @param v Vehicle that entered a depot.
1476  */
VehicleEnterDepot(Vehicle * v)1477 void VehicleEnterDepot(Vehicle *v)
1478 {
1479 	/* Always work with the front of the vehicle */
1480 	assert(v == v->First());
1481 
1482 	switch (v->type) {
1483 		case VEH_TRAIN: {
1484 			Train *t = Train::From(v);
1485 			SetWindowClassesDirty(WC_TRAINS_LIST);
1486 			/* Clear path reservation */
1487 			SetDepotReservation(t->tile, false);
1488 			if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
1489 
1490 			UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
1491 			t->wait_counter = 0;
1492 			t->force_proceed = TFP_NONE;
1493 			ClrBit(t->flags, VRF_TOGGLE_REVERSE);
1494 			t->ConsistChanged(CCF_ARRANGE);
1495 			break;
1496 		}
1497 
1498 		case VEH_ROAD:
1499 			SetWindowClassesDirty(WC_ROADVEH_LIST);
1500 			break;
1501 
1502 		case VEH_SHIP: {
1503 			SetWindowClassesDirty(WC_SHIPS_LIST);
1504 			Ship *ship = Ship::From(v);
1505 			ship->state = TRACK_BIT_DEPOT;
1506 			ship->UpdateCache();
1507 			ship->UpdateViewport(true, true);
1508 			SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
1509 			break;
1510 		}
1511 
1512 		case VEH_AIRCRAFT:
1513 			SetWindowClassesDirty(WC_AIRCRAFT_LIST);
1514 			HandleAircraftEnterHangar(Aircraft::From(v));
1515 			break;
1516 		default: NOT_REACHED();
1517 	}
1518 	SetWindowDirty(WC_VEHICLE_VIEW, v->index);
1519 
1520 	if (v->type != VEH_TRAIN) {
1521 		/* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
1522 		 * We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */
1523 		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
1524 	}
1525 	SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
1526 
1527 	v->vehstatus |= VS_HIDDEN;
1528 	v->cur_speed = 0;
1529 
1530 	VehicleServiceInDepot(v);
1531 
1532 	/* After a vehicle trigger, the graphics and properties of the vehicle could change. */
1533 	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1534 	v->MarkDirty();
1535 
1536 	InvalidateWindowData(WC_VEHICLE_VIEW, v->index);
1537 
1538 	if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1539 		SetWindowDirty(WC_VEHICLE_VIEW, v->index);
1540 
1541 		const Order *real_order = v->GetOrder(v->cur_real_order_index);
1542 
1543 		/* Test whether we are heading for this depot. If not, do nothing.
1544 		 * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
1545 		if ((v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
1546 				real_order != nullptr && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
1547 				(v->type == VEH_AIRCRAFT ? v->current_order.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
1548 			/* We are heading for another depot, keep driving. */
1549 			return;
1550 		}
1551 
1552 		if (v->current_order.IsRefit()) {
1553 			Backup<CompanyID> cur_company(_current_company, v->owner, FILE_LINE);
1554 			CommandCost cost = DoCommand(v->tile, v->index, v->current_order.GetRefitCargo() | 0xFF << 8, DC_EXEC, GetCmdRefitVeh(v));
1555 			cur_company.Restore();
1556 
1557 			if (cost.Failed()) {
1558 				_vehicles_to_autoreplace[v] = false;
1559 				if (v->owner == _local_company) {
1560 					/* Notify the user that we stopped the vehicle */
1561 					SetDParam(0, v->index);
1562 					AddVehicleAdviceNewsItem(STR_NEWS_ORDER_REFIT_FAILED, v->index);
1563 				}
1564 			} else if (cost.GetCost() != 0) {
1565 				v->profit_this_year -= cost.GetCost() << 8;
1566 				if (v->owner == _local_company) {
1567 					ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
1568 				}
1569 			}
1570 		}
1571 
1572 		if (v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
1573 			/* Part of orders */
1574 			v->DeleteUnreachedImplicitOrders();
1575 			UpdateVehicleTimetable(v, true);
1576 			v->IncrementImplicitOrderIndex();
1577 		}
1578 		if (v->current_order.GetDepotActionType() & ODATFB_HALT) {
1579 			/* Vehicles are always stopped on entering depots. Do not restart this one. */
1580 			_vehicles_to_autoreplace[v] = false;
1581 			/* Invalidate last_loading_station. As the link from the station
1582 			 * before the stop to the station after the stop can't be predicted
1583 			 * we shouldn't construct it when the vehicle visits the next stop. */
1584 			v->last_loading_station = INVALID_STATION;
1585 			if (v->owner == _local_company) {
1586 				SetDParam(0, v->index);
1587 				AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index);
1588 			}
1589 			AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
1590 		}
1591 		v->current_order.MakeDummy();
1592 	}
1593 }
1594 
1595 
1596 /**
1597  * Update the position of the vehicle. This will update the hash that tells
1598  *  which vehicles are on a tile.
1599  */
UpdatePosition()1600 void Vehicle::UpdatePosition()
1601 {
1602 	UpdateVehicleTileHash(this, false);
1603 }
1604 
1605 /**
1606  * Update the bounding box co-ordinates of the vehicle
1607  * @param update_cache Update the cached values for previous co-ordinate values
1608 */
UpdateBoundingBoxCoordinates(bool update_cache) const1609 void Vehicle::UpdateBoundingBoxCoordinates(bool update_cache) const
1610 {
1611 	Rect new_coord;
1612 	this->sprite_cache.sprite_seq.GetBounds(&new_coord);
1613 
1614 	Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
1615 	new_coord.left   += pt.x;
1616 	new_coord.top    += pt.y;
1617 	new_coord.right  += pt.x + 2 * ZOOM_LVL_BASE;
1618 	new_coord.bottom += pt.y + 2 * ZOOM_LVL_BASE;
1619 
1620 	if (update_cache) {
1621 		/*
1622 		 * If the old coordinates are invalid, set the cache to the new coordinates for correct
1623 		 * behaviour the next time the coordinate cache is checked.
1624 		 */
1625 		this->sprite_cache.old_coord = this->coord.left == INVALID_COORD ? new_coord : this->coord;
1626 	}
1627 	else {
1628 		/* Extend the bounds of the existing cached bounding box so the next dirty window is correct */
1629 		this->sprite_cache.old_coord.left   = std::min(this->sprite_cache.old_coord.left,   this->coord.left);
1630 		this->sprite_cache.old_coord.top    = std::min(this->sprite_cache.old_coord.top,    this->coord.top);
1631 		this->sprite_cache.old_coord.right  = std::max(this->sprite_cache.old_coord.right,  this->coord.right);
1632 		this->sprite_cache.old_coord.bottom = std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom);
1633 	}
1634 
1635 	this->coord = new_coord;
1636 }
1637 
1638 /**
1639  * Update the vehicle on the viewport, updating the right hash and setting the new coordinates.
1640  * @param dirty Mark the (new and old) coordinates of the vehicle as dirty.
1641  */
UpdateViewport(bool dirty)1642 void Vehicle::UpdateViewport(bool dirty)
1643 {
1644 	/* If the existing cache is invalid we should ignore it, as it will be set to the current coords by UpdateBoundingBoxCoordinates */
1645 	bool ignore_cached_coords = this->sprite_cache.old_coord.left == INVALID_COORD;
1646 
1647 	this->UpdateBoundingBoxCoordinates(true);
1648 
1649 	if (ignore_cached_coords) {
1650 		UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, INVALID_COORD, INVALID_COORD);
1651 	} else {
1652 		UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
1653 	}
1654 
1655 	if (dirty) {
1656 		if (ignore_cached_coords) {
1657 			this->sprite_cache.is_viewport_candidate = this->MarkAllViewportsDirty();
1658 		} else {
1659 			this->sprite_cache.is_viewport_candidate = ::MarkAllViewportsDirty(
1660 				std::min(this->sprite_cache.old_coord.left, this->coord.left),
1661 				std::min(this->sprite_cache.old_coord.top, this->coord.top),
1662 				std::max(this->sprite_cache.old_coord.right, this->coord.right),
1663 				std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom));
1664 		}
1665 	}
1666 }
1667 
1668 /**
1669  * Update the position of the vehicle, and update the viewport.
1670  */
UpdatePositionAndViewport()1671 void Vehicle::UpdatePositionAndViewport()
1672 {
1673 	this->UpdatePosition();
1674 	this->UpdateViewport(true);
1675 }
1676 
1677 /**
1678  * Marks viewports dirty where the vehicle's image is.
1679  * @return true if at least one viewport has a dirty block
1680  */
MarkAllViewportsDirty() const1681 bool Vehicle::MarkAllViewportsDirty() const
1682 {
1683 	return ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
1684 }
1685 
1686 /**
1687  * Get position information of a vehicle when moving one pixel in the direction it is facing
1688  * @param v Vehicle to move
1689  * @return Position information after the move
1690  */
GetNewVehiclePos(const Vehicle * v)1691 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
1692 {
1693 	static const int8 _delta_coord[16] = {
1694 		-1,-1,-1, 0, 1, 1, 1, 0, /* x */
1695 		-1, 0, 1, 1, 1, 0,-1,-1, /* y */
1696 	};
1697 
1698 	int x = v->x_pos + _delta_coord[v->direction];
1699 	int y = v->y_pos + _delta_coord[v->direction + 8];
1700 
1701 	GetNewVehiclePosResult gp;
1702 	gp.x = x;
1703 	gp.y = y;
1704 	gp.old_tile = v->tile;
1705 	gp.new_tile = TileVirtXY(x, y);
1706 	return gp;
1707 }
1708 
1709 static const Direction _new_direction_table[] = {
1710 	DIR_N,  DIR_NW, DIR_W,
1711 	DIR_NE, DIR_SE, DIR_SW,
1712 	DIR_E,  DIR_SE, DIR_S
1713 };
1714 
GetDirectionTowards(const Vehicle * v,int x,int y)1715 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
1716 {
1717 	int i = 0;
1718 
1719 	if (y >= v->y_pos) {
1720 		if (y != v->y_pos) i += 3;
1721 		i += 3;
1722 	}
1723 
1724 	if (x >= v->x_pos) {
1725 		if (x != v->x_pos) i++;
1726 		i++;
1727 	}
1728 
1729 	Direction dir = v->direction;
1730 
1731 	DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
1732 	if (dirdiff == DIRDIFF_SAME) return dir;
1733 	return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
1734 }
1735 
1736 /**
1737  * Call the tile callback function for a vehicle entering a tile
1738  * @param v    Vehicle entering the tile
1739  * @param tile Tile entered
1740  * @param x    X position
1741  * @param y    Y position
1742  * @return Some meta-data over the to be entered tile.
1743  * @see VehicleEnterTileStatus to see what the bits in the return value mean.
1744  */
VehicleEnterTile(Vehicle * v,TileIndex tile,int x,int y)1745 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
1746 {
1747 	return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
1748 }
1749 
1750 /**
1751  * Initializes the structure. Vehicle unit numbers are supposed not to change after
1752  * struct initialization, except after each call to this->NextID() the returned value
1753  * is assigned to a vehicle.
1754  * @param type type of vehicle
1755  * @param owner owner of vehicles
1756  */
FreeUnitIDGenerator(VehicleType type,CompanyID owner)1757 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(nullptr), maxid(0), curid(0)
1758 {
1759 	/* Find maximum */
1760 	for (const Vehicle *v : Vehicle::Iterate()) {
1761 		if (v->type == type && v->owner == owner) {
1762 			this->maxid = std::max<UnitID>(this->maxid, v->unitnumber);
1763 		}
1764 	}
1765 
1766 	if (this->maxid == 0) return;
1767 
1768 	/* Reserving 'maxid + 2' because we need:
1769 	 * - space for the last item (with v->unitnumber == maxid)
1770 	 * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
1771 	this->cache = CallocT<bool>(this->maxid + 2);
1772 
1773 	/* Fill the cache */
1774 	for (const Vehicle *v : Vehicle::Iterate()) {
1775 		if (v->type == type && v->owner == owner) {
1776 			this->cache[v->unitnumber] = true;
1777 		}
1778 	}
1779 }
1780 
1781 /** Returns next free UnitID. Supposes the last returned value was assigned to a vehicle. */
NextID()1782 UnitID FreeUnitIDGenerator::NextID()
1783 {
1784 	if (this->maxid <= this->curid) return ++this->curid;
1785 
1786 	while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
1787 
1788 	return this->curid;
1789 }
1790 
1791 /**
1792  * Get an unused unit number for a vehicle (if allowed).
1793  * @param type Type of vehicle
1794  * @return A unused unit number for the given type of vehicle if it is allowed to build one, else \c UINT16_MAX.
1795  */
GetFreeUnitNumber(VehicleType type)1796 UnitID GetFreeUnitNumber(VehicleType type)
1797 {
1798 	/* Check whether it is allowed to build another vehicle. */
1799 	uint max_veh;
1800 	switch (type) {
1801 		case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
1802 		case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
1803 		case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
1804 		case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
1805 		default: NOT_REACHED();
1806 	}
1807 
1808 	const Company *c = Company::Get(_current_company);
1809 	if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
1810 
1811 	FreeUnitIDGenerator gen(type, _current_company);
1812 
1813 	return gen.NextID();
1814 }
1815 
1816 
1817 /**
1818  * Check whether we can build infrastructure for the given
1819  * vehicle type. This to disable building stations etc. when
1820  * you are not allowed/able to have the vehicle type yet.
1821  * @param type the vehicle type to check this for
1822  * @return true if there is any reason why you may build
1823  *         the infrastructure for the given vehicle type
1824  */
CanBuildVehicleInfrastructure(VehicleType type,byte subtype)1825 bool CanBuildVehicleInfrastructure(VehicleType type, byte subtype)
1826 {
1827 	assert(IsCompanyBuildableVehicleType(type));
1828 
1829 	if (!Company::IsValidID(_local_company)) return false;
1830 
1831 	UnitID max;
1832 	switch (type) {
1833 		case VEH_TRAIN:
1834 			if (!HasAnyRailtypesAvail(_local_company)) return false;
1835 			max = _settings_game.vehicle.max_trains;
1836 			break;
1837 		case VEH_ROAD:
1838 			if (!HasAnyRoadTypesAvail(_local_company, (RoadTramType)subtype)) return false;
1839 			max = _settings_game.vehicle.max_roadveh;
1840 			break;
1841 		case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
1842 		case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
1843 		default: NOT_REACHED();
1844 	}
1845 
1846 	/* We can build vehicle infrastructure when we may build the vehicle type */
1847 	if (max > 0) {
1848 		/* Can we actually build the vehicle type? */
1849 		for (const Engine *e : Engine::IterateType(type)) {
1850 			if (type == VEH_ROAD && GetRoadTramType(e->u.road.roadtype) != (RoadTramType)subtype) continue;
1851 			if (HasBit(e->company_avail, _local_company)) return true;
1852 		}
1853 		return false;
1854 	}
1855 
1856 	/* We should be able to build infrastructure when we have the actual vehicle type */
1857 	for (const Vehicle *v : Vehicle::Iterate()) {
1858 		if (v->type == VEH_ROAD && GetRoadTramType(RoadVehicle::From(v)->roadtype) != (RoadTramType)subtype) continue;
1859 		if (v->owner == _local_company && v->type == type) return true;
1860 	}
1861 
1862 	return false;
1863 }
1864 
1865 
1866 /**
1867  * Determines the #LiveryScheme for a vehicle.
1868  * @param engine_type Engine of the vehicle.
1869  * @param parent_engine_type Engine of the front vehicle, #INVALID_ENGINE if vehicle is at front itself.
1870  * @param v the vehicle, \c nullptr if in purchase list etc.
1871  * @return livery scheme to use.
1872  */
GetEngineLiveryScheme(EngineID engine_type,EngineID parent_engine_type,const Vehicle * v)1873 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
1874 {
1875 	CargoID cargo_type = v == nullptr ? (CargoID)CT_INVALID : v->cargo_type;
1876 	const Engine *e = Engine::Get(engine_type);
1877 	switch (e->type) {
1878 		default: NOT_REACHED();
1879 		case VEH_TRAIN:
1880 			if (v != nullptr && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
1881 				/* Wagonoverrides use the colour scheme of the front engine.
1882 				 * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
1883 				engine_type = parent_engine_type;
1884 				e = Engine::Get(engine_type);
1885 				/* Note: Luckily cargo_type is not needed for engines */
1886 			}
1887 
1888 			if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1889 			if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1890 			if (e->u.rail.railveh_type == RAILVEH_WAGON) {
1891 				if (!CargoSpec::Get(cargo_type)->is_freight) {
1892 					if (parent_engine_type == INVALID_ENGINE) {
1893 						return LS_PASSENGER_WAGON_STEAM;
1894 					} else {
1895 						bool is_mu = HasBit(EngInfo(parent_engine_type)->misc_flags, EF_RAIL_IS_MU);
1896 						switch (RailVehInfo(parent_engine_type)->engclass) {
1897 							default: NOT_REACHED();
1898 							case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
1899 							case EC_DIESEL:   return is_mu ? LS_DMU : LS_PASSENGER_WAGON_DIESEL;
1900 							case EC_ELECTRIC: return is_mu ? LS_EMU : LS_PASSENGER_WAGON_ELECTRIC;
1901 							case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
1902 							case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
1903 						}
1904 					}
1905 				} else {
1906 					return LS_FREIGHT_WAGON;
1907 				}
1908 			} else {
1909 				bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
1910 
1911 				switch (e->u.rail.engclass) {
1912 					default: NOT_REACHED();
1913 					case EC_STEAM:    return LS_STEAM;
1914 					case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
1915 					case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
1916 					case EC_MONORAIL: return LS_MONORAIL;
1917 					case EC_MAGLEV:   return LS_MAGLEV;
1918 				}
1919 			}
1920 
1921 		case VEH_ROAD:
1922 			/* Always use the livery of the front */
1923 			if (v != nullptr && parent_engine_type != INVALID_ENGINE) {
1924 				engine_type = parent_engine_type;
1925 				e = Engine::Get(engine_type);
1926 				cargo_type = v->First()->cargo_type;
1927 			}
1928 			if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1929 			if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1930 
1931 			/* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
1932 			if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
1933 				/* Tram */
1934 				return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
1935 			} else {
1936 				/* Bus or truck */
1937 				return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
1938 			}
1939 
1940 		case VEH_SHIP:
1941 			if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1942 			if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1943 			return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
1944 
1945 		case VEH_AIRCRAFT:
1946 			switch (e->u.air.subtype) {
1947 				case AIR_HELI: return LS_HELICOPTER;
1948 				case AIR_CTOL: return LS_SMALL_PLANE;
1949 				case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
1950 				default: NOT_REACHED();
1951 			}
1952 	}
1953 }
1954 
1955 /**
1956  * Determines the livery for a vehicle.
1957  * @param engine_type EngineID of the vehicle
1958  * @param company Owner of the vehicle
1959  * @param parent_engine_type EngineID of the front vehicle. INVALID_VEHICLE if vehicle is at front itself.
1960  * @param v the vehicle. nullptr if in purchase list etc.
1961  * @param livery_setting The livery settings to use for acquiring the livery information.
1962  * @return livery to use
1963  */
GetEngineLivery(EngineID engine_type,CompanyID company,EngineID parent_engine_type,const Vehicle * v,byte livery_setting)1964 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
1965 {
1966 	const Company *c = Company::Get(company);
1967 	LiveryScheme scheme = LS_DEFAULT;
1968 
1969 	if (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company)) {
1970 		if (v != nullptr) {
1971 			const Group *g = Group::GetIfValid(v->First()->group_id);
1972 			if (g != nullptr) {
1973 				/* Traverse parents until we find a livery or reach the top */
1974 				while (g->livery.in_use == 0 && g->parent != INVALID_GROUP) {
1975 					g = Group::Get(g->parent);
1976 				}
1977 				if (g->livery.in_use != 0) return &g->livery;
1978 			}
1979 		}
1980 
1981 		/* The default livery is always available for use, but its in_use flag determines
1982 		 * whether any _other_ liveries are in use. */
1983 		if (c->livery[LS_DEFAULT].in_use != 0) {
1984 			/* Determine the livery scheme to use */
1985 			scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
1986 		}
1987 	}
1988 
1989 	return &c->livery[scheme];
1990 }
1991 
1992 
GetEngineColourMap(EngineID engine_type,CompanyID company,EngineID parent_engine_type,const Vehicle * v)1993 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
1994 {
1995 	PaletteID map = (v != nullptr) ? v->colourmap : PAL_NONE;
1996 
1997 	/* Return cached value if any */
1998 	if (map != PAL_NONE) return map;
1999 
2000 	const Engine *e = Engine::Get(engine_type);
2001 
2002 	/* Check if we should use the colour map callback */
2003 	if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
2004 		uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
2005 		/* Failure means "use the default two-colour" */
2006 		if (callback != CALLBACK_FAILED) {
2007 			static_assert(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
2008 			map = GB(callback, 0, 14);
2009 			/* If bit 14 is set, then the company colours are applied to the
2010 			 * map else it's returned as-is. */
2011 			if (!HasBit(callback, 14)) {
2012 				/* Update cache */
2013 				if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2014 				return map;
2015 			}
2016 		}
2017 	}
2018 
2019 	bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
2020 
2021 	if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
2022 
2023 	/* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
2024 	if (!Company::IsValidID(company)) return map;
2025 
2026 	const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
2027 
2028 	map += livery->colour1;
2029 	if (twocc) map += livery->colour2 * 16;
2030 
2031 	/* Update cache */
2032 	if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2033 	return map;
2034 }
2035 
2036 /**
2037  * Get the colour map for an engine. This used for unbuilt engines in the user interface.
2038  * @param engine_type ID of engine
2039  * @param company ID of company
2040  * @return A ready-to-use palette modifier
2041  */
GetEnginePalette(EngineID engine_type,CompanyID company)2042 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
2043 {
2044 	return GetEngineColourMap(engine_type, company, INVALID_ENGINE, nullptr);
2045 }
2046 
2047 /**
2048  * Get the colour map for a vehicle.
2049  * @param v Vehicle to get colour map for
2050  * @return A ready-to-use palette modifier
2051  */
GetVehiclePalette(const Vehicle * v)2052 PaletteID GetVehiclePalette(const Vehicle *v)
2053 {
2054 	if (v->IsGroundVehicle()) {
2055 		return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
2056 	}
2057 
2058 	return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
2059 }
2060 
2061 /**
2062  * Delete all implicit orders which were not reached.
2063  */
DeleteUnreachedImplicitOrders()2064 void Vehicle::DeleteUnreachedImplicitOrders()
2065 {
2066 	if (this->IsGroundVehicle()) {
2067 		uint16 &gv_flags = this->GetGroundVehicleFlags();
2068 		if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
2069 			/* Do not delete orders, only skip them */
2070 			ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
2071 			this->cur_implicit_order_index = this->cur_real_order_index;
2072 			InvalidateVehicleOrder(this, 0);
2073 			return;
2074 		}
2075 	}
2076 
2077 	const Order *order = this->GetOrder(this->cur_implicit_order_index);
2078 	while (order != nullptr) {
2079 		if (this->cur_implicit_order_index == this->cur_real_order_index) break;
2080 
2081 		if (order->IsType(OT_IMPLICIT)) {
2082 			DeleteOrder(this, this->cur_implicit_order_index);
2083 			/* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2084 			order = this->GetOrder(this->cur_implicit_order_index);
2085 		} else {
2086 			/* Skip non-implicit orders, e.g. service-orders */
2087 			order = order->next;
2088 			this->cur_implicit_order_index++;
2089 		}
2090 
2091 		/* Wrap around */
2092 		if (order == nullptr) {
2093 			order = this->GetOrder(0);
2094 			this->cur_implicit_order_index = 0;
2095 		}
2096 	}
2097 }
2098 
2099 /**
2100  * Prepare everything to begin the loading when arriving at a station.
2101  * @pre IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP.
2102  */
BeginLoading()2103 void Vehicle::BeginLoading()
2104 {
2105 	assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
2106 
2107 	uint32 travel_time = this->current_order_time;
2108 	if (this->current_order.IsType(OT_GOTO_STATION) &&
2109 			this->current_order.GetDestination() == this->last_station_visited) {
2110 		this->DeleteUnreachedImplicitOrders();
2111 
2112 		/* Now both order indices point to the destination station, and we can start loading */
2113 		this->current_order.MakeLoading(true);
2114 		UpdateVehicleTimetable(this, true);
2115 
2116 		/* Furthermore add the Non Stop flag to mark that this station
2117 		 * is the actual destination of the vehicle, which is (for example)
2118 		 * necessary to be known for HandleTrainLoading to determine
2119 		 * whether the train is lost or not; not marking a train lost
2120 		 * that arrives at random stations is bad. */
2121 		this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
2122 
2123 	} else {
2124 		/* We weren't scheduled to stop here. Insert an implicit order
2125 		 * to show that we are stopping here.
2126 		 * While only groundvehicles have implicit orders, e.g. aircraft might still enter
2127 		 * the 'wrong' terminal when skipping orders etc. */
2128 		Order *in_list = this->GetOrder(this->cur_implicit_order_index);
2129 		if (this->IsGroundVehicle() &&
2130 				(in_list == nullptr || !in_list->IsType(OT_IMPLICIT) ||
2131 				in_list->GetDestination() != this->last_station_visited)) {
2132 			bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
2133 			/* Do not create consecutive duplicates of implicit orders */
2134 			Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : nullptr);
2135 			if (prev_order == nullptr ||
2136 					(!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
2137 					prev_order->GetDestination() != this->last_station_visited) {
2138 
2139 				/* Prefer deleting implicit orders instead of inserting new ones,
2140 				 * so test whether the right order follows later. In case of only
2141 				 * implicit orders treat the last order in the list like an
2142 				 * explicit one, except if the overall number of orders surpasses
2143 				 * IMPLICIT_ORDER_ONLY_CAP. */
2144 				int target_index = this->cur_implicit_order_index;
2145 				bool found = false;
2146 				while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) {
2147 					const Order *order = this->GetOrder(target_index);
2148 					if (order == nullptr) break; // No orders.
2149 					if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
2150 						found = true;
2151 						break;
2152 					}
2153 					target_index++;
2154 					if (target_index >= this->orders.list->GetNumOrders()) {
2155 						if (this->GetNumManualOrders() == 0 &&
2156 								this->GetNumOrders() < IMPLICIT_ORDER_ONLY_CAP) {
2157 							break;
2158 						}
2159 						target_index = 0;
2160 					}
2161 					if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop.
2162 				}
2163 
2164 				if (found) {
2165 					if (suppress_implicit_orders) {
2166 						/* Skip to the found order */
2167 						this->cur_implicit_order_index = target_index;
2168 						InvalidateVehicleOrder(this, 0);
2169 					} else {
2170 						/* Delete all implicit orders up to the station we just reached */
2171 						const Order *order = this->GetOrder(this->cur_implicit_order_index);
2172 						while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
2173 							if (order->IsType(OT_IMPLICIT)) {
2174 								DeleteOrder(this, this->cur_implicit_order_index);
2175 								/* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2176 								order = this->GetOrder(this->cur_implicit_order_index);
2177 							} else {
2178 								/* Skip non-implicit orders, e.g. service-orders */
2179 								order = order->next;
2180 								this->cur_implicit_order_index++;
2181 							}
2182 
2183 							/* Wrap around */
2184 							if (order == nullptr) {
2185 								order = this->GetOrder(0);
2186 								this->cur_implicit_order_index = 0;
2187 							}
2188 							assert(order != nullptr);
2189 						}
2190 					}
2191 				} else if (!suppress_implicit_orders &&
2192 						((this->orders.list == nullptr ? OrderList::CanAllocateItem() : this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID)) &&
2193 						Order::CanAllocateItem()) {
2194 					/* Insert new implicit order */
2195 					Order *implicit_order = new Order();
2196 					implicit_order->MakeImplicit(this->last_station_visited);
2197 					InsertOrder(this, implicit_order, this->cur_implicit_order_index);
2198 					if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
2199 
2200 					/* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
2201 					 * Reenable it for this vehicle */
2202 					uint16 &gv_flags = this->GetGroundVehicleFlags();
2203 					ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
2204 				}
2205 			}
2206 		}
2207 		this->current_order.MakeLoading(false);
2208 	}
2209 
2210 	if (this->last_loading_station != INVALID_STATION &&
2211 			this->last_loading_station != this->last_station_visited &&
2212 			((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2213 			(this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0)) {
2214 		IncreaseStats(Station::Get(this->last_loading_station), this, this->last_station_visited, travel_time);
2215 	}
2216 
2217 	PrepareUnload(this);
2218 
2219 	SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
2220 	SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
2221 	SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
2222 	SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
2223 
2224 	Station::Get(this->last_station_visited)->MarkTilesDirty(true);
2225 	this->cur_speed = 0;
2226 	this->MarkDirty();
2227 }
2228 
2229 /**
2230  * Return all reserved cargo packets to the station and reset all packets
2231  * staged for transfer.
2232  * @param st the station where the reserved packets should go.
2233  */
CancelReservation(StationID next,Station * st)2234 void Vehicle::CancelReservation(StationID next, Station *st)
2235 {
2236 	for (Vehicle *v = this; v != nullptr; v = v->next) {
2237 		VehicleCargoList &cargo = v->cargo;
2238 		if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
2239 			Debug(misc, 1, "cancelling cargo reservation");
2240 			cargo.Return(UINT_MAX, &st->goods[v->cargo_type].cargo, next);
2241 			cargo.SetTransferLoadPlace(st->xy);
2242 		}
2243 		cargo.KeepAll();
2244 	}
2245 }
2246 
2247 /**
2248  * Perform all actions when leaving a station.
2249  * @pre this->current_order.IsType(OT_LOADING)
2250  */
LeaveStation()2251 void Vehicle::LeaveStation()
2252 {
2253 	assert(this->current_order.IsType(OT_LOADING));
2254 
2255 	delete this->cargo_payment;
2256 	assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
2257 
2258 	/* Only update the timetable if the vehicle was supposed to stop here. */
2259 	if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
2260 
2261 	if ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2262 			(this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
2263 		if (this->current_order.CanLeaveWithCargo(this->last_loading_station != INVALID_STATION)) {
2264 			/* Refresh next hop stats to make sure we've done that at least once
2265 			 * during the stop and that refit_cap == cargo_cap for each vehicle in
2266 			 * the consist. */
2267 			this->ResetRefitCaps();
2268 			LinkRefresher::Run(this);
2269 
2270 			/* if the vehicle could load here or could stop with cargo loaded set the last loading station */
2271 			this->last_loading_station = this->last_station_visited;
2272 		} else {
2273 			/* if the vehicle couldn't load and had to unload or transfer everything
2274 			 * set the last loading station to invalid as it will leave empty. */
2275 			this->last_loading_station = INVALID_STATION;
2276 		}
2277 	}
2278 
2279 	this->current_order.MakeLeaveStation();
2280 	Station *st = Station::Get(this->last_station_visited);
2281 	this->CancelReservation(INVALID_STATION, st);
2282 	st->loading_vehicles.remove(this);
2283 
2284 	HideFillingPercent(&this->fill_percent_te_id);
2285 	trip_occupancy = CalcPercentVehicleFilled(this, nullptr);
2286 
2287 	if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
2288 		/* Trigger station animation (trains only) */
2289 		if (IsTileType(this->tile, MP_STATION)) {
2290 			TriggerStationRandomisation(st, this->tile, SRT_TRAIN_DEPARTS);
2291 			TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
2292 		}
2293 
2294 		SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
2295 	}
2296 
2297 	this->MarkDirty();
2298 }
2299 
2300 /**
2301  * Reset all refit_cap in the consist to cargo_cap.
2302  */
ResetRefitCaps()2303 void Vehicle::ResetRefitCaps()
2304 {
2305 	for (Vehicle *v = this; v != nullptr; v = v->Next()) v->refit_cap = v->cargo_cap;
2306 }
2307 
2308 /**
2309  * Handle the loading of the vehicle; when not it skips through dummy
2310  * orders and does nothing in all other cases.
2311  * @param mode is the non-first call for this vehicle in this tick?
2312  */
HandleLoading(bool mode)2313 void Vehicle::HandleLoading(bool mode)
2314 {
2315 	switch (this->current_order.GetType()) {
2316 		case OT_LOADING: {
2317 			uint wait_time = std::max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2318 
2319 			/* Not the first call for this tick, or still loading */
2320 			if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
2321 
2322 			this->PlayLeaveStationSound();
2323 
2324 			this->LeaveStation();
2325 
2326 			/* Only advance to next order if we just loaded at the current one */
2327 			const Order *order = this->GetOrder(this->cur_implicit_order_index);
2328 			if (order == nullptr ||
2329 					(!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2330 					order->GetDestination() != this->last_station_visited) {
2331 				return;
2332 			}
2333 			break;
2334 		}
2335 
2336 		case OT_DUMMY: break;
2337 
2338 		default: return;
2339 	}
2340 
2341 	this->IncrementImplicitOrderIndex();
2342 }
2343 
2344 /**
2345  * Get a map of cargoes and free capacities in the consist.
2346  * @param capacities Map to be filled with cargoes and capacities.
2347  */
GetConsistFreeCapacities(SmallMap<CargoID,uint> & capacities) const2348 void Vehicle::GetConsistFreeCapacities(SmallMap<CargoID, uint> &capacities) const
2349 {
2350 	for (const Vehicle *v = this; v != nullptr; v = v->Next()) {
2351 		if (v->cargo_cap == 0) continue;
2352 		std::pair<CargoID, uint> *pair = capacities.Find(v->cargo_type);
2353 		if (pair == capacities.End()) {
2354 			capacities.push_back({v->cargo_type, v->cargo_cap - v->cargo.StoredCount()});
2355 		} else {
2356 			pair->second += v->cargo_cap - v->cargo.StoredCount();
2357 		}
2358 	}
2359 }
2360 
GetConsistTotalCapacity() const2361 uint Vehicle::GetConsistTotalCapacity() const
2362 {
2363 	uint result = 0;
2364 	for (const Vehicle *v = this; v != nullptr; v = v->Next()) {
2365 		result += v->cargo_cap;
2366 	}
2367 	return result;
2368 }
2369 
2370 /**
2371  * Send this vehicle to the depot using the given command(s).
2372  * @param flags   the command flags (like execute and such).
2373  * @param command the command to execute.
2374  * @return the cost of the depot action.
2375  */
SendToDepot(DoCommandFlag flags,DepotCommand command)2376 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
2377 {
2378 	CommandCost ret = CheckOwnership(this->owner);
2379 	if (ret.Failed()) return ret;
2380 
2381 	if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
2382 	if (this->IsStoppedInDepot()) return CMD_ERROR;
2383 
2384 	if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2385 		bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
2386 		if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
2387 			/* We called with a different DEPOT_SERVICE setting.
2388 			 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2389 			 * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
2390 			if (flags & DC_EXEC) {
2391 				this->current_order.SetDepotOrderType(ODTF_MANUAL);
2392 				this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
2393 				SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
2394 			}
2395 			return CommandCost();
2396 		}
2397 
2398 		if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancellation of depot orders
2399 		if (flags & DC_EXEC) {
2400 			/* If the orders to 'goto depot' are in the orders list (forced servicing),
2401 			 * then skip to the next order; effectively cancelling this forced service */
2402 			if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex();
2403 
2404 			if (this->IsGroundVehicle()) {
2405 				uint16 &gv_flags = this->GetGroundVehicleFlags();
2406 				SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
2407 			}
2408 
2409 			this->current_order.MakeDummy();
2410 			SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
2411 		}
2412 		return CommandCost();
2413 	}
2414 
2415 	TileIndex location;
2416 	DestinationID destination;
2417 	bool reverse;
2418 	static const StringID no_depot[] = {STR_ERROR_UNABLE_TO_FIND_ROUTE_TO, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR};
2419 	if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
2420 
2421 	if (flags & DC_EXEC) {
2422 		if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2423 
2424 		if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2425 			uint16 &gv_flags = this->GetGroundVehicleFlags();
2426 			SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
2427 		}
2428 
2429 		this->SetDestTile(location);
2430 		this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
2431 		if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
2432 		SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
2433 
2434 		/* If there is no depot in front and the train is not already reversing, reverse automatically (trains only) */
2435 		if (this->type == VEH_TRAIN && (reverse ^ HasBit(Train::From(this)->flags, VRF_REVERSING))) {
2436 			DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
2437 		}
2438 
2439 		if (this->type == VEH_AIRCRAFT) {
2440 			Aircraft *a = Aircraft::From(this);
2441 			if (a->state == FLYING && a->targetairport != destination) {
2442 				/* The aircraft is now heading for a different hangar than the next in the orders */
2443 				extern void AircraftNextAirportPos_and_Order(Aircraft *a);
2444 				AircraftNextAirportPos_and_Order(a);
2445 			}
2446 		}
2447 	}
2448 
2449 	return CommandCost();
2450 
2451 }
2452 
2453 /**
2454  * Update the cached visual effect.
2455  * @param allow_power_change true if the wagon-is-powered-state may change.
2456  */
UpdateVisualEffect(bool allow_power_change)2457 void Vehicle::UpdateVisualEffect(bool allow_power_change)
2458 {
2459 	bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2460 	const Engine *e = this->GetEngine();
2461 
2462 	/* Evaluate properties */
2463 	byte visual_effect;
2464 	switch (e->type) {
2465 		case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
2466 		case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
2467 		case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
2468 		default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
2469 	}
2470 
2471 	/* Check powered wagon / visual effect callback */
2472 	if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
2473 		uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2474 
2475 		if (callback != CALLBACK_FAILED) {
2476 			if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2477 
2478 			callback = GB(callback, 0, 8);
2479 			/* Avoid accidentally setting 'visual_effect' to the default value
2480 			 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2481 			if (callback == VE_DEFAULT) {
2482 				assert(HasBit(callback, VE_DISABLE_EFFECT));
2483 				SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2484 			}
2485 			visual_effect = callback;
2486 		}
2487 	}
2488 
2489 	/* Apply default values */
2490 	if (visual_effect == VE_DEFAULT ||
2491 			(!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2492 		/* Only train engines have default effects.
2493 		 * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2494 		if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
2495 			if (visual_effect == VE_DEFAULT) {
2496 				visual_effect = 1 << VE_DISABLE_EFFECT;
2497 			} else {
2498 				SetBit(visual_effect, VE_DISABLE_EFFECT);
2499 			}
2500 		} else {
2501 			if (visual_effect == VE_DEFAULT) {
2502 				/* Also set the offset */
2503 				visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
2504 			}
2505 			SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
2506 		}
2507 	}
2508 
2509 	this->vcache.cached_vis_effect = visual_effect;
2510 
2511 	if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2512 		ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2513 		ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
2514 	}
2515 }
2516 
2517 static const int8 _vehicle_smoke_pos[8] = {
2518 	1, 1, 1, 0, -1, -1, -1, 0
2519 };
2520 
2521 /**
2522  * Call CBID_VEHICLE_SPAWN_VISUAL_EFFECT and spawn requested effects.
2523  * @param v Vehicle to create effects for.
2524  */
SpawnAdvancedVisualEffect(const Vehicle * v)2525 static void SpawnAdvancedVisualEffect(const Vehicle *v)
2526 {
2527 	uint16 callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v);
2528 	if (callback == CALLBACK_FAILED) return;
2529 
2530 	uint count = GB(callback, 0, 2);
2531 	bool auto_center = HasBit(callback, 13);
2532 	bool auto_rotate = !HasBit(callback, 14);
2533 
2534 	int8 l_center = 0;
2535 	if (auto_center) {
2536 		/* For road vehicles: Compute offset from vehicle position to vehicle center */
2537 		if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2538 	} else {
2539 		/* For trains: Compute offset from vehicle position to sprite position */
2540 		if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2541 	}
2542 
2543 	Direction l_dir = v->direction;
2544 	if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir);
2545 	Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
2546 
2547 	int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2548 	int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2549 
2550 	for (uint i = 0; i < count; i++) {
2551 		uint32 reg = GetRegister(0x100 + i);
2552 		uint type = GB(reg,  0, 8);
2553 		int8 x    = GB(reg,  8, 8);
2554 		int8 y    = GB(reg, 16, 8);
2555 		int8 z    = GB(reg, 24, 8);
2556 
2557 		if (auto_rotate) {
2558 			int8 l = x;
2559 			int8 t = y;
2560 			x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2561 			y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2562 		}
2563 
2564 		if (type >= 0xF0) {
2565 			switch (type) {
2566 				case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2567 				case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2568 				case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2569 				case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2570 				default: break;
2571 			}
2572 		}
2573 	}
2574 }
2575 
2576 /**
2577  * Draw visual effects (smoke and/or sparks) for a vehicle chain.
2578  * @pre this->IsPrimaryVehicle()
2579  */
ShowVisualEffect() const2580 void Vehicle::ShowVisualEffect() const
2581 {
2582 	assert(this->IsPrimaryVehicle());
2583 	bool sound = false;
2584 
2585 	/* Do not show any smoke when:
2586 	 * - vehicle smoke is disabled by the player
2587 	 * - the vehicle is slowing down or stopped (by the player)
2588 	 * - the vehicle is moving very slowly
2589 	 */
2590 	if (_settings_game.vehicle.smoke_amount == 0 ||
2591 			this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
2592 			this->cur_speed < 2) {
2593 		return;
2594 	}
2595 
2596 	/* Use the speed as limited by underground and orders. */
2597 	uint max_speed = this->GetCurrentMaxSpeed();
2598 
2599 	if (this->type == VEH_TRAIN) {
2600 		const Train *t = Train::From(this);
2601 		/* For trains, do not show any smoke when:
2602 		 * - the train is reversing
2603 		 * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2604 		 */
2605 		if (HasBit(t->flags, VRF_REVERSING) ||
2606 				(IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
2607 				t->cur_speed >= max_speed)) {
2608 			return;
2609 		}
2610 	}
2611 
2612 	const Vehicle *v = this;
2613 
2614 	do {
2615 		bool advanced = HasBit(v->vcache.cached_vis_effect, VE_ADVANCED_EFFECT);
2616 		int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
2617 		VisualEffectSpawnModel effect_model = VESM_NONE;
2618 		if (advanced) {
2619 			effect_offset = VE_OFFSET_CENTRE;
2620 			effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, 0, VE_ADVANCED_EFFECT);
2621 			if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
2622 		} else {
2623 			effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
2624 			assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
2625 			static_assert((uint)VESM_STEAM    == (uint)VE_TYPE_STEAM);
2626 			static_assert((uint)VESM_DIESEL   == (uint)VE_TYPE_DIESEL);
2627 			static_assert((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
2628 		}
2629 
2630 		/* Show no smoke when:
2631 		 * - Smoke has been disabled for this vehicle
2632 		 * - The vehicle is not visible
2633 		 * - The vehicle is under a bridge
2634 		 * - The vehicle is on a depot tile
2635 		 * - The vehicle is on a tunnel tile
2636 		 * - The vehicle is a train engine that is currently unpowered */
2637 		if (effect_model == VESM_NONE ||
2638 				v->vehstatus & VS_HIDDEN ||
2639 				IsBridgeAbove(v->tile) ||
2640 				IsDepotTile(v->tile) ||
2641 				IsTunnelTile(v->tile) ||
2642 				(v->type == VEH_TRAIN &&
2643 				!HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
2644 			continue;
2645 		}
2646 
2647 		EffectVehicleType evt = EV_END;
2648 		switch (effect_model) {
2649 			case VESM_STEAM:
2650 				/* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2651 				 * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2652 				 * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2653 				 * REGULATION:
2654 				 * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2655 				if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2656 					evt = EV_STEAM_SMOKE;
2657 				}
2658 				break;
2659 
2660 			case VESM_DIESEL: {
2661 				/* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2662 				 * when smoke emission stops.
2663 				 * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2664 				 * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2665 				 * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2666 				 * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2667 				 * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2668 				 * maximum speed no diesel_smoke is emitted.
2669 				 * REGULATION:
2670 				 * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2671 				 * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2672 				int power_weight_effect = 0;
2673 				if (v->type == VEH_TRAIN) {
2674 					power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2675 				}
2676 				if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2677 						Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2678 					evt = EV_DIESEL_SMOKE;
2679 				}
2680 				break;
2681 			}
2682 
2683 			case VESM_ELECTRIC:
2684 				/* Electric train's spark - more often occurs when train is departing (more load)
2685 				 * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2686 				 * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2687 				 * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2688 				 * REGULATION:
2689 				 * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2690 				if (GB(v->tick_counter, 0, 2) == 0 &&
2691 						Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2692 					evt = EV_ELECTRIC_SPARK;
2693 				}
2694 				break;
2695 
2696 			default:
2697 				NOT_REACHED();
2698 		}
2699 
2700 		if (evt != EV_END && advanced) {
2701 			sound = true;
2702 			SpawnAdvancedVisualEffect(v);
2703 		} else if (evt != EV_END) {
2704 			sound = true;
2705 
2706 			/* The effect offset is relative to a point 4 units behind the vehicle's
2707 			 * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2708 			 * correction factor. */
2709 			if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2710 
2711 			int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2712 			int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2713 
2714 			if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
2715 				x = -x;
2716 				y = -y;
2717 			}
2718 
2719 			CreateEffectVehicleRel(v, x, y, 10, evt);
2720 		}
2721 	} while ((v = v->Next()) != nullptr);
2722 
2723 	if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2724 }
2725 
2726 /**
2727  * Set the next vehicle of this vehicle.
2728  * @param next the next vehicle. nullptr removes the next vehicle.
2729  */
SetNext(Vehicle * next)2730 void Vehicle::SetNext(Vehicle *next)
2731 {
2732 	assert(this != next);
2733 
2734 	if (this->next != nullptr) {
2735 		/* We had an old next vehicle. Update the first and previous pointers */
2736 		for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
2737 			v->first = this->next;
2738 		}
2739 		this->next->previous = nullptr;
2740 	}
2741 
2742 	this->next = next;
2743 
2744 	if (this->next != nullptr) {
2745 		/* A new next vehicle. Update the first and previous pointers */
2746 		if (this->next->previous != nullptr) this->next->previous->next = nullptr;
2747 		this->next->previous = this;
2748 		for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
2749 			v->first = this->first;
2750 		}
2751 	}
2752 }
2753 
2754 /**
2755  * Adds this vehicle to a shared vehicle chain.
2756  * @param shared_chain a vehicle of the chain with shared vehicles.
2757  * @pre !this->IsOrderListShared()
2758  */
AddToShared(Vehicle * shared_chain)2759 void Vehicle::AddToShared(Vehicle *shared_chain)
2760 {
2761 	assert(this->previous_shared == nullptr && this->next_shared == nullptr);
2762 
2763 	if (shared_chain->orders.list == nullptr) {
2764 		assert(shared_chain->previous_shared == nullptr);
2765 		assert(shared_chain->next_shared == nullptr);
2766 		this->orders.list = shared_chain->orders.list = new OrderList(nullptr, shared_chain);
2767 	}
2768 
2769 	this->next_shared     = shared_chain->next_shared;
2770 	this->previous_shared = shared_chain;
2771 
2772 	shared_chain->next_shared = this;
2773 
2774 	if (this->next_shared != nullptr) this->next_shared->previous_shared = this;
2775 
2776 	shared_chain->orders.list->AddVehicle(this);
2777 }
2778 
2779 /**
2780  * Removes the vehicle from the shared order list.
2781  */
RemoveFromShared()2782 void Vehicle::RemoveFromShared()
2783 {
2784 	/* Remember if we were first and the old window number before RemoveVehicle()
2785 	 * as this changes first if needed. */
2786 	bool were_first = (this->FirstShared() == this);
2787 	VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
2788 
2789 	this->orders.list->RemoveVehicle(this);
2790 
2791 	if (!were_first) {
2792 		/* We are not the first shared one, so only relink our previous one. */
2793 		this->previous_shared->next_shared = this->NextShared();
2794 	}
2795 
2796 	if (this->next_shared != nullptr) this->next_shared->previous_shared = this->previous_shared;
2797 
2798 
2799 	if (this->orders.list->GetNumVehicles() == 1) {
2800 		/* When there is only one vehicle, remove the shared order list window. */
2801 		CloseWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
2802 		InvalidateVehicleOrder(this->FirstShared(), VIWD_MODIFY_ORDERS);
2803 	} else if (were_first) {
2804 		/* If we were the first one, update to the new first one.
2805 		 * Note: FirstShared() is already the new first */
2806 		InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
2807 	}
2808 
2809 	this->next_shared     = nullptr;
2810 	this->previous_shared = nullptr;
2811 }
2812 
VehiclesYearlyLoop()2813 void VehiclesYearlyLoop()
2814 {
2815 	for (Vehicle *v : Vehicle::Iterate()) {
2816 		if (v->IsPrimaryVehicle()) {
2817 			/* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
2818 			Money profit = v->GetDisplayProfitThisYear();
2819 			if (v->age >= 730 && profit < 0) {
2820 				if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
2821 					SetDParam(0, v->index);
2822 					SetDParam(1, profit);
2823 					AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_UNPROFITABLE, v->index);
2824 				}
2825 				AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
2826 			}
2827 
2828 			v->profit_last_year = v->profit_this_year;
2829 			v->profit_this_year = 0;
2830 			SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
2831 		}
2832 	}
2833 	GroupStatistics::UpdateProfits();
2834 	SetWindowClassesDirty(WC_TRAINS_LIST);
2835 	SetWindowClassesDirty(WC_SHIPS_LIST);
2836 	SetWindowClassesDirty(WC_ROADVEH_LIST);
2837 	SetWindowClassesDirty(WC_AIRCRAFT_LIST);
2838 }
2839 
2840 
2841 /**
2842  * Can this station be used by the given engine type?
2843  * @param engine_type the type of vehicles to test
2844  * @param st the station to test for
2845  * @return true if and only if the vehicle of the type can use this station.
2846  * @note For road vehicles the Vehicle is needed to determine whether it can
2847  *       use the station. This function will return true for road vehicles
2848  *       when at least one of the facilities is available.
2849  */
CanVehicleUseStation(EngineID engine_type,const Station * st)2850 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
2851 {
2852 	const Engine *e = Engine::GetIfValid(engine_type);
2853 	assert(e != nullptr);
2854 
2855 	switch (e->type) {
2856 		case VEH_TRAIN:
2857 			return (st->facilities & FACIL_TRAIN) != 0;
2858 
2859 		case VEH_ROAD:
2860 			/* For road vehicles we need the vehicle to know whether it can actually
2861 			 * use the station, but if it doesn't have facilities for RVs it is
2862 			 * certainly not possible that the station can be used. */
2863 			return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
2864 
2865 		case VEH_SHIP:
2866 			return (st->facilities & FACIL_DOCK) != 0;
2867 
2868 		case VEH_AIRCRAFT:
2869 			return (st->facilities & FACIL_AIRPORT) != 0 &&
2870 					(st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
2871 
2872 		default:
2873 			return false;
2874 	}
2875 }
2876 
2877 /**
2878  * Can this station be used by the given vehicle?
2879  * @param v the vehicle to test
2880  * @param st the station to test for
2881  * @return true if and only if the vehicle can use this station.
2882  */
CanVehicleUseStation(const Vehicle * v,const Station * st)2883 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
2884 {
2885 	if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != nullptr;
2886 
2887 	return CanVehicleUseStation(v->engine_type, st);
2888 }
2889 
2890 /**
2891  * Access the ground vehicle cache of the vehicle.
2892  * @pre The vehicle is a #GroundVehicle.
2893  * @return #GroundVehicleCache of the vehicle.
2894  */
GetGroundVehicleCache()2895 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
2896 {
2897 	assert(this->IsGroundVehicle());
2898 	if (this->type == VEH_TRAIN) {
2899 		return &Train::From(this)->gcache;
2900 	} else {
2901 		return &RoadVehicle::From(this)->gcache;
2902 	}
2903 }
2904 
2905 /**
2906  * Access the ground vehicle cache of the vehicle.
2907  * @pre The vehicle is a #GroundVehicle.
2908  * @return #GroundVehicleCache of the vehicle.
2909  */
GetGroundVehicleCache() const2910 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
2911 {
2912 	assert(this->IsGroundVehicle());
2913 	if (this->type == VEH_TRAIN) {
2914 		return &Train::From(this)->gcache;
2915 	} else {
2916 		return &RoadVehicle::From(this)->gcache;
2917 	}
2918 }
2919 
2920 /**
2921  * Access the ground vehicle flags of the vehicle.
2922  * @pre The vehicle is a #GroundVehicle.
2923  * @return #GroundVehicleFlags of the vehicle.
2924  */
GetGroundVehicleFlags()2925 uint16 &Vehicle::GetGroundVehicleFlags()
2926 {
2927 	assert(this->IsGroundVehicle());
2928 	if (this->type == VEH_TRAIN) {
2929 		return Train::From(this)->gv_flags;
2930 	} else {
2931 		return RoadVehicle::From(this)->gv_flags;
2932 	}
2933 }
2934 
2935 /**
2936  * Access the ground vehicle flags of the vehicle.
2937  * @pre The vehicle is a #GroundVehicle.
2938  * @return #GroundVehicleFlags of the vehicle.
2939  */
GetGroundVehicleFlags() const2940 const uint16 &Vehicle::GetGroundVehicleFlags() const
2941 {
2942 	assert(this->IsGroundVehicle());
2943 	if (this->type == VEH_TRAIN) {
2944 		return Train::From(this)->gv_flags;
2945 	} else {
2946 		return RoadVehicle::From(this)->gv_flags;
2947 	}
2948 }
2949 
2950 /**
2951  * Calculates the set of vehicles that will be affected by a given selection.
2952  * @param[in,out] set Set of affected vehicles.
2953  * @param v First vehicle of the selection.
2954  * @param num_vehicles Number of vehicles in the selection (not counting articulated parts).
2955  * @pre \a set must be empty.
2956  * @post \a set will contain the vehicles that will be refitted.
2957  */
GetVehicleSet(VehicleSet & set,Vehicle * v,uint8 num_vehicles)2958 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
2959 {
2960 	if (v->type == VEH_TRAIN) {
2961 		Train *u = Train::From(v);
2962 		/* Only include whole vehicles, so start with the first articulated part */
2963 		u = u->GetFirstEnginePart();
2964 
2965 		/* Include num_vehicles vehicles, not counting articulated parts */
2966 		for (; u != nullptr && num_vehicles > 0; num_vehicles--) {
2967 			do {
2968 				/* Include current vehicle in the selection. */
2969 				include(set, u->index);
2970 
2971 				/* If the vehicle is multiheaded, add the other part too. */
2972 				if (u->IsMultiheaded()) include(set, u->other_multiheaded_part->index);
2973 
2974 				u = u->Next();
2975 			} while (u != nullptr && u->IsArticulatedPart());
2976 		}
2977 	}
2978 }
2979