OpenTTD Source 20260107-master-g88a467db19
vehicle.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#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 "vehicle_func.h"
29#include "autoreplace_func.h"
30#include "autoreplace_gui.h"
31#include "station_base.h"
32#include "ai/ai.hpp"
33#include "depot_func.h"
34#include "network/network.h"
35#include "core/pool_func.hpp"
36#include "economy_base.h"
38#include "roadstop_base.h"
39#include "core/random_func.hpp"
40#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#include "autoreplace_cmd.h"
55#include "misc_cmd.h"
56#include "train_cmd.h"
57#include "vehicle_cmd.h"
58#include "newgrf_roadstop.h"
59#include "timer/timer.h"
63
64#include "table/strings.h"
65
66#include "safeguards.h"
67
68/* Number of bits in the hash to use from each vehicle coord */
69static const uint GEN_HASHX_BITS = 6;
70static const uint GEN_HASHY_BITS = 6;
71
72/* Size of each hash bucket */
73static const uint GEN_HASHX_BUCKET_BITS = 7;
74static const uint GEN_HASHY_BUCKET_BITS = 6;
75
76/* Compute hash for vehicle coord */
77static inline uint GetViewportHashX(int x)
78{
79 return GB(x, GEN_HASHX_BUCKET_BITS + ZOOM_BASE_SHIFT, GEN_HASHX_BITS);
80}
81
82static inline uint GetViewportHashY(int y)
83{
84 return GB(y, GEN_HASHY_BUCKET_BITS + ZOOM_BASE_SHIFT, GEN_HASHY_BITS) << GEN_HASHX_BITS;
85}
86
87static inline uint GetViewportHash(int x, int y)
88{
89 return GetViewportHashX(x) + GetViewportHashY(y);
90}
91
92/* Maximum size until hash repeats */
93static const uint GEN_HASHX_SIZE = 1 << (GEN_HASHX_BUCKET_BITS + GEN_HASHX_BITS + ZOOM_BASE_SHIFT);
94static const uint GEN_HASHY_SIZE = 1 << (GEN_HASHY_BUCKET_BITS + GEN_HASHY_BITS + ZOOM_BASE_SHIFT);
95
96/* Increments to reach next bucket in hash table */
97static const uint GEN_HASHX_INC = 1;
98static const uint GEN_HASHY_INC = 1 << GEN_HASHX_BITS;
99
100/* Mask to wrap-around buckets */
101static const uint GEN_HASHX_MASK = (1 << GEN_HASHX_BITS) - 1;
102static const uint GEN_HASHY_MASK = ((1 << GEN_HASHY_BITS) - 1) << GEN_HASHX_BITS;
103
104
108
109
110
114void VehicleSpriteSeq::GetBounds(Rect *bounds) const
115{
116 bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
117 for (uint i = 0; i < this->count; ++i) {
118 const Sprite *spr = GetSprite(this->seq[i].sprite, SpriteType::Normal);
119 if (i == 0) {
120 bounds->left = spr->x_offs;
121 bounds->top = spr->y_offs;
122 bounds->right = spr->width + spr->x_offs - 1;
123 bounds->bottom = spr->height + spr->y_offs - 1;
124 } else {
125 if (spr->x_offs < bounds->left) bounds->left = spr->x_offs;
126 if (spr->y_offs < bounds->top) bounds->top = spr->y_offs;
127 int right = spr->width + spr->x_offs - 1;
128 int bottom = spr->height + spr->y_offs - 1;
129 if (right > bounds->right) bounds->right = right;
130 if (bottom > bounds->bottom) bounds->bottom = bottom;
131 }
132 }
133}
134
142void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const
143{
144 for (uint i = 0; i < this->count; ++i) {
145 PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal;
146 DrawSprite(this->seq[i].sprite, pal, x, y);
147 }
148}
149
156bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
157{
158 /* We can always generate the Company pointer when we have the vehicle.
159 * However this takes time and since the Company pointer is often present
160 * when this function is called then it's faster to pass the pointer as an
161 * argument rather than finding it again. */
162 assert(c == Company::Get(this->owner));
163
164 if (use_renew_setting && !c->settings.engine_renew) return false;
165 if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
166
167 /* Only engines need renewing */
168 if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
169
170 return true;
171}
172
179{
180 assert(v != nullptr);
181 SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
182
183 do {
188 /* Prevent vehicles from breaking down directly after exiting the depot. */
189 v->breakdown_chance /= 4;
190 if (_settings_game.difficulty.vehicle_breakdowns == 1) v->breakdown_chance = 0; // on reduced breakdown
191 v = v->Next();
192 } while (v != nullptr && v->HasEngineType());
193}
194
202{
203 /* Stopped or crashed vehicles will not move, as such making unmovable
204 * vehicles to go for service is lame. */
205 if (this->vehstatus.Any({VehState::Stopped, VehState::Crashed})) return false;
206
207 /* Are we ready for the next service cycle? */
208 const Company *c = Company::Get(this->owner);
209
210 /* Service intervals can be measured in different units, which we handle individually. */
211 if (this->ServiceIntervalIsPercent()) {
212 /* Service interval is in percents. */
213 if (this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) return false;
215 /* Service interval is in minutes. */
216 if (this->date_of_last_service + (this->GetServiceInterval() * EconomyTime::DAYS_IN_ECONOMY_MONTH) >= TimerGameEconomy::date) return false;
217 } else {
218 /* Service interval is in days. */
219 if (this->date_of_last_service + this->GetServiceInterval() >= TimerGameEconomy::date) return false;
220 }
221
222 /* If we're servicing anyway, because we have not disabled servicing when
223 * there are no breakdowns or we are playing with breakdowns, bail out. */
226 return true;
227 }
228
229 /* Test whether there is some pending autoreplace.
230 * Note: We do this after the service-interval test.
231 * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
232 bool pending_replace = false;
233 Money needed_money = c->settings.engine_renew_money;
234 if (needed_money > GetAvailableMoney(c->index)) return false;
235
236 for (const Vehicle *v = this; v != nullptr; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : nullptr) {
237 bool replace_when_old = false;
238 EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
239
240 /* Check engine availability */
241 if (new_engine == EngineID::Invalid() || !Engine::Get(new_engine)->company_avail.Test(v->owner)) continue;
242 /* Is the vehicle old if we are not always replacing? */
243 if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
244
245 /* Check refittability */
246 CargoTypes available_cargo_types, union_mask;
247 GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
248 /* Is there anything to refit? */
249 if (union_mask != 0) {
251 CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type);
252 if (!HasAtMostOneBit(cargo_mask)) {
253 CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(new_engine);
254 if ((cargo_mask & new_engine_default_cargoes) != cargo_mask) {
255 /* We cannot refit to mixed cargoes in an automated way */
256 continue;
257 }
258 /* engine_type is already a mixed cargo type which matches the incoming vehicle by default, no refit required */
259 } else {
260 /* Did the old vehicle carry anything? */
262 /* We can't refit the vehicle to carry the cargo we want */
263 if (!HasBit(available_cargo_types, cargo_type)) continue;
264 }
265 }
266 }
267
268 /* Check money.
269 * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
270 pending_replace = true;
271 needed_money += 2 * Engine::Get(new_engine)->GetCost();
272 if (needed_money > GetAvailableMoney(c->index)) return false;
273 }
274
275 return pending_replace;
276}
277
284{
285 if (this->HasDepotOrder()) return false;
286 if (this->current_order.IsType(OT_LOADING)) return false;
287 if (this->current_order.IsType(OT_GOTO_DEPOT) && !this->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::Service)) return false;
288 return NeedsServicing();
289}
290
292{
293 assert(!this->vehstatus.Test(VehState::Crashed));
294 assert(this->Previous() == nullptr); // IsPrimaryVehicle fails for free-wagon-chains
295
296 uint pass = 0;
297 /* Stop the vehicle. */
299 /* crash all wagons, and count passengers */
300 for (Vehicle *v = this; v != nullptr; v = v->Next()) {
301 /* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */
302 if (IsCargoInClass(v->cargo_type, CargoClass::Passengers)) pass += v->cargo.TotalCount();
303 v->vehstatus.Set(VehState::Crashed);
304 v->MarkAllViewportsDirty();
305 }
306
307 /* Dirty some windows */
312
313 delete this->cargo_payment;
314 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
315
316 return RandomRange(pass + 1); // Randomise deceased passengers.
317}
318
319
328void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBug bug_type, bool critical)
329{
330 const Engine *e = Engine::Get(engine);
331 GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
332
333 /* Missing GRF. Nothing useful can be done in this situation. */
334 if (grfconfig == nullptr) return;
335
336 if (!grfconfig->grf_bugs.Test(bug_type)) {
337 grfconfig->grf_bugs.Set(bug_type);
338 ShowErrorMessage(GetEncodedString(part1, grfconfig->GetName()),
339 GetEncodedString(part2, std::monostate{}, engine), WL_CRITICAL);
341 }
342
343 /* debug output */
344 Debug(grf, 0, "{}", StrMakeValid(GetString(part1, grfconfig->GetName())));
345
346 Debug(grf, 0, "{}", StrMakeValid(GetString(part2, std::monostate{}, engine)));
347}
348
355{
356 /* show a warning once for each engine in whole game and once for each GRF after each game load */
357 const Engine *engine = u->GetEngine();
358 uint32_t grfid = engine->grf_prop.grfid;
359 GRFConfig *grfconfig = GetGRFConfig(grfid);
360 if (_gamelog.GRFBugReverse(grfid, engine->grf_prop.local_id) || !grfconfig->grf_bugs.Test(GRFBug::VehLength)) {
361 ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GRFBug::VehLength, true);
362 }
363}
364
371{
372 this->type = type;
373 this->coord.left = INVALID_COORD;
375 this->group_id = DEFAULT_GROUP;
376 this->fill_percent_te_id = INVALID_TE_ID;
377 this->first = this;
378 this->colourmap = PAL_NONE;
379 this->cargo_age_counter = 1;
380 this->last_station_visited = StationID::Invalid();
381 this->last_loading_station = StationID::Invalid();
382}
383
384/* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
385 * lookup times at the expense of memory usage. */
386constexpr uint TILE_HASH_BITS = 7;
387constexpr uint TILE_HASH_SIZE = 1 << TILE_HASH_BITS;
388constexpr uint TILE_HASH_MASK = TILE_HASH_SIZE - 1;
389constexpr uint TOTAL_TILE_HASH_SIZE = 1 << (TILE_HASH_BITS * 2);
390
391/* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
392 * Profiling results show that 0 is fastest. */
393constexpr uint TILE_HASH_RES = 0;
394
398static inline uint GetTileHash1D(uint p)
399{
400 return GB(p, TILE_HASH_RES, TILE_HASH_BITS);
401}
402
406static inline uint IncTileHash1D(uint h)
407{
408 return (h + 1) & TILE_HASH_MASK;
409}
410
414static inline uint ComposeTileHash(uint hx, uint hy)
415{
416 return hx | hy << TILE_HASH_BITS;
417}
418
422static inline uint GetTileHash(uint x, uint y)
423{
425}
426
427static std::array<Vehicle *, TOTAL_TILE_HASH_SIZE> _vehicle_tile_hash{};
428
433VehiclesNearTileXY::Iterator::Iterator(int32_t x, int32_t y, uint max_dist)
434{
435 /* There are no negative tile coordinates */
436 this->pos_rect.left = std::max<int>(0, x - max_dist);
437 this->pos_rect.right = std::max<int>(0, x + max_dist);
438 this->pos_rect.top = std::max<int>(0, y - max_dist);
439 this->pos_rect.bottom = std::max<int>(0, y + max_dist);
440
441 if (2 * max_dist < TILE_HASH_MASK * TILE_SIZE) {
442 /* Hash area to scan */
443 this->hxmin = this->hx = GetTileHash1D(this->pos_rect.left / TILE_SIZE);
444 this->hxmax = GetTileHash1D(this->pos_rect.right / TILE_SIZE);
445 this->hymin = this->hy = GetTileHash1D(this->pos_rect.top / TILE_SIZE);
446 this->hymax = GetTileHash1D(this->pos_rect.bottom / TILE_SIZE);
447 } else {
448 /* Scan all */
449 this->hxmin = this->hx = 0;
450 this->hxmax = TILE_HASH_MASK;
451 this->hymin = this->hy = 0;
452 this->hymax = TILE_HASH_MASK;
453 }
454
455 this->current_veh = _vehicle_tile_hash[ComposeTileHash(this->hx, this->hy)];
456 this->SkipEmptyBuckets();
457 this->SkipFalseMatches();
458}
459
464{
465 assert(this->current_veh != nullptr);
466 this->current_veh = this->current_veh->hash_tile_next;
467 this->SkipEmptyBuckets();
468}
469
474{
475 while (this->current_veh == nullptr) {
476 if (this->hx != this->hxmax) {
477 this->hx = IncTileHash1D(this->hx);
478 } else if (this->hy != this->hymax) {
479 this->hx = this->hxmin;
480 this->hy = IncTileHash1D(this->hy);
481 } else {
482 return;
483 }
484 this->current_veh = _vehicle_tile_hash[ComposeTileHash(this->hx, this->hy)];
485 }
486}
487
492{
493 while (this->current_veh != nullptr && !this->pos_rect.Contains({this->current_veh->x_pos, this->current_veh->y_pos})) this->Increment();
494}
495
501{
502 this->current = _vehicle_tile_hash[GetTileHash(TileX(tile), TileY(tile))];
503 this->SkipFalseMatches();
504}
505
511{
512 this->current = this->current->hash_tile_next;
513}
514
519{
520 while (this->current != nullptr && this->current->tile != this->tile) this->Increment();
521}
522
529{
530 int z = GetTileMaxPixelZ(tile);
531
532 /* Value v is not safe in MP games, however, it is used to generate a local
533 * error message only (which may be different for different machines).
534 * Such a message does not affect MP synchronisation.
535 */
536 for (const Vehicle *v : VehiclesOnTile(tile)) {
537 if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) continue;
538 if (v->z_pos > z) continue;
539
540 return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
541 }
542 return CommandCost();
543}
544
553{
554 for (TileIndex t : {tile, endtile}) {
555 /* Value v is not safe in MP games, however, it is used to generate a local
556 * error message only (which may be different for different machines).
557 * Such a message does not affect MP synchronisation.
558 */
559 for (const Vehicle *v : VehiclesOnTile(t)) {
560 if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) continue;
561 if (v == ignore) continue;
562 return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
563 }
564 }
565 return CommandCost();
566}
567
577{
578 /* Value v is not safe in MP games, however, it is used to generate a local
579 * error message only (which may be different for different machines).
580 * Such a message does not affect MP synchronisation.
581 */
582 for (const Vehicle *v : VehiclesOnTile(tile)) {
583 if (v->type != VEH_TRAIN) continue;
584
585 const Train *t = Train::From(v);
586 if ((t->track != track_bits) && !TracksOverlap(t->track | track_bits)) continue;
587
588 return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
589 }
590 return CommandCost();
591}
592
593static void UpdateVehicleTileHash(Vehicle *v, bool remove)
594{
595 Vehicle **old_hash = v->hash_tile_current;
596 Vehicle **new_hash;
597
598 if (remove) {
599 new_hash = nullptr;
600 } else {
601 new_hash = &_vehicle_tile_hash[GetTileHash(TileX(v->tile), TileY(v->tile))];
602 }
603
604 if (old_hash == new_hash) return;
605
606 /* Remove from the old position in the hash table */
607 if (old_hash != nullptr) {
610 }
611
612 /* Insert vehicle at beginning of the new position in the hash table */
613 if (new_hash != nullptr) {
614 v->hash_tile_next = *new_hash;
615 if (v->hash_tile_next != nullptr) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next;
616 v->hash_tile_prev = new_hash;
617 *new_hash = v;
618 }
619
620 /* Remember current hash position */
621 v->hash_tile_current = new_hash;
622}
623
624static std::array<Vehicle *, 1 << (GEN_HASHX_BITS + GEN_HASHY_BITS)> _vehicle_viewport_hash{};
625
626static void UpdateVehicleViewportHash(Vehicle *v, int x, int y, int old_x, int old_y)
627{
628 Vehicle **old_hash, **new_hash;
629
630 new_hash = (x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GetViewportHash(x, y)];
631 old_hash = (old_x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GetViewportHash(old_x, old_y)];
632
633 if (old_hash == new_hash) return;
634
635 /* remove from hash table? */
636 if (old_hash != nullptr) {
639 }
640
641 /* insert into hash table? */
642 if (new_hash != nullptr) {
643 v->hash_viewport_next = *new_hash;
645 v->hash_viewport_prev = new_hash;
646 *new_hash = v;
647 }
648}
649
650void ResetVehicleHash()
651{
652 for (Vehicle *v : Vehicle::Iterate()) { v->hash_tile_current = nullptr; }
653 _vehicle_viewport_hash.fill(nullptr);
654 _vehicle_tile_hash.fill(nullptr);
655}
656
657void ResetVehicleColourMap()
658{
659 for (Vehicle *v : Vehicle::Iterate()) { v->colourmap = PAL_NONE; }
660}
661
666using AutoreplaceMap = std::map<VehicleID, bool>;
667static AutoreplaceMap _vehicles_to_autoreplace;
668
669void InitializeVehicles()
670{
671 _vehicles_to_autoreplace.clear();
672 ResetVehicleHash();
673}
674
675uint CountVehiclesInChain(const Vehicle *v)
676{
677 uint count = 0;
678 do count++; while ((v = v->Next()) != nullptr);
679 return count;
680}
681
687{
688 switch (this->type) {
689 case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
690 case VEH_TRAIN:
691 return !this->IsArticulatedPart() && // tenders and other articulated parts
692 !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
693 case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
694 case VEH_SHIP: return true;
695 default: return false; // Only count company buildable vehicles
696 }
697}
698
704{
705 switch (this->type) {
706 case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft();
707 case VEH_TRAIN:
708 case VEH_ROAD:
709 case VEH_SHIP: return true;
710 default: return false;
711 }
712}
713
720{
721 return Engine::Get(this->engine_type);
722}
723
730{
731 return this->GetEngine()->GetGRF();
732}
733
739uint32_t Vehicle::GetGRFID() const
740{
741 return this->GetEngine()->GetGRFID();
742}
743
750{
751 this->date_of_last_service = std::max(this->date_of_last_service + interval, TimerGameEconomy::Date(0));
752 /* date_of_last_service_newgrf is not updated here as it must stay stable
753 * for vehicles outside of a depot. */
754}
755
764{
765 if (path_found) {
766 /* Route found, is the vehicle marked with "lost" flag? */
767 if (!this->vehicle_flags.Test(VehicleFlag::PathfinderLost)) return;
768
769 /* Clear the flag as the PF's problem was solved. */
770 this->vehicle_flags.Reset(VehicleFlag::PathfinderLost);
773 /* Delete the news item. */
775 return;
776 }
777
778 /* Were we already lost? */
779 if (this->vehicle_flags.Test(VehicleFlag::PathfinderLost)) return;
780
781 /* It is first time the problem occurred, set the "lost" flag. */
782 this->vehicle_flags.Set(VehicleFlag::PathfinderLost);
785
786 /* Unbunching data is no longer valid. */
787 this->ResetDepotUnbunching();
788
789 /* Notify user about the event. */
790 AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
792 AddVehicleAdviceNewsItem(AdviceType::VehicleLost, GetEncodedString(STR_NEWS_VEHICLE_IS_LOST, this->index), this->index);
793 }
794}
795
798{
799 if (CleaningPool()) return;
800
801 if (Station::IsValidID(this->last_station_visited)) {
802 Station *st = Station::Get(this->last_station_visited);
803 st->loading_vehicles.remove(this);
804
805 HideFillingPercent(&this->fill_percent_te_id);
806 this->CancelReservation(StationID::Invalid(), st);
807 delete this->cargo_payment;
808 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
809 }
810
811 if (this->IsEngineCountable()) {
813 if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
815
816 if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
818 }
819
820 Company::Get(this->owner)->freeunits[this->type].ReleaseID(this->unitnumber);
821
822 if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
823 Aircraft *a = Aircraft::From(this);
825 if (st != nullptr) {
826 const auto &layout = st->airport.GetFTA()->layout;
827 st->airport.blocks.Reset(layout[a->previous_pos].blocks | layout[a->pos].blocks);
828 }
829 }
830
831
832 if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
834 if (!v->vehstatus.Test(VehState::Crashed) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
835 /* Leave the drive through roadstop, when you have not already left it. */
837 }
838
839 if (v->disaster_vehicle != VehicleID::Invalid()) ReleaseDisasterVehicle(v->disaster_vehicle);
840 }
841
842 if (this->Previous() == nullptr) {
844 }
845
846 if (this->IsPrimaryVehicle()) {
847 CloseWindowById(WC_VEHICLE_VIEW, this->index);
849 CloseWindowById(WC_VEHICLE_REFIT, this->index);
852 SetWindowDirty(WC_COMPANY, this->owner);
854 }
856
857 this->cargo.Truncate();
860
861 StopGlobalFollowVehicle(this);
862}
863
865{
866 if (CleaningPool()) {
867 this->cargo.OnCleanPool();
868 return;
869 }
870
871 /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
872 * it may happen that vehicle chain is deleted when visible */
873 if (!this->vehstatus.Test(VehState::Hidden)) this->MarkAllViewportsDirty();
874
875 Vehicle *v = this->Next();
876 this->SetNext(nullptr);
877
878 delete v;
879
880 UpdateVehicleTileHash(this, true);
881 UpdateVehicleViewportHash(this, INVALID_COORD, 0, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
882 if (this->type != VEH_EFFECT) {
883 DeleteVehicleNews(this->index);
884 DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
885 }
886}
887
893{
894 /* Vehicle should stop in the depot if it was in 'stopping' state */
895 _vehicles_to_autoreplace[v->index] = !v->vehstatus.Test(VehState::Stopped);
896
897 /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
898 * stopping in the depot, so we stop it to ensure that it will not reserve
899 * the path out of the depot before we might autoreplace it to a different
900 * engine. The new engine would not own the reserved path we store that we
901 * stopped the vehicle, so autoreplace can start it again */
903}
904
909{
910 if (_game_mode != GM_NORMAL) return;
911
912 /* Run the calendar day proc for every DAY_TICKS vehicle starting at TimerGameCalendar::date_fract. */
914 Vehicle *v = Vehicle::Get(i);
915 if (v == nullptr) continue;
916 v->OnNewCalendarDay();
917 }
918}
919
926{
927 if (_game_mode != GM_NORMAL) return;
928
929 /* Run the economy day proc for every DAY_TICKS vehicle starting at TimerGameEconomy::date_fract. */
931 Vehicle *v = Vehicle::Get(i);
932 if (v == nullptr) continue;
933
934 /* Call the 32-day callback if needed */
935 if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
936 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
937 if (callback != CALLBACK_FAILED) {
938 if (HasBit(callback, 0)) {
939 TriggerVehicleRandomisation(v, VehicleRandomTrigger::Callback32); // Trigger vehicle trigger 10
940 }
941
942 /* After a vehicle trigger, the graphics and properties of the vehicle could change.
943 * Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */
944 if (callback != 0) v->First()->MarkDirty();
945
946 if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
947 }
948 }
949
950 /* This is called once per day for each vehicle, but not in the first tick of the day */
951 v->OnNewEconomyDay();
952 }
953}
954
955void CallVehicleTicks()
956{
957 _vehicles_to_autoreplace.clear();
958
960
961 {
963 for (Station *st : Station::Iterate()) LoadUnloadStation(st);
964 }
969
970 for (Vehicle *v : Vehicle::Iterate()) {
971 [[maybe_unused]] VehicleID vehicle_index = v->index;
972
973 /* Vehicle could be deleted in this tick */
974 if (!v->Tick()) {
975 assert(Vehicle::Get(vehicle_index) == nullptr);
976 continue;
977 }
978
979 assert(Vehicle::Get(vehicle_index) == v);
980
981 switch (v->type) {
982 default: break;
983
984 case VEH_TRAIN:
985 case VEH_ROAD:
986 case VEH_AIRCRAFT:
987 case VEH_SHIP: {
988 Vehicle *front = v->First();
989
990 if (v->vcache.cached_cargo_age_period != 0) {
992 if (--v->cargo_age_counter == 0) {
993 v->cargo.AgeCargo();
995 }
996 }
997
998 /* Do not play any sound when crashed */
999 if (front->vehstatus.Test(VehState::Crashed)) continue;
1000
1001 /* Do not play any sound when in depot or tunnel */
1002 if (v->vehstatus.Test(VehState::Hidden)) continue;
1003
1004 /* Do not play any sound when stopped */
1005 if (front->vehstatus.Test(VehState::Stopped) && (front->type != VEH_TRAIN || front->cur_speed == 0)) continue;
1006
1007 /* Update motion counter for animation purposes. */
1008 v->motion_counter += front->cur_speed;
1009
1010 /* Check vehicle type specifics */
1011 switch (v->type) {
1012 case VEH_TRAIN:
1013 if (!Train::From(v)->IsEngine()) continue;
1014 break;
1015
1016 case VEH_ROAD:
1017 if (!RoadVehicle::From(v)->IsFrontEngine()) continue;
1018 break;
1019
1020 case VEH_AIRCRAFT:
1021 if (!Aircraft::From(v)->IsNormalAircraft()) continue;
1022 break;
1023
1024 default:
1025 break;
1026 }
1027
1028 /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
1029 if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
1030
1031 /* Play an alternating running sound every 16 ticks */
1032 if (GB(v->tick_counter, 0, 4) == 0) {
1033 /* Play running sound when speed > 0 and not braking */
1034 bool running = (front->cur_speed > 0) && !front->vehstatus.Any({VehState::Stopped, VehState::TrainSlowing});
1036 }
1037
1038 break;
1039 }
1040 }
1041 }
1042
1044 for (auto &it : _vehicles_to_autoreplace) {
1045 Vehicle *v = Vehicle::Get(it.first);
1046 /* Autoreplace needs the current company set as the vehicle owner */
1047 cur_company.Change(v->owner);
1048
1049 /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
1050 * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
1051 * they are already leaving the depot again before being replaced. */
1052 if (it.second) v->vehstatus.Reset(VehState::Stopped);
1053
1054 /* Store the position of the effect as the vehicle pointer will become invalid later */
1055 int x = v->x_pos;
1056 int y = v->y_pos;
1057 int z = v->z_pos;
1058
1063
1064 if (!IsLocalCompany()) continue;
1065
1066 if (res.Succeeded()) {
1067 ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
1068 continue;
1069 }
1070
1071 StringID error_message = res.GetErrorMessage();
1072 if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
1073
1074 if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
1075
1076 EncodedString headline;
1077 if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
1078 headline = GetEncodedString(error_message, v->index);
1079 } else {
1080 headline = GetEncodedString(STR_NEWS_VEHICLE_AUTORENEW_FAILED, v->index, error_message, std::monostate{});
1081 }
1082
1084 }
1085
1086 cur_company.Restore();
1087}
1088
1093static void DoDrawVehicle(const Vehicle *v)
1094{
1095 PaletteID pal = PAL_NONE;
1096
1098
1099 /* Check whether the vehicle shall be transparent due to the game state */
1100 bool shadowed = v->vehstatus.Test(VehState::Shadow);
1101
1102 if (v->type == VEH_EFFECT) {
1103 /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
1104 * However, transparent smoke and bubbles look weird, so always hide them. */
1106 if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
1107 }
1108
1110 for (uint i = 0; i < v->sprite_cache.sprite_seq.count; ++i) {
1111 PaletteID pal2 = v->sprite_cache.sprite_seq.seq[i].pal;
1112 if (!pal2 || v->vehstatus.Test(VehState::Crashed)) pal2 = pal;
1113 AddSortableSpriteToDraw(v->sprite_cache.sprite_seq.seq[i].sprite, pal2, v->x_pos, v->y_pos, v->z_pos, v->bounds, shadowed);
1114 }
1116}
1117
1123{
1124 /* The bounding rectangle */
1125 const int l = dpi->left;
1126 const int r = dpi->left + dpi->width;
1127 const int t = dpi->top;
1128 const int b = dpi->top + dpi->height;
1129
1130 /* Border size of MAX_VEHICLE_PIXEL_xy */
1131 const int xb = MAX_VEHICLE_PIXEL_X * ZOOM_BASE;
1132 const int yb = MAX_VEHICLE_PIXEL_Y * ZOOM_BASE;
1133
1134 /* The hash area to scan */
1135 uint xl, xu, yl, yu;
1136
1137 if (static_cast<uint>(dpi->width + xb) < GEN_HASHX_SIZE) {
1138 xl = GetViewportHashX(l - xb);
1139 xu = GetViewportHashX(r);
1140 } else {
1141 /* scan whole hash row */
1142 xl = 0;
1143 xu = GEN_HASHX_MASK;
1144 }
1145
1146 if (static_cast<uint>(dpi->height + yb) < GEN_HASHY_SIZE) {
1147 yl = GetViewportHashY(t - yb);
1148 yu = GetViewportHashY(b);
1149 } else {
1150 /* scan whole column */
1151 yl = 0;
1152 yu = GEN_HASHY_MASK;
1153 }
1154
1155 for (uint y = yl;; y = (y + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1156 for (uint x = xl;; x = (x + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1157 const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
1158
1159 while (v != nullptr) {
1160
1161 if (!v->vehstatus.Test(VehState::Hidden) &&
1162 l <= v->coord.right + xb &&
1163 t <= v->coord.bottom + yb &&
1164 r >= v->coord.left - xb &&
1165 b >= v->coord.top - yb)
1166 {
1167 /*
1168 * This vehicle can potentially be drawn as part of this viewport and
1169 * needs to be revalidated, as the sprite may not be correct.
1170 */
1172 VehicleSpriteSeq seq;
1173 v->GetImage(v->direction, EIT_ON_MAP, &seq);
1174
1175 if (seq.IsValid() && v->sprite_cache.sprite_seq != seq) {
1176 v->sprite_cache.sprite_seq = seq;
1177 /*
1178 * A sprite change may also result in a bounding box change,
1179 * so we need to update the bounding box again before we
1180 * check to see if the vehicle should be drawn. Note that
1181 * we can't interfere with the viewport hash at this point,
1182 * so we keep the original hash on the assumption there will
1183 * not be a significant change in the top and left coordinates
1184 * of the vehicle.
1185 */
1187
1188 }
1189
1191 }
1192
1193 if (l <= v->coord.right &&
1194 t <= v->coord.bottom &&
1195 r >= v->coord.left &&
1196 b >= v->coord.top) DoDrawVehicle(v);
1197 }
1198
1199 v = v->hash_viewport_next;
1200 }
1201
1202 if (x == xu) break;
1203 }
1204
1205 if (y == yu) break;
1206 }
1207}
1208
1216Vehicle *CheckClickOnVehicle(const Viewport &vp, int x, int y)
1217{
1218 Vehicle *found = nullptr;
1219 uint dist, best_dist = UINT_MAX;
1220
1221 x -= vp.left;
1222 y -= vp.top;
1223 if (!IsInsideMM(x, 0, vp.width) || !IsInsideMM(y, 0, vp.height)) return nullptr;
1224
1225 x = ScaleByZoom(x, vp.zoom) + vp.virtual_left;
1226 y = ScaleByZoom(y, vp.zoom) + vp.virtual_top;
1227
1228 /* Border size of MAX_VEHICLE_PIXEL_xy */
1229 const int xb = MAX_VEHICLE_PIXEL_X * ZOOM_BASE;
1230 const int yb = MAX_VEHICLE_PIXEL_Y * ZOOM_BASE;
1231
1232 /* The hash area to scan */
1233 uint xl = GetViewportHashX(x - xb);
1234 uint xu = GetViewportHashX(x);
1235 uint yl = GetViewportHashY(y - yb);
1236 uint yu = GetViewportHashY(y);
1237
1238 for (uint hy = yl;; hy = (hy + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1239 for (uint hx = xl;; hx = (hx + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1240 Vehicle *v = _vehicle_viewport_hash[hx + hy]; // already masked & 0xFFF
1241
1242 while (v != nullptr) {
1244 x >= v->coord.left && x <= v->coord.right &&
1245 y >= v->coord.top && y <= v->coord.bottom) {
1246
1247 dist = std::max(
1248 abs(((v->coord.left + v->coord.right) >> 1) - x),
1249 abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1250 );
1251
1252 if (dist < best_dist) {
1253 found = v;
1254 best_dist = dist;
1255 }
1256 }
1257 v = v->hash_viewport_next;
1258 }
1259 if (hx == xu) break;
1260 }
1261 if (hy == yu) break;
1262 }
1263
1264 return found;
1265}
1266
1272{
1273 v->value -= v->value >> 8;
1275}
1276
1277static const uint8_t _breakdown_chance[64] = {
1278 3, 3, 3, 3, 3, 3, 3, 3,
1279 4, 4, 5, 5, 6, 6, 7, 7,
1280 8, 8, 9, 9, 10, 10, 11, 11,
1281 12, 13, 13, 13, 13, 14, 15, 16,
1282 17, 19, 21, 25, 28, 31, 34, 37,
1283 40, 44, 48, 52, 56, 60, 64, 68,
1284 72, 80, 90, 100, 110, 120, 130, 140,
1285 150, 170, 190, 210, 230, 250, 250, 250,
1286};
1287
1288void CheckVehicleBreakdown(Vehicle *v)
1289{
1290 int rel, rel_old;
1291
1292 /* decrease reliability */
1295 v->reliability = rel = std::max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
1296 if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
1297 }
1298
1299 if (v->breakdown_ctr != 0 || v->vehstatus.Test(VehState::Stopped) ||
1301 v->cur_speed < 5 || _game_mode == GM_MENU) {
1302 return;
1303 }
1304
1305 uint32_t r = Random();
1306
1307 /* increase chance of failure */
1308 int chance = v->breakdown_chance + 1;
1309 if (Chance16I(1, 25, r)) chance += 25;
1310 v->breakdown_chance = ClampTo<uint8_t>(chance);
1311
1312 /* calculate reliability value to use in comparison */
1313 rel = v->reliability;
1314 if (v->type == VEH_SHIP) rel += 0x6666;
1315
1316 /* reduced breakdowns? */
1317 if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
1318
1319 /* check if to break down */
1320 if (_breakdown_chance[ClampTo<uint16_t>(rel) >> 10] <= v->breakdown_chance) {
1321 v->breakdown_ctr = GB(r, 16, 6) + 0x3F;
1322 v->breakdown_delay = GB(r, 24, 7) + 0x80;
1323 v->breakdown_chance = 0;
1324 }
1325}
1326
1334{
1335 /* Possible states for Vehicle::breakdown_ctr
1336 * 0 - vehicle is running normally
1337 * 1 - vehicle is currently broken down
1338 * 2 - vehicle is going to break down now
1339 * >2 - vehicle is counting down to the actual breakdown event */
1340 switch (this->breakdown_ctr) {
1341 case 0:
1342 return false;
1343
1344 case 2:
1345 this->breakdown_ctr = 1;
1346
1347 if (this->breakdowns_since_last_service != 255) {
1348 this->breakdowns_since_last_service++;
1349 }
1350
1351 if (this->type == VEH_AIRCRAFT) {
1352 /* Aircraft just need this flag, the rest is handled elsewhere */
1353 this->vehstatus.Set(VehState::AircraftBroken);
1354 } else {
1355 this->cur_speed = 0;
1356
1357 if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
1358 bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP;
1359 SndPlayVehicleFx((_settings_game.game_creation.landscape != LandscapeType::Toyland) ?
1362 }
1363
1364 if (!this->vehstatus.Test(VehState::Hidden) && !EngInfo(this->engine_type)->misc_flags.Test(EngineMiscFlag::NoBreakdownSmoke)) {
1366 if (u != nullptr) u->animation_state = this->breakdown_delay * 2;
1367 }
1368 }
1369
1370 this->MarkDirty(); // Update graphics after speed is zeroed
1371 SetWindowDirty(WC_VEHICLE_VIEW, this->index);
1372 SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
1373
1374 [[fallthrough]];
1375 case 1:
1376 /* Aircraft breakdowns end only when arriving at the airport */
1377 if (this->type == VEH_AIRCRAFT) return false;
1378
1379 /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
1380 if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
1381 if (--this->breakdown_delay == 0) {
1382 this->breakdown_ctr = 0;
1383 this->MarkDirty();
1384 SetWindowDirty(WC_VEHICLE_VIEW, this->index);
1385 }
1386 }
1387 return true;
1388
1389 default:
1390 if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
1391 return false;
1392 }
1393}
1394
1406
1412{
1413 if (v->age < CalendarTime::MAX_DATE) v->age++;
1414
1415 if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
1416
1417 auto age = v->age - v->max_age;
1418 for (int32_t i = 0; i <= 4; i++) {
1420 v->reliability_spd_dec <<= 1;
1421 break;
1422 }
1423 }
1424
1426
1427 /* Don't warn if warnings are disabled */
1429
1430 /* Don't warn about vehicles which are non-primary (e.g., part of an articulated vehicle), don't belong to us, are crashed, or are stopped */
1431 if (v->Previous() != nullptr || v->owner != _local_company || v->vehstatus.Any({VehState::Crashed, VehState::Stopped})) return;
1432
1433 const Company *c = Company::Get(v->owner);
1434 /* Don't warn if a renew is active */
1435 if (c->settings.engine_renew && v->GetEngine()->company_avail.Any()) return;
1436 /* Don't warn if a replacement is active */
1438
1439 StringID str;
1441 str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1443 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1445 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1446 } else {
1447 return;
1448 }
1449
1451}
1452
1462uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
1463{
1464 int count = 0;
1465 int max = 0;
1466 int cars = 0;
1467 int unloading = 0;
1468 bool loading = false;
1469
1470 bool is_loading = front->current_order.IsType(OT_LOADING);
1471
1472 /* The station may be nullptr when the (colour) string does not need to be set. */
1474 assert(colour == nullptr || (st != nullptr && is_loading));
1475
1476 bool order_no_load = is_loading && front->current_order.GetLoadType() == OrderLoadType::NoLoad;
1477 bool order_full_load = is_loading && front->current_order.IsFullLoadOrder();
1478
1479 /* Count up max and used */
1480 for (const Vehicle *v = front; v != nullptr; v = v->Next()) {
1481 count += v->cargo.StoredCount();
1482 max += v->cargo_cap;
1483 if (v->cargo_cap != 0 && colour != nullptr) {
1484 unloading += v->vehicle_flags.Test(VehicleFlag::CargoUnloading) ? 1 : 0;
1485 loading |= !order_no_load &&
1486 (order_full_load || st->goods[v->cargo_type].HasRating()) &&
1488 cars++;
1489 }
1490 }
1491
1492 if (colour != nullptr) {
1493 if (unloading == 0 && loading) {
1494 *colour = STR_PERCENT_UP;
1495 } else if (unloading == 0 && !loading) {
1496 *colour = STR_PERCENT_NONE;
1497 } else if (cars == unloading || !loading) {
1498 *colour = STR_PERCENT_DOWN;
1499 } else {
1500 *colour = STR_PERCENT_UP_DOWN;
1501 }
1502 }
1503
1504 /* Train without capacity */
1505 if (max == 0) return 100;
1506
1507 /* Return the percentage */
1508 if (count * 2 < max) {
1509 /* Less than 50%; round up, so that 0% means really empty. */
1510 return CeilDiv(count * 100, max);
1511 } else {
1512 /* More than 50%; round down, so that 100% means really full. */
1513 return (count * 100) / max;
1514 }
1515}
1516
1522{
1523 /* Always work with the front of the vehicle */
1524 assert(v == v->First());
1525
1526 switch (v->type) {
1527 case VEH_TRAIN: {
1528 Train *t = Train::From(v);
1530 /* Clear path reservation */
1531 SetDepotReservation(t->tile, false);
1533
1535 t->wait_counter = 0;
1536 t->force_proceed = TFP_NONE;
1539 break;
1540 }
1541
1542 case VEH_ROAD:
1544 break;
1545
1546 case VEH_SHIP: {
1548 Ship *ship = Ship::From(v);
1549 ship->state = TRACK_BIT_DEPOT;
1550 ship->UpdateCache();
1551 ship->UpdateViewport(true, true);
1553 break;
1554 }
1555
1556 case VEH_AIRCRAFT:
1559 break;
1560 default: NOT_REACHED();
1561 }
1563
1564 if (v->type != VEH_TRAIN) {
1565 /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
1566 * 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 */
1568 }
1570
1572 v->cur_speed = 0;
1573
1575
1576 /* Store that the vehicle entered a depot this tick */
1578
1579 /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
1580 TriggerVehicleRandomisation(v, VehicleRandomTrigger::Depot);
1581 v->MarkDirty();
1582
1584
1585 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1587
1588 const Order *real_order = v->GetOrder(v->cur_real_order_index);
1589
1590 /* Test whether we are heading for this depot. If not, do nothing.
1591 * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
1593 real_order != nullptr && !real_order->GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot) &&
1595 /* We are heading for another depot, keep driving. */
1596 return;
1597 }
1598
1599 if (v->current_order.IsRefit()) {
1600 Backup<CompanyID> cur_company(_current_company, v->owner);
1601 CommandCost cost = std::get<0>(Command<CMD_REFIT_VEHICLE>::Do(DoCommandFlag::Execute, v->index, v->current_order.GetRefitCargo(), 0xFF, false, false, 0));
1602 cur_company.Restore();
1603
1604 if (cost.Failed()) {
1605 _vehicles_to_autoreplace[v->index] = false;
1606 if (v->owner == _local_company) {
1607 /* Notify the user that we stopped the vehicle */
1608 AddVehicleAdviceNewsItem(AdviceType::RefitFailed, GetEncodedString(STR_NEWS_ORDER_REFIT_FAILED, v->index), v->index);
1609 }
1610 } else if (cost.GetCost() != 0) {
1611 v->profit_this_year -= cost.GetCost() << 8;
1612 if (v->owner == _local_company) {
1614 }
1615 }
1616 }
1617
1619 /* Part of orders */
1621 UpdateVehicleTimetable(v, true);
1623 }
1625 /* Vehicles are always stopped on entering depots. Do not restart this one. */
1626 _vehicles_to_autoreplace[v->index] = false;
1627 /* Invalidate last_loading_station. As the link from the station
1628 * before the stop to the station after the stop can't be predicted
1629 * we shouldn't construct it when the vehicle visits the next stop. */
1630 v->last_loading_station = StationID::Invalid();
1631
1632 /* Clear unbunching data. */
1634
1635 /* Announce that the vehicle is waiting to players and AIs. */
1636 if (v->owner == _local_company) {
1637 AddVehicleAdviceNewsItem(AdviceType::VehicleWaiting, GetEncodedString(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index), v->index);
1638 }
1639 AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
1640 }
1641
1642 /* If we've entered our unbunching depot, record the round trip duration. */
1645 if (v->round_trip_time == 0) {
1646 /* This might be our first round trip. */
1647 v->round_trip_time = measured_round_trip;
1648 } else {
1649 /* If we have a previous trip, smooth the effects of outlier trip calculations caused by jams or other interference. */
1650 v->round_trip_time = Clamp(measured_round_trip, (v->round_trip_time / 2), ClampTo<TimerGameTick::Ticks>(v->round_trip_time * 2));
1651 }
1652 }
1653
1655 }
1656}
1657
1658
1664{
1665 UpdateVehicleTileHash(this, false);
1666}
1667
1672void Vehicle::UpdateBoundingBoxCoordinates(bool update_cache) const
1673{
1674 Rect new_coord;
1675 this->sprite_cache.sprite_seq.GetBounds(&new_coord);
1676
1677 /* z-bounds are not used. */
1678 Point pt = RemapCoords(this->x_pos + this->bounds.origin.x + this->bounds.offset.x, this->y_pos + this->bounds.origin.y + this->bounds.offset.y, this->z_pos);
1679 new_coord.left += pt.x;
1680 new_coord.top += pt.y;
1681 new_coord.right += pt.x + 2 * ZOOM_BASE;
1682 new_coord.bottom += pt.y + 2 * ZOOM_BASE;
1683
1684 extern bool _draw_bounding_boxes;
1685 if (_draw_bounding_boxes) {
1686 int x = this->x_pos + this->bounds.origin.x;
1687 int y = this->y_pos + this->bounds.origin.y;
1688 int z = this->z_pos + this->bounds.origin.z;
1689 new_coord.left = std::min(new_coord.left, RemapCoords(x + bounds.extent.x, y, z).x);
1690 new_coord.right = std::max(new_coord.right, RemapCoords(x, y + bounds.extent.y, z).x + 1);
1691 new_coord.top = std::min(new_coord.top, RemapCoords(x, y, z + bounds.extent.z).y);
1692 new_coord.bottom = std::max(new_coord.bottom, RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1);
1693 }
1694
1695 if (update_cache) {
1696 /*
1697 * If the old coordinates are invalid, set the cache to the new coordinates for correct
1698 * behaviour the next time the coordinate cache is checked.
1699 */
1700 this->sprite_cache.old_coord = this->coord.left == INVALID_COORD ? new_coord : this->coord;
1701 }
1702 else {
1703 /* Extend the bounds of the existing cached bounding box so the next dirty window is correct */
1704 this->sprite_cache.old_coord.left = std::min(this->sprite_cache.old_coord.left, this->coord.left);
1705 this->sprite_cache.old_coord.top = std::min(this->sprite_cache.old_coord.top, this->coord.top);
1706 this->sprite_cache.old_coord.right = std::max(this->sprite_cache.old_coord.right, this->coord.right);
1707 this->sprite_cache.old_coord.bottom = std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom);
1708 }
1709
1710 this->coord = new_coord;
1711}
1712
1718{
1719 /* If the existing cache is invalid we should ignore it, as it will be set to the current coords by UpdateBoundingBoxCoordinates */
1720 bool ignore_cached_coords = this->sprite_cache.old_coord.left == INVALID_COORD;
1721
1722 this->UpdateBoundingBoxCoordinates(true);
1723
1724 if (ignore_cached_coords) {
1725 UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, INVALID_COORD, INVALID_COORD);
1726 } else {
1727 UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
1728 }
1729
1730 if (dirty) {
1731 if (ignore_cached_coords) {
1732 this->sprite_cache.is_viewport_candidate = this->MarkAllViewportsDirty();
1733 } else {
1734 this->sprite_cache.is_viewport_candidate = ::MarkAllViewportsDirty(
1735 std::min(this->sprite_cache.old_coord.left, this->coord.left),
1736 std::min(this->sprite_cache.old_coord.top, this->coord.top),
1737 std::max(this->sprite_cache.old_coord.right, this->coord.right),
1738 std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom));
1739 }
1740 }
1741}
1742
1747{
1748 if (this->type != VEH_EFFECT) this->UpdatePosition();
1749 this->UpdateViewport(true);
1750}
1751
1757{
1758 return ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
1759}
1760
1767{
1768 static const int8_t _delta_coord[16] = {
1769 -1,-1,-1, 0, 1, 1, 1, 0, /* x */
1770 -1, 0, 1, 1, 1, 0,-1,-1, /* y */
1771 };
1772
1773 int x = v->x_pos + _delta_coord[v->direction];
1774 int y = v->y_pos + _delta_coord[v->direction + 8];
1775
1777 gp.x = x;
1778 gp.y = y;
1779 gp.old_tile = v->tile;
1780 gp.new_tile = TileVirtXY(x, y);
1781 return gp;
1782}
1783
1784static const Direction _new_direction_table[] = {
1785 DIR_N, DIR_NW, DIR_W,
1788};
1789
1790Direction GetDirectionTowards(const Vehicle *v, int x, int y)
1791{
1792 int i = 0;
1793
1794 if (y >= v->y_pos) {
1795 if (y != v->y_pos) i += 3;
1796 i += 3;
1797 }
1798
1799 if (x >= v->x_pos) {
1800 if (x != v->x_pos) i++;
1801 i++;
1802 }
1803
1804 Direction dir = v->direction;
1805
1806 DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
1807 if (dirdiff == DIRDIFF_SAME) return dir;
1808 return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
1809}
1810
1821{
1822 return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
1823}
1824
1831{
1832 for (auto it = std::begin(this->used_bitmap); it != std::end(this->used_bitmap); ++it) {
1833 BitmapStorage available = ~(*it);
1834 if (available == 0) continue;
1835 return static_cast<UnitID>(std::distance(std::begin(this->used_bitmap), it) * BITMAP_SIZE + FindFirstBit(available) + 1);
1836 }
1837 return static_cast<UnitID>(this->used_bitmap.size() * BITMAP_SIZE + 1);
1838}
1839
1846{
1847 if (index == 0 || index == UINT16_MAX) return index;
1848
1849 index--;
1850
1851 size_t slot = index / BITMAP_SIZE;
1852 if (slot >= this->used_bitmap.size()) this->used_bitmap.resize(slot + 1);
1853 SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
1854
1855 return index + 1;
1856}
1857
1863{
1864 if (index == 0 || index == UINT16_MAX) return;
1865
1866 index--;
1867
1868 assert(index / BITMAP_SIZE < this->used_bitmap.size());
1869 ClrBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
1870}
1871
1878{
1879 /* Check whether it is allowed to build another vehicle. */
1880 uint max_veh;
1881 switch (type) {
1882 case VEH_TRAIN: max_veh = _settings_game.vehicle.max_trains; break;
1883 case VEH_ROAD: max_veh = _settings_game.vehicle.max_roadveh; break;
1884 case VEH_SHIP: max_veh = _settings_game.vehicle.max_ships; break;
1885 case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
1886 default: NOT_REACHED();
1887 }
1888
1890 if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
1891
1892 return c->freeunits[type].NextID();
1893}
1894
1895
1905{
1906 assert(IsCompanyBuildableVehicleType(type));
1907
1908 if (!Company::IsValidID(_local_company)) return false;
1909
1910 UnitID max;
1911 switch (type) {
1912 case VEH_TRAIN:
1913 if (!HasAnyRailTypesAvail(_local_company)) return false;
1915 break;
1916 case VEH_ROAD:
1917 if (!HasAnyRoadTypesAvail(_local_company, (RoadTramType)subtype)) return false;
1919 break;
1920 case VEH_SHIP: max = _settings_game.vehicle.max_ships; break;
1922 default: NOT_REACHED();
1923 }
1924
1925 /* We can build vehicle infrastructure when we may build the vehicle type */
1926 if (max > 0) {
1927 /* Can we actually build the vehicle type? */
1928 for (const Engine *e : Engine::IterateType(type)) {
1929 if (type == VEH_ROAD && GetRoadTramType(e->VehInfo<RoadVehicleInfo>().roadtype) != (RoadTramType)subtype) continue;
1930 if (e->company_avail.Test(_local_company)) return true;
1931 }
1932 return false;
1933 }
1934
1935 /* We should be able to build infrastructure when we have the actual vehicle type */
1936 for (const Vehicle *v : Vehicle::Iterate()) {
1937 if (v->type == VEH_ROAD && GetRoadTramType(RoadVehicle::From(v)->roadtype) != (RoadTramType)subtype) continue;
1938 if (v->owner == _local_company && v->type == type) return true;
1939 }
1940
1941 return false;
1942}
1943
1944
1952LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
1953{
1954 CargoType cargo_type = v == nullptr ? INVALID_CARGO : v->cargo_type;
1955 const Engine *e = Engine::Get(engine_type);
1956 switch (e->type) {
1957 default: NOT_REACHED();
1958 case VEH_TRAIN:
1959 if (v != nullptr && parent_engine_type != EngineID::Invalid() && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->VehInfo<RailVehicleInfo>().railveh_type != RAILVEH_WAGON))) {
1960 /* Wagonoverrides use the colour scheme of the front engine.
1961 * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
1962 engine_type = parent_engine_type;
1963 e = Engine::Get(engine_type);
1964 /* Note: Luckily cargo_type is not needed for engines */
1965 }
1966
1967 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
1968 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
1969 assert(IsValidCargoType(cargo_type));
1970 if (e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) {
1971 if (!CargoSpec::Get(cargo_type)->is_freight) {
1972 if (parent_engine_type == EngineID::Invalid()) {
1973 return LS_PASSENGER_WAGON_STEAM;
1974 } else {
1975 bool is_mu = EngInfo(parent_engine_type)->misc_flags.Test(EngineMiscFlag::RailIsMU);
1976 switch (RailVehInfo(parent_engine_type)->engclass) {
1977 default: NOT_REACHED();
1978 case EC_STEAM: return LS_PASSENGER_WAGON_STEAM;
1979 case EC_DIESEL: return is_mu ? LS_DMU : LS_PASSENGER_WAGON_DIESEL;
1980 case EC_ELECTRIC: return is_mu ? LS_EMU : LS_PASSENGER_WAGON_ELECTRIC;
1981 case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
1982 case EC_MAGLEV: return LS_PASSENGER_WAGON_MAGLEV;
1983 }
1984 }
1985 } else {
1986 return LS_FREIGHT_WAGON;
1987 }
1988 } else {
1989 bool is_mu = e->info.misc_flags.Test(EngineMiscFlag::RailIsMU);
1990
1991 switch (e->VehInfo<RailVehicleInfo>().engclass) {
1992 default: NOT_REACHED();
1993 case EC_STEAM: return LS_STEAM;
1994 case EC_DIESEL: return is_mu ? LS_DMU : LS_DIESEL;
1995 case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
1996 case EC_MONORAIL: return LS_MONORAIL;
1997 case EC_MAGLEV: return LS_MAGLEV;
1998 }
1999 }
2000
2001 case VEH_ROAD:
2002 /* Always use the livery of the front */
2003 if (v != nullptr && parent_engine_type != EngineID::Invalid()) {
2004 engine_type = parent_engine_type;
2005 e = Engine::Get(engine_type);
2006 cargo_type = v->First()->cargo_type;
2007 }
2008 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
2009 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
2010 assert(IsValidCargoType(cargo_type));
2011
2012 /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
2014 /* Tram */
2015 return IsCargoInClass(cargo_type, CargoClass::Passengers) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
2016 } else {
2017 /* Bus or truck */
2018 return IsCargoInClass(cargo_type, CargoClass::Passengers) ? LS_BUS : LS_TRUCK;
2019 }
2020
2021 case VEH_SHIP:
2022 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
2023 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
2024 assert(IsValidCargoType(cargo_type));
2025 return IsCargoInClass(cargo_type, CargoClass::Passengers) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
2026
2027 case VEH_AIRCRAFT:
2028 switch (e->VehInfo<AircraftVehicleInfo>().subtype) {
2029 case AIR_HELI: return LS_HELICOPTER;
2030 case AIR_CTOL: return LS_SMALL_PLANE;
2031 case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
2032 default: NOT_REACHED();
2033 }
2034 }
2035}
2036
2046const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, uint8_t livery_setting)
2047{
2048 const Company *c = Company::Get(company);
2049 LiveryScheme scheme = LS_DEFAULT;
2050
2051 if (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company)) {
2052 if (v != nullptr) {
2053 const Group *g = Group::GetIfValid(v->First()->group_id);
2054 if (g != nullptr) {
2055 /* Traverse parents until we find a livery or reach the top */
2056 while (!g->livery.in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary}) && g->parent != GroupID::Invalid()) {
2057 g = Group::Get(g->parent);
2058 }
2059 if (g->livery.in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) return &g->livery;
2060 }
2061 }
2062
2063 /* The default livery is always available for use, but its in_use flag determines
2064 * whether any _other_ liveries are in use. */
2065 if (c->livery[LS_DEFAULT].in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) {
2066 /* Determine the livery scheme to use */
2067 scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
2068 }
2069 }
2070
2071 return &c->livery[scheme];
2072}
2073
2074
2075static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
2076{
2077 PaletteID map = (v != nullptr) ? v->colourmap : PAL_NONE;
2078
2079 /* Return cached value if any */
2080 if (map != PAL_NONE) return map;
2081
2082 const Engine *e = Engine::Get(engine_type);
2083
2084 /* Check if we should use the colour map callback */
2086 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
2087 /* Failure means "use the default two-colour" */
2088 if (callback != CALLBACK_FAILED) {
2089 static_assert(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
2090 map = GB(callback, 0, 14);
2091 /* If bit 14 is set, then the company colours are applied to the
2092 * map else it's returned as-is. */
2093 if (!HasBit(callback, 14)) {
2094 /* Update cache */
2095 if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2096 return map;
2097 }
2098 }
2099 }
2100
2101 bool twocc = e->info.misc_flags.Test(EngineMiscFlag::Uses2CC);
2102
2103 if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
2104
2105 /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
2106 if (!Company::IsValidID(company)) return map;
2107
2108 const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
2109
2110 map += livery->colour1;
2111 if (twocc) map += livery->colour2 * 16;
2112
2113 /* Update cache */
2114 if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2115 return map;
2116}
2117
2125{
2126 return GetEngineColourMap(engine_type, company, EngineID::Invalid(), nullptr);
2127}
2128
2135{
2136 if (v->IsGroundVehicle()) {
2137 return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
2138 }
2139
2140 return GetEngineColourMap(v->engine_type, v->owner, EngineID::Invalid(), v);
2141}
2142
2147{
2148 if (this->IsGroundVehicle()) {
2149 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2150 if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
2151 /* Do not delete orders, only skip them */
2153 this->cur_implicit_order_index = this->cur_real_order_index;
2154 InvalidateVehicleOrder(this, 0);
2155 return;
2156 }
2157 }
2158
2159 auto orders = this->Orders();
2160 VehicleOrderID cur = this->cur_implicit_order_index;
2161 while (cur != INVALID_VEH_ORDER_ID) {
2162 if (this->cur_implicit_order_index == this->cur_real_order_index) break;
2163
2164 if (orders[cur].IsType(OT_IMPLICIT)) {
2165 DeleteOrder(this, this->cur_implicit_order_index);
2166 /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2167 } else {
2168 /* Skip non-implicit orders, e.g. service-orders */
2169 if (cur < this->orders->GetNext(cur)) {
2170 this->cur_implicit_order_index++;
2171 } else {
2172 /* Wrapped around. */
2173 this->cur_implicit_order_index = 0;
2174 }
2175 cur = this->orders->GetNext(cur);
2176 }
2177 }
2178}
2179
2185{
2186 assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
2187
2188 TimerGameTick::Ticks travel_time = TimerGameTick::counter - this->last_loading_tick;
2189 if (this->current_order.IsType(OT_GOTO_STATION) &&
2190 this->current_order.GetDestination() == this->last_station_visited) {
2191 this->DeleteUnreachedImplicitOrders();
2192
2193 /* Now both order indices point to the destination station, and we can start loading */
2194 this->current_order.MakeLoading(true);
2195 UpdateVehicleTimetable(this, true);
2196
2197 /* Furthermore add the Non Stop flag to mark that this station
2198 * is the actual destination of the vehicle, which is (for example)
2199 * necessary to be known for HandleTrainLoading to determine
2200 * whether the train is lost or not; not marking a train lost
2201 * that arrives at random stations is bad. */
2202 this->current_order.SetNonStopType({OrderNonStopFlag::NoIntermediate, OrderNonStopFlag::NoDestination});
2203
2204 } else {
2205 /* We weren't scheduled to stop here. Insert an implicit order
2206 * to show that we are stopping here.
2207 * While only groundvehicles have implicit orders, e.g. aircraft might still enter
2208 * the 'wrong' terminal when skipping orders etc. */
2209 Order *in_list = this->GetOrder(this->cur_implicit_order_index);
2210 if (this->IsGroundVehicle() &&
2211 (in_list == nullptr || !in_list->IsType(OT_IMPLICIT) ||
2212 in_list->GetDestination() != this->last_station_visited)) {
2213 bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
2214 /* Do not create consecutive duplicates of implicit orders */
2215 const Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : nullptr);
2216 if (prev_order == nullptr ||
2217 (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
2218 prev_order->GetDestination() != this->last_station_visited) {
2219
2220 /* Prefer deleting implicit orders instead of inserting new ones,
2221 * so test whether the right order follows later. In case of only
2222 * implicit orders treat the last order in the list like an
2223 * explicit one, except if the overall number of orders surpasses
2224 * IMPLICIT_ORDER_ONLY_CAP. */
2225 int target_index = this->cur_implicit_order_index;
2226 bool found = false;
2227 while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) {
2228 const Order *order = this->GetOrder(target_index);
2229 if (order == nullptr) break; // No orders.
2230 if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
2231 found = true;
2232 break;
2233 }
2234 target_index++;
2235 if (target_index >= this->orders->GetNumOrders()) {
2236 if (this->GetNumManualOrders() == 0 &&
2237 this->GetNumOrders() < IMPLICIT_ORDER_ONLY_CAP) {
2238 break;
2239 }
2240 target_index = 0;
2241 }
2242 if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop.
2243 }
2244
2245 if (found) {
2246 if (suppress_implicit_orders) {
2247 /* Skip to the found order */
2248 this->cur_implicit_order_index = target_index;
2249 InvalidateVehicleOrder(this, 0);
2250 } else {
2251 /* Delete all implicit orders up to the station we just reached */
2252 const Order *order = this->GetOrder(this->cur_implicit_order_index);
2253 while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
2254 if (order->IsType(OT_IMPLICIT)) {
2255 DeleteOrder(this, this->cur_implicit_order_index);
2256 } else {
2257 /* Skip non-implicit orders, e.g. service-orders */
2258 ++this->cur_implicit_order_index;
2259 }
2260 order = this->GetOrder(this->cur_implicit_order_index);
2261
2262 /* Wrapped around. */
2263 if (order == nullptr) {
2264 this->cur_implicit_order_index = 0;
2265 order = this->GetOrder(this->cur_implicit_order_index);
2266 }
2267 assert(order != nullptr);
2268 }
2269 }
2270 } else if (!suppress_implicit_orders &&
2271 (this->orders == nullptr ? OrderList::CanAllocateItem() : this->orders->GetNumOrders() < MAX_VEH_ORDER_ID)) {
2272 /* Insert new implicit order */
2273 Order implicit_order{};
2274 implicit_order.MakeImplicit(this->last_station_visited);
2275 InsertOrder(this, std::move(implicit_order), this->cur_implicit_order_index);
2276 if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
2277
2278 /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
2279 * Reenable it for this vehicle */
2280 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2282 }
2283 }
2284 }
2285 this->current_order.MakeLoading(false);
2286 }
2287
2288 if (this->last_loading_station != StationID::Invalid() &&
2289 this->last_loading_station != this->last_station_visited &&
2290 (this->current_order.GetLoadType() != OrderLoadType::NoLoad ||
2291 this->current_order.GetUnloadType() != OrderUnloadType::NoUnload)) {
2292 IncreaseStats(Station::Get(this->last_loading_station), this, this->last_station_visited, travel_time);
2293 }
2294
2295 PrepareUnload(this);
2296
2297 SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
2299 SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
2300 SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
2301
2302 Station::Get(this->last_station_visited)->MarkTilesDirty(true);
2303 this->cur_speed = 0;
2304 this->MarkDirty();
2305}
2306
2313{
2314 for (Vehicle *v = this; v != nullptr; v = v->next) {
2315 VehicleCargoList &cargo = v->cargo;
2316 if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
2317 Debug(misc, 1, "cancelling cargo reservation");
2318 cargo.Return(UINT_MAX, &st->goods[v->cargo_type].GetOrCreateData().cargo, next, v->tile);
2319 }
2320 cargo.KeepAll();
2321 }
2322}
2323
2329{
2330 assert(this->current_order.IsType(OT_LOADING));
2331
2332 delete this->cargo_payment;
2333 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
2334
2335 /* Only update the timetable if the vehicle was supposed to stop here. */
2336 if (this->current_order.GetNonStopType().Any()) UpdateVehicleTimetable(this, false);
2337
2338 if (this->current_order.GetLoadType() != OrderLoadType::NoLoad ||
2339 this->current_order.GetUnloadType() != OrderUnloadType::NoUnload) {
2340 if (this->current_order.CanLeaveWithCargo(this->last_loading_station != StationID::Invalid())) {
2341 /* Refresh next hop stats to make sure we've done that at least once
2342 * during the stop and that refit_cap == cargo_cap for each vehicle in
2343 * the consist. */
2344 this->ResetRefitCaps();
2345 LinkRefresher::Run(this);
2346
2347 /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
2348 this->last_loading_station = this->last_station_visited;
2349 this->last_loading_tick = TimerGameTick::counter;
2350 } else {
2351 /* if the vehicle couldn't load and had to unload or transfer everything
2352 * set the last loading station to invalid as it will leave empty. */
2353 this->last_loading_station = StationID::Invalid();
2354 }
2355 }
2356
2357 this->current_order.MakeLeaveStation();
2358 Station *st = Station::Get(this->last_station_visited);
2359 this->CancelReservation(StationID::Invalid(), st);
2360 st->loading_vehicles.remove(this);
2361
2362 HideFillingPercent(&this->fill_percent_te_id);
2363 trip_occupancy = CalcPercentVehicleFilled(this, nullptr);
2364
2365 if (this->type == VEH_TRAIN && !this->vehstatus.Test(VehState::Crashed)) {
2366 /* Trigger station animation (trains only) */
2367 if (IsTileType(this->tile, MP_STATION)) {
2369 TriggerStationAnimation(st, this->tile, StationAnimationTrigger::VehicleDeparts);
2370 }
2371
2373 }
2374 if (this->type == VEH_ROAD && !this->vehstatus.Test(VehState::Crashed)) {
2375 /* Trigger road stop animation */
2376 if (IsStationRoadStopTile(this->tile)) {
2378 TriggerRoadStopAnimation(st, this->tile, StationAnimationTrigger::VehicleDeparts);
2379 }
2380 }
2381
2382
2383 this->MarkDirty();
2384}
2385
2390{
2391 for (Vehicle *v = this; v != nullptr; v = v->Next()) v->refit_cap = v->cargo_cap;
2392}
2393
2398{
2399 Company::Get(this->owner)->freeunits[this->type].ReleaseID(this->unitnumber);
2400 this->unitnumber = 0;
2401}
2402
2409{
2410 switch (this->current_order.GetType()) {
2411 case OT_LOADING: {
2412 TimerGameTick::Ticks wait_time = std::max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2413
2414 /* Not the first call for this tick, or still loading */
2415 if (mode || !this->vehicle_flags.Test(VehicleFlag::LoadingFinished) || this->current_order_time < wait_time) return;
2416
2417 this->PlayLeaveStationSound();
2418
2419 this->LeaveStation();
2420
2421 /* Only advance to next order if we just loaded at the current one */
2422 const Order *order = this->GetOrder(this->cur_implicit_order_index);
2423 if (order == nullptr ||
2424 (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2425 order->GetDestination() != this->last_station_visited) {
2426 return;
2427 }
2428 break;
2429 }
2430
2431 case OT_DUMMY: break;
2432
2433 default: return;
2434 }
2435
2436 this->IncrementImplicitOrderIndex();
2437}
2438
2444{
2445 return std::ranges::any_of(this->Orders(), [](const Order &o) {
2446 return o.IsType(OT_GOTO_STATION) && o.IsFullLoadOrder();
2447 });
2448}
2449
2455{
2456 return std::ranges::any_of(this->Orders(), [](const Order &o) { return o.IsType(OT_CONDITIONAL); });
2457}
2458
2464{
2465 return std::ranges::any_of(this->Orders(), [](const Order &o) {
2466 return o.IsType(OT_GOTO_DEPOT) && o.GetDepotActionType().Test(OrderDepotActionFlag::Unbunch);
2467 });
2468}
2469
2475{
2476 /* If we are headed for the first order, we must wrap around back to the last order. */
2477 bool is_first_order = (v->GetOrder(v->cur_implicit_order_index) == v->GetFirstOrder());
2478 const Order *previous_order = (is_first_order) ? v->GetLastOrder() : v->GetOrder(v->cur_implicit_order_index - 1);
2479
2480 if (previous_order == nullptr || !previous_order->IsType(OT_GOTO_DEPOT)) return false;
2481 return previous_order->GetDepotActionType().Test(OrderDepotActionFlag::Unbunch);
2482}
2483
2488{
2489 /* Don't do anything if this is not our unbunching order. */
2490 if (!PreviousOrderIsUnbunching(this)) return;
2491
2492 /* Set the start point for this round trip time. */
2493 this->depot_unbunching_last_departure = TimerGameTick::counter;
2494
2495 /* Tell the timetable we are now "on time." */
2496 this->lateness_counter = 0;
2498
2499 /* Find the average travel time of vehicles that we share orders with. */
2500 int num_vehicles = 0;
2501 TimerGameTick::Ticks total_travel_time = 0;
2502
2503 Vehicle *u = this->FirstShared();
2504 for (; u != nullptr; u = u->NextShared()) {
2505 /* Ignore vehicles that are manually stopped or crashed. */
2506 if (u->vehstatus.Any({VehState::Stopped, VehState::Crashed})) continue;
2507
2508 num_vehicles++;
2509 total_travel_time += u->round_trip_time;
2510 }
2511
2512 /* Make sure we cannot divide by 0. */
2513 num_vehicles = std::max(num_vehicles, 1);
2514
2515 /* Calculate the separation by finding the average travel time, then calculating equal separation (minimum 1 tick) between vehicles. */
2516 TimerGameTick::Ticks separation = std::max((total_travel_time / num_vehicles / num_vehicles), 1);
2517 TimerGameTick::TickCounter next_departure = TimerGameTick::counter + separation;
2518
2519 /* Set the departure time of all vehicles that we share orders with. */
2520 u = this->FirstShared();
2521 for (; u != nullptr; u = u->NextShared()) {
2522 /* Ignore vehicles that are manually stopped or crashed. */
2523 if (u->vehstatus.Any({VehState::Stopped, VehState::Crashed})) continue;
2524
2525 u->depot_unbunching_next_departure = next_departure;
2527 }
2528}
2529
2535{
2536 assert(this->IsInDepot());
2537
2538 /* Don't bother if there are no vehicles sharing orders. */
2539 if (!this->IsOrderListShared()) return false;
2540
2541 /* Don't do anything if there aren't enough orders. */
2542 if (this->GetNumOrders() <= 1) return false;
2543
2544 /* Don't do anything if this is not our unbunching order. */
2545 if (!PreviousOrderIsUnbunching(this)) return false;
2546
2547 return (this->depot_unbunching_next_departure > TimerGameTick::counter);
2548};
2549
2557{
2558 CommandCost ret = CheckOwnership(this->owner);
2559 if (ret.Failed()) return ret;
2560
2561 if (this->vehstatus.Test(VehState::Crashed)) return CMD_ERROR;
2562 if (this->IsStoppedInDepot()) return CMD_ERROR;
2563
2564 /* No matter why we're headed to the depot, unbunching data is no longer valid. */
2565 if (flags.Test(DoCommandFlag::Execute)) this->ResetDepotUnbunching();
2566
2567 if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2568 bool halt_in_depot = this->current_order.GetDepotActionType().Test(OrderDepotActionFlag::Halt);
2569 if (command.Test(DepotCommandFlag::Service) == halt_in_depot) {
2570 /* We called with a different DEPOT_SERVICE setting.
2571 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2572 * Note: the if is (true for requesting service == true for ordered to stop in depot) */
2573 if (flags.Test(DoCommandFlag::Execute)) {
2574 this->current_order.SetDepotOrderType({});
2575 this->current_order.SetDepotActionType(halt_in_depot ? OrderDepotActionFlags{} : OrderDepotActionFlag::Halt);
2577 }
2578 return CommandCost();
2579 }
2580
2581 if (command.Test(DepotCommandFlag::DontCancel)) return CMD_ERROR; // Requested no cancellation of depot orders
2582 if (flags.Test(DoCommandFlag::Execute)) {
2583 /* If the orders to 'goto depot' are in the orders list (forced servicing),
2584 * then skip to the next order; effectively cancelling this forced service */
2585 if (this->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) this->IncrementRealOrderIndex();
2586
2587 if (this->IsGroundVehicle()) {
2588 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2590 }
2591
2592 this->current_order.MakeDummy();
2594 }
2595 return CommandCost();
2596 }
2597
2598 ClosestDepot closest_depot = this->FindClosestDepot();
2599 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};
2600 if (!closest_depot.found) return CommandCost(no_depot[this->type]);
2601
2602 if (flags.Test(DoCommandFlag::Execute)) {
2603 if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2604
2605 if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2606 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2608 }
2609
2610 this->SetDestTile(closest_depot.location);
2611 this->current_order.MakeGoToDepot(closest_depot.destination.ToDepotID(), {});
2612 if (!command.Test(DepotCommandFlag::Service)) this->current_order.SetDepotActionType(OrderDepotActionFlag::Halt);
2614
2615 /* If there is no depot in front and the train is not already reversing, reverse automatically (trains only) */
2616 if (this->type == VEH_TRAIN && (closest_depot.reverse ^ Train::From(this)->flags.Test(VehicleRailFlag::Reversing))) {
2618 }
2619
2620 if (this->type == VEH_AIRCRAFT) {
2621 Aircraft *a = Aircraft::From(this);
2622 if (a->state == FLYING && a->targetairport != closest_depot.destination) {
2623 /* The aircraft is now heading for a different hangar than the next in the orders */
2625 }
2626 }
2627 }
2628
2629 return CommandCost();
2630
2631}
2632
2637void Vehicle::UpdateVisualEffect(bool allow_power_change)
2638{
2639 bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2640 const Engine *e = this->GetEngine();
2641
2642 /* Evaluate properties */
2643 uint8_t visual_effect;
2644 switch (e->type) {
2645 case VEH_TRAIN: visual_effect = e->VehInfo<RailVehicleInfo>().visual_effect; break;
2646 case VEH_ROAD: visual_effect = e->VehInfo<RoadVehicleInfo>().visual_effect; break;
2647 case VEH_SHIP: visual_effect = e->VehInfo<ShipVehicleInfo>().visual_effect; break;
2648 default: visual_effect = 1 << VE_DISABLE_EFFECT; break;
2649 }
2650
2651 /* Check powered wagon / visual effect callback */
2653 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2654
2655 if (callback != CALLBACK_FAILED) {
2656 if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2657
2658 callback = GB(callback, 0, 8);
2659 /* Avoid accidentally setting 'visual_effect' to the default value
2660 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2661 if (callback == VE_DEFAULT) {
2662 assert(HasBit(callback, VE_DISABLE_EFFECT));
2663 SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2664 }
2665 visual_effect = callback;
2666 }
2667 }
2668
2669 /* Apply default values */
2670 if (visual_effect == VE_DEFAULT ||
2671 (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2672 /* Only train engines have default effects.
2673 * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2674 if (e->type != VEH_TRAIN || e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON || !IsInsideMM(e->VehInfo<RailVehicleInfo>().engclass, EC_STEAM, EC_MONORAIL)) {
2675 if (visual_effect == VE_DEFAULT) {
2676 visual_effect = 1 << VE_DISABLE_EFFECT;
2677 } else {
2678 SetBit(visual_effect, VE_DISABLE_EFFECT);
2679 }
2680 } else {
2681 if (visual_effect == VE_DEFAULT) {
2682 /* Also set the offset */
2683 visual_effect = (VE_OFFSET_CENTRE - (e->VehInfo<RailVehicleInfo>().engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
2684 }
2685 SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->VehInfo<RailVehicleInfo>().engclass - EC_STEAM + VE_TYPE_STEAM);
2686 }
2687 }
2688
2689 this->vcache.cached_vis_effect = visual_effect;
2690
2691 if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2692 ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2693 ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GRFBug::VehPoweredWagon, false);
2694 }
2695}
2696
2697static const int8_t _vehicle_smoke_pos[8] = {
2698 1, 1, 1, 0, -1, -1, -1, 0
2699};
2700
2706{
2707 std::array<int32_t, 4> regs100;
2708 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v, regs100);
2709 if (callback == CALLBACK_FAILED) return;
2710
2711 uint count = GB(callback, 0, 2);
2712 assert(count <= std::size(regs100));
2713 bool auto_center = HasBit(callback, 13);
2714 bool auto_rotate = !HasBit(callback, 14);
2715
2716 int8_t l_center = 0;
2717 if (auto_center) {
2718 /* For road vehicles: Compute offset from vehicle position to vehicle center */
2719 if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2720 } else {
2721 /* For trains: Compute offset from vehicle position to sprite position */
2722 if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2723 }
2724
2725 Direction l_dir = v->direction;
2726 if (v->type == VEH_TRAIN && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) l_dir = ReverseDir(l_dir);
2727 Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
2728
2729 int8_t x_center = _vehicle_smoke_pos[l_dir] * l_center;
2730 int8_t y_center = _vehicle_smoke_pos[t_dir] * l_center;
2731
2732 for (uint i = 0; i < count; i++) {
2733 int32_t reg = regs100[i];
2734 uint type = GB(reg, 0, 8);
2735 int8_t x = GB(reg, 8, 8);
2736 int8_t y = GB(reg, 16, 8);
2737 int8_t z = GB(reg, 24, 8);
2738
2739 if (auto_rotate) {
2740 int8_t l = x;
2741 int8_t t = y;
2742 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2743 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2744 }
2745
2746 if (type >= 0xF0) {
2747 switch (type) {
2748 case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2749 case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2750 case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2751 case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2752 default: break;
2753 }
2754 }
2755 }
2756}
2757
2763static bool IsBridgeAboveVehicle(const Vehicle *v)
2764{
2765 if (IsBridgeTile(v->tile)) {
2766 /* If the vehicle is 'on' a bridge tile, check the real position of the vehicle. If it's different then the
2767 * vehicle is on the middle of the bridge, which cannot have a bridge above. */
2768 TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
2769 if (tile != v->tile) return false;
2770 }
2771 return IsBridgeAbove(v->tile);
2772}
2773
2779{
2780 assert(this->IsPrimaryVehicle());
2781 bool sound = false;
2782
2783 /* Do not show any smoke when:
2784 * - vehicle smoke is disabled by the player
2785 * - the vehicle is slowing down or stopped (by the player)
2786 * - the vehicle is moving very slowly
2787 */
2789 this->vehstatus.Any({VehState::TrainSlowing, VehState::Stopped}) ||
2790 this->cur_speed < 2) {
2791 return;
2792 }
2793
2794 /* Use the speed as limited by underground and orders. */
2795 uint max_speed = this->GetCurrentMaxSpeed();
2796
2797 if (this->type == VEH_TRAIN) {
2798 const Train *t = Train::From(this);
2799 /* For trains, do not show any smoke when:
2800 * - the train is reversing
2801 * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2802 */
2803 if (t->flags.Test(VehicleRailFlag::Reversing) ||
2805 t->cur_speed >= max_speed)) {
2806 return;
2807 }
2808 }
2809
2810 const Vehicle *v = this;
2811
2812 do {
2815 VisualEffectSpawnModel effect_model = VESM_NONE;
2816 if (advanced) {
2817 effect_offset = VE_OFFSET_CENTRE;
2819 if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
2820 } else {
2822 assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
2823 static_assert((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
2824 static_assert((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL);
2825 static_assert((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
2826 }
2827
2828 /* Show no smoke when:
2829 * - Smoke has been disabled for this vehicle
2830 * - The vehicle is not visible
2831 * - The vehicle is under a bridge
2832 * - The vehicle is on a depot tile
2833 * - The vehicle is on a tunnel tile
2834 * - The vehicle is a train engine that is currently unpowered */
2835 if (effect_model == VESM_NONE ||
2838 IsDepotTile(v->tile) ||
2839 IsTunnelTile(v->tile) ||
2840 (v->type == VEH_TRAIN &&
2841 !HasPowerOnRail(Train::From(v)->railtypes, GetTileRailType(v->tile)))) {
2842 continue;
2843 }
2844
2845 EffectVehicleType evt = EV_END;
2846 switch (effect_model) {
2847 case VESM_STEAM:
2848 /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2849 * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2850 * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2851 * REGULATION:
2852 * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2853 if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2854 evt = EV_STEAM_SMOKE;
2855 }
2856 break;
2857
2858 case VESM_DIESEL: {
2859 /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2860 * when smoke emission stops.
2861 * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2862 * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2863 * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2864 * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2865 * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2866 * maximum speed no diesel_smoke is emitted.
2867 * REGULATION:
2868 * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2869 * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2870 int power_weight_effect = 0;
2871 if (v->type == VEH_TRAIN) {
2872 power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2873 }
2874 if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2875 Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2876 evt = EV_DIESEL_SMOKE;
2877 }
2878 break;
2879 }
2880
2881 case VESM_ELECTRIC:
2882 /* Electric train's spark - more often occurs when train is departing (more load)
2883 * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2884 * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2885 * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2886 * REGULATION:
2887 * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2888 if (GB(v->tick_counter, 0, 2) == 0 &&
2889 Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2890 evt = EV_ELECTRIC_SPARK;
2891 }
2892 break;
2893
2894 default:
2895 NOT_REACHED();
2896 }
2897
2898 if (evt != EV_END && advanced) {
2899 sound = true;
2901 } else if (evt != EV_END) {
2902 sound = true;
2903
2904 /* The effect offset is relative to a point 4 units behind the vehicle's
2905 * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2906 * correction factor. */
2907 if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2908
2909 int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2910 int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2911
2912 if (v->type == VEH_TRAIN && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) {
2913 x = -x;
2914 y = -y;
2915 }
2916
2917 CreateEffectVehicleRel(v, x, y, 10, evt);
2918 }
2919 } while ((v = v->Next()) != nullptr);
2920
2921 if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2922}
2923
2929{
2930 assert(this != next);
2931
2932 if (this->next != nullptr) {
2933 /* We had an old next vehicle. Update the first and previous pointers */
2934 for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
2935 v->first = this->next;
2936 }
2937 this->next->previous = nullptr;
2938 }
2939
2940 this->next = next;
2941
2942 if (this->next != nullptr) {
2943 /* A new next vehicle. Update the first and previous pointers */
2944 if (this->next->previous != nullptr) this->next->previous->next = nullptr;
2945 this->next->previous = this;
2946 for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
2947 v->first = this->first;
2948 }
2949 }
2950}
2951
2958{
2959 assert(this->previous_shared == nullptr && this->next_shared == nullptr);
2960
2961 if (shared_chain->orders == nullptr) {
2962 assert(shared_chain->previous_shared == nullptr);
2963 assert(shared_chain->next_shared == nullptr);
2964 this->orders = shared_chain->orders = OrderList::Create(shared_chain);
2965 }
2966
2967 this->next_shared = shared_chain->next_shared;
2968 this->previous_shared = shared_chain;
2969
2970 shared_chain->next_shared = this;
2971
2972 if (this->next_shared != nullptr) this->next_shared->previous_shared = this;
2973
2974 shared_chain->orders->AddVehicle(this);
2975}
2976
2981{
2982 /* Remember if we were first and the old window number before RemoveVehicle()
2983 * as this changes first if needed. */
2984 bool were_first = (this->FirstShared() == this);
2985 VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
2986
2987 this->orders->RemoveVehicle(this);
2988
2989 if (!were_first) {
2990 /* We are not the first shared one, so only relink our previous one. */
2991 this->previous_shared->next_shared = this->NextShared();
2992 }
2993
2994 if (this->next_shared != nullptr) this->next_shared->previous_shared = this->previous_shared;
2995
2996
2997 if (this->orders->GetNumVehicles() == 1) {
2998 /* When there is only one vehicle, remove the shared order list window. */
3000 InvalidateVehicleOrder(this->FirstShared(), VIWD_MODIFY_ORDERS);
3001 } else if (were_first) {
3002 /* If we were the first one, update to the new first one.
3003 * Note: FirstShared() is already the new first */
3004 InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.ToWindowNumber(), this->FirstShared()->index.base() | (1U << 31));
3005 }
3006
3007 this->next_shared = nullptr;
3008 this->previous_shared = nullptr;
3009}
3010
3011static const IntervalTimer<TimerGameEconomy> _economy_vehicles_yearly({TimerGameEconomy::YEAR, TimerGameEconomy::Priority::VEHICLE}, [](auto)
3012{
3013 for (Vehicle *v : Vehicle::Iterate()) {
3014 if (v->IsPrimaryVehicle()) {
3015 /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
3016 Money profit = v->GetDisplayProfitThisYear();
3017 if (v->economy_age >= VEHICLE_PROFIT_MIN_AGE && profit < 0) {
3020 GetEncodedString(TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_VEHICLE_UNPROFITABLE_PERIOD : STR_NEWS_VEHICLE_UNPROFITABLE_YEAR, v->index, profit),
3021 v->index);
3022 }
3023 AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
3024 }
3025
3027 v->profit_this_year = 0;
3029 }
3030 }
3036});
3037
3047bool CanVehicleUseStation(EngineID engine_type, const Station *st)
3048{
3049 const Engine *e = Engine::GetIfValid(engine_type);
3050 assert(e != nullptr);
3051
3052 switch (e->type) {
3053 case VEH_TRAIN:
3055
3056 case VEH_ROAD:
3057 /* For road vehicles we need the vehicle to know whether it can actually
3058 * use the station, but if it doesn't have facilities for RVs it is
3059 * certainly not possible that the station can be used. */
3061
3062 case VEH_SHIP:
3064
3065 case VEH_AIRCRAFT:
3068
3069 default:
3070 return false;
3071 }
3072}
3073
3080bool CanVehicleUseStation(const Vehicle *v, const Station *st)
3081{
3082 if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != nullptr;
3083
3084 return CanVehicleUseStation(v->engine_type, st);
3085}
3086
3094{
3095 switch (v->type) {
3096 case VEH_TRAIN:
3097 return STR_ERROR_NO_RAIL_STATION;
3098
3099 case VEH_ROAD: {
3100 const RoadVehicle *rv = RoadVehicle::From(v);
3101 RoadStop *rs = st->GetPrimaryRoadStop(rv->IsBus() ? RoadStopType::Bus : RoadStopType::Truck);
3102
3103 StringID err = rv->IsBus() ? STR_ERROR_NO_BUS_STATION : STR_ERROR_NO_TRUCK_STATION;
3104
3105 for (; rs != nullptr; rs = rs->next) {
3106 /* Articulated vehicles cannot use bay road stops, only drive-through. Make sure the vehicle can actually use this bay stop */
3108 err = STR_ERROR_NO_STOP_ARTICULATED_VEHICLE;
3109 continue;
3110 }
3111
3112 /* Bay stop errors take precedence, but otherwise the vehicle may not be compatible with the roadtype/tramtype of this station tile.
3113 * We give bay stop errors precedence because they are usually a bus sent to a tram station or vice versa. */
3114 if (!HasTileAnyRoadType(rs->xy, rv->compatible_roadtypes) && err != STR_ERROR_NO_STOP_ARTICULATED_VEHICLE) {
3115 err = RoadTypeIsRoad(rv->roadtype) ? STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE : STR_ERROR_NO_STOP_COMPATIBLE_TRAM_TYPE;
3116 continue;
3117 }
3118 }
3119
3120 return err;
3121 }
3122
3123 case VEH_SHIP:
3124 return STR_ERROR_NO_DOCK;
3125
3126 case VEH_AIRCRAFT:
3127 if (!st->facilities.Test(StationFacility::Airport)) return STR_ERROR_NO_AIRPORT;
3128 if (v->GetEngine()->VehInfo<AircraftVehicleInfo>().subtype & AIR_CTOL) {
3129 return STR_ERROR_AIRPORT_NO_PLANES;
3130 } else {
3131 return STR_ERROR_AIRPORT_NO_HELICOPTERS;
3132 }
3133
3134 default:
3135 return INVALID_STRING_ID;
3136 }
3137}
3138
3145{
3146 assert(this->IsGroundVehicle());
3147 if (this->type == VEH_TRAIN) {
3148 return &Train::From(this)->gcache;
3149 } else {
3150 return &RoadVehicle::From(this)->gcache;
3151 }
3152}
3153
3160{
3161 assert(this->IsGroundVehicle());
3162 if (this->type == VEH_TRAIN) {
3163 return &Train::From(this)->gcache;
3164 } else {
3165 return &RoadVehicle::From(this)->gcache;
3166 }
3167}
3168
3175{
3176 assert(this->IsGroundVehicle());
3177 if (this->type == VEH_TRAIN) {
3178 return Train::From(this)->gv_flags;
3179 } else {
3180 return RoadVehicle::From(this)->gv_flags;
3181 }
3182}
3183
3189const uint16_t &Vehicle::GetGroundVehicleFlags() const
3190{
3191 assert(this->IsGroundVehicle());
3192 if (this->type == VEH_TRAIN) {
3193 return Train::From(this)->gv_flags;
3194 } else {
3195 return RoadVehicle::From(this)->gv_flags;
3196 }
3197}
3198
3207void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8_t num_vehicles)
3208{
3209 if (v->type == VEH_TRAIN) {
3210 Train *u = Train::From(v);
3211 /* Only include whole vehicles, so start with the first articulated part */
3212 u = u->GetFirstEnginePart();
3213
3214 /* Include num_vehicles vehicles, not counting articulated parts */
3215 for (; u != nullptr && num_vehicles > 0; num_vehicles--) {
3216 do {
3217 /* Include current vehicle in the selection. */
3218 include(set, u->index);
3219
3220 /* If the vehicle is multiheaded, add the other part too. */
3221 if (u->IsMultiheaded()) include(set, u->other_multiheaded_part->index);
3222
3223 u = u->Next();
3224 } while (u != nullptr && u->IsArticulatedPart());
3225 }
3226 }
3227}
3228
3234{
3235 uint32_t max_weight = 0;
3236
3237 for (const Vehicle *u = this; u != nullptr; u = u->Next()) {
3238 max_weight += u->GetMaxWeight();
3239 }
3240
3241 return max_weight;
3242}
3243
3249{
3250 uint32_t max_weight = GetDisplayMaxWeight();
3251 if (max_weight == 0) return 0;
3252 return GetGroundVehicleCache()->cached_power * 10u / max_weight;
3253}
3254
3262{
3263 while (true) {
3264 if (v1 == nullptr && v2 == nullptr) return true;
3265 if (v1 == nullptr || v2 == nullptr) return false;
3266 if (v1->GetEngine() != v2->GetEngine()) return false;
3267 v1 = v1->GetNextVehicle();
3268 v2 = v2->GetNextVehicle();
3269 }
3270}
3271
3279{
3280 return std::ranges::equal(v1->Orders(), v2->Orders(), [](const Order &o1, const Order &o2) { return o1.Equals(o2); });
3281}
Base functions for all AIs.
Base for aircraft.
void AircraftNextAirportPos_and_Order(Aircraft *v)
set the right pos when heading to other airports after takeoff
Station * GetTargetAirportIfValid(const Aircraft *v)
Returns aircraft's target station if v->target_airport is a valid station with airport.
@ AIR_SHADOW
shadow of the aircraft
Definition aircraft.h:31
void HandleAircraftEnterHangar(Aircraft *v)
Handle Aircraft specific tasks when an Aircraft enters a hangar.
@ FLYING
Vehicle is flying in the air.
Definition airport.h:77
CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoType *cargo_type)
Get cargo mask of all cargoes carried by an articulated vehicle.
void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, CargoTypes *union_mask, CargoTypes *intersection_mask)
Merges the refit_masks of all articulated parts.
CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine)
Get the cargo mask of the parts of a given engine.
Functions related to articulated vehicles.
Command definitions related to autoreplace.
Functions related to autoreplacing.
EngineID EngineReplacementForCompany(const Company *c, EngineID engine, GroupID group, bool *replace_when_old=nullptr)
Retrieve the engine replacement for the given company and original engine type.
bool EngineHasReplacementForCompany(const Company *c, EngineID engine, GroupID group)
Check if a company has a replacement set up for the given engine.
void InvalidateAutoreplaceWindow(EngineID e, GroupID id_g)
Rebuild the left autoreplace list if an engine is removed or added.
Functions related to the autoreplace GUIs.
Class for backupping variables and making sure they are restored later.
@ PathfinderLost
Vehicle's pathfinder is lost.
@ StopLoading
Don't load anymore during the next load cycle.
@ LoadingFinished
Vehicle has finished loading.
@ CargoUnloading
Vehicle is unloading cargo.
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr bool HasAtMostOneBit(T value)
Test whether value has at most 1 bit set.
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Map accessor functions for bridges.
bool IsBridgeTile(Tile t)
checks if there is a bridge on this tile
Definition bridge_map.h:35
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:104
@ Passengers
Passengers.
bool IsCargoInClass(CargoType cargo, CargoClasses cc)
Does cargo c have cargo class cc?
Definition cargotype.h:236
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:235
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
@ MTA_LOAD
Load the cargo from the station.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
StringID GetErrorMessage() const
Returns the error message of a command.
static constexpr int DAYS_IN_ECONOMY_MONTH
Days in an economy month, when in wallclock timekeeping mode.
Container for an encoded string, created by GetEncodedString.
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:160
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
static Pool::IterateWrapperFiltered< Engine, EngineTypeFilter > IterateType(VehicleType vt, size_t from=0)
Returns an iterable ensemble of all valid engines of the given type.
CargoGRFFileProps grf_prop
Link to NewGRF.
Definition engine_base.h:71
CompanyMask company_avail
Bit for each company whether the engine is available for that company.
Definition engine_base.h:40
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:62
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:94
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:49
Enum-as-bit-set wrapper.
UnitID UseID(UnitID index)
Use a unit number.
Definition vehicle.cpp:1845
void ReleaseID(UnitID index)
Release a unit number.
Definition vehicle.cpp:1862
UnitID NextID() const
Find first unused unit number.
Definition vehicle.cpp:1830
bool GRFBugReverse(uint32_t grfid, uint16_t internal_id)
Logs GRF bug - rail vehicle has different length after reversing.
Definition gamelog.cpp:482
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
static void Run(Vehicle *v, bool allow_merge=true, bool is_full_loading=false)
Refresh all links the given vehicle will visit.
Definition refresh.cpp:26
static void Reset(PerformanceElement elem)
Store the previous accumulator value and reset for a new cycle of accumulating measurements.
RAII class for measuring simple elements of performance.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Date date
Current date in days (day counter).
static DateFract date_fract
Fractional part of the day.
static constexpr TimerGame< struct Economy >::Date MAX_DATE
The date of the last day of the max year.
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
static Date date
Current date in days (day counter).
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static DateFract date_fract
Fractional part of the day.
uint64_t TickCounter
The type that the tick counter is stored in.
static TickCounter counter
Monotonic counter, in ticks, since start of game.
int32_t Ticks
The type to store ticks in.
static constexpr Date DateAtStartOfYear(Year year)
Calculate the date of the first day of a given year.
CargoList that is used for vehicles.
uint ActionCount(MoveToAction action) const
Returns the amount of cargo designated for a given purpose.
uint Return(uint max_move, StationCargoList *dest, StationID next_station, TileIndex current_tile)
Returns reserved cargo to the station and removes it from the cache.
void KeepAll()
Marks all cargo in the vehicle as to be kept.
void AgeCargo()
Ages the all cargo in this list.
uint StoredCount() const
Returns sum of cargo on board the vehicle (ie not only reserved).
void SkipEmptyBuckets()
Advance the internal state until we reach a non-empty bucket, or the end.
Definition vehicle.cpp:473
Iterator(int32_t x, int32_t y, uint max_dist)
Iterator constructor.
Definition vehicle.cpp:433
void Increment()
Advance the internal state to the next potential vehicle.
Definition vehicle.cpp:463
void SkipFalseMatches()
Advance the internal state until it reaches a vehicle within the search area.
Definition vehicle.cpp:491
Iterator(TileIndex tile)
Iterator constructor.
Definition vehicle.cpp:500
void Increment()
Advance the internal state to the next potential vehicle.
Definition vehicle.cpp:510
void SkipFalseMatches()
Advance the internal state until it reaches a vehicle on the correct tile or the end.
Definition vehicle.cpp:518
Iterate over all vehicles on a tile.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
static void SubtractMoneyFromCompany(Company *c, const CommandCost &cost)
Deduct costs of a command from the money of a company.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
Money GetAvailableMoney(CompanyID company)
Get the amount of money that a company has available, or INT64_MAX if there is no such valid company.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
bool IsLocalCompany()
Is the current company the local company?
Some simple functions to help with accessing containers.
bool include(Container &container, typename Container::const_reference &item)
Helper function to append an item to a container if it is not already contained.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Functions related to depots.
void DeleteDepotHighlightOfVehicle(const Vehicle *v)
Removes the highlight of a vehicle in a depot window.
Map related accessors for depots.
bool IsDepotTile(Tile tile)
Is the given tile a tile with a depot on it?
Definition depot_map.h:42
DirDiff DirDifference(Direction d0, Direction d1)
Calculate the difference between two directions.
Direction ReverseDir(Direction d)
Return the reverse of a direction.
Direction ChangeDir(Direction d, DirDiff delta)
Change a direction by a given difference.
DirDiff
Enumeration for the difference between two directions.
@ DIRDIFF_45LEFT
Angle of 45 degrees left.
@ DIRDIFF_REVERSE
One direction is the opposite of the other one.
@ DIRDIFF_45RIGHT
Angle of 45 degrees right.
@ DIRDIFF_SAME
Both directions faces to the same direction.
@ DIRDIFF_90RIGHT
Angle of 90 degrees right.
Direction
Defines the 8 directions on the map.
@ DIR_SW
Southwest.
@ DIR_NW
Northwest.
@ DIR_N
North.
@ DIR_SE
Southeast.
@ DIR_S
South.
@ DIR_NE
Northeast.
@ DIR_W
West.
@ DIR_E
East.
@ INVALID_DIAGDIR
Flag for an invalid DiagDirection.
void LoadUnloadStation(Station *st)
Load/unload the vehicles in this station according to the order they entered.
Definition economy.cpp:1922
void PrepareUnload(Vehicle *front_v)
Prepare the vehicle to be unloaded.
Definition economy.cpp:1248
Base classes related to the economy.
@ EXPENSES_NEW_VEHICLES
New vehicles.
EffectVehicle * CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular vehicle.
Base class for all effect vehicles.
Functions related to effect vehicles.
EffectVehicleType
Effect vehicle types.
@ EV_BREAKDOWN_SMOKE
Smoke of broken vehicles except aircraft.
@ EV_STEAM_SMOKE
Smoke of steam engines.
@ EV_DIESEL_SMOKE
Smoke of diesel engines.
@ EV_BREAKDOWN_SMOKE_AIRCRAFT
Smoke of broken aircraft.
@ EV_ELECTRIC_SPARK
Sparks of electric engines.
@ AIR_CTOL
Conventional Take Off and Landing, i.e. planes.
@ RoadIsTram
Road vehicle is a tram/light rail vehicle.
@ NoBreakdownSmoke
Do not show black smoke during a breakdown.
@ Uses2CC
Vehicle uses two company colours.
@ RailIsMU
Rail vehicle is a multiple-unit (DMU/EMU)
@ VE_TYPE_DEFAULT
Use default from engine class.
Definition engine_type.h:61
@ VE_TYPE_COUNT
Number of bits used for the effect type.
Definition engine_type.h:60
@ VE_OFFSET_CENTRE
Value of offset corresponding to a position above the centre of the vehicle.
Definition engine_type.h:57
@ VE_TYPE_ELECTRIC
Electric sparks.
Definition engine_type.h:64
@ VE_TYPE_START
First bit used for the type of effect.
Definition engine_type.h:59
@ VE_OFFSET_COUNT
Number of bits used for the offset.
Definition engine_type.h:56
@ VE_ADVANCED_EFFECT
Flag for advanced effects.
Definition engine_type.h:67
@ VE_DISABLE_EFFECT
Flag to disable visual effect.
Definition engine_type.h:66
@ VE_TYPE_STEAM
Steam plumes.
Definition engine_type.h:62
@ VE_TYPE_DIESEL
Diesel fumes.
Definition engine_type.h:63
@ VE_DEFAULT
Default value to indicate that visual effect should be based on engine class.
Definition engine_type.h:70
@ VE_OFFSET_START
First bit that contains the offset (0 = front, 8 = centre, 15 = rear)
Definition engine_type.h:55
@ VE_DISABLE_WAGON_POWER
Flag to disable wagon power.
Definition engine_type.h:68
@ EC_DIESEL
Diesel rail engine.
Definition engine_type.h:40
@ EC_STEAM
Steam rail engine.
Definition engine_type.h:39
@ EC_MAGLEV
Maglev engine.
Definition engine_type.h:43
@ EC_ELECTRIC
Electric rail engine.
Definition engine_type.h:41
@ EC_MONORAIL
Mono rail engine.
Definition engine_type.h:42
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:34
Functions related to errors.
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition error.h:27
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
Types for recording game performance data.
@ PFE_GL_SHIPS
Time spent processing ships.
@ PFE_GL_AIRCRAFT
Time spent processing aircraft.
@ PFE_GL_ECONOMY
Time spent processing cargo movement.
@ PFE_GL_ROADVEHS
Time spend processing road vehicles.
@ PFE_GL_TRAINS
Time spent processing trains.
Gamelog _gamelog
Gamelog instance.
Definition gamelog.cpp:31
Functions to be called to log fundamental changes to the game.
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:1034
@ Normal
The most basic (normal) sprite.
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
bool MarkAllViewportsDirty(int left, int top, int right, int bottom)
Mark all viewports that display an area as dirty (in need of repaint).
void MarkTilesDirty(bool cargo_change) const
Marks the tiles of the station as dirty.
Definition station.cpp:247
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
virtual void MarkDirty()
Marks the vehicles to be redrawn and updates cached variables.
void DeleteGroupHighlightOfVehicle(const Vehicle *v)
Removes the highlight of a vehicle in a group window.
Functions/definitions that have something to do with groups.
static constexpr GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition group_type.h:18
const TileTypeProcs *const _tile_type_procs[16]
Tile callback functions for each type of tile.
Definition landscape.cpp:69
Point RemapCoords(int x, int y, int z)
Map 3D world or tile coordinate to equivalent 2D coordinate as used in the viewports and smallmap.
Definition landscape.h:81
@ Random
Randomise borders.
Declaration of link graph classes used for cargo distribution.
static const uint8_t LIT_ALL
Show the liveries of all companies.
Definition livery.h:19
LiveryScheme
List of different livery schemes.
Definition livery.h:22
static const uint8_t LIT_COMPANY
Show the liveries of your own company.
Definition livery.h:18
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:416
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:437
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:427
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
Miscellaneous command definitions.
void HideFillingPercent(TextEffectID *te_id)
Hide vehicle loading indicators.
Definition misc_gui.cpp:586
void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost)
Display animated income or costs on the map.
Definition misc_gui.cpp:513
bool _networking
are we in networking mode?
Definition network.cpp:66
Basic functions/variables used all over the place.
@ VisualEffect
Visual effects and wagon power (trains, road vehicles and ships)
@ ColourRemap
Change colour mapping of vehicle.
@ CBID_VEHICLE_SPAWN_VISUAL_EFFECT
Called to spawn visual effects for vehicles.
@ CBID_VEHICLE_COLOUR_MAPPING
Called to determine if a specific colour map should be used for a vehicle instead of the default live...
@ CBID_VEHICLE_32DAY_CALLBACK
Called for every vehicle every 32 days (not all on same date though).
@ CBID_VEHICLE_VISUAL_EFFECT
Visual effects and wagon power.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
GRFConfig * GetGRFConfig(uint32_t grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
GRFBug
Encountered GRF bugs.
@ VehPoweredWagon
Powered wagon changed poweredness state when not inside a depot.
@ VehLength
Length of rail vehicle changes when not inside a depot.
Functions/types related to NewGRF debugging.
GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
Get the GrfSpecFeature associated with the tile.
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
bool UsesWagonOverride(const Vehicle *v)
Check if a wagon is currently using a wagon override.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, std::span< int32_t > regs100)
Evaluate a newgrf callback for vehicles.
void TriggerRoadStopRandomisation(BaseStation *st, TileIndex tile, StationRandomTrigger trigger, CargoType cargo_type)
Trigger road stop randomisation.
NewGRF definitions and structures for road stops.
bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force)
Checks whether a NewGRF wants to play a different vehicle sound effect.
Functions related to NewGRF provided sounds.
@ VSE_VISUAL_EFFECT
Vehicle visual effect (steam, diesel smoke or electric spark) is shown.
@ VSE_RUNNING
Vehicle running normally.
@ VSE_STOPPED_16
Every 16 ticks while the vehicle is stopped (speed == 0).
@ VSE_RUNNING_16
Every 16 ticks while the vehicle is running (speed > 0).
@ VSE_BREAKDOWN
Vehicle breaking down.
void TriggerStationRandomisation(BaseStation *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoType cargo_type)
Trigger station randomisation.
Header file for NewGRF stations.
Functions related to news.
void AddVehicleAdviceNewsItem(AdviceType advice_type, EncodedString &&headline, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition news_func.h:40
void DeleteVehicleNews(VehicleID vid, AdviceType advice_type=AdviceType::Invalid)
Delete news with a given advice type about a vehicle.
@ VehicleLost
The vehicle has become lost.
@ VehicleWaiting
The vehicle is waiting in the depot.
@ AutorenewFailed
Autorenew or autoreplace failed.
@ VehicleOld
The vehicle is starting to get old.
@ VehicleUnprofitable
The vehicle is costing you money.
@ RefitFailed
The refit order failed to execute.
@ Error
A game paused because a (critical) error.
@ Normal
A game normally paused.
Functions related to order backups.
void InsertOrder(Vehicle *v, Order &&new_o, VehicleOrderID sel_ord)
Insert a new order but skip the validation.
void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
Delete an order but skip the parameter validation.
void InvalidateVehicleOrder(const Vehicle *v, int data)
Updates the widgets of a vehicle which contains the order-data.
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
@ NoUnload
Totally no unloading will be done.
@ NoDestination
The vehicle will stop at any station it passes except the destination, aka via.
@ NoIntermediate
The vehicle will not stop at any stations it passes except the destination, aka non-stop.
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition order_type.h:18
@ NoLoad
Do not load anything.
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition order_type.h:41
@ Halt
Service the vehicle and then halt it.
@ NearestDepot
Send the vehicle to the nearest depot.
@ Unbunch
Service the vehicle and then unbunch it.
@ PartOfOrders
This depot order is because of a regular order.
@ Service
This depot order is because of the servicing limit.
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition order_type.h:39
static const uint IMPLICIT_ORDER_ONLY_CAP
Maximum number of orders in implicit-only lists before we start searching harder for duplicates.
Definition order_type.h:47
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
bool HasAnyRailTypesAvail(const CompanyID company)
Test if any buildable railtype is available for a company.
Definition rail.cpp:78
RailType GetTileRailType(Tile tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
Definition rail.cpp:37
bool HasPowerOnRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType got power on a tile with a given RailType.
Definition rail.h:376
void SetDepotReservation(Tile t, bool b)
Set the reservation state of the depot.
Definition rail_map.h:269
Pseudo random number generator.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
bool Chance16I(const uint32_t a, const uint32_t b, const uint32_t r)
Checks if a given randomize-number is below a given probability.
bool Chance16(const uint32_t a, const uint32_t b, const std::source_location location=std::source_location::current())
Flips a coin with given probability.
Declaration of link refreshing utility.
bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt)
Test if any buildable RoadType is available for a company.
Definition road.cpp:152
bool HasTileAnyRoadType(Tile t, RoadTypes rts)
Check if a tile has one of the specified road types.
Definition road_map.h:206
RoadTramType
The different types of road type.
Definition road_type.h:37
Base class for roadstops.
Road vehicle states.
@ RVSB_IN_DT_ROAD_STOP
The vehicle is in a drive-through road stop.
Definition roadveh.h:51
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Base for ships.
SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner)
Update signals, starting at one side of a tile Will check tile next to this at opposite side too.
Definition signal.cpp:647
Functions related to sound.
@ SND_3A_BREAKDOWN_TRAIN_SHIP_TOYLAND
58 == 0x3A Breakdown: train or ship (toyland)
Definition sound_type.h:105
@ SND_10_BREAKDOWN_TRAIN_SHIP
14 == 0x0E Breakdown: train or ship (non-toyland)
Definition sound_type.h:61
@ SND_0F_BREAKDOWN_ROADVEHICLE
13 == 0x0D Breakdown: road vehicle (non-toyland)
Definition sound_type.h:60
@ SND_35_BREAKDOWN_ROADVEHICLE_TOYLAND
53 == 0x35 Breakdown: road vehicle (toyland)
Definition sound_type.h:100
Functions to cache sprites in memory.
static const PaletteID PALETTE_RECOLOUR_START
First recolour sprite for company colours.
Definition sprites.h:1588
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1619
Base classes/functions for stations.
void IncreaseStats(Station *st, CargoType cargo, StationID next_station_id, uint capacity, uint usage, uint32_t time, EdgeUpdateModes modes)
Increase capacity for a link stat given by station cargo and next hop.
bool IsStationRoadStopTile(Tile t)
Is tile t a road stop station?
bool IsBayRoadStopTile(Tile t)
Is tile t a bay (non-drive through) road stop station?
bool IsRailStationTile(Tile t)
Is this tile a station tile and a rail station?
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
RoadStopType GetRoadStopType(Tile t)
Get the road stop type of this tile.
Definition station_map.h:56
@ Bus
A standard stop for buses.
@ Truck
A standard stop for trucks.
@ Dock
Station with a dock.
@ TruckStop
Station with truck stops.
@ Train
Station with train station.
@ Airport
Station with an airport.
@ BusStop
Station with bus stops.
@ VehicleDeparts
Trigger platform when train leaves.
@ VehicleDeparts
Trigger platform when train leaves.
Definition of base types and functions in a cross-platform compatible way.
static void StrMakeValid(Builder &builder, StringConsumer &consumer, StringValidationSettings settings)
Copies the valid (UTF-8) characters from consumer to the builder.
Definition string.cpp:119
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Information about a aircraft vehicle.
uint8_t subtype
Type of aircraft.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:72
uint8_t pos
Next desired position of the aircraft.
Definition aircraft.h:74
uint8_t state
State of the airport.
Definition aircraft.h:77
bool IsNormalAircraft() const
Check if the aircraft type is a normal flying device; eg not a rotor or a shadow.
Definition aircraft.h:120
uint8_t previous_pos
Previous desired position of the aircraft.
Definition aircraft.h:75
StationID targetairport
Airport to go to next.
Definition aircraft.h:76
@ Airplanes
Can planes land on this airport type?
@ Helicopters
Can helicopters land on this airport type?
std::vector< AirportFTA > layout
state machine for airport
Definition airport.h:191
Flags flags
Flags for this airport type.
Definition airport.h:194
AirportBlocks blocks
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
const AirportFTAClass * GetFTA() const
Get the finite-state machine for this airport or the finite-state machine for the dummy airport in ca...
Class to backup a specific variable and restore it later.
void Restore()
Restore the variable.
TimerGameTick::TickCounter depot_unbunching_next_departure
When the vehicle will next try to leave its unbunching depot.
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
TimerGameTick::Ticks round_trip_time
How many ticks for a single circumnavigation of the orders.
VehicleFlags vehicle_flags
Used for gradual loading and other miscellaneous things (.
TimerGameTick::TickCounter depot_unbunching_last_departure
When the vehicle last left its unbunching depot.
VehicleOrderID cur_implicit_order_index
The index to the current implicit order.
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
StationFacilities facilities
The facilities that this station has.
VehicleType type
Type of vehicle.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
GUISettings gui
settings related to the GUI
Structure to return information about the closest depot location, and whether it could be found.
DestinationID destination
The DestinationID as used for orders.
CompanySettings settings
settings specific for each company
uint32_t engine_renew_money
minimum amount of money before autorenew is used
int16_t engine_renew_months
months before/after the maximum vehicle age a vehicle should be renewed
bool engine_renew
is autorenew enabled
std::array< GroupStatistics, VEH_COMPANY_END > group_all
NOSAVE: Statistics for the ALL_GROUP group.
T y
Y coordinate.
T x
X coordinate.
uint8_t vehicle_breakdowns
likelihood of vehicles breaking down
Data about how and where to blit pixels.
Definition gfx_type.h:157
A special vehicle is one of the following:
TransparencyOption GetTransparencyOption() const
Determines the transparency option affecting the effect.
uint16_t animation_state
State primarily used to change the graphics/behaviour.
EngineMiscFlags misc_flags
Miscellaneous flags.
VehicleCallbackMasks callback_mask
Bitmask of vehicle callbacks that have to be called.
Information about GRF, used in the game and (part of it) in savegames.
GRFBugs grf_bugs
NOSAVE: bugs in this GRF in this run,.
std::string GetName() const
Get the name of this grf.
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced this entity.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:114
bool lost_vehicle_warn
if a vehicle can't find its destination, show a warning
bool vehicle_income_warn
if a vehicle isn't generating income, show a warning
bool show_track_reservation
highlight reserved tracks.
uint8_t liveries
options for displaying company liveries, 0=none, 1=self, 2=all
bool old_vehicle_warn
if a vehicle is getting old, show a warning
LandscapeType landscape
the landscape we're currently in
DifficultySettings difficulty
settings related to the difficulty
GameCreationSettings game_creation
settings used during the creation of a game (map)
VehicleSettings vehicle
options for vehicles
OrderSettings order
settings related to orders
Position information of a vehicle after it moved.
TileIndex new_tile
Tile of the vehicle after moving.
int y
x and y position of the vehicle after moving
TileIndex old_tile
Current tile of the vehicle.
Cached, frequently calculated values.
EngineID first_engine
Cached EngineID of the front vehicle. EngineID::Invalid() for the front vehicle itself.
bool IsMultiheaded() const
Check if the vehicle is a multiheaded engine.
static void CountVehicle(const Vehicle *v, int delta)
Update num_vehicle when adding or removing a vehicle.
static void VehicleReachedMinAge(const Vehicle *v)
Add a vehicle to the profit sum of its group.
static void CountEngine(const Vehicle *v, int delta)
Update num_engines when adding/removing an engine.
static void UpdateAutoreplace(CompanyID company)
Update autoreplace_defined and autoreplace_finished of all statistics of a company.
static void UpdateProfits()
Recompute the profits for all groups.
Group data.
Definition group.h:73
Livery livery
Custom colour scheme for vehicles in this group.
Definition group.h:79
GroupID parent
Parent group.
Definition group.h:85
Information about a particular livery.
Definition livery.h:79
Flags in_use
Livery flags.
Definition livery.h:86
Colours colour2
Second colour, for vehicles with 2CC support.
Definition livery.h:88
Colours colour1
First colour, for all vehicles.
Definition livery.h:87
bool revalidate_before_draw
We need to do a GetImage() and check bounds before drawing this sprite.
VehicleSpriteSeq sprite_seq
Vehicle appearance.
Rect old_coord
Co-ordinates from the last valid bounding box.
static void ClearVehicle(const Vehicle *v)
Clear/update the (clone) vehicle from an order backup.
void AddVehicle(Vehicle *v)
Adds the given vehicle to this shared order list.
Definition order_base.h:412
bool no_servicing_if_no_breakdowns
don't send vehicles to depot when breakdowns are disabled
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition order_base.h:150
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:99
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:66
CargoType GetRefitCargo() const
Get the cargo to to refit to.
Definition order_base.h:127
bool IsFullLoadOrder() const
Is this order a OrderLoadType::FullLoad or OrderLoadType::FullLoadAny?
Definition order_base.h:135
void MakeDummy()
Makes this order a Dummy order.
OrderLoadType GetLoadType() const
How must the consist be loaded?
Definition order_base.h:142
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition order_base.h:152
bool ShouldStopAtStation(const Vehicle *v, StationID station) const
Check whether the given vehicle should stop at the given station based on this order and the non-stop...
void MakeImplicit(StationID destination)
Makes this order an implicit order.
bool IsRefit() const
Is this order a refit order.
Definition order_base.h:113
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static size_t GetPoolSize()
Returns first unused index.
static T * Create(Targs &&... args)
Creates a new T-object in the associated pool.
static Titem * Get(auto index)
Returns Titem with given index.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
const Tindex index
Index of this pool item.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Base class for all pools.
Information about a rail vehicle.
Definition engine_type.h:74
EngineClass engclass
Class of engine for this vehicle.
Definition engine_type.h:86
Specification of a rectangle with absolute coordinates of all edges.
A Stop for a Road Vehicle.
void Leave(RoadVehicle *rv)
Leave the road stop.
Definition roadstop.cpp:203
RoadStop * next
Next stop of the given type at this station.
TileIndex xy
Position on the map.
static RoadStop * GetByTile(TileIndex tile, RoadStopType type)
Find a roadstop at given tile.
Definition roadstop.cpp:253
Information about a road vehicle.
RoadType roadtype
Road type.
Buses, trucks and trams belong to this class.
Definition roadveh.h:98
uint8_t state
Definition roadveh.h:100
RoadTypes compatible_roadtypes
NOSAVE: Roadtypes this consist is powered on.
Definition roadveh.h:110
bool IsBus() const
Check whether a roadvehicle is a bus.
RoadType roadtype
NOSAVE: Roadtype of this vehicle.
Definition roadveh.h:108
VehicleID disaster_vehicle
NOSAVE: Disaster vehicle targetting this vehicle.
Definition roadveh.h:109
Information about a ship vehicle.
Definition engine_type.h:99
All ships have this type.
Definition ship.h:32
TrackBits state
The "track" the ship is following.
Definition ship.h:34
void UpdateCache()
Update the caches of this ship.
Definition ship_cmd.cpp:231
static bool IsValidID(auto index)
Tests whether given index is a valid index for station of this type.
static Station * Get(auto index)
Gets station with given index.
static Station * GetIfValid(auto index)
Returns station if the index is a valid index for this station type.
T * Next() const
Get next vehicle in the chain.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
void UpdateViewport(bool force_update, bool update_delta)
Update vehicle sprite- and position caches.
T * GetFirstEnginePart()
Get the first part of an articulated engine.
Data structure describing a sprite.
uint16_t width
Width of the sprite.
uint16_t height
Height of the sprite.
int16_t y_offs
Number of pixels to shift the sprite downwards.
int16_t x_offs
Number of pixels to shift the sprite to the right.
Station data structure.
std::array< GoodsEntry, NUM_CARGO > goods
Goods at this station.
Airport airport
Tile area the airport covers.
VehicleEnterTileProc * vehicle_enter_tile_proc
Called when a vehicle enters a tile.
Definition tile_cmd.h:164
'Train' is either a loco or a wagon.
Definition train.h:91
void ConsistChanged(ConsistChangeFlags allowed_changes)
Recalculates the cached stuff of a train.
uint16_t wait_counter
Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through sign...
Definition train.h:94
uint8_t cached_vis_effect
Visual effect to show (see VisualEffect)
uint16_t cached_cargo_age_period
Number of ticks before carried cargo is aged.
The information about a vehicle list.
Definition vehiclelist.h:32
WindowNumber ToWindowNumber() const
Pack a VehicleListIdentifier in 32 bits so it can be used as unique WindowNumber.
UnitID max_ships
max ships in game per company
UnitID max_trains
max trains in game per company
uint8_t smoke_amount
amount of smoke/sparks locomotives produce
UnitID max_aircraft
max planes in game per company
UnitID max_roadveh
max trucks in game per company
Sprite sequence for a vehicle part.
bool IsValid() const
Check whether the sequence contains any sprites.
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition vehicle.cpp:142
Vehicle data structure.
Money GetDisplayProfitThisYear() const
Gets the profit vehicle had this year.
CargoPayment * cargo_payment
The cargo payment we're currently in.
EngineID engine_type
The type of engine used for this vehicle.
uint16_t cargo_age_counter
Ticks till cargo is aged next.
int32_t z_pos
z coordinate.
uint16_t & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition vehicle.cpp:3174
Direction direction
facing
void ShiftDates(TimerGameEconomy::Date interval)
Shift all dates by given interval.
Definition vehicle.cpp:749
const Order * GetLastOrder() const
Returns the last order of a vehicle, or nullptr if it doesn't exists.
TimerGameEconomy::Date economy_age
Age in economy days.
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition vehicle.cpp:719
virtual uint Crash(bool flooded=false)
Crash the (whole) vehicle chain.
Definition vehicle.cpp:291
Order * GetOrder(int index) const
Returns order 'index' of a vehicle or nullptr when it doesn't exists.
bool HasDepotOrder() const
Checks if a vehicle has a depot in its order list.
void LeaveStation()
Perform all actions when leaving a station.
Definition vehicle.cpp:2328
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:2957
VehicleCargoList cargo
The cargo this vehicle is carrying.
Vehicle ** hash_tile_prev
NOSAVE: Previous vehicle in the tile location hash.
bool HasUnbunchingOrder() const
Check if the current vehicle has an unbunching order.
Definition vehicle.cpp:2463
TimerGameEconomy::Date date_of_last_service
Last economy date the vehicle had a service at a depot.
uint16_t cargo_cap
total capacity
StationID last_loading_station
Last station the vehicle has stopped at and could possibly leave from with any cargo loaded.
const Order * GetFirstOrder() const
Get the first order of the vehicles order list.
CommandCost SendToDepot(DoCommandFlags flags, DepotCommandFlags command)
Send this vehicle to the depot using the given command(s).
Definition vehicle.cpp:2556
void ReleaseUnitNumber()
Release the vehicle's unit number.
Definition vehicle.cpp:2397
void UpdateBoundingBoxCoordinates(bool update_cache) const
Update the bounding box co-ordinates of the vehicle.
Definition vehicle.cpp:1672
uint8_t day_counter
Increased by one for each day.
void HandleLoading(bool mode=false)
Handle the loading of the vehicle; when not it skips through dummy orders and does nothing in all oth...
Definition vehicle.cpp:2408
Money profit_this_year
Profit this year << 8, low 8 bits are fract.
bool HasArticulatedPart() const
Check if an engine has an articulated part.
SpriteID colourmap
NOSAVE: cached colour mapping.
uint8_t breakdown_ctr
Counter for managing breakdown events.
uint8_t breakdown_delay
Counter for managing breakdown length.
Vehicle * GetNextVehicle() const
Get the next real (non-articulated part) vehicle in the consist.
GroupID group_id
Index of group Pool array.
void IncrementImplicitOrderIndex()
Increments cur_implicit_order_index, keeps care of the wrap-around and invalidates the GUI.
bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
VehStates vehstatus
Status.
TimerGameCalendar::Date date_of_last_service_newgrf
Last calendar date the vehicle had a service at a depot, unchanged by the date cheat to protect again...
Vehicle * first
NOSAVE: pointer to the first vehicle in the chain.
void CancelReservation(StationID next, Station *st)
Return all reserved cargo packets to the station and reset all packets staged for transfer.
Definition vehicle.cpp:2312
Money profit_last_year
Profit last year << 8, low 8 bits are fract.
bool IsEngineCountable() const
Check if a vehicle is counted in num_engines in each company struct.
Definition vehicle.cpp:686
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
bool NeedsAutorenewing(const Company *c, bool use_renew_setting=true) const
Function to tell if a vehicle needs to be autorenewed.
Definition vehicle.cpp:156
void UpdateVisualEffect(bool allow_power_change=true)
Update the cached visual effect.
Definition vehicle.cpp:2637
void LeaveUnbunchingDepot()
Leave an unbunching depot and calculate the next departure time for shared order vehicles.
Definition vehicle.cpp:2487
CargoType cargo_type
type of cargo this vehicle is carrying
Vehicle * previous_shared
NOSAVE: pointer to the previous vehicle in the shared order chain.
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Order current_order
The current order (+ status, like: loading)
void PreDestructor()
Destroy all stuff that (still) needs the virtual functions to work properly.
Definition vehicle.cpp:797
Vehicle(VehicleID index, VehicleType type=VEH_INVALID)
Vehicle constructor.
Definition vehicle.cpp:370
void HandlePathfindingResult(bool path_found)
Handle the pathfinding result, especially the lost status.
Definition vehicle.cpp:763
Vehicle * Next() const
Get the next vehicle of this vehicle.
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
const GRFFile * GetGRF() const
Retrieve the NewGRF the vehicle is tied to.
Definition vehicle.cpp:729
OrderList * orders
Pointer to the order list for this vehicle.
uint32_t GetDisplayMinPowerToWeight() const
Calculates the minimum power-to-weight ratio using the maximum weight of the ground vehicle.
Definition vehicle.cpp:3248
void UpdateViewport(bool dirty)
Update the vehicle on the viewport, updating the right hash and setting the new coordinates.
Definition vehicle.cpp:1717
Money value
Value of the vehicle.
bool MarkAllViewportsDirty() const
Marks viewports dirty where the vehicle's image is.
Definition vehicle.cpp:1756
uint16_t refit_cap
Capacity left over from before last refit.
VehicleCache vcache
Cache of often used vehicle values.
uint32_t motion_counter
counter to occasionally play a vehicle sound.
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition vehicle.cpp:739
SpriteBounds bounds
Bounding box of vehicle.
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition vehicle.cpp:3144
virtual void OnNewEconomyDay()
Calls the new economy day handler of the vehicle.
Vehicle ** hash_tile_current
NOSAVE: Cache of the current hash chain.
virtual void OnNewCalendarDay()
Calls the new calendar day handler of the vehicle.
Vehicle * NextShared() const
Get the next vehicle of the shared vehicle chain.
bool HasFullLoadOrder() const
Check if the current vehicle has a full load order.
Definition vehicle.cpp:2443
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
void BeginLoading()
Prepare everything to begin the loading when arriving at a station.
Definition vehicle.cpp:2184
Vehicle * hash_tile_next
NOSAVE: Next vehicle in the tile location hash.
uint16_t cur_speed
current speed
Vehicle * previous
NOSAVE: pointer to the previous vehicle in the chain.
~Vehicle() override
We want to 'destruct' the right class.
Definition vehicle.cpp:864
bool IsFrontEngine() const
Check if the vehicle is a front engine.
bool HasEngineType() const
Check whether Vehicle::engine_type has any meaning.
Definition vehicle.cpp:703
TimerGameCalendar::Date age
Age in calendar days.
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition vehicle.cpp:2534
TextEffectID fill_percent_te_id
a text-effect id to a loading indicator object
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition vehicle.cpp:2928
uint8_t breakdowns_since_last_service
Counter for the amount of breakdowns.
Vehicle * next
pointer to the next vehicle in the chain
TimerGameCalendar::Date max_age
Maximum age.
MutableSpriteCache sprite_cache
Cache of sprites and values related to recalculating them, see MutableSpriteCache.
uint16_t reliability
Reliability.
uint32_t GetDisplayMaxWeight() const
Calculates the maximum weight of the ground vehicle when loaded.
Definition vehicle.cpp:3233
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition vehicle.cpp:2980
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds,...
Definition vehicle.cpp:1333
void UpdatePositionAndViewport()
Update the position of the vehicle, and update the viewport.
Definition vehicle.cpp:1746
Vehicle * Previous() const
Get the previous vehicle of this vehicle.
Rect coord
NOSAVE: Graphical bounding box of the vehicle, i.e. what to redraw on moves.
uint16_t reliability_spd_dec
Reliability decrease speed.
uint8_t tick_counter
Increased by one for each tick.
TileIndex tile
Current tile index.
virtual bool Tick()
Calls the tick handler of the vehicle.
TileIndex dest_tile
Heading for this tile.
bool NeedsServicing() const
Check if the vehicle needs to go to a depot in near future (if a opportunity presents itself) for ser...
Definition vehicle.cpp:201
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition vehicle.cpp:2454
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1663
StationID last_station_visited
The last station we stopped at.
void ResetRefitCaps()
Reset all refit_cap in the consist to cargo_cap.
Definition vehicle.cpp:2389
uint8_t breakdown_chance
Current chance of breakdowns.
void ShowVisualEffect() const
Draw visual effects (smoke and/or sparks) for a vehicle chain.
Definition vehicle.cpp:2778
Owner owner
Which company owns the vehicle?
Vehicle * next_shared
pointer to the next vehicle that shares the order
bool NeedsAutomaticServicing() const
Checks if the current order should be interrupted for a service-in-depot order.
Definition vehicle.cpp:283
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition vehicle.cpp:2146
Vehicle ** hash_viewport_prev
NOSAVE: Previous vehicle in the visual location hash.
virtual void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
Gets the sprite to show for the given direction.
Vehicle * hash_viewport_next
NOSAVE: Next vehicle in the visual location hash.
Data structure for viewport, display of a part of the world.
int top
Screen coordinate top edge of the viewport.
int width
Screen width of the viewport.
ZoomLevel zoom
The zoom level of the viewport.
int virtual_top
Virtual top coordinate.
int virtual_left
Virtual left coordinate.
int left
Screen coordinate left edge of the viewport.
int height
Screen height of the viewport.
VehicleEnterTileStates VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
Call the tile callback function for a vehicle entering a tile.
Definition vehicle.cpp:1820
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition tile_map.h:312
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
static constexpr int MAX_VEHICLE_PIXEL_Y
Maximum height of a vehicle in pixels in ZOOM_BASE.
Definition tile_type.h:22
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
static constexpr int MAX_VEHICLE_PIXEL_X
Maximum width of a vehicle in pixels in ZOOM_BASE.
Definition tile_type.h:21
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.
Functions related to time tabling.
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
Update the timetable for the vehicle.
bool TracksOverlap(TrackBits bits)
Checks if the given tracks overlap, ie form a crossing.
Definition track_func.h:645
TrackBits
Allow incrementing of Track variables.
Definition track_type.h:35
@ TRACK_BIT_DEPOT
Bitflag for a depot.
Definition track_type.h:53
Base for the train class.
@ Reversed
Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle ...
Definition train.h:31
@ Flipped
Reverse the visible direction of the vehicle.
Definition train.h:28
@ LeavingStation
Train is just leaving a station.
Definition train.h:33
@ Reversing
Train is slowing down to reverse.
Definition train.h:26
@ TFP_NONE
Normal operation.
Definition train.h:39
static constexpr ConsistChangeFlags CCF_ARRANGE
Valid changes for arranging the consist in a depot.
Definition train.h:56
Command definitions related to trains.
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
TransparencyOption
Transparency option bits: which position in _transparency_opt stands for which transparency.
@ TO_INVALID
Invalid transparency option.
uint16_t UnitID
Type for the company global vehicle unit number.
Map accessors for tunnels.
bool IsTunnelTile(Tile t)
Is this a tunnel (entrance)?
Definition tunnel_map.h:34
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBug bug_type, bool critical)
Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
Definition vehicle.cpp:328
static uint GetTileHash(uint x, uint y)
Compute hash for tile coordinate.
Definition vehicle.cpp:422
static void VehicleEnteredDepotThisTick(Vehicle *v)
Adds a vehicle to the list of vehicles that visited a depot this tick.
Definition vehicle.cpp:892
static void SpawnAdvancedVisualEffect(const Vehicle *v)
Call CBID_VEHICLE_SPAWN_VISUAL_EFFECT and spawn requested effects.
Definition vehicle.cpp:2705
static uint GetTileHash1D(uint p)
Compute hash for 1D tile coordinate.
Definition vehicle.cpp:398
void VehicleLengthChanged(const Vehicle *u)
Logs a bug in GRF and shows a warning message if this is for the first time this happened.
Definition vehicle.cpp:354
VehiclePool _vehicle_pool("Vehicle")
The pool with all our precious vehicles.
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition vehicle.cpp:178
static void RunEconomyVehicleDayProc()
Increases the day counter for all vehicles and calls 1-day and 32-day handlers.
Definition vehicle.cpp:925
static uint ComposeTileHash(uint hx, uint hy)
Compose two 1D hashes into 2D hash.
Definition vehicle.cpp:414
static uint IncTileHash1D(uint h)
Increment 1D hash to next bucket.
Definition vehicle.cpp:406
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3047
Vehicle * CheckClickOnVehicle(const Viewport &vp, int x, int y)
Find the vehicle close to the clicked coordinates.
Definition vehicle.cpp:1216
std::map< VehicleID, bool > AutoreplaceMap
List of vehicles that should check for autoreplace this tick.
Definition vehicle.cpp:666
static bool IsBridgeAboveVehicle(const Vehicle *v)
Test if a bridge is above a vehicle.
Definition vehicle.cpp:2763
static bool PreviousOrderIsUnbunching(const Vehicle *v)
Check if the previous order is a depot unbunching order.
Definition vehicle.cpp:2474
static void DoDrawVehicle(const Vehicle *v)
Add vehicle sprite for drawing to the screen.
Definition vehicle.cpp:1093
@ Unclickable
Vehicle is not clickable by the user (shadow vehicles).
@ Crashed
Vehicle is crashed.
@ Shadow
Vehicle is a shadow vehicle.
@ TrainSlowing
Train is slowing down.
@ AircraftBroken
Aircraft is broken down.
@ Hidden
Vehicle is not visible.
@ DefaultPalette
Use default vehicle palette.
@ Stopped
Vehicle is stopped by the player.
VisualEffectSpawnModel
Models for spawning visual effects.
@ VESM_ELECTRIC
Electric model.
@ VESM_STEAM
Steam model.
@ VESM_DIESEL
Diesel model.
@ VESM_NONE
No visual effect.
static const int32_t INVALID_COORD
Sentinel for an invalid coordinate.
Command definitions for vehicles.
Functions related to vehicles.
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBug bug_type, bool critical)
Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
Definition vehicle.cpp:328
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:528
bool VehiclesHaveSameEngineList(const Vehicle *v1, const Vehicle *v2)
Checks if two vehicle chains have the same list of engines.
Definition vehicle.cpp:3261
bool VehiclesHaveSameOrderList(const Vehicle *v1, const Vehicle *v2)
Checks if two vehicles have the same list of orders.
Definition vehicle.cpp:3278
SpriteID GetEnginePalette(EngineID engine_type, CompanyID company)
Get the colour map for an engine.
Definition vehicle.cpp:2124
void VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition vehicle.cpp:1521
static const TimerGameEconomy::Date VEHICLE_PROFIT_MIN_AGE
Only vehicles older than this have a meaningful profit.
void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8_t num_vehicles)
Calculates the set of vehicles that will be affected by a given selection.
Definition vehicle.cpp:3207
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition vehicle.cpp:1877
void RunVehicleCalendarDayProc()
Age all vehicles, spreading out the action using the current TimerGameCalendar::date_fract.
Definition vehicle.cpp:908
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition vehicle.cpp:178
CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
Tests if a vehicle interacts with the specified track bits.
Definition vehicle.cpp:576
LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
Determines the LiveryScheme for a vehicle.
Definition vehicle.cpp:1952
void ViewportAddVehicles(DrawPixelInfo *dpi)
Add the vehicle sprites that should be drawn at a part of the screen.
Definition vehicle.cpp:1122
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition vehicle.cpp:1766
StringID GetVehicleCannotUseStationReason(const Vehicle *v, const Station *st)
Get reason string why this station can't be used by the given vehicle.
Definition vehicle.cpp:3093
void ReleaseDisasterVehicle(VehicleID vehicle)
Notify disasters that we are about to delete a vehicle.
void DecreaseVehicleValue(Vehicle *v)
Decrease the value of a vehicle.
Definition vehicle.cpp:1271
void EconomyAgeVehicle(Vehicle *v)
Update economy age of a vehicle.
Definition vehicle.cpp:1399
const struct Livery * GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, uint8_t livery_setting)
Determines the livery for a vehicle.
Definition vehicle.cpp:2046
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore=nullptr)
Finds vehicle in tunnel / bridge.
Definition vehicle.cpp:552
bool CanBuildVehicleInfrastructure(VehicleType type, uint8_t subtype=0)
Check whether we can build infrastructure for the given vehicle type.
Definition vehicle.cpp:1904
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition vehicle.cpp:1411
SpriteID GetVehiclePalette(const Vehicle *v)
Get the colour map for a vehicle.
Definition vehicle.cpp:2134
uint8_t CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1462
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
@ VIWD_MODIFY_ORDERS
Other order modifications.
Definition vehicle_gui.h:36
WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition vehicle_gui.h:97
@ EIT_ON_MAP
Vehicle drawn in viewport.
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_DISASTER
Disaster vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_EFFECT
Effect vehicle type (smoke, explosions, sparks, bubbles)
@ VEH_TRAIN
Train vehicle type.
@ Callback32
All vehicles in consist: 32 day callback requested rerandomisation.
@ Depot
Front vehicle only: Consist arrived in depot.
@ DontCancel
Don't cancel current goto depot command if any.
@ Service
The vehicle will leave the depot right after arrival (service only)
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
Functions and type for generating vehicle lists.
@ VL_SHARED_ORDERS
Index is the first vehicle of the shared orders.
Definition vehiclelist.h:24
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition viewport.cpp:764
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:663
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:774
Functions related to (drawing on) viewports.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1195
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3208
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3300
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, WidgetID widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition window.cpp:3194
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3178
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition window.cpp:3318
@ WC_ROADVEH_LIST
Road vehicle list; Window numbers:
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
@ WC_SHIPS_LIST
Ships list; Window numbers:
@ WC_STATION_VIEW
Station view; Window numbers:
@ WC_TRAINS_LIST
Trains list; Window numbers:
@ WC_VEHICLE_REFIT
Vehicle refit; Window numbers:
@ WC_VEHICLE_DETAILS
Vehicle details; Window numbers:
@ WC_COMPANY
Company view; Window numbers:
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
@ WC_VEHICLE_TIMETABLE
Vehicle timetable; Window numbers:
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers:
Functions related to zooming.
int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZoomLevel::Min) When shifting right,...
Definition zoom_func.h:22