OpenTTD Source 20260421-master-gc2fbc6fdeb
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
9
10#include "stdafx.h"
11#include "error.h"
12#include "roadveh.h"
13#include "ship.h"
14#include "spritecache.h"
15#include "timetable.h"
16#include "viewport_func.h"
17#include "news_func.h"
18#include "command_func.h"
19#include "company_func.h"
20#include "train.h"
21#include "aircraft.h"
22#include "newgrf_debug.h"
23#include "newgrf_sound.h"
24#include "newgrf_station.h"
25#include "group_gui.h"
26#include "strings_func.h"
27#include "zoom_func.h"
28#include "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
70static const uint GEN_HASHX_BITS = 6;
71static const uint GEN_HASHY_BITS = 6;
73
76static const uint GEN_HASHX_BUCKET_BITS = 7;
77static const uint GEN_HASHY_BUCKET_BITS = 6;
79
80/* Compute hash for vehicle coord */
81static inline uint GetViewportHashX(int x)
82{
83 return GB(x, GEN_HASHX_BUCKET_BITS + ZOOM_BASE_SHIFT, GEN_HASHX_BITS);
84}
85
86static inline uint GetViewportHashY(int y)
87{
88 return GB(y, GEN_HASHY_BUCKET_BITS + ZOOM_BASE_SHIFT, GEN_HASHY_BITS) << GEN_HASHX_BITS;
89}
90
91static inline uint GetViewportHash(int x, int y)
92{
93 return GetViewportHashX(x) + GetViewportHashY(y);
94}
95
98static const uint GEN_HASHX_SIZE = 1 << (GEN_HASHX_BUCKET_BITS + GEN_HASHX_BITS + ZOOM_BASE_SHIFT);
99static const uint GEN_HASHY_SIZE = 1 << (GEN_HASHY_BUCKET_BITS + GEN_HASHY_BITS + ZOOM_BASE_SHIFT);
101
104static const uint GEN_HASHX_INC = 1;
105static const uint GEN_HASHY_INC = 1 << GEN_HASHX_BITS;
107
110static const uint GEN_HASHX_MASK = (1 << GEN_HASHX_BITS) - 1;
111static const uint GEN_HASHY_MASK = ((1 << GEN_HASHY_BITS) - 1) << GEN_HASHX_BITS;
113
117
118
119
123void VehicleSpriteSeq::GetBounds(Rect *bounds) const
124{
125 bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
126 for (uint i = 0; i < this->count; ++i) {
127 const Sprite *spr = GetSprite(this->seq[i].sprite, SpriteType::Normal);
128 if (i == 0) {
129 bounds->left = spr->x_offs;
130 bounds->top = spr->y_offs;
131 bounds->right = spr->width + spr->x_offs - 1;
132 bounds->bottom = spr->height + spr->y_offs - 1;
133 } else {
134 if (spr->x_offs < bounds->left) bounds->left = spr->x_offs;
135 if (spr->y_offs < bounds->top) bounds->top = spr->y_offs;
136 int right = spr->width + spr->x_offs - 1;
137 int bottom = spr->height + spr->y_offs - 1;
138 if (right > bounds->right) bounds->right = right;
139 if (bottom > bounds->bottom) bounds->bottom = bottom;
140 }
141 }
142}
143
151void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const
152{
153 for (uint i = 0; i < this->count; ++i) {
154 PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal;
155 DrawSprite(this->seq[i].sprite, pal, x, y);
156 }
157}
158
165bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
166{
167 /* We can always generate the Company pointer when we have the vehicle.
168 * However this takes time and since the Company pointer is often present
169 * when this function is called then it's faster to pass the pointer as an
170 * argument rather than finding it again. */
171 assert(c == Company::Get(this->owner));
172
173 if (use_renew_setting && !c->settings.engine_renew) return false;
174 if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
175
176 /* Only engines need renewing */
177 if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
178
179 return true;
180}
181
188{
189 assert(v != nullptr);
190 SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
191
192 do {
197 /* Prevent vehicles from breaking down directly after exiting the depot. */
198 v->breakdown_chance /= 4;
199 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::Reduced) v->breakdown_chance = 0; // on reduced breakdown
200 v = v->Next();
201 } while (v != nullptr && v->HasEngineType());
202}
203
211{
212 /* Stopped or crashed vehicles will not move, as such making unmovable
213 * vehicles to go for service is lame. */
214 if (this->vehstatus.Any({VehState::Stopped, VehState::Crashed})) return false;
215
216 /* Are we ready for the next service cycle? */
217 const Company *c = Company::Get(this->owner);
218
219 /* Service intervals can be measured in different units, which we handle individually. */
220 if (this->ServiceIntervalIsPercent()) {
221 /* Service interval is in percents. */
222 if (this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) return false;
224 /* Service interval is in minutes. */
225 if (this->date_of_last_service + (this->GetServiceInterval() * EconomyTime::DAYS_IN_ECONOMY_MONTH) >= TimerGameEconomy::date) return false;
226 } else {
227 /* Service interval is in days. */
228 if (this->date_of_last_service + this->GetServiceInterval() >= TimerGameEconomy::date) return false;
229 }
230
231 /* If we're servicing anyway, because we have not disabled servicing when
232 * there are no breakdowns or we are playing with breakdowns, bail out. */
233 if (!_settings_game.order.no_servicing_if_no_breakdowns ||
234 _settings_game.difficulty.vehicle_breakdowns != VehicleBreakdowns::None) {
235 return true;
236 }
237
238 /* Test whether there is some pending autoreplace.
239 * Note: We do this after the service-interval test.
240 * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
241 bool pending_replace = false;
242 Money needed_money = c->settings.engine_renew_money;
243 if (needed_money > GetAvailableMoney(c->index)) return false;
244
245 for (const Vehicle *v = this; v != nullptr; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : nullptr) {
246 bool replace_when_old = false;
247 EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
248
249 /* Check engine availability */
250 if (new_engine == EngineID::Invalid() || !Engine::Get(new_engine)->company_avail.Test(v->owner)) continue;
251 /* Is the vehicle old if we are not always replacing? */
252 if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
253
254 /* Check refittability */
255 CargoTypes available_cargo_types, union_mask;
256 GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
257 /* Is there anything to refit? */
258 if (union_mask != 0) {
260 CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type);
261 if (!HasAtMostOneBit(cargo_mask)) {
262 CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(new_engine);
263 if ((cargo_mask & new_engine_default_cargoes) != cargo_mask) {
264 /* We cannot refit to mixed cargoes in an automated way */
265 continue;
266 }
267 /* engine_type is already a mixed cargo type which matches the incoming vehicle by default, no refit required */
268 } else {
269 /* Did the old vehicle carry anything? */
271 /* We can't refit the vehicle to carry the cargo we want */
272 if (!HasBit(available_cargo_types, cargo_type)) continue;
273 }
274 }
275 }
276
277 /* Check money.
278 * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
279 pending_replace = true;
280 needed_money += 2 * Engine::Get(new_engine)->GetCost();
281 if (needed_money > GetAvailableMoney(c->index)) return false;
282 }
283
284 return pending_replace;
285}
286
293{
294 if (this->HasDepotOrder()) return false;
295 if (this->current_order.IsType(OT_LOADING)) return false;
296 if (this->current_order.IsType(OT_GOTO_DEPOT) && !this->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::Service)) return false;
297 return NeedsServicing();
298}
299
301{
302 assert(!this->vehstatus.Test(VehState::Crashed));
303 assert(this->Previous() == nullptr); // IsPrimaryVehicle fails for free-wagon-chains
304
305 uint pass = 0;
306 /* Stop the vehicle. */
307 if (this->IsPrimaryVehicle()) this->vehstatus.Set(VehState::Stopped);
308 /* crash all wagons, and count passengers */
309 for (Vehicle *v = this; v != nullptr; v = v->Next()) {
310 /* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */
311 if (IsCargoInClass(v->cargo_type, CargoClass::Passengers)) pass += v->cargo.TotalCount();
312 v->vehstatus.Set(VehState::Crashed);
313 v->MarkAllViewportsDirty();
314 }
315
316 /* Dirty some windows */
321
322 delete this->cargo_payment;
323 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
324
325 return RandomRange(pass + 1); // Randomise deceased passengers.
326}
327
328
337void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBug bug_type, bool critical)
338{
339 const Engine *e = Engine::Get(engine);
340 GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
341
342 /* Missing GRF. Nothing useful can be done in this situation. */
343 if (grfconfig == nullptr) return;
344
345 if (!grfconfig->grf_bugs.Test(bug_type)) {
346 grfconfig->grf_bugs.Set(bug_type);
347 ShowErrorMessage(GetEncodedString(part1, grfconfig->GetName()),
348 GetEncodedString(part2, std::monostate{}, engine), WL_CRITICAL);
349 if (!_networking) Command<Commands::Pause>::Do(DoCommandFlag::Execute, critical ? PauseMode::Error : PauseMode::Normal, true);
350 }
351
352 /* debug output */
353 Debug(grf, 0, "{}", StrMakeValid(GetString(part1, grfconfig->GetName())));
354
355 Debug(grf, 0, "{}", StrMakeValid(GetString(part2, std::monostate{}, engine)));
356}
357
364{
365 /* show a warning once for each engine in whole game and once for each GRF after each game load */
366 const Engine *engine = u->GetEngine();
367 uint32_t grfid = engine->grf_prop.grfid;
368 GRFConfig *grfconfig = GetGRFConfig(grfid);
369 if (_gamelog.GRFBugReverse(grfid, engine->grf_prop.local_id) || !grfconfig->grf_bugs.Test(GRFBug::VehLength)) {
370 ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GRFBug::VehLength, true);
371 }
372}
373
380{
381 this->type = type;
382 this->coord.left = INVALID_COORD;
383 this->sprite_cache.old_coord.left = INVALID_COORD;
384 this->group_id = DEFAULT_GROUP;
385 this->fill_percent_te_id = INVALID_TE_ID;
386 this->first = this;
387 this->last = this;
388 this->colourmap = PAL_NONE;
389 this->cargo_age_counter = 1;
390 this->last_station_visited = StationID::Invalid();
391 this->last_loading_station = StationID::Invalid();
392}
393
398constexpr uint TILE_HASH_BITS = 7;
399constexpr uint TILE_HASH_SIZE = 1 << TILE_HASH_BITS;
400constexpr uint TILE_HASH_MASK = TILE_HASH_SIZE - 1;
401constexpr uint TOTAL_TILE_HASH_SIZE = 1 << (TILE_HASH_BITS * 2);
403
408constexpr uint TILE_HASH_RES = 0;
409
415static inline uint GetTileHash1D(uint p)
416{
417 return GB(p, TILE_HASH_RES, TILE_HASH_BITS);
418}
419
425static inline uint IncTileHash1D(uint h)
426{
427 return (h + 1) & TILE_HASH_MASK;
428}
429
436static inline uint ComposeTileHash(uint hx, uint hy)
437{
438 return hx | hy << TILE_HASH_BITS;
439}
440
447static inline uint GetTileHash(uint x, uint y)
448{
450}
451
452static std::array<Vehicle *, TOTAL_TILE_HASH_SIZE> _vehicle_tile_hash{};
453
461VehiclesNearTileXY::Iterator::Iterator(int32_t x, int32_t y, uint max_dist)
462{
463 /* There are no negative tile coordinates */
464 this->pos_rect.left = std::max<int>(0, x - max_dist);
465 this->pos_rect.right = std::max<int>(0, x + max_dist);
466 this->pos_rect.top = std::max<int>(0, y - max_dist);
467 this->pos_rect.bottom = std::max<int>(0, y + max_dist);
468
469 if (2 * max_dist < TILE_HASH_MASK * TILE_SIZE) {
470 /* Hash area to scan */
471 this->hxmin = this->hx = GetTileHash1D(this->pos_rect.left / TILE_SIZE);
472 this->hxmax = GetTileHash1D(this->pos_rect.right / TILE_SIZE);
473 this->hymin = this->hy = GetTileHash1D(this->pos_rect.top / TILE_SIZE);
474 this->hymax = GetTileHash1D(this->pos_rect.bottom / TILE_SIZE);
475 } else {
476 /* Scan all */
477 this->hxmin = this->hx = 0;
478 this->hxmax = TILE_HASH_MASK;
479 this->hymin = this->hy = 0;
480 this->hymax = TILE_HASH_MASK;
481 }
482
483 this->current_veh = _vehicle_tile_hash[ComposeTileHash(this->hx, this->hy)];
484 this->SkipEmptyBuckets();
485 this->SkipFalseMatches();
486}
487
492{
493 assert(this->current_veh != nullptr);
494 this->current_veh = this->current_veh->hash_tile_next;
495 this->SkipEmptyBuckets();
496}
497
502{
503 while (this->current_veh == nullptr) {
504 if (this->hx != this->hxmax) {
505 this->hx = IncTileHash1D(this->hx);
506 } else if (this->hy != this->hymax) {
507 this->hx = this->hxmin;
508 this->hy = IncTileHash1D(this->hy);
509 } else {
510 return;
511 }
512 this->current_veh = _vehicle_tile_hash[ComposeTileHash(this->hx, this->hy)];
513 }
514}
515
520{
521 while (this->current_veh != nullptr && !this->pos_rect.Contains({this->current_veh->x_pos, this->current_veh->y_pos})) this->Increment();
522}
523
530{
531 this->current = _vehicle_tile_hash[GetTileHash(TileX(tile), TileY(tile))];
532 this->SkipFalseMatches();
533}
534
540{
541 this->current = this->current->hash_tile_next;
542}
543
548{
549 while (this->current != nullptr && this->current->tile != this->tile) this->Increment();
550}
551
558{
559 int z = GetTileMaxPixelZ(tile);
560
561 /* Value v is not safe in MP games, however, it is used to generate a local
562 * error message only (which may be different for different machines).
563 * Such a message does not affect MP synchronisation.
564 */
565 for (const Vehicle *v : VehiclesOnTile(tile)) {
566 if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) continue;
567 if (v->z_pos > z) continue;
568
569 return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
570 }
571 return CommandCost();
572}
573
582{
583 for (TileIndex t : {tile, endtile}) {
584 /* Value v is not safe in MP games, however, it is used to generate a local
585 * error message only (which may be different for different machines).
586 * Such a message does not affect MP synchronisation.
587 */
588 for (const Vehicle *v : VehiclesOnTile(t)) {
589 if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) continue;
590 if (v == ignore) continue;
591 return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
592 }
593 }
594 return CommandCost();
595}
596
606{
607 /* Value v is not safe in MP games, however, it is used to generate a local
608 * error message only (which may be different for different machines).
609 * Such a message does not affect MP synchronisation.
610 */
611 for (const Vehicle *v : VehiclesOnTile(tile)) {
612 if (v->type != VEH_TRAIN) continue;
613
614 const Train *t = Train::From(v);
615 if ((t->track != track_bits) && !TracksOverlap(t->track | track_bits)) continue;
616
617 return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
618 }
619 return CommandCost();
620}
621
622static void UpdateVehicleTileHash(Vehicle *v, bool remove)
623{
624 Vehicle **old_hash = v->hash_tile_current;
625 Vehicle **new_hash;
626
627 if (remove) {
628 new_hash = nullptr;
629 } else {
630 new_hash = &_vehicle_tile_hash[GetTileHash(TileX(v->tile), TileY(v->tile))];
631 }
632
633 if (old_hash == new_hash) return;
634
635 /* Remove from the old position in the hash table */
636 if (old_hash != nullptr) {
639 }
640
641 /* Insert vehicle at beginning of the new position in the hash table */
642 if (new_hash != nullptr) {
643 v->hash_tile_next = *new_hash;
644 if (v->hash_tile_next != nullptr) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next;
645 v->hash_tile_prev = new_hash;
646 *new_hash = v;
647 }
648
649 /* Remember current hash position */
650 v->hash_tile_current = new_hash;
651}
652
653static std::array<Vehicle *, 1 << (GEN_HASHX_BITS + GEN_HASHY_BITS)> _vehicle_viewport_hash{};
654
655static void UpdateVehicleViewportHash(Vehicle *v, int x, int y, int old_x, int old_y)
656{
657 Vehicle **old_hash, **new_hash;
658
659 new_hash = (x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GetViewportHash(x, y)];
660 old_hash = (old_x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GetViewportHash(old_x, old_y)];
661
662 if (old_hash == new_hash) return;
663
664 /* remove from hash table? */
665 if (old_hash != nullptr) {
668 }
669
670 /* insert into hash table? */
671 if (new_hash != nullptr) {
672 v->hash_viewport_next = *new_hash;
674 v->hash_viewport_prev = new_hash;
675 *new_hash = v;
676 }
677}
678
679void ResetVehicleHash()
680{
681 for (Vehicle *v : Vehicle::Iterate()) { v->hash_tile_current = nullptr; }
682 _vehicle_viewport_hash.fill(nullptr);
683 _vehicle_tile_hash.fill(nullptr);
684}
685
686void ResetVehicleColourMap()
687{
688 for (Vehicle *v : Vehicle::Iterate()) { v->colourmap = PAL_NONE; }
689}
690
695using AutoreplaceMap = std::map<VehicleID, bool>;
696static AutoreplaceMap _vehicles_to_autoreplace;
697
698void InitializeVehicles()
699{
700 _vehicles_to_autoreplace.clear();
701 ResetVehicleHash();
702}
703
704uint CountVehiclesInChain(const Vehicle *v)
705{
706 uint count = 0;
707 do count++; while ((v = v->Next()) != nullptr);
708 return count;
709}
710
716{
717 switch (this->type) {
718 case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
719 case VEH_TRAIN:
720 return !this->IsArticulatedPart() && // tenders and other articulated parts
721 !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
722 case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
723 case VEH_SHIP: return true;
724 default: return false; // Only count company buildable vehicles
725 }
726}
727
733{
734 switch (this->type) {
735 case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft();
736 case VEH_TRAIN:
737 case VEH_ROAD:
738 case VEH_SHIP: return true;
739 default: return false;
740 }
741}
742
749{
750 return Engine::Get(this->engine_type);
751}
752
759{
760 return this->GetEngine()->GetGRF();
761}
762
768uint32_t Vehicle::GetGRFID() const
769{
770 return this->GetEngine()->GetGRFID();
771}
772
779{
780 this->date_of_last_service = std::max(this->date_of_last_service + interval, TimerGameEconomy::Date(0));
781 /* date_of_last_service_newgrf is not updated here as it must stay stable
782 * for vehicles outside of a depot. */
783}
784
793{
794 if (path_found) {
795 /* Route found, is the vehicle marked with "lost" flag? */
796 if (!this->vehicle_flags.Test(VehicleFlag::PathfinderLost)) return;
797
798 /* Clear the flag as the PF's problem was solved. */
802 /* Delete the news item. */
804 return;
805 }
806
807 /* Were we already lost? */
808 if (this->vehicle_flags.Test(VehicleFlag::PathfinderLost)) return;
809
810 /* It is first time the problem occurred, set the "lost" flag. */
814
815 /* Unbunching data is no longer valid. */
816 this->ResetDepotUnbunching();
817
818 /* Notify user about the event. */
819 AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
820 if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
821 AddVehicleAdviceNewsItem(AdviceType::VehicleLost, GetEncodedString(STR_NEWS_VEHICLE_IS_LOST, this->index), this->index);
822 }
823}
824
827{
828 if (CleaningPool()) return;
829
832 st->loading_vehicles.remove(this);
833
835 this->CancelReservation(StationID::Invalid(), st);
836 delete this->cargo_payment;
837 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
838 }
839
840 if (this->IsEngineCountable()) {
842 if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
844
847 }
848
849 Company::Get(this->owner)->freeunits[this->type].ReleaseID(this->unitnumber);
850
851 if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
852 Aircraft *a = Aircraft::From(this);
854 if (st != nullptr) {
855 const auto &layout = st->airport.GetFTA()->layout;
856 st->airport.blocks.Reset(layout[a->previous_pos].blocks | layout[a->pos].blocks);
857 }
858 }
859
860
861 if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
863 if (!v->vehstatus.Test(VehState::Crashed) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
864 /* Leave the drive through roadstop, when you have not already left it. */
866 }
867
868 if (v->disaster_vehicle != VehicleID::Invalid()) ReleaseDisasterVehicle(v->disaster_vehicle);
869 }
870
871 if (this->Previous() == nullptr) {
873 }
874
875 if (this->IsPrimaryVehicle()) {
883 }
885
886 this->cargo.Truncate();
889
890 StopGlobalFollowVehicle(this);
891}
892
894{
895 if (CleaningPool()) {
896 this->cargo.OnCleanPool();
897 return;
898 }
899
900 /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
901 * it may happen that vehicle chain is deleted when visible */
902 if (!this->vehstatus.Test(VehState::Hidden)) this->MarkAllViewportsDirty();
903
904 Vehicle *v = this->Next();
905 this->SetNext(nullptr);
906
907 delete v;
908
909 UpdateVehicleTileHash(this, true);
910 UpdateVehicleViewportHash(this, INVALID_COORD, 0, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
911 if (this->type != VEH_EFFECT) {
914 }
915}
916
922{
923 /* Vehicle should stop in the depot if it was in 'stopping' state */
924 _vehicles_to_autoreplace[v->index] = !v->vehstatus.Test(VehState::Stopped);
925
926 /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
927 * stopping in the depot, so we stop it to ensure that it will not reserve
928 * the path out of the depot before we might autoreplace it to a different
929 * engine. The new engine would not own the reserved path we store that we
930 * stopped the vehicle, so autoreplace can start it again */
932}
933
938{
939 if (_game_mode != GM_NORMAL) return;
940
941 /* Run the calendar day proc for every DAY_TICKS vehicle starting at TimerGameCalendar::date_fract. */
943 Vehicle *v = Vehicle::Get(i);
944 if (v == nullptr) continue;
945 v->OnNewCalendarDay();
946 }
947}
948
955{
956 if (_game_mode != GM_NORMAL) return;
957
958 /* Run the economy day proc for every DAY_TICKS vehicle starting at TimerGameEconomy::date_fract. */
960 Vehicle *v = Vehicle::Get(i);
961 if (v == nullptr) continue;
962
963 /* Call the 32-day callback if needed */
964 if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
965 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
966 if (callback != CALLBACK_FAILED) {
967 if (HasBit(callback, 0)) {
968 TriggerVehicleRandomisation(v, VehicleRandomTrigger::Callback32); // Trigger vehicle trigger 10
969 }
970
971 /* After a vehicle trigger, the graphics and properties of the vehicle could change.
972 * Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */
973 if (callback != 0) v->First()->MarkDirty();
974
975 if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
976 }
977 }
978
979 /* This is called once per day for each vehicle, but not in the first tick of the day */
980 v->OnNewEconomyDay();
981 }
982}
983
984void CallVehicleTicks()
985{
986 _vehicles_to_autoreplace.clear();
987
989
990 {
991 PerformanceMeasurer framerate(PFE_GL_ECONOMY);
993 }
998
999 for (Vehicle *v : Vehicle::Iterate()) {
1000 [[maybe_unused]] VehicleID vehicle_index = v->index;
1001
1002 /* Vehicle could be deleted in this tick */
1003 if (!v->Tick()) {
1004 assert(Vehicle::Get(vehicle_index) == nullptr);
1005 continue;
1006 }
1007
1008 assert(Vehicle::Get(vehicle_index) == v);
1009
1010 switch (v->type) {
1011 default: break;
1012
1013 case VEH_TRAIN:
1014 case VEH_ROAD:
1015 case VEH_AIRCRAFT:
1016 case VEH_SHIP: {
1017 Vehicle *front = v->First();
1018
1019 if (v->vcache.cached_cargo_age_period != 0) {
1021 if (--v->cargo_age_counter == 0) {
1022 v->cargo.AgeCargo();
1024 }
1025 }
1026
1027 /* Do not play any sound when crashed */
1028 if (front->vehstatus.Test(VehState::Crashed)) continue;
1029
1030 /* Do not play any sound when in depot or tunnel */
1031 if (v->vehstatus.Test(VehState::Hidden)) continue;
1032
1033 /* Do not play any sound when stopped */
1034 if (front->vehstatus.Test(VehState::Stopped) && (front->type != VEH_TRAIN || front->cur_speed == 0)) continue;
1035
1036 /* Update motion counter for animation purposes. */
1037 v->motion_counter += front->cur_speed;
1038
1039 /* Check vehicle type specifics */
1040 switch (v->type) {
1041 case VEH_TRAIN:
1042 if (!Train::From(v)->IsEngine()) continue;
1043 break;
1044
1045 case VEH_ROAD:
1046 if (!RoadVehicle::From(v)->IsFrontEngine()) continue;
1047 break;
1048
1049 case VEH_AIRCRAFT:
1050 if (!Aircraft::From(v)->IsNormalAircraft()) continue;
1051 break;
1052
1053 default:
1054 break;
1055 }
1056
1057 /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
1058 if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
1059
1060 /* Play an alternating running sound every 16 ticks */
1061 if (GB(v->tick_counter, 0, 4) == 0) {
1062 /* Play running sound when speed > 0 and not braking */
1063 bool running = (front->cur_speed > 0) && !front->vehstatus.Any({VehState::Stopped, VehState::TrainSlowing});
1065 }
1066
1067 break;
1068 }
1069 }
1070 }
1071
1072 Backup<CompanyID> cur_company(_current_company);
1073 for (auto &it : _vehicles_to_autoreplace) {
1074 Vehicle *v = Vehicle::Get(it.first);
1075 /* Autoreplace needs the current company set as the vehicle owner */
1076 cur_company.Change(v->owner);
1077
1078 /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
1079 * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
1080 * they are already leaving the depot again before being replaced. */
1081 if (it.second) v->vehstatus.Reset(VehState::Stopped);
1082
1083 /* Store the position of the effect as the vehicle pointer will become invalid later */
1084 int x = v->x_pos;
1085 int y = v->y_pos;
1086 int z = v->z_pos;
1087
1090 CommandCost res = Command<Commands::AutoreplaceVehicle>::Do(DoCommandFlag::Execute, v->index);
1092
1093 if (!IsLocalCompany()) continue;
1094
1095 if (res.Succeeded()) {
1096 ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
1097 continue;
1098 }
1099
1100 StringID error_message = res.GetErrorMessage();
1101 if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
1102
1103 if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
1104
1105 EncodedString headline;
1106 if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
1107 headline = GetEncodedString(error_message, v->index);
1108 } else {
1109 headline = GetEncodedString(STR_NEWS_VEHICLE_AUTORENEW_FAILED, v->index, error_message, std::monostate{});
1110 }
1111
1112 AddVehicleAdviceNewsItem(AdviceType::AutorenewFailed, std::move(headline), v->index);
1113 }
1114
1115 cur_company.Restore();
1116}
1117
1122static void DoDrawVehicle(const Vehicle *v)
1123{
1124 PaletteID pal = PAL_NONE;
1125
1127
1128 /* Check whether the vehicle shall be transparent due to the game state */
1129 bool shadowed = v->vehstatus.Test(VehState::Shadow);
1130
1131 if (v->type == VEH_EFFECT) {
1132 /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
1133 * However, transparent smoke and bubbles look weird, so always hide them. */
1135 if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
1136 }
1137
1139 for (uint i = 0; i < v->sprite_cache.sprite_seq.count; ++i) {
1140 PaletteID pal2 = v->sprite_cache.sprite_seq.seq[i].pal;
1141 if (!pal2 || v->vehstatus.Test(VehState::Crashed)) pal2 = pal;
1142 AddSortableSpriteToDraw(v->sprite_cache.sprite_seq.seq[i].sprite, pal2, v->x_pos, v->y_pos, v->z_pos, v->bounds, shadowed);
1143 }
1145}
1146
1152{
1153 /* The bounding rectangle */
1154 const int l = dpi->left;
1155 const int r = dpi->left + dpi->width;
1156 const int t = dpi->top;
1157 const int b = dpi->top + dpi->height;
1158
1159 /* Border size of MAX_VEHICLE_PIXEL_xy */
1160 const int xb = MAX_VEHICLE_PIXEL_X * ZOOM_BASE;
1161 const int yb = MAX_VEHICLE_PIXEL_Y * ZOOM_BASE;
1162
1163 /* The hash area to scan */
1164 uint xl, xu, yl, yu;
1165
1166 if (static_cast<uint>(dpi->width + xb) < GEN_HASHX_SIZE) {
1167 xl = GetViewportHashX(l - xb);
1168 xu = GetViewportHashX(r);
1169 } else {
1170 /* scan whole hash row */
1171 xl = 0;
1172 xu = GEN_HASHX_MASK;
1173 }
1174
1175 if (static_cast<uint>(dpi->height + yb) < GEN_HASHY_SIZE) {
1176 yl = GetViewportHashY(t - yb);
1177 yu = GetViewportHashY(b);
1178 } else {
1179 /* scan whole column */
1180 yl = 0;
1181 yu = GEN_HASHY_MASK;
1182 }
1183
1184 for (uint y = yl;; y = (y + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1185 for (uint x = xl;; x = (x + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1186 const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
1187
1188 while (v != nullptr) {
1189
1190 if (!v->vehstatus.Test(VehState::Hidden) &&
1191 l <= v->coord.right + xb &&
1192 t <= v->coord.bottom + yb &&
1193 r >= v->coord.left - xb &&
1194 b >= v->coord.top - yb)
1195 {
1196 /*
1197 * This vehicle can potentially be drawn as part of this viewport and
1198 * needs to be revalidated, as the sprite may not be correct.
1199 */
1201 VehicleSpriteSeq seq;
1202 v->GetImage(v->direction, EIT_ON_MAP, &seq);
1203
1204 if (seq.IsValid() && v->sprite_cache.sprite_seq != seq) {
1205 v->sprite_cache.sprite_seq = seq;
1206 /*
1207 * A sprite change may also result in a bounding box change,
1208 * so we need to update the bounding box again before we
1209 * check to see if the vehicle should be drawn. Note that
1210 * we can't interfere with the viewport hash at this point,
1211 * so we keep the original hash on the assumption there will
1212 * not be a significant change in the top and left coordinates
1213 * of the vehicle.
1214 */
1216
1217 }
1218
1220 }
1221
1222 if (l <= v->coord.right &&
1223 t <= v->coord.bottom &&
1224 r >= v->coord.left &&
1225 b >= v->coord.top) DoDrawVehicle(v);
1226 }
1227
1228 v = v->hash_viewport_next;
1229 }
1230
1231 if (x == xu) break;
1232 }
1233
1234 if (y == yu) break;
1235 }
1236}
1237
1245Vehicle *CheckClickOnVehicle(const Viewport &vp, int x, int y)
1246{
1247 Vehicle *found = nullptr;
1248 uint dist, best_dist = UINT_MAX;
1249
1250 x -= vp.left;
1251 y -= vp.top;
1252 if (!IsInsideMM(x, 0, vp.width) || !IsInsideMM(y, 0, vp.height)) return nullptr;
1253
1254 x = ScaleByZoom(x, vp.zoom) + vp.virtual_left;
1255 y = ScaleByZoom(y, vp.zoom) + vp.virtual_top;
1256
1257 /* Border size of MAX_VEHICLE_PIXEL_xy */
1258 const int xb = MAX_VEHICLE_PIXEL_X * ZOOM_BASE;
1259 const int yb = MAX_VEHICLE_PIXEL_Y * ZOOM_BASE;
1260
1261 /* The hash area to scan */
1262 uint xl = GetViewportHashX(x - xb);
1263 uint xu = GetViewportHashX(x);
1264 uint yl = GetViewportHashY(y - yb);
1265 uint yu = GetViewportHashY(y);
1266
1267 for (uint hy = yl;; hy = (hy + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1268 for (uint hx = xl;; hx = (hx + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1269 Vehicle *v = _vehicle_viewport_hash[hx + hy]; // already masked & 0xFFF
1270
1271 while (v != nullptr) {
1272 if (!v->vehstatus.Any({VehState::Hidden, VehState::Unclickable}) &&
1273 x >= v->coord.left && x <= v->coord.right &&
1274 y >= v->coord.top && y <= v->coord.bottom) {
1275
1276 dist = std::max(
1277 abs(((v->coord.left + v->coord.right) >> 1) - x),
1278 abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1279 );
1280
1281 if (dist < best_dist) {
1282 found = v;
1283 best_dist = dist;
1284 }
1285 }
1286 v = v->hash_viewport_next;
1287 }
1288 if (hx == xu) break;
1289 }
1290 if (hy == yu) break;
1291 }
1292
1293 return found;
1294}
1295
1301{
1302 v->value -= v->value >> 8;
1304}
1305
1306static const uint8_t _breakdown_chance[64] = {
1307 3, 3, 3, 3, 3, 3, 3, 3,
1308 4, 4, 5, 5, 6, 6, 7, 7,
1309 8, 8, 9, 9, 10, 10, 11, 11,
1310 12, 13, 13, 13, 13, 14, 15, 16,
1311 17, 19, 21, 25, 28, 31, 34, 37,
1312 40, 44, 48, 52, 56, 60, 64, 68,
1313 72, 80, 90, 100, 110, 120, 130, 140,
1314 150, 170, 190, 210, 230, 250, 250, 250,
1315};
1316
1322{
1323 /* Vehicles in the menu don't break down. */
1324 if (_game_mode == GM_MENU) return;
1325
1326 /* If both breakdowns and automatic servicing are disabled, we don't decrease reliability or break down. */
1327 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::None && _settings_game.order.no_servicing_if_no_breakdowns) return;
1328
1329 /* With Reduced breakdowns, vehicles (un)loading at stations don't lose reliability. */
1330 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::Reduced && v->current_order.IsType(OT_LOADING)) return;
1331
1332 /* Decrease reliability. */
1333 int rel, rel_old;
1334 v->reliability = rel = std::max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
1335 if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
1336
1337 /* Some vehicles lose reliability but won't break down. */
1338 /* Breakdowns are disabled. */
1339 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::None) return;
1340 /* The vehicle is already broken down. */
1341 if (v->breakdown_ctr != 0) return;
1342 /* The vehicle is stopped or going very slow. */
1343 if (v->cur_speed < 5) return;
1344 /* The vehicle has been manually stopped. */
1345 if (v->vehstatus.Test(VehState::Stopped)) return;
1346
1347 /* Time to consider breaking down. */
1348
1349 uint32_t r = Random();
1350
1351 /* Increase chance of failure. */
1352 int chance = v->breakdown_chance + 1;
1353 if (Chance16I(1, 25, r)) chance += 25;
1355
1356 /* Calculate reliability value to use in comparison. */
1357 rel = v->reliability;
1358 if (v->type == VEH_SHIP) rel += 0x6666;
1359
1360 /* Reduce the chance if the player has chosen the Reduced setting. */
1361 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::Reduced) rel += 0x6666;
1362
1363 /* Check the random chance and inform the vehicle of the result. */
1364 if (_breakdown_chance[ClampTo<uint16_t>(rel) >> 10] <= v->breakdown_chance) {
1365 v->breakdown_ctr = GB(r, 16, 6) + 0x3F;
1366 v->breakdown_delay = GB(r, 24, 7) + 0x80;
1367 v->breakdown_chance = 0;
1368 }
1369}
1370
1378{
1379 /* Possible states for Vehicle::breakdown_ctr
1380 * 0 - vehicle is running normally
1381 * 1 - vehicle is currently broken down
1382 * 2 - vehicle is going to break down now
1383 * >2 - vehicle is counting down to the actual breakdown event */
1384 switch (this->breakdown_ctr) {
1385 case 0:
1386 return false;
1387
1388 case 2:
1389 this->breakdown_ctr = 1;
1390
1391 if (this->breakdowns_since_last_service != 255) {
1393 }
1394
1395 if (this->type == VEH_AIRCRAFT) {
1396 /* Aircraft just need this flag, the rest is handled elsewhere */
1398 } else {
1399 this->cur_speed = 0;
1400
1401 if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
1402 bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP;
1403 SndPlayVehicleFx((_settings_game.game_creation.landscape != LandscapeType::Toyland) ?
1406 }
1407
1408 if (!this->vehstatus.Test(VehState::Hidden) && !EngInfo(this->engine_type)->misc_flags.Test(EngineMiscFlag::NoBreakdownSmoke)) {
1410 if (u != nullptr) u->animation_state = this->breakdown_delay * 2;
1411 }
1412 }
1413
1414 this->MarkDirty(); // Update graphics after speed is zeroed
1417
1418 [[fallthrough]];
1419 case 1:
1420 /* Aircraft breakdowns end only when arriving at the airport */
1421 if (this->type == VEH_AIRCRAFT) return false;
1422
1423 /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
1424 if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
1425 if (--this->breakdown_delay == 0) {
1426 this->breakdown_ctr = 0;
1427 this->MarkDirty();
1429 }
1430 }
1431 return true;
1432
1433 default:
1434 if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
1435 return false;
1436 }
1437}
1438
1450
1456{
1457 if (v->age < CalendarTime::MAX_DATE) v->age++;
1458
1459 if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
1460
1461 auto age = v->age - v->max_age;
1462 for (int32_t i = 0; i <= 4; i++) {
1464 v->reliability_spd_dec <<= 1;
1465 break;
1466 }
1467 }
1468
1470
1471 /* Don't warn if warnings are disabled */
1472 if (!_settings_client.gui.old_vehicle_warn) return;
1473
1474 /* 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 */
1475 if (v->Previous() != nullptr || v->owner != _local_company || v->vehstatus.Any({VehState::Crashed, VehState::Stopped})) return;
1476
1477 const Company *c = Company::Get(v->owner);
1478 /* Don't warn if a renew is active */
1479 if (c->settings.engine_renew && v->GetEngine()->company_avail.Any()) return;
1480 /* Don't warn if a replacement is active */
1482
1483 StringID str;
1485 str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1487 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1489 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1490 } else {
1491 return;
1492 }
1493
1495}
1496
1506uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
1507{
1508 int count = 0;
1509 int max = 0;
1510 int cars = 0;
1511 int unloading = 0;
1512 bool loading = false;
1513
1514 bool is_loading = front->current_order.IsType(OT_LOADING);
1515
1516 /* The station may be nullptr when the (colour) string does not need to be set. */
1518 assert(colour == nullptr || (st != nullptr && is_loading));
1519
1520 bool order_no_load = is_loading && front->current_order.GetLoadType() == OrderLoadType::NoLoad;
1521 bool order_full_load = is_loading && front->current_order.IsFullLoadOrder();
1522
1523 /* Count up max and used */
1524 for (const Vehicle *v = front; v != nullptr; v = v->Next()) {
1525 count += v->cargo.StoredCount();
1526 max += v->cargo_cap;
1527 if (v->cargo_cap != 0 && colour != nullptr) {
1528 unloading += v->vehicle_flags.Test(VehicleFlag::CargoUnloading) ? 1 : 0;
1529 loading |= !order_no_load &&
1530 (order_full_load || st->goods[v->cargo_type].HasRating()) &&
1532 cars++;
1533 }
1534 }
1535
1536 if (colour != nullptr) {
1537 if (unloading == 0 && loading) {
1538 *colour = STR_PERCENT_UP;
1539 } else if (unloading == 0 && !loading) {
1540 *colour = STR_PERCENT_NONE;
1541 } else if (cars == unloading || !loading) {
1542 *colour = STR_PERCENT_DOWN;
1543 } else {
1544 *colour = STR_PERCENT_UP_DOWN;
1545 }
1546 }
1547
1548 /* Train without capacity */
1549 if (max == 0) return 100;
1550
1551 /* Return the percentage */
1552 if (count * 2 < max) {
1553 /* Less than 50%; round up, so that 0% means really empty. */
1554 return CeilDiv(count * 100, max);
1555 } else {
1556 /* More than 50%; round down, so that 100% means really full. */
1557 return (count * 100) / max;
1558 }
1559}
1560
1566{
1567 /* Always work with the front of the vehicle */
1568 assert(v == v->First());
1569
1570 switch (v->type) {
1571 case VEH_TRAIN: {
1572 Train *t = Train::From(v);
1574 /* Clear path reservation */
1575 SetDepotReservation(t->tile, false);
1576 if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
1577
1579 t->wait_counter = 0;
1583 break;
1584 }
1585
1586 case VEH_ROAD:
1588 break;
1589
1590 case VEH_SHIP: {
1592 Ship *ship = Ship::From(v);
1593 ship->state = TRACK_BIT_DEPOT;
1594 ship->UpdateCache();
1595 ship->UpdateViewport(true, true);
1597 break;
1598 }
1599
1600 case VEH_AIRCRAFT:
1603 break;
1604 default: NOT_REACHED();
1605 }
1606 if (v->type != VEH_TRAIN) {
1607 /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
1608 * 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 */
1610 }
1612
1614 v->cur_speed = 0;
1615
1617
1618 /* Store that the vehicle entered a depot this tick */
1620
1621 /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
1622 TriggerVehicleRandomisation(v, VehicleRandomTrigger::Depot);
1623 v->MarkDirty();
1624
1626
1627 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1628 const Order *real_order = v->GetOrder(v->cur_real_order_index);
1629
1630 /* Test whether we are heading for this depot. If not, do nothing.
1631 * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
1633 real_order != nullptr && !real_order->GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot) &&
1635 /* We are heading for another depot, keep driving. */
1636 return;
1637 }
1638
1639 if (v->current_order.IsRefit()) {
1640 Backup<CompanyID> cur_company(_current_company, v->owner);
1641 CommandCost cost = std::get<0>(Command<Commands::RefitVehicle>::Do(DoCommandFlag::Execute, v->index, v->current_order.GetRefitCargo(), 0xFF, false, false, 0));
1642 cur_company.Restore();
1643
1644 if (cost.Failed()) {
1645 _vehicles_to_autoreplace[v->index] = false;
1646 if (v->owner == _local_company) {
1647 /* Notify the user that we stopped the vehicle */
1648 AddVehicleAdviceNewsItem(AdviceType::RefitFailed, GetEncodedString(STR_NEWS_ORDER_REFIT_FAILED, v->index), v->index);
1649 }
1650 } else if (cost.GetCost() != 0) {
1651 v->profit_this_year -= cost.GetCost() << 8;
1652 if (v->owner == _local_company) {
1654 }
1655 }
1656 }
1657
1659 /* Part of orders */
1661 UpdateVehicleTimetable(v, true);
1663 }
1665 /* Vehicles are always stopped on entering depots. Do not restart this one. */
1666 _vehicles_to_autoreplace[v->index] = false;
1667 /* Invalidate last_loading_station. As the link from the station
1668 * before the stop to the station after the stop can't be predicted
1669 * we shouldn't construct it when the vehicle visits the next stop. */
1670 v->last_loading_station = StationID::Invalid();
1671
1672 /* Clear unbunching data. */
1674
1675 /* Announce that the vehicle is waiting to players and AIs. */
1676 if (v->owner == _local_company) {
1677 AddVehicleAdviceNewsItem(AdviceType::VehicleWaiting, GetEncodedString(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index), v->index);
1678 }
1679 AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
1680 }
1681
1682 /* If we've entered our unbunching depot, record the round trip duration. */
1685 if (v->round_trip_time == 0) {
1686 /* This might be our first round trip. */
1687 v->round_trip_time = measured_round_trip;
1688 } else {
1689 /* If we have a previous trip, smooth the effects of outlier trip calculations caused by jams or other interference. */
1690 v->round_trip_time = Clamp(measured_round_trip, (v->round_trip_time / 2), ClampTo<TimerGameTick::Ticks>(v->round_trip_time * 2));
1691 }
1692 }
1693
1695 }
1696}
1697
1698
1704{
1705 UpdateVehicleTileHash(this, false);
1706}
1707
1712void Vehicle::UpdateBoundingBoxCoordinates(bool update_cache) const
1713{
1714 Rect new_coord;
1715 this->sprite_cache.sprite_seq.GetBounds(&new_coord);
1716
1717 /* z-bounds are not used. */
1718 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);
1719 new_coord.left += pt.x;
1720 new_coord.top += pt.y;
1721 new_coord.right += pt.x + 2 * ZOOM_BASE;
1722 new_coord.bottom += pt.y + 2 * ZOOM_BASE;
1723
1724 extern bool _draw_bounding_boxes;
1725 if (_draw_bounding_boxes) {
1726 int x = this->x_pos + this->bounds.origin.x;
1727 int y = this->y_pos + this->bounds.origin.y;
1728 int z = this->z_pos + this->bounds.origin.z;
1729 new_coord.left = std::min(new_coord.left, RemapCoords(x + bounds.extent.x, y, z).x);
1730 new_coord.right = std::max(new_coord.right, RemapCoords(x, y + bounds.extent.y, z).x + 1);
1731 new_coord.top = std::min(new_coord.top, RemapCoords(x, y, z + bounds.extent.z).y);
1732 new_coord.bottom = std::max(new_coord.bottom, RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1);
1733 }
1734
1735 if (update_cache) {
1736 /*
1737 * If the old coordinates are invalid, set the cache to the new coordinates for correct
1738 * behaviour the next time the coordinate cache is checked.
1739 */
1740 this->sprite_cache.old_coord = this->coord.left == INVALID_COORD ? new_coord : this->coord;
1741 }
1742 else {
1743 /* Extend the bounds of the existing cached bounding box so the next dirty window is correct */
1744 this->sprite_cache.old_coord.left = std::min(this->sprite_cache.old_coord.left, this->coord.left);
1745 this->sprite_cache.old_coord.top = std::min(this->sprite_cache.old_coord.top, this->coord.top);
1746 this->sprite_cache.old_coord.right = std::max(this->sprite_cache.old_coord.right, this->coord.right);
1747 this->sprite_cache.old_coord.bottom = std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom);
1748 }
1749
1750 this->coord = new_coord;
1751}
1752
1758{
1759 /* If the existing cache is invalid we should ignore it, as it will be set to the current coords by UpdateBoundingBoxCoordinates */
1760 bool ignore_cached_coords = this->sprite_cache.old_coord.left == INVALID_COORD;
1761
1762 this->UpdateBoundingBoxCoordinates(true);
1763
1764 if (ignore_cached_coords) {
1765 UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, INVALID_COORD, INVALID_COORD);
1766 } else {
1767 UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
1768 }
1769
1770 if (dirty) {
1771 if (ignore_cached_coords) {
1772 this->sprite_cache.is_viewport_candidate = this->MarkAllViewportsDirty();
1773 } else {
1774 this->sprite_cache.is_viewport_candidate = ::MarkAllViewportsDirty(
1775 std::min(this->sprite_cache.old_coord.left, this->coord.left),
1776 std::min(this->sprite_cache.old_coord.top, this->coord.top),
1777 std::max(this->sprite_cache.old_coord.right, this->coord.right),
1778 std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom));
1779 }
1780 }
1781}
1782
1787{
1788 if (this->type != VEH_EFFECT) this->UpdatePosition();
1789 this->UpdateViewport(true);
1790}
1791
1797{
1798 return ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
1799}
1800
1807{
1808 static const int8_t _delta_coord[16] = {
1809 -1,-1,-1, 0, 1, 1, 1, 0, /* x */
1810 -1, 0, 1, 1, 1, 0,-1,-1, /* y */
1811 };
1812
1813 int x = v->x_pos + _delta_coord[v->GetMovingDirection()];
1814 int y = v->y_pos + _delta_coord[v->GetMovingDirection() + 8];
1815
1817 gp.x = x;
1818 gp.y = y;
1819 gp.old_tile = v->tile;
1820 gp.new_tile = TileVirtXY(x, y);
1821 return gp;
1822}
1823
1824static const Direction _new_direction_table[] = {
1825 DIR_N, DIR_NW, DIR_W,
1828};
1829
1830Direction GetDirectionTowards(const Vehicle *v, int x, int y)
1831{
1832 int i = 0;
1833
1834 if (y >= v->y_pos) {
1835 if (y != v->y_pos) i += 3;
1836 i += 3;
1837 }
1838
1839 if (x >= v->x_pos) {
1840 if (x != v->x_pos) i++;
1841 i++;
1842 }
1843
1844 Direction dir = v->GetMovingDirection();
1845
1846 DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
1847 if (dirdiff == DIRDIFF_SAME) return dir;
1848 return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
1849}
1850
1860VehicleEnterTileStates VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
1861{
1862 return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
1863}
1864
1871{
1872 for (auto it = std::begin(this->used_bitmap); it != std::end(this->used_bitmap); ++it) {
1873 BitmapStorage available = ~(*it);
1874 if (available == 0) continue;
1875 return static_cast<UnitID>(std::distance(std::begin(this->used_bitmap), it) * BITMAP_SIZE + FindFirstBit(available) + 1);
1876 }
1877 return static_cast<UnitID>(this->used_bitmap.size() * BITMAP_SIZE + 1);
1878}
1879
1886{
1887 if (index == 0 || index == UINT16_MAX) return index;
1888
1889 index--;
1890
1891 size_t slot = index / BITMAP_SIZE;
1892 if (slot >= this->used_bitmap.size()) this->used_bitmap.resize(slot + 1);
1893 SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
1894
1895 return index + 1;
1896}
1897
1903{
1904 if (index == 0 || index == UINT16_MAX) return;
1905
1906 index--;
1907
1908 assert(index / BITMAP_SIZE < this->used_bitmap.size());
1909 ClrBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
1910}
1911
1918{
1919 /* Check whether it is allowed to build another vehicle. */
1920 uint max_veh;
1921 switch (type) {
1922 case VEH_TRAIN: max_veh = _settings_game.vehicle.max_trains; break;
1923 case VEH_ROAD: max_veh = _settings_game.vehicle.max_roadveh; break;
1924 case VEH_SHIP: max_veh = _settings_game.vehicle.max_ships; break;
1925 case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
1926 default: NOT_REACHED();
1927 }
1928
1930 if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
1931
1932 return c->freeunits[type].NextID();
1933}
1934
1935
1946{
1947 assert(IsCompanyBuildableVehicleType(type));
1948
1949 if (!Company::IsValidID(_local_company)) return false;
1950
1951 UnitID max;
1952 switch (type) {
1953 case VEH_TRAIN:
1954 if (!HasAnyRailTypesAvail(_local_company)) return false;
1955 max = _settings_game.vehicle.max_trains;
1956 break;
1957 case VEH_ROAD:
1958 if (!HasAnyRoadTypesAvail(_local_company, subtype)) return false;
1959 max = _settings_game.vehicle.max_roadveh;
1960 break;
1961 case VEH_SHIP: max = _settings_game.vehicle.max_ships; break;
1962 case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
1963 default: NOT_REACHED();
1964 }
1965
1966 /* We can build vehicle infrastructure when we may build the vehicle type */
1967 if (max > 0) {
1968 /* Can we actually build the vehicle type? */
1969 for (const Engine *e : Engine::IterateType(type)) {
1970 if (type == VEH_ROAD && GetRoadTramType(e->VehInfo<RoadVehicleInfo>().roadtype) != subtype) continue;
1971 if (e->company_avail.Test(_local_company)) return true;
1972 }
1973 return false;
1974 }
1975
1976 /* We should be able to build infrastructure when we have the actual vehicle type */
1977 for (const Vehicle *v : Vehicle::Iterate()) {
1978 if (v->type == VEH_ROAD && GetRoadTramType(RoadVehicle::From(v)->roadtype) != subtype) continue;
1979 if (v->owner == _local_company && v->type == type) return true;
1980 }
1981
1982 return false;
1983}
1984
1985
1993LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
1994{
1995 CargoType cargo_type = v == nullptr ? INVALID_CARGO : v->cargo_type;
1996 const Engine *e = Engine::Get(engine_type);
1997 switch (e->type) {
1998 default: NOT_REACHED();
1999 case VEH_TRAIN:
2000 if (v != nullptr && parent_engine_type != EngineID::Invalid() && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->VehInfo<RailVehicleInfo>().railveh_type != RAILVEH_WAGON))) {
2001 /* Wagonoverrides use the colour scheme of the front engine.
2002 * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
2003 engine_type = parent_engine_type;
2004 e = Engine::Get(engine_type);
2005 /* Note: Luckily cargo_type is not needed for engines */
2006 }
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 if (e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) {
2012 if (!CargoSpec::Get(cargo_type)->is_freight) {
2013 if (parent_engine_type == EngineID::Invalid()) {
2014 return LS_PASSENGER_WAGON_STEAM;
2015 } else {
2016 bool is_mu = EngInfo(parent_engine_type)->misc_flags.Test(EngineMiscFlag::RailIsMU);
2017 switch (RailVehInfo(parent_engine_type)->engclass) {
2018 default: NOT_REACHED();
2019 case EC_STEAM: return LS_PASSENGER_WAGON_STEAM;
2020 case EC_DIESEL: return is_mu ? LS_DMU : LS_PASSENGER_WAGON_DIESEL;
2021 case EC_ELECTRIC: return is_mu ? LS_EMU : LS_PASSENGER_WAGON_ELECTRIC;
2022 case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
2023 case EC_MAGLEV: return LS_PASSENGER_WAGON_MAGLEV;
2024 }
2025 }
2026 } else {
2027 return LS_FREIGHT_WAGON;
2028 }
2029 } else {
2030 bool is_mu = e->info.misc_flags.Test(EngineMiscFlag::RailIsMU);
2031
2032 switch (e->VehInfo<RailVehicleInfo>().engclass) {
2033 default: NOT_REACHED();
2034 case EC_STEAM: return LS_STEAM;
2035 case EC_DIESEL: return is_mu ? LS_DMU : LS_DIESEL;
2036 case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
2037 case EC_MONORAIL: return LS_MONORAIL;
2038 case EC_MAGLEV: return LS_MAGLEV;
2039 }
2040 }
2041
2042 case VEH_ROAD:
2043 /* Always use the livery of the front */
2044 if (v != nullptr && parent_engine_type != EngineID::Invalid()) {
2045 engine_type = parent_engine_type;
2046 e = Engine::Get(engine_type);
2047 cargo_type = v->First()->cargo_type;
2048 }
2049 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
2050 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
2051 assert(IsValidCargoType(cargo_type));
2052
2053 /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
2055 /* Tram */
2056 return IsCargoInClass(cargo_type, CargoClass::Passengers) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
2057 } else {
2058 /* Bus or truck */
2059 return IsCargoInClass(cargo_type, CargoClass::Passengers) ? LS_BUS : LS_TRUCK;
2060 }
2061
2062 case VEH_SHIP:
2063 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
2064 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
2065 assert(IsValidCargoType(cargo_type));
2066 return IsCargoInClass(cargo_type, CargoClass::Passengers) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
2067
2068 case VEH_AIRCRAFT:
2069 switch (e->VehInfo<AircraftVehicleInfo>().subtype) {
2070 case AIR_HELI: return LS_HELICOPTER;
2071 case AIR_CTOL: return LS_SMALL_PLANE;
2072 case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
2073 default: NOT_REACHED();
2074 }
2075 }
2076}
2077
2087const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, uint8_t livery_setting)
2088{
2089 const Company *c = Company::Get(company);
2090 LiveryScheme scheme = LS_DEFAULT;
2091
2092 if (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company)) {
2093 if (v != nullptr) {
2094 const Group *g = Group::GetIfValid(v->First()->group_id);
2095 if (g != nullptr) {
2096 /* Traverse parents until we find a livery or reach the top */
2097 while (!g->livery.in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary}) && g->parent != GroupID::Invalid()) {
2098 g = Group::Get(g->parent);
2099 }
2100 if (g->livery.in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) return &g->livery;
2101 }
2102 }
2103
2104 /* The default livery is always available for use, but its in_use flag determines
2105 * whether any _other_ liveries are in use. */
2106 if (c->livery[LS_DEFAULT].in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) {
2107 /* Determine the livery scheme to use */
2108 scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
2109 }
2110 }
2111
2112 return &c->livery[scheme];
2113}
2114
2115
2116static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
2117{
2118 PaletteID map = (v != nullptr) ? v->colourmap : PAL_NONE;
2119
2120 /* Return cached value if any */
2121 if (map != PAL_NONE) return map;
2122
2123 const Engine *e = Engine::Get(engine_type);
2124
2125 /* Check if we should use the colour map callback */
2127 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
2128 /* Failure means "use the default two-colour" */
2129 if (callback != CALLBACK_FAILED) {
2130 static_assert(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
2131 map = GB(callback, 0, 14);
2132 /* If bit 14 is set, then the company colours are applied to the
2133 * map else it's returned as-is. */
2134 if (!HasBit(callback, 14)) {
2135 /* Update cache */
2136 if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2137 return map;
2138 }
2139 }
2140 }
2141
2142 bool twocc = e->info.misc_flags.Test(EngineMiscFlag::Uses2CC);
2143
2144 if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
2145
2146 /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
2147 if (!Company::IsValidID(company)) return map;
2148
2149 const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
2150
2151 map += livery->GetRecolourOffset(twocc);
2152
2153 /* Update cache */
2154 if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2155 return map;
2156}
2157
2164PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
2165{
2166 return GetEngineColourMap(engine_type, company, EngineID::Invalid(), nullptr);
2167}
2168
2175{
2176 if (v->IsGroundVehicle()) {
2177 return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
2178 }
2179
2180 return GetEngineColourMap(v->engine_type, v->owner, EngineID::Invalid(), v);
2181}
2182
2187{
2188 if (this->IsGroundVehicle()) {
2189 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2190 if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
2191 /* Do not delete orders, only skip them */
2194 InvalidateVehicleOrder(this, 0);
2195 return;
2196 }
2197 }
2198
2199 auto orders = this->Orders();
2201 while (cur != INVALID_VEH_ORDER_ID) {
2202 if (this->cur_implicit_order_index == this->cur_real_order_index) break;
2203
2204 if (orders[cur].IsType(OT_IMPLICIT)) {
2206 /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2207 } else {
2208 /* Skip non-implicit orders, e.g. service-orders */
2209 if (cur < this->orders->GetNext(cur)) {
2211 } else {
2212 /* Wrapped around. */
2213 this->cur_implicit_order_index = 0;
2214 }
2215 cur = this->orders->GetNext(cur);
2216 }
2217 }
2218}
2219
2225{
2226 assert(IsTileType(this->GetMovingFront()->tile, TileType::Station) || this->type == VEH_SHIP);
2227
2229 if (this->current_order.IsType(OT_GOTO_STATION) &&
2230 this->current_order.GetDestination() == this->last_station_visited) {
2232
2233 /* Now both order indices point to the destination station, and we can start loading */
2234 this->current_order.MakeLoading(true);
2235 UpdateVehicleTimetable(this, true);
2236
2237 /* Furthermore add the Non Stop flag to mark that this station
2238 * is the actual destination of the vehicle, which is (for example)
2239 * necessary to be known for HandleTrainLoading to determine
2240 * whether the train is lost or not; not marking a train lost
2241 * that arrives at random stations is bad. */
2243
2244 } else {
2245 /* We weren't scheduled to stop here. Insert an implicit order
2246 * to show that we are stopping here.
2247 * While only groundvehicles have implicit orders, e.g. aircraft might still enter
2248 * the 'wrong' terminal when skipping orders etc. */
2249 Order *in_list = this->GetOrder(this->cur_implicit_order_index);
2250 if (this->IsGroundVehicle() &&
2251 (in_list == nullptr || !in_list->IsType(OT_IMPLICIT) ||
2252 in_list->GetDestination() != this->last_station_visited)) {
2253 bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
2254 /* Do not create consecutive duplicates of implicit orders */
2255 const Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : nullptr);
2256 if (prev_order == nullptr ||
2257 (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
2258 prev_order->GetDestination() != this->last_station_visited) {
2259
2260 /* Prefer deleting implicit orders instead of inserting new ones,
2261 * so test whether the right order follows later. In case of only
2262 * implicit orders treat the last order in the list like an
2263 * explicit one, except if the overall number of orders surpasses
2264 * IMPLICIT_ORDER_ONLY_CAP. */
2265 int target_index = this->cur_implicit_order_index;
2266 bool found = false;
2267 while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) {
2268 const Order *order = this->GetOrder(target_index);
2269 if (order == nullptr) break; // No orders.
2270 if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
2271 found = true;
2272 break;
2273 }
2274 target_index++;
2275 if (target_index >= this->orders->GetNumOrders()) {
2276 if (this->GetNumManualOrders() == 0 &&
2278 break;
2279 }
2280 target_index = 0;
2281 }
2282 if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop.
2283 }
2284
2285 if (found) {
2286 if (suppress_implicit_orders) {
2287 /* Skip to the found order */
2288 this->cur_implicit_order_index = target_index;
2289 InvalidateVehicleOrder(this, 0);
2290 } else {
2291 /* Delete all implicit orders up to the station we just reached */
2292 const Order *order = this->GetOrder(this->cur_implicit_order_index);
2293 while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
2294 if (order->IsType(OT_IMPLICIT)) {
2296 } else {
2297 /* Skip non-implicit orders, e.g. service-orders */
2299 }
2300 order = this->GetOrder(this->cur_implicit_order_index);
2301
2302 /* Wrapped around. */
2303 if (order == nullptr) {
2304 this->cur_implicit_order_index = 0;
2305 order = this->GetOrder(this->cur_implicit_order_index);
2306 }
2307 assert(order != nullptr);
2308 }
2309 }
2310 } else if (!suppress_implicit_orders &&
2311 (this->orders == nullptr ? OrderList::CanAllocateItem() : this->orders->GetNumOrders() < MAX_VEH_ORDER_ID)) {
2312 /* Insert new implicit order */
2313 Order implicit_order{};
2314 implicit_order.MakeImplicit(this->last_station_visited);
2315 InsertOrder(this, std::move(implicit_order), this->cur_implicit_order_index);
2317
2318 /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
2319 * Reenable it for this vehicle */
2320 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2322 }
2323 }
2324 }
2325 this->current_order.MakeLoading(false);
2326 }
2327
2328 if (this->last_loading_station != StationID::Invalid() &&
2330 (this->current_order.GetLoadType() != OrderLoadType::NoLoad ||
2331 this->current_order.GetUnloadType() != OrderUnloadType::NoUnload)) {
2332 IncreaseStats(Station::Get(this->last_loading_station), this, this->last_station_visited, travel_time);
2333 }
2334
2335 PrepareUnload(this);
2336
2341
2343 this->cur_speed = 0;
2344 this->MarkDirty();
2345}
2346
2354{
2355 for (Vehicle *v = this; v != nullptr; v = v->next) {
2357 if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
2358 Debug(misc, 1, "cancelling cargo reservation");
2359 cargo.Return(UINT_MAX, &st->goods[v->cargo_type].GetOrCreateData().cargo, next, v->tile);
2360 }
2361 cargo.KeepAll();
2362 }
2363}
2364
2370{
2371 assert(this->current_order.IsType(OT_LOADING));
2372
2373 delete this->cargo_payment;
2374 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
2375
2376 /* Only update the timetable if the vehicle was supposed to stop here. */
2377 if (this->current_order.GetNonStopType().Any()) UpdateVehicleTimetable(this, false);
2378
2379 if (this->current_order.GetLoadType() != OrderLoadType::NoLoad ||
2380 this->current_order.GetUnloadType() != OrderUnloadType::NoUnload) {
2381 if (this->current_order.CanLeaveWithCargo(this->last_loading_station != StationID::Invalid())) {
2382 /* Refresh next hop stats to make sure we've done that at least once
2383 * during the stop and that refit_cap == cargo_cap for each vehicle in
2384 * the consist. */
2385 this->ResetRefitCaps();
2386 LinkRefresher::Run(this);
2387
2388 /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
2391 } else {
2392 /* if the vehicle couldn't load and had to unload or transfer everything
2393 * set the last loading station to invalid as it will leave empty. */
2394 this->last_loading_station = StationID::Invalid();
2395 }
2396 }
2397
2398 this->current_order.MakeLeaveStation();
2400 this->CancelReservation(StationID::Invalid(), st);
2401 st->loading_vehicles.remove(this);
2402
2405
2406 if (this->type == VEH_TRAIN && !this->vehstatus.Test(VehState::Crashed)) {
2407 /* Trigger station animation (trains only) */
2408 TileIndex tile = this->GetMovingFront()->tile;
2411 TriggerStationAnimation(st, tile, StationAnimationTrigger::VehicleDeparts);
2412 }
2413
2415 }
2416 if (this->type == VEH_ROAD && !this->vehstatus.Test(VehState::Crashed)) {
2417 /* Trigger road stop animation */
2418 if (IsStationRoadStopTile(this->tile)) {
2420 TriggerRoadStopAnimation(st, this->tile, StationAnimationTrigger::VehicleDeparts);
2421 }
2422 }
2423
2424
2425 this->MarkDirty();
2426}
2427
2432{
2433 for (Vehicle *v = this; v != nullptr; v = v->Next()) v->refit_cap = v->cargo_cap;
2434}
2435
2440{
2441 Company::Get(this->owner)->freeunits[this->type].ReleaseID(this->unitnumber);
2442 this->unitnumber = 0;
2443}
2444
2451{
2452 switch (this->current_order.GetType()) {
2453 case OT_LOADING: {
2454 TimerGameTick::Ticks wait_time = std::max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2455
2456 /* Not the first call for this tick, or still loading */
2457 if (mode || !this->vehicle_flags.Test(VehicleFlag::LoadingFinished) || this->current_order_time < wait_time) return;
2458
2459 this->PlayLeaveStationSound();
2460
2461 this->LeaveStation();
2462
2463 /* Only advance to next order if we just loaded at the current one */
2464 const Order *order = this->GetOrder(this->cur_implicit_order_index);
2465 if (order == nullptr ||
2466 (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2467 order->GetDestination() != this->last_station_visited) {
2468 return;
2469 }
2470 break;
2471 }
2472
2473 case OT_DUMMY: break;
2474
2475 default: return;
2476 }
2477
2479}
2480
2486{
2487 return std::ranges::any_of(this->Orders(), [](const Order &o) {
2488 return o.IsType(OT_GOTO_STATION) && o.IsFullLoadOrder();
2489 });
2490}
2491
2497{
2498 return std::ranges::any_of(this->Orders(), [](const Order &o) { return o.IsType(OT_CONDITIONAL); });
2499}
2500
2506{
2507 return std::ranges::any_of(this->Orders(), [](const Order &o) {
2508 return o.IsType(OT_GOTO_DEPOT) && o.GetDepotActionType().Test(OrderDepotActionFlag::Unbunch);
2509 });
2510}
2511
2518{
2519 /* If we are headed for the first order, we must wrap around back to the last order. */
2520 bool is_first_order = (v->GetOrder(v->cur_implicit_order_index) == v->GetFirstOrder());
2521 const Order *previous_order = (is_first_order) ? v->GetLastOrder() : v->GetOrder(v->cur_implicit_order_index - 1);
2522
2523 if (previous_order == nullptr || !previous_order->IsType(OT_GOTO_DEPOT)) return false;
2524 return previous_order->GetDepotActionType().Test(OrderDepotActionFlag::Unbunch);
2525}
2526
2531{
2532 /* Don't do anything if this is not our unbunching order. */
2533 if (!PreviousOrderIsUnbunching(this)) return;
2534
2535 /* Set the start point for this round trip time. */
2537
2538 /* Tell the timetable we are now "on time." */
2539 this->lateness_counter = 0;
2541
2542 /* Find the average travel time of vehicles that we share orders with. */
2543 int num_vehicles = 0;
2544 TimerGameTick::Ticks total_travel_time = 0;
2545
2546 Vehicle *u = this->FirstShared();
2547 for (; u != nullptr; u = u->NextShared()) {
2548 /* Ignore vehicles that are manually stopped or crashed. */
2549 if (u->vehstatus.Any({VehState::Stopped, VehState::Crashed})) continue;
2550
2551 num_vehicles++;
2552 total_travel_time += u->round_trip_time;
2553 }
2554
2555 /* Make sure we cannot divide by 0. */
2556 num_vehicles = std::max(num_vehicles, 1);
2557
2558 /* Calculate the separation by finding the average travel time, then calculating equal separation (minimum 1 tick) between vehicles. */
2559 TimerGameTick::Ticks separation = std::max((total_travel_time / num_vehicles / num_vehicles), 1);
2560 TimerGameTick::TickCounter next_departure = TimerGameTick::counter + separation;
2561
2562 /* Set the departure time of all vehicles that we share orders with. */
2563 u = this->FirstShared();
2564 for (; u != nullptr; u = u->NextShared()) {
2565 /* Ignore vehicles that are manually stopped or crashed. */
2566 if (u->vehstatus.Any({VehState::Stopped, VehState::Crashed})) continue;
2567
2568 u->depot_unbunching_next_departure = next_departure;
2570 }
2571}
2572
2578{
2579 assert(this->IsInDepot());
2580
2581 /* Don't bother if there are no vehicles sharing orders. */
2582 if (!this->IsOrderListShared()) return false;
2583
2584 /* Don't do anything if there aren't enough orders. */
2585 if (this->GetNumOrders() <= 1) return false;
2586
2587 /* Don't do anything if this is not our unbunching order. */
2588 if (!PreviousOrderIsUnbunching(this)) return false;
2589
2591};
2592
2599CommandCost Vehicle::SendToDepot(DoCommandFlags flags, DepotCommandFlags command)
2600{
2601 CommandCost ret = CheckOwnership(this->owner);
2602 if (ret.Failed()) return ret;
2603
2604 if (this->vehstatus.Test(VehState::Crashed)) return CMD_ERROR;
2605 if (this->IsStoppedInDepot()) return CMD_ERROR;
2606
2607 /* No matter why we're headed to the depot, unbunching data is no longer valid. */
2609
2610 if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2611 bool halt_in_depot = this->current_order.GetDepotActionType().Test(OrderDepotActionFlag::Halt);
2612 if (command.Test(DepotCommandFlag::Service) == halt_in_depot) {
2613 /* We called with a different DEPOT_SERVICE setting.
2614 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2615 * Note: the if is (true for requesting service == true for ordered to stop in depot) */
2616 if (flags.Test(DoCommandFlag::Execute)) {
2617 this->current_order.SetDepotOrderType({});
2618 this->current_order.SetDepotActionType(halt_in_depot ? OrderDepotActionFlags{} : OrderDepotActionFlag::Halt);
2620 }
2621 return CommandCost();
2622 }
2623
2624 if (command.Test(DepotCommandFlag::DontCancel)) return CMD_ERROR; // Requested no cancellation of depot orders
2625 if (flags.Test(DoCommandFlag::Execute)) {
2626 /* If the orders to 'goto depot' are in the orders list (forced servicing),
2627 * then skip to the next order; effectively cancelling this forced service */
2628 if (this->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) this->IncrementRealOrderIndex();
2629
2630 if (this->IsGroundVehicle()) {
2631 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2633 }
2634
2635 this->current_order.MakeDummy();
2637 }
2638 return CommandCost();
2639 }
2640
2641 ClosestDepot closest_depot = this->FindClosestDepot();
2642 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_UNABLE_TO_FIND_LOCAL_HANGAR};
2643 if (!closest_depot.found) return CommandCost(no_depot[this->type]);
2644
2645 if (flags.Test(DoCommandFlag::Execute)) {
2646 if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2647
2648 if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2649 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2651 }
2652
2653 this->SetDestTile(closest_depot.location);
2654 this->current_order.MakeGoToDepot(closest_depot.destination.ToDepotID(), {});
2655 if (!command.Test(DepotCommandFlag::Service)) this->current_order.SetDepotActionType(OrderDepotActionFlag::Halt);
2657
2658 /* If there is no depot in front and the train is not already reversing, reverse automatically (trains only) */
2659 if (this->type == VEH_TRAIN && (closest_depot.reverse ^ Train::From(this)->flags.Test(VehicleRailFlag::Reversing))) {
2660 Command<Commands::ReverseTrainDirection>::Do(DoCommandFlag::Execute, this->index, false);
2661 }
2662
2663 if (this->type == VEH_AIRCRAFT) {
2664 Aircraft *a = Aircraft::From(this);
2665 if (a->state == FLYING && a->targetairport != closest_depot.destination) {
2666 /* The aircraft is now heading for a different hangar than the next in the orders */
2668 }
2669 }
2670 }
2671
2672 return CommandCost();
2673
2674}
2675
2680void Vehicle::UpdateVisualEffect(bool allow_power_change)
2681{
2682 bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2683 const Engine *e = this->GetEngine();
2684
2685 /* Evaluate properties */
2686 uint8_t visual_effect;
2687 switch (e->type) {
2688 case VEH_TRAIN: visual_effect = e->VehInfo<RailVehicleInfo>().visual_effect; break;
2689 case VEH_ROAD: visual_effect = e->VehInfo<RoadVehicleInfo>().visual_effect; break;
2690 case VEH_SHIP: visual_effect = e->VehInfo<ShipVehicleInfo>().visual_effect; break;
2691 default: visual_effect = 1 << VE_DISABLE_EFFECT; break;
2692 }
2693
2694 /* Check powered wagon / visual effect callback */
2696 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2697
2698 if (callback != CALLBACK_FAILED) {
2699 if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2700
2701 callback = GB(callback, 0, 8);
2702 /* Avoid accidentally setting 'visual_effect' to the default value
2703 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2704 if (callback == VE_DEFAULT) {
2705 assert(HasBit(callback, VE_DISABLE_EFFECT));
2706 SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2707 }
2708 visual_effect = callback;
2709 }
2710 }
2711
2712 /* Apply default values */
2713 if (visual_effect == VE_DEFAULT ||
2714 (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2715 /* Only train engines have default effects.
2716 * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2717 if (e->type != VEH_TRAIN || e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON || !IsInsideMM(e->VehInfo<RailVehicleInfo>().engclass, EC_STEAM, EC_MONORAIL)) {
2718 if (visual_effect == VE_DEFAULT) {
2719 visual_effect = 1 << VE_DISABLE_EFFECT;
2720 } else {
2721 SetBit(visual_effect, VE_DISABLE_EFFECT);
2722 }
2723 } else {
2724 if (visual_effect == VE_DEFAULT) {
2725 /* Also set the offset */
2726 visual_effect = (VE_OFFSET_CENTRE - (e->VehInfo<RailVehicleInfo>().engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
2727 }
2728 SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->VehInfo<RailVehicleInfo>().engclass - EC_STEAM + VE_TYPE_STEAM);
2729 }
2730 }
2731
2732 this->vcache.cached_vis_effect = visual_effect;
2733
2734 if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2735 ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2736 ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GRFBug::VehPoweredWagon, false);
2737 }
2738}
2739
2740static const int8_t _vehicle_smoke_pos[8] = {
2741 1, 1, 1, 0, -1, -1, -1, 0
2742};
2743
2749{
2750 std::array<int32_t, 4> regs100;
2751 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v, regs100);
2752 if (callback == CALLBACK_FAILED) return;
2753
2754 uint count = GB(callback, 0, 2);
2755 assert(count <= std::size(regs100));
2756 bool auto_center = HasBit(callback, 13);
2757 bool auto_rotate = !HasBit(callback, 14);
2758
2759 int8_t l_center = 0;
2760 if (auto_center) {
2761 /* For road vehicles: Compute offset from vehicle position to vehicle center */
2762 if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2763 } else {
2764 /* For trains: Compute offset from vehicle position to sprite position */
2765 if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2766 }
2767
2768 Direction l_dir = v->direction;
2769 if (v->type == VEH_TRAIN && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) l_dir = ReverseDir(l_dir);
2770 Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
2771
2772 int8_t x_center = _vehicle_smoke_pos[l_dir] * l_center;
2773 int8_t y_center = _vehicle_smoke_pos[t_dir] * l_center;
2774
2775 for (uint i = 0; i < count; i++) {
2776 int32_t reg = regs100[i];
2777 uint type = GB(reg, 0, 8);
2778 int8_t x = GB(reg, 8, 8);
2779 int8_t y = GB(reg, 16, 8);
2780 int8_t z = GB(reg, 24, 8);
2781
2782 if (auto_rotate) {
2783 int8_t l = x;
2784 int8_t t = y;
2785 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2786 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2787 }
2788
2789 if (type >= 0xF0) {
2790 switch (type) {
2791 case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2792 case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2793 case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2794 case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2795 default: break;
2796 }
2797 }
2798 }
2799}
2800
2806static bool IsBridgeAboveVehicle(const Vehicle *v)
2807{
2808 if (IsBridgeTile(v->tile)) {
2809 /* If the vehicle is 'on' a bridge tile, check the real position of the vehicle. If it's different then the
2810 * vehicle is on the middle of the bridge, which cannot have a bridge above. */
2811 TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
2812 if (tile != v->tile) return false;
2813 }
2814 return IsBridgeAbove(v->tile);
2815}
2816
2822{
2823 assert(this->IsPrimaryVehicle());
2824 bool sound = false;
2825
2826 /* Do not show any smoke when:
2827 * - vehicle smoke is disabled by the player
2828 * - the vehicle is slowing down or stopped (by the player)
2829 * - the vehicle is moving very slowly
2830 */
2831 if (_settings_game.vehicle.smoke_amount == 0 ||
2832 this->vehstatus.Any({VehState::TrainSlowing, VehState::Stopped}) ||
2833 this->cur_speed < 2) {
2834 return;
2835 }
2836
2837 /* Use the speed as limited by underground and orders. */
2838 uint max_speed = this->GetCurrentMaxSpeed();
2839
2840 if (this->type == VEH_TRAIN) {
2841 const Train *t = Train::From(this);
2842 const Train *moving_front = t->GetMovingFront();
2843 /* For trains, do not show any smoke when:
2844 * - the train is reversing
2845 * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2846 */
2848 (IsRailStationTile(moving_front->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(moving_front->tile)) &&
2849 t->cur_speed >= max_speed)) {
2850 return;
2851 }
2852 }
2853
2854 const Vehicle *v = this;
2855
2856 do {
2859 VisualEffectSpawnModel effect_model = VESM_NONE;
2860 if (advanced) {
2861 effect_offset = VE_OFFSET_CENTRE;
2863 if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
2864 } else {
2866 assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
2867 static_assert((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
2868 static_assert((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL);
2869 static_assert((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
2870 }
2871
2872 /* Show no smoke when:
2873 * - Smoke has been disabled for this vehicle
2874 * - The vehicle is not visible
2875 * - The vehicle is under a bridge
2876 * - The vehicle is on a depot tile
2877 * - The vehicle is on a tunnel tile
2878 * - The vehicle is a train engine that is currently unpowered */
2879 if (effect_model == VESM_NONE ||
2882 IsDepotTile(v->tile) ||
2883 IsTunnelTile(v->tile) ||
2884 (v->type == VEH_TRAIN &&
2885 !HasPowerOnRail(Train::From(v)->railtypes, GetTileRailType(v->tile)))) {
2886 continue;
2887 }
2888
2889 EffectVehicleType evt = EV_END;
2890 switch (effect_model) {
2891 case VESM_STEAM:
2892 /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2893 * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2894 * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2895 * REGULATION:
2896 * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2897 if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2898 evt = EV_STEAM_SMOKE;
2899 }
2900 break;
2901
2902 case VESM_DIESEL: {
2903 /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2904 * when smoke emission stops.
2905 * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2906 * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2907 * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2908 * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2909 * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2910 * maximum speed no diesel_smoke is emitted.
2911 * REGULATION:
2912 * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2913 * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2914 int power_weight_effect = 0;
2915 if (v->type == VEH_TRAIN) {
2916 power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2917 }
2918 if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2919 Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2920 evt = EV_DIESEL_SMOKE;
2921 }
2922 break;
2923 }
2924
2925 case VESM_ELECTRIC:
2926 /* Electric train's spark - more often occurs when train is departing (more load)
2927 * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2928 * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2929 * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2930 * REGULATION:
2931 * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2932 if (GB(v->tick_counter, 0, 2) == 0 &&
2933 Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2934 evt = EV_ELECTRIC_SPARK;
2935 }
2936 break;
2937
2938 default:
2939 NOT_REACHED();
2940 }
2941
2942 if (evt != EV_END && advanced) {
2943 sound = true;
2945 } else if (evt != EV_END) {
2946 sound = true;
2947
2948 /* The effect offset is relative to a point 4 units behind the vehicle's
2949 * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2950 * correction factor. */
2951 if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2952
2953 int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2954 int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2955
2956 if (v->type == VEH_TRAIN && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) {
2957 x = -x;
2958 y = -y;
2959 }
2960
2961 CreateEffectVehicleRel(v, x, y, 10, evt);
2962 }
2963 } while ((v = v->Next()) != nullptr);
2964
2965 if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2966}
2967
2973{
2974 assert(this != next);
2975
2976 if (this->next != nullptr) {
2977 /* We had an old next vehicle. Update the first and previous pointers */
2978 for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
2979 v->first = this->next;
2980 }
2981 this->next->previous = nullptr;
2982 }
2983
2984 this->next = next;
2985
2986 if (this->next != nullptr) {
2987 /* A new next vehicle. Update the first and previous pointers */
2988 if (this->next->previous != nullptr) this->next->previous->next = nullptr;
2989 this->next->previous = this;
2990 for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
2991 v->first = this->first;
2992 }
2993 }
2994
2995 /* Update last vehicle of the entire chain. */
2996 Vehicle *new_last = this;
2997 while (new_last->Next() != nullptr) new_last = new_last->Next();
2998 for (Vehicle *v = this->first; v!= nullptr; v = v->Next()) {
2999 v->last = new_last;
3000 }
3001}
3002
3009{
3010 assert(this->previous_shared == nullptr && this->next_shared == nullptr);
3011
3012 if (shared_chain->orders == nullptr) {
3013 assert(shared_chain->previous_shared == nullptr);
3014 assert(shared_chain->next_shared == nullptr);
3015 this->orders = shared_chain->orders = OrderList::Create(shared_chain);
3016 }
3017
3018 this->next_shared = shared_chain->next_shared;
3019 this->previous_shared = shared_chain;
3020
3021 shared_chain->next_shared = this;
3022
3023 if (this->next_shared != nullptr) this->next_shared->previous_shared = this;
3024
3025 shared_chain->orders->AddVehicle(this);
3026}
3027
3032{
3033 /* Remember if we were first and the old window number before RemoveVehicle()
3034 * as this changes first if needed. */
3035 bool were_first = (this->FirstShared() == this);
3037
3038 this->orders->RemoveVehicle(this);
3039
3040 if (!were_first) {
3041 /* We are not the first shared one, so only relink our previous one. */
3042 this->previous_shared->next_shared = this->NextShared();
3043 }
3044
3045 if (this->next_shared != nullptr) this->next_shared->previous_shared = this->previous_shared;
3046
3047
3048 if (this->orders->GetNumVehicles() == 1) {
3049 /* When there is only one vehicle, remove the shared order list window. */
3052 } else if (were_first) {
3053 /* If we were the first one, update to the new first one.
3054 * Note: FirstShared() is already the new first */
3055 InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.ToWindowNumber(), this->FirstShared()->index.base() | (1U << 31));
3056 }
3057
3058 this->next_shared = nullptr;
3059 this->previous_shared = nullptr;
3060}
3061
3062static const IntervalTimer<TimerGameEconomy> _economy_vehicles_yearly({TimerGameEconomy::Trigger::Year, TimerGameEconomy::Priority::Vehicle}, [](auto)
3063{
3064 for (Vehicle *v : Vehicle::Iterate()) {
3065 if (v->IsPrimaryVehicle()) {
3066 /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
3067 Money profit = v->GetDisplayProfitThisYear();
3068 if (v->economy_age >= VEHICLE_PROFIT_MIN_AGE && profit < 0) {
3071 GetEncodedString(TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_VEHICLE_UNPROFITABLE_PERIOD : STR_NEWS_VEHICLE_UNPROFITABLE_YEAR, v->index, profit),
3072 v->index);
3073 }
3074 AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
3075 }
3076
3078 v->profit_this_year = 0;
3080 }
3081 }
3087});
3088
3098bool CanVehicleUseStation(EngineID engine_type, const Station *st)
3099{
3100 const Engine *e = Engine::GetIfValid(engine_type);
3101 assert(e != nullptr);
3102
3103 switch (e->type) {
3104 case VEH_TRAIN:
3106
3107 case VEH_ROAD:
3108 /* For road vehicles we need the vehicle to know whether it can actually
3109 * use the station, but if it doesn't have facilities for RVs it is
3110 * certainly not possible that the station can be used. */
3112
3113 case VEH_SHIP:
3115
3116 case VEH_AIRCRAFT:
3119
3120 default:
3121 return false;
3122 }
3123}
3124
3131bool CanVehicleUseStation(const Vehicle *v, const Station *st)
3132{
3133 if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != nullptr;
3134
3135 return CanVehicleUseStation(v->engine_type, st);
3136}
3137
3145{
3146 switch (v->type) {
3147 case VEH_TRAIN:
3148 return STR_ERROR_NO_RAIL_STATION;
3149
3150 case VEH_ROAD: {
3151 const RoadVehicle *rv = RoadVehicle::From(v);
3152 RoadStop *rs = st->GetPrimaryRoadStop(rv->IsBus() ? RoadStopType::Bus : RoadStopType::Truck);
3153
3154 StringID err = rv->IsBus() ? STR_ERROR_NO_BUS_STATION : STR_ERROR_NO_TRUCK_STATION;
3155
3156 for (; rs != nullptr; rs = rs->next) {
3157 /* Articulated vehicles cannot use bay road stops, only drive-through. Make sure the vehicle can actually use this bay stop */
3159 err = STR_ERROR_NO_STOP_ARTICULATED_VEHICLE;
3160 continue;
3161 }
3162
3163 /* Bay stop errors take precedence, but otherwise the vehicle may not be compatible with the roadtype/tramtype of this station tile.
3164 * We give bay stop errors precedence because they are usually a bus sent to a tram station or vice versa. */
3165 if (!HasTileAnyRoadType(rs->xy, rv->compatible_roadtypes) && err != STR_ERROR_NO_STOP_ARTICULATED_VEHICLE) {
3166 err = RoadTypeIsRoad(rv->roadtype) ? STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE : STR_ERROR_NO_STOP_COMPATIBLE_TRAM_TYPE;
3167 continue;
3168 }
3169 }
3170
3171 return err;
3172 }
3173
3174 case VEH_SHIP:
3175 return STR_ERROR_NO_DOCK;
3176
3177 case VEH_AIRCRAFT:
3178 if (!st->facilities.Test(StationFacility::Airport)) return STR_ERROR_NO_AIRPORT;
3179 if (v->GetEngine()->VehInfo<AircraftVehicleInfo>().subtype & AIR_CTOL) {
3180 return STR_ERROR_AIRPORT_NO_PLANES;
3181 } else {
3182 return STR_ERROR_AIRPORT_NO_HELICOPTERS;
3183 }
3184
3185 default:
3186 return INVALID_STRING_ID;
3187 }
3188}
3189
3196{
3197 assert(this->IsGroundVehicle());
3198 if (this->type == VEH_TRAIN) {
3199 return &Train::From(this)->gcache;
3200 } else {
3201 return &RoadVehicle::From(this)->gcache;
3202 }
3203}
3204
3211{
3212 assert(this->IsGroundVehicle());
3213 if (this->type == VEH_TRAIN) {
3214 return &Train::From(this)->gcache;
3215 } else {
3216 return &RoadVehicle::From(this)->gcache;
3217 }
3218}
3219
3226{
3227 assert(this->IsGroundVehicle());
3228 if (this->type == VEH_TRAIN) {
3229 return Train::From(this)->gv_flags;
3230 } else {
3231 return RoadVehicle::From(this)->gv_flags;
3232 }
3233}
3234
3240const uint16_t &Vehicle::GetGroundVehicleFlags() const
3241{
3242 assert(this->IsGroundVehicle());
3243 if (this->type == VEH_TRAIN) {
3244 return Train::From(this)->gv_flags;
3245 } else {
3246 return RoadVehicle::From(this)->gv_flags;
3247 }
3248}
3249
3258void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8_t num_vehicles)
3259{
3260 if (v->type == VEH_TRAIN) {
3261 Train *u = Train::From(v);
3262 /* Only include whole vehicles, so start with the first articulated part */
3263 u = u->GetFirstEnginePart();
3264
3265 /* Include num_vehicles vehicles, not counting articulated parts */
3266 for (; u != nullptr && num_vehicles > 0; num_vehicles--) {
3267 do {
3268 /* Include current vehicle in the selection. */
3269 include(set, u->index);
3270
3271 /* If the vehicle is multiheaded, add the other part too. */
3272 if (u->IsMultiheaded()) include(set, u->other_multiheaded_part->index);
3273
3274 u = u->Next();
3275 } while (u != nullptr && u->IsArticulatedPart());
3276 }
3277 }
3278}
3279
3285{
3286 uint32_t max_weight = 0;
3287
3288 for (const Vehicle *u = this; u != nullptr; u = u->Next()) {
3289 max_weight += u->GetMaxWeight();
3290 }
3291
3292 return max_weight;
3293}
3294
3300{
3301 uint32_t max_weight = GetDisplayMaxWeight();
3302 if (max_weight == 0) return 0;
3303 return GetGroundVehicleCache()->cached_power * 10u / max_weight;
3304}
3305
3313{
3314 while (true) {
3315 if (v1 == nullptr && v2 == nullptr) return true;
3316 if (v1 == nullptr || v2 == nullptr) return false;
3317 if (v1->GetEngine() != v2->GetEngine()) return false;
3318 v1 = v1->GetNextVehicle();
3319 v2 = v2->GetNextVehicle();
3320 }
3321}
3322
3330{
3331 return std::ranges::equal(v1->Orders(), v2->Orders(), [](const Order &o1, const Order &o2) { return o1.Equals(o2); });
3332}
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:108
@ Passengers
Passengers.
Definition cargotype.h:51
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.
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.
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
UnitID UseID(UnitID index)
Use a unit number.
Definition vehicle.cpp:1885
void ReleaseID(UnitID index)
Release a unit number.
Definition vehicle.cpp:1902
UnitID NextID() const
Find first unused unit number.
Definition vehicle.cpp:1870
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.
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
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.
StrongType::Typedef< int32_t, struct YearTag< struct Calendar >, StrongType::Compare, StrongType::Integer > Year
static constexpr Date DateAtStartOfYear(Year year)
StrongType::Typedef< int32_t, DateTag< struct Economy >, StrongType::Compare, StrongType::Integer > Date
CargoList that is used for vehicles.
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:501
Iterator(int32_t x, int32_t y, uint max_dist)
Iterator constructor.
Definition vehicle.cpp:461
void Increment()
Advance the internal state to the next potential vehicle.
Definition vehicle.cpp:491
void SkipFalseMatches()
Advance the internal state until it reaches a vehicle within the search area.
Definition vehicle.cpp:519
Iterator(TileIndex tile)
Iterator constructor.
Definition vehicle.cpp:529
void Increment()
Advance the internal state to the next potential vehicle.
Definition vehicle.cpp:539
void SkipFalseMatches()
Advance the internal state until it reaches a vehicle on the correct tile or the end.
Definition vehicle.cpp:547
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:45
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:1929
void PrepareUnload(Vehicle *front_v)
Prepare the vehicle to be unloaded.
Definition economy.cpp:1254
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
PoolID< uint16_t, struct EngineIDTag, 64000, 0xFFFF > EngineID
Unique identification number of an engine.
Definition engine_type.h:26
@ 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:1038
@ Normal
The most basic (normal) sprite.
Definition gfx_type.h:358
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:250
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 EnumClassIndexContainer< std::array< const TileTypeProcs *, to_underlying(TileType::MaxSize)>, TileType > _tile_type_procs
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
@ Toyland
Landscape with funky industries and vehicles.
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
#define Point
Macro that prevents name conflicts between included headers.
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:407
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:429
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:419
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
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
Miscellaneous command definitions.
void HideFillingPercent(TextEffectID *te_id)
Hide vehicle loading indicators.
Definition misc_gui.cpp:580
void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost)
Display animated income or costs on the map.
Definition misc_gui.cpp:506
bool _networking
are we in networking mode?
Definition network.cpp:67
Basic functions/variables used all over the place.
GrfSpecFeature GetGrfSpecFeature(VehicleType type)
Get the GrfSpecFeature associated with a VehicleType.
Definition newgrf.cpp:1904
@ 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.
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:43
void DeleteVehicleNews(VehicleID vid, AdviceType advice_type=AdviceType::Invalid)
Delete news with a given advice type about a vehicle.
@ Company
Company news item. (Newspaper with face).
Definition news_type.h:82
@ Vehicle
Vehicle news item. (new engine available).
Definition news_type.h:81
@ VehicleLost
The vehicle has become lost.
Definition news_type.h:57
@ VehicleWaiting
The vehicle is waiting in the depot.
Definition news_type.h:60
@ AutorenewFailed
Autorenew or autoreplace failed.
Definition news_type.h:53
@ VehicleOld
The vehicle is starting to get old.
Definition news_type.h:58
@ VehicleUnprofitable
The vehicle is costing you money.
Definition news_type.h:59
@ RefitFailed
The refit order failed to execute.
Definition news_type.h:55
@ Error
A game paused because a (critical) error.
Definition openttd.h:72
@ Normal
A game normally paused.
Definition openttd.h:69
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.
Definition order_type.h:71
@ NonStop
The vehicle will not stop at any stations it passes except the destination, aka non-stop.
Definition order_type.h:88
@ GoVia
The vehicle will stop at any station it passes except the destination, aka via.
Definition order_type.h:89
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.
Definition order_type.h:81
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition order_type.h:41
@ Halt
Service the vehicle and then halt it.
Definition order_type.h:118
@ NearestDepot
Send the vehicle to the nearest depot.
Definition order_type.h:119
@ Unbunch
Service the vehicle and then unbunch it.
Definition order_type.h:120
@ PartOfOrders
This depot order is because of a regular order.
Definition order_type.h:109
@ Service
This depot order is because of the servicing limit.
Definition order_type.h:108
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:80
RailType GetTileRailType(Tile tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
Definition rail.cpp:39
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:377
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:153
bool HasTileAnyRoadType(Tile t, RoadTypes rts)
Check if a tile has one of the specified road types.
Definition road_map.h:232
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:654
Functions related to sound.
@ SND_3A_BREAKDOWN_TRAIN_SHIP_TOYLAND
58 == 0x3A Breakdown: train or ship (toyland)
Definition sound_type.h:106
@ SND_10_BREAKDOWN_TRAIN_SHIP
14 == 0x0E Breakdown: train or ship (non-toyland)
Definition sound_type.h:62
@ SND_0F_BREAKDOWN_ROADVEHICLE
13 == 0x0D Breakdown: road vehicle (non-toyland)
Definition sound_type.h:61
@ SND_35_BREAKDOWN_ROADVEHICLE_TOYLAND
53 == 0x35 Breakdown: road vehicle (toyland)
Definition sound_type.h:101
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:73
uint8_t pos
Next desired position of the aircraft.
Definition aircraft.h:75
uint8_t state
State of the airport.
Definition aircraft.h:78
bool IsNormalAircraft() const
Check if the aircraft type is a normal flying device; eg not a rotor or a shadow.
Definition aircraft.h:121
uint8_t previous_pos
Previous desired position of the aircraft.
Definition aircraft.h:76
StationID targetairport
Airport to go to next.
Definition aircraft.h:77
@ Airplanes
Can planes land on this airport type?
Definition airport.h:162
@ Helicopters
Can helicopters land on this airport type?
Definition airport.h:163
std::vector< AirportFTA > layout
state machine for airport
Definition airport.h:190
Flags flags
Flags for this airport type.
Definition airport.h:193
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.
TimerGameTick::Ticks lateness_counter
How many ticks late (or early if negative) this vehicle is.
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:139
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.
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:118
bool vehicle_income_warn
if a vehicle isn't generating income, show a warning
uint8_t liveries
options for displaying company liveries, 0=none, 1=self, 2=all
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.
uint32_t cached_power
Total power of the consist (valid only for the first engine).
uint8_t cached_veh_length
Length of this vehicle in units of 1/VEHICLE_LENGTH of normal length. It is cached because this can b...
GroundVehicleCache gcache
Cache of often calculated values.
bool IsRearDualheaded() const
Tell if we are dealing with the rear end of a multiheaded engine.
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:74
Livery livery
Custom colour scheme for vehicles in this group.
Definition group.h:80
GroupID parent
Parent group.
Definition group.h:86
Information about a particular livery.
Definition livery.h:79
Flags in_use
Livery flags.
Definition livery.h:87
uint8_t GetRecolourOffset(bool use_secondary=true) const
Get offset for recolour palette.
Definition livery.h:96
bool revalidate_before_draw
We need to do a GetImage() and check bounds before drawing this sprite.
VehicleSpriteSeq sprite_seq
Vehicle appearance.
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:525
If you change this, keep in mind that it is also saved in 2 other places:
Definition order_base.h:34
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition order_base.h:170
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:100
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:67
CargoType GetRefitCargo() const
Get the cargo to to refit to.
Definition order_base.h:128
bool IsFullLoadOrder() const
Is this order a OrderLoadType::FullLoad or OrderLoadType::FullLoadAny?
Definition order_base.h:136
void MakeDummy()
Makes this order a Dummy order.
OrderLoadType GetLoadType() const
How must the consist be loaded?
Definition order_base.h:146
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition order_base.h:176
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:114
static Pool::IterateWrapper< Vehicle > Iterate(size_t from=0)
static Company * Get(auto index)
static Group * GetIfValid(auto index)
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:105
uint8_t state
Definition roadveh.h:107
RoadTypes compatible_roadtypes
NOSAVE: Roadtypes this consist is powered on.
Definition roadveh.h:117
bool IsBus() const
Check whether a roadvehicle is a bus.
RoadType roadtype
NOSAVE: Roadtype of this vehicle.
Definition roadveh.h:115
VehicleID disaster_vehicle
NOSAVE: Disaster vehicle targetting this vehicle.
Definition roadveh.h:116
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:232
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
static Station * Get(auto index)
static Station * GetIfValid(auto index)
T * GetMovingFront() const
Get the moving front of the vehicle chain.
T * Next() const
Get next vehicle in the chain.
static Train * From(Vehicle *v)
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.
'Train' is either a loco or a wagon.
Definition train.h:97
Train * GetNextUnit() const
Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consis...
Definition train.h:156
Train * other_multiheaded_part
Link between the two ends of a multiheaded engine.
Definition train.h:105
TrainForceProceeding force_proceed
How the train should behave when it encounters next obstacle.
Definition train.h:111
TrackBits track
On which track the train currently is.
Definition train.h:110
VehicleRailFlags flags
Which flags has this train currently set.
Definition train.h:98
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:100
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.
Sprite sequence for a vehicle part.
bool IsValid() const
Check whether the sequence contains any sprites.
void GetBounds(Rect *bounds) const
Determine shared bounds of all sprites.
Definition vehicle.cpp:123
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition vehicle.cpp:151
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.
Vehicle * last
NOSAVE: pointer for the last vehicle in the chain.
uint16_t & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition vehicle.cpp:3225
Direction direction
facing
void ShiftDates(TimerGameEconomy::Date interval)
Shift all dates by given interval.
Definition vehicle.cpp:778
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.
bool IsOrderListShared() const
Check if we share our orders with another vehicle.
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition vehicle.cpp:748
Direction GetMovingDirection() const
Get the moving direction of this vehicle chain.
void IncrementRealOrderIndex()
Advanced cur_real_order_index to the next real order, keeps care of the wrap-around and invalidates t...
virtual uint Crash(bool flooded=false)
Crash the (whole) vehicle chain.
Definition vehicle.cpp:300
bool IsStoppedInDepot() const
Check whether the vehicle is in the depot and stopped.
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:2369
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:3008
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:2505
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.
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
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:2599
void ReleaseUnitNumber()
Release the vehicle's unit number.
Definition vehicle.cpp:2439
virtual void SetDestTile(TileIndex tile)
Set the destination of this vehicle.
void UpdateBoundingBoxCoordinates(bool update_cache) const
Update the bounding box co-ordinates of the vehicle.
Definition vehicle.cpp:1712
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:2450
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:2353
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:715
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:165
void UpdateVisualEffect(bool allow_power_change=true)
Update the cached visual effect.
Definition vehicle.cpp:2680
void LeaveUnbunchingDepot()
Leave an unbunching depot and calculate the next departure time for shared order vehicles.
Definition vehicle.cpp:2530
CargoType cargo_type
type of cargo this vehicle is carrying
Vehicle * previous_shared
NOSAVE: pointer to the previous vehicle in the shared order chain.
VehicleOrderID GetNumManualOrders() const
Get the number of manually added orders this vehicle has.
Vehicle * First() const
Get the first vehicle of this vehicle chain.
int8_t trip_occupancy
NOSAVE: Occupancy of vehicle of the current trip (updated after leaving a station).
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:826
TimerGameTick::TickCounter last_loading_tick
Last TimerGameTick::counter tick that the vehicle has stopped at a station and could possibly leave w...
Vehicle(VehicleID index, VehicleType type=VEH_INVALID)
Vehicle constructor.
Definition vehicle.cpp:379
void HandlePathfindingResult(bool path_found)
Handle the pathfinding result, especially the lost status.
Definition vehicle.cpp:792
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:758
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:3299
Vehicle * GetMovingFront() const
Get the moving front of the vehicle chain.
virtual ClosestDepot FindClosestDepot()
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
void UpdateViewport(bool dirty)
Update the vehicle on the viewport, updating the right hash and setting the new coordinates.
Definition vehicle.cpp:1757
Money value
Value of the vehicle.
bool MarkAllViewportsDirty() const
Marks viewports dirty where the vehicle's image is.
Definition vehicle.cpp:1796
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:768
SpriteBounds bounds
Bounding box of vehicle.
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition vehicle.cpp:3195
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.
virtual int GetCurrentMaxSpeed() const
Calculates the maximum speed of the vehicle under its current conditions.
bool HasFullLoadOrder() const
Check if the current vehicle has a full load order.
Definition vehicle.cpp:2485
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:2224
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:893
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:732
TimerGameCalendar::Date age
Age in calendar days.
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition vehicle.cpp:2577
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:2972
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:3284
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition vehicle.cpp:3031
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds,...
Definition vehicle.cpp:1377
void UpdatePositionAndViewport()
Update the position of the vehicle, and update the viewport.
Definition vehicle.cpp:1786
Vehicle * Previous() const
Get the previous vehicle of this vehicle.
virtual void PlayLeaveStationSound(bool force=false) const
Play the sound associated with leaving the station.
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.
virtual bool IsInDepot() const
Check whether the vehicle is in the depot.
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:210
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition vehicle.cpp:2496
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1703
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:2431
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:2821
Owner owner
Which company owns the vehicle?
UnitID unitnumber
unit number, for display purposes only
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:292
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition vehicle.cpp:2186
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:1860
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
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
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
@ Station
A tile of a station or airport.
Definition tile_type.h:54
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:650
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
@ LeavingStation
Train is just leaving a station.
Definition train.h:33
@ Reversing
Train is slowing down to reverse.
Definition train.h:26
@ Flipped
Reverse the visible direction of the vehicle.
Definition train.h:28
@ TFP_NONE
Normal operation.
Definition train.h:40
static constexpr ConsistChangeFlags CCF_ARRANGE
Valid changes for arranging the consist in a depot.
Definition train.h:57
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:337
constexpr uint TILE_HASH_MASK
Definition vehicle.cpp:400
static uint GetTileHash(uint x, uint y)
Compute hash for tile coordinate.
Definition vehicle.cpp:447
static const uint GEN_HASHX_MASK
Definition vehicle.cpp:110
static const uint GEN_HASHY_MASK
Definition vehicle.cpp:111
static void VehicleEnteredDepotThisTick(Vehicle *v)
Adds a vehicle to the list of vehicles that visited a depot this tick.
Definition vehicle.cpp:921
static void SpawnAdvancedVisualEffect(const Vehicle *v)
Call CBID_VEHICLE_SPAWN_VISUAL_EFFECT and spawn requested effects.
Definition vehicle.cpp:2748
constexpr uint TOTAL_TILE_HASH_SIZE
Definition vehicle.cpp:401
static const uint GEN_HASHY_INC
Definition vehicle.cpp:105
static uint GetTileHash1D(uint p)
Compute hash for 1D tile coordinate.
Definition vehicle.cpp:415
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:363
static const uint GEN_HASHY_BITS
Definition vehicle.cpp:71
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:187
static const uint GEN_HASHY_BUCKET_BITS
Definition vehicle.cpp:77
static void RunEconomyVehicleDayProc()
Increases the day counter for all vehicles and calls 1-day and 32-day handlers.
Definition vehicle.cpp:954
constexpr uint TILE_HASH_SIZE
Definition vehicle.cpp:399
static const uint GEN_HASHY_SIZE
Definition vehicle.cpp:99
constexpr uint TILE_HASH_BITS
Definition vehicle.cpp:398
static uint ComposeTileHash(uint hx, uint hy)
Compose two 1D hashes into 2D hash.
Definition vehicle.cpp:436
static const uint GEN_HASHX_BUCKET_BITS
Definition vehicle.cpp:76
static uint IncTileHash1D(uint h)
Increment 1D hash to next bucket.
Definition vehicle.cpp:425
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3098
static const uint GEN_HASHX_BITS
Definition vehicle.cpp:70
Vehicle * CheckClickOnVehicle(const Viewport &vp, int x, int y)
Find the vehicle close to the clicked coordinates.
Definition vehicle.cpp:1245
static const uint GEN_HASHX_INC
Definition vehicle.cpp:104
static const uint GEN_HASHX_SIZE
Definition vehicle.cpp:98
std::map< VehicleID, bool > AutoreplaceMap
List of vehicles that should check for autoreplace this tick.
Definition vehicle.cpp:695
static bool IsBridgeAboveVehicle(const Vehicle *v)
Test if a bridge is above a vehicle.
Definition vehicle.cpp:2806
constexpr uint TILE_HASH_RES
Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
Definition vehicle.cpp:408
static bool PreviousOrderIsUnbunching(const Vehicle *v)
Check if the previous order is a depot unbunching order.
Definition vehicle.cpp:2517
static void DoDrawVehicle(const Vehicle *v)
Add vehicle sprite for drawing to the screen.
Definition vehicle.cpp:1122
@ Crashed
Vehicle is crashed.
@ Shadow
Vehicle is a shadow vehicle.
@ 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.
Pool< Vehicle, VehicleID, 512 > VehiclePool
A vehicle pool for a little over 1 million vehicles.
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:337
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:557
bool VehiclesHaveSameEngineList(const Vehicle *v1, const Vehicle *v2)
Checks if two vehicle chains have the same list of engines.
Definition vehicle.cpp:3312
bool VehiclesHaveSameOrderList(const Vehicle *v1, const Vehicle *v2)
Checks if two vehicles have the same list of orders.
Definition vehicle.cpp:3329
SpriteID GetEnginePalette(EngineID engine_type, CompanyID company)
Get the colour map for an engine.
Definition vehicle.cpp:2164
void VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition vehicle.cpp:1565
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:3258
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition vehicle.cpp:1917
void RunVehicleCalendarDayProc()
Age all vehicles, spreading out the action using the current TimerGameCalendar::date_fract.
Definition vehicle.cpp:937
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition vehicle.cpp:187
CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
Tests if a vehicle interacts with the specified track bits.
Definition vehicle.cpp:605
LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
Determines the LiveryScheme for a vehicle.
Definition vehicle.cpp:1993
void CheckVehicleBreakdown(Vehicle *v)
Periodic check for a vehicle to maybe break down.
Definition vehicle.cpp:1321
void ViewportAddVehicles(DrawPixelInfo *dpi)
Add the vehicle sprites that should be drawn at a part of the screen.
Definition vehicle.cpp:1151
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition vehicle.cpp:1806
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:3144
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:1300
void EconomyAgeVehicle(Vehicle *v)
Update economy age of a vehicle.
Definition vehicle.cpp:1443
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:2087
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore=nullptr)
Finds vehicle in tunnel / bridge.
Definition vehicle.cpp:581
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition vehicle.cpp:1455
SpriteID GetVehiclePalette(const Vehicle *v)
Get the colour map for a vehicle.
Definition vehicle.cpp:2174
uint8_t CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1506
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
bool CanBuildVehicleInfrastructure(VehicleType type, RoadTramType subtype=RoadTramType::Invalid)
Check whether we can build infrastructure for the given vehicle type.
Definition vehicle.cpp:1945
@ 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.
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
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:759
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:658
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:769
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:1209
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3230
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:3322
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:3216
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3200
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:3340
@ 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:
@ Station
station encountered (could be a target next time)
Definition yapf_type.hpp:26
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