OpenTTD Source 20260731-master-g77ba2b244a
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 "script/api/script_event_types.hpp"
60#include "timer/timer.h"
64
65#include "table/strings.h"
66
67#include "safeguards.h"
68
71static const uint GEN_HASHX_BITS = 6;
72static const uint GEN_HASHY_BITS = 6;
74
77static const uint GEN_HASHX_BUCKET_BITS = 7;
78static const uint GEN_HASHY_BUCKET_BITS = 6;
80
81/* Compute hash for vehicle coord */
82static inline uint GetViewportHashX(int x)
83{
84 return GB(x, GEN_HASHX_BUCKET_BITS + ZOOM_BASE_SHIFT, GEN_HASHX_BITS);
85}
86
87static inline uint GetViewportHashY(int y)
88{
89 return GB(y, GEN_HASHY_BUCKET_BITS + ZOOM_BASE_SHIFT, GEN_HASHY_BITS) << GEN_HASHX_BITS;
90}
91
92static inline uint GetViewportHash(int x, int y)
93{
94 return GetViewportHashX(x) + GetViewportHashY(y);
95}
96
99static const uint GEN_HASHX_SIZE = 1 << (GEN_HASHX_BUCKET_BITS + GEN_HASHX_BITS + ZOOM_BASE_SHIFT);
100static const uint GEN_HASHY_SIZE = 1 << (GEN_HASHY_BUCKET_BITS + GEN_HASHY_BITS + ZOOM_BASE_SHIFT);
102
105static const uint GEN_HASHX_INC = 1;
106static const uint GEN_HASHY_INC = 1 << GEN_HASHX_BITS;
108
111static const uint GEN_HASHX_MASK = (1 << GEN_HASHX_BITS) - 1;
112static const uint GEN_HASHY_MASK = ((1 << GEN_HASHY_BITS) - 1) << GEN_HASHX_BITS;
114
118
119
120
124void VehicleSpriteSeq::GetBounds(Rect *bounds) const
125{
126 bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
127 for (uint i = 0; i < this->count; ++i) {
128 const Sprite *spr = GetSprite(this->seq[i].sprite, SpriteType::Normal);
129 if (i == 0) {
130 bounds->left = spr->x_offs;
131 bounds->top = spr->y_offs;
132 bounds->right = spr->width + spr->x_offs - 1;
133 bounds->bottom = spr->height + spr->y_offs - 1;
134 } else {
135 if (spr->x_offs < bounds->left) bounds->left = spr->x_offs;
136 if (spr->y_offs < bounds->top) bounds->top = spr->y_offs;
137 int right = spr->width + spr->x_offs - 1;
138 int bottom = spr->height + spr->y_offs - 1;
139 if (right > bounds->right) bounds->right = right;
140 if (bottom > bounds->bottom) bounds->bottom = bottom;
141 }
142 }
143}
144
152void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const
153{
154 for (uint i = 0; i < this->count; ++i) {
155 PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal;
156 DrawSprite(this->seq[i].sprite, pal, x, y);
157 }
158}
159
166bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
167{
168 /* We can always generate the Company pointer when we have the vehicle.
169 * However this takes time and since the Company pointer is often present
170 * when this function is called then it's faster to pass the pointer as an
171 * argument rather than finding it again. */
172 assert(c == Company::Get(this->owner));
173
174 if (use_renew_setting && !c->settings.engine_renew) return false;
175 if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
176
177 /* Only engines need renewing */
178 if (this->type == VehicleType::Train && !Train::From(this)->IsEngine()) return false;
179
180 return true;
181}
182
189{
190 assert(v != nullptr);
191 SetWindowDirty(WindowClass::VehicleDetails, v->index); // ensure that last service date and reliability are updated
192
193 do {
198 /* Prevent vehicles from breaking down directly after exiting the depot. */
199 v->breakdown_chance /= 4;
200 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::Reduced) v->breakdown_chance = 0; // on reduced breakdown
201 v = v->Next();
202 } while (v != nullptr && v->HasEngineType());
203}
204
212{
213 /* Stopped or crashed vehicles will not move, as such making unmovable
214 * vehicles to go for service is lame. */
215 if (this->vehstatus.Any({VehState::Stopped, VehState::Crashed})) return false;
216
217 /* Are we ready for the next service cycle? */
218 const Company *c = Company::Get(this->owner);
219
220 /* Service intervals can be measured in different units, which we handle individually. */
221 if (this->ServiceIntervalIsPercent()) {
222 /* Service interval is in percents. */
223 if (this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) return false;
225 /* Service interval is in minutes. */
226 if (this->date_of_last_service + (this->GetServiceInterval() * EconomyTime::DAYS_IN_ECONOMY_MONTH) >= TimerGameEconomy::date) return false;
227 } else {
228 /* Service interval is in days. */
229 if (this->date_of_last_service + this->GetServiceInterval() >= TimerGameEconomy::date) return false;
230 }
231
232 /* If we're servicing anyway, because we have not disabled servicing when
233 * there are no breakdowns or we are playing with breakdowns, bail out. */
234 if (!_settings_game.order.no_servicing_if_no_breakdowns ||
235 _settings_game.difficulty.vehicle_breakdowns != VehicleBreakdowns::None) {
236 return true;
237 }
238
239 /* Test whether there is some pending autoreplace.
240 * Note: We do this after the service-interval test.
241 * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
242 bool pending_replace = false;
243 Money needed_money = c->settings.engine_renew_money;
244 if (needed_money > GetAvailableMoney(c->index)) return false;
245
246 for (const Vehicle *v = this; v != nullptr; v = (v->type == VehicleType::Train) ? Train::From(v)->GetNextUnit() : nullptr) {
247 bool replace_when_old = false;
248 EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
249
250 /* Check engine availability */
251 if (new_engine == EngineID::Invalid() || !Engine::Get(new_engine)->company_avail.Test(v->owner)) continue;
252 /* Is the vehicle old if we are not always replacing? */
253 if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
254
255 /* Check refittability */
256 CargoTypes available_cargo_types, union_mask;
257 GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
258 /* Is there anything to refit? */
259 if (union_mask.Any()) {
262 if (!HasAtMostOneBit(cargo_mask.base())) {
263 CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(new_engine);
264 if ((cargo_mask & new_engine_default_cargoes) != cargo_mask) {
265 /* We cannot refit to mixed cargoes in an automated way */
266 continue;
267 }
268 /* engine_type is already a mixed cargo type which matches the incoming vehicle by default, no refit required */
269 } else {
270 /* Did the old vehicle carry anything? */
272 /* We can't refit the vehicle to carry the cargo we want */
273 if (!available_cargo_types.Test(cargo_type)) continue;
274 }
275 }
276 }
277
278 /* Check money.
279 * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
280 pending_replace = true;
281 needed_money += 2 * Engine::Get(new_engine)->GetCost();
282 if (needed_money > GetAvailableMoney(c->index)) return false;
283 }
284
285 return pending_replace;
286}
287
294{
295 if (this->HasDepotOrder()) return false;
296 if (this->current_order.IsType(OT_LOADING)) return false;
297 if (this->current_order.IsType(OT_GOTO_DEPOT) && !this->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::Service)) return false;
298 return NeedsServicing();
299}
300
302{
303 assert(!this->vehstatus.Test(VehState::Crashed));
304 assert(this->Previous() == nullptr); // IsPrimaryVehicle fails for free-wagon-chains
305
306 uint pass = 0;
307 /* Stop the vehicle. */
308 if (this->IsPrimaryVehicle()) this->vehstatus.Set(VehState::Stopped);
309 /* crash all wagons, and count passengers */
310 for (Vehicle *v = this; v != nullptr; v = v->Next()) {
311 /* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */
312 if (IsCargoInClass(v->cargo_type, CargoClass::Passengers)) pass += v->cargo.TotalCount();
313 v->vehstatus.Set(VehState::Crashed);
314 v->MarkAllViewportsDirty();
315 }
316
317 /* Dirty some windows */
319 SetWindowWidgetDirty(WindowClass::VehicleView, this->index, WID_VV_START_STOP);
320 SetWindowDirty(WindowClass::VehicleDetails, this->index);
321 SetWindowDirty(WindowClass::VehicleDepot, this->GetMovingFront()->tile);
322
323 delete this->cargo_payment;
324 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
325
326 return RandomRange(pass + 1); // Randomise deceased passengers.
327}
328
329
338void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBug bug_type, bool critical)
339{
340 const Engine *e = Engine::Get(engine);
341 GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
342
343 /* Missing GRF. Nothing useful can be done in this situation. */
344 if (grfconfig == nullptr) return;
345
346 if (!grfconfig->grf_bugs.Test(bug_type)) {
347 grfconfig->grf_bugs.Set(bug_type);
348 ShowErrorMessage(GetEncodedString(part1, grfconfig->GetName()),
349 GetEncodedString(part2, std::monostate{}, engine), WarningLevel::Critical);
350 if (!_networking) Command<Commands::Pause>::Do(DoCommandFlag::Execute, critical ? PauseMode::Error : PauseMode::Normal, true);
351 }
352
353 /* debug output */
354 Debug(grf, 0, "{}", StrMakeValid(GetString(part1, grfconfig->GetName())));
355
356 Debug(grf, 0, "{}", StrMakeValid(GetString(part2, std::monostate{}, engine)));
357}
358
365{
366 /* show a warning once for each engine in whole game and once for each GRF after each game load */
367 const Engine *engine = u->GetEngine();
368 GrfID grfid = engine->grf_prop.grfid;
369 GRFConfig *grfconfig = GetGRFConfig(grfid);
370 if (_gamelog.GRFBugReverse(grfid, engine->grf_prop.local_id) || !grfconfig->grf_bugs.Test(GRFBug::VehLength)) {
371 ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GRFBug::VehLength, true);
372 }
373}
374
381{
382 this->type = type;
383 this->coord.left = INVALID_COORD;
384 this->sprite_cache.old_coord.left = INVALID_COORD;
385 this->group_id = DEFAULT_GROUP;
386 this->fill_percent_te_id = INVALID_TE_ID;
387 this->first = this;
388 this->last = this;
389 this->colourmap = PAL_NONE;
390 this->cargo_age_counter = 1;
391 this->last_station_visited = StationID::Invalid();
392 this->last_loading_station = StationID::Invalid();
393}
394
399constexpr uint TILE_HASH_BITS = 7;
400constexpr uint TILE_HASH_SIZE = 1 << TILE_HASH_BITS;
401constexpr uint TILE_HASH_MASK = TILE_HASH_SIZE - 1;
402constexpr uint TOTAL_TILE_HASH_SIZE = 1 << (TILE_HASH_BITS * 2);
404
409constexpr uint TILE_HASH_RES = 0;
410
416static inline uint GetTileHash1D(uint p)
417{
418 return GB(p, TILE_HASH_RES, TILE_HASH_BITS);
419}
420
426static inline uint IncTileHash1D(uint h)
427{
428 return (h + 1) & TILE_HASH_MASK;
429}
430
437static inline uint ComposeTileHash(uint hx, uint hy)
438{
439 return hx | hy << TILE_HASH_BITS;
440}
441
448static inline uint GetTileHash(uint x, uint y)
449{
451}
452
453static std::array<Vehicle *, TOTAL_TILE_HASH_SIZE> _vehicle_tile_hash{};
454
462VehiclesNearTileXY::Iterator::Iterator(int32_t x, int32_t y, uint max_dist)
463{
464 /* There are no negative tile coordinates */
465 this->pos_rect.left = std::max<int>(0, x - max_dist);
466 this->pos_rect.right = std::max<int>(0, x + max_dist);
467 this->pos_rect.top = std::max<int>(0, y - max_dist);
468 this->pos_rect.bottom = std::max<int>(0, y + max_dist);
469
470 if (2 * max_dist < TILE_HASH_MASK * TILE_SIZE) {
471 /* Hash area to scan */
472 this->hxmin = this->hx = GetTileHash1D(this->pos_rect.left / TILE_SIZE);
473 this->hxmax = GetTileHash1D(this->pos_rect.right / TILE_SIZE);
474 this->hymin = this->hy = GetTileHash1D(this->pos_rect.top / TILE_SIZE);
475 this->hymax = GetTileHash1D(this->pos_rect.bottom / TILE_SIZE);
476 } else {
477 /* Scan all */
478 this->hxmin = this->hx = 0;
479 this->hxmax = TILE_HASH_MASK;
480 this->hymin = this->hy = 0;
481 this->hymax = TILE_HASH_MASK;
482 }
483
484 this->current_veh = _vehicle_tile_hash[ComposeTileHash(this->hx, this->hy)];
485 this->SkipEmptyBuckets();
486 this->SkipFalseMatches();
487}
488
493{
494 assert(this->current_veh != nullptr);
495 this->current_veh = this->current_veh->hash_tile_next;
496 this->SkipEmptyBuckets();
497}
498
503{
504 while (this->current_veh == nullptr) {
505 if (this->hx != this->hxmax) {
506 this->hx = IncTileHash1D(this->hx);
507 } else if (this->hy != this->hymax) {
508 this->hx = this->hxmin;
509 this->hy = IncTileHash1D(this->hy);
510 } else {
511 return;
512 }
513 this->current_veh = _vehicle_tile_hash[ComposeTileHash(this->hx, this->hy)];
514 }
515}
516
521{
522 while (this->current_veh != nullptr && !this->pos_rect.Contains({this->current_veh->x_pos, this->current_veh->y_pos})) this->Increment();
523}
524
531{
532 this->current = _vehicle_tile_hash[GetTileHash(TileX(tile), TileY(tile))];
533 this->SkipFalseMatches();
534}
535
541{
542 this->current = this->current->hash_tile_next;
543}
544
549{
550 while (this->current != nullptr && this->current->tile != this->tile) this->Increment();
551}
552
559{
560 int z = GetTileMaxPixelZ(tile);
561
562 /* Value v is not safe in MP games, however, it is used to generate a local
563 * error message only (which may be different for different machines).
564 * Such a message does not affect MP synchronisation.
565 */
566 for (const Vehicle *v : VehiclesOnTile(tile)) {
567 if (v->type == VehicleType::Disaster || (v->type == VehicleType::Aircraft && v->subtype == AIR_SHADOW)) continue;
568 if (v->z_pos > z) continue;
569
570 return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + to_underlying(v->type));
571 }
572 return CommandCost();
573}
574
583{
584 for (TileIndex t : {tile, endtile}) {
585 /* Value v is not safe in MP games, however, it is used to generate a local
586 * error message only (which may be different for different machines).
587 * Such a message does not affect MP synchronisation.
588 */
589 for (const Vehicle *v : VehiclesOnTile(t)) {
590 if (v->type != VehicleType::Train && v->type != VehicleType::Road && v->type != VehicleType::Ship) continue;
591 if (v == ignore) continue;
592 return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + to_underlying(v->type));
593 }
594 }
595 return CommandCost();
596}
597
607{
608 /* Value v is not safe in MP games, however, it is used to generate a local
609 * error message only (which may be different for different machines).
610 * Such a message does not affect MP synchronisation.
611 */
612 for (const Vehicle *v : VehiclesOnTile(tile)) {
613 if (v->type != VehicleType::Train) continue;
614
615 const Train *t = Train::From(v);
616 if ((t->track != track_bits) && !TracksOverlap(t->track | track_bits)) continue;
617
618 return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + to_underlying(v->type));
619 }
620 return CommandCost();
621}
622
623static void UpdateVehicleTileHash(Vehicle *v, bool remove)
624{
625 Vehicle **old_hash = v->hash_tile_current;
626 Vehicle **new_hash;
627
628 if (remove) {
629 new_hash = nullptr;
630 } else {
631 new_hash = &_vehicle_tile_hash[GetTileHash(TileX(v->tile), TileY(v->tile))];
632 }
633
634 if (old_hash == new_hash) return;
635
636 /* Remove from the old position in the hash table */
637 if (old_hash != nullptr) {
640 }
641
642 /* Insert vehicle at beginning of the new position in the hash table */
643 if (new_hash != nullptr) {
644 v->hash_tile_next = *new_hash;
645 if (v->hash_tile_next != nullptr) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next;
646 v->hash_tile_prev = new_hash;
647 *new_hash = v;
648 }
649
650 /* Remember current hash position */
651 v->hash_tile_current = new_hash;
652}
653
654static std::array<Vehicle *, 1 << (GEN_HASHX_BITS + GEN_HASHY_BITS)> _vehicle_viewport_hash{};
655
656static void UpdateVehicleViewportHash(Vehicle *v, int x, int y, int old_x, int old_y)
657{
658 Vehicle **old_hash, **new_hash;
659
660 new_hash = (x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GetViewportHash(x, y)];
661 old_hash = (old_x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GetViewportHash(old_x, old_y)];
662
663 if (old_hash == new_hash) return;
664
665 /* remove from hash table? */
666 if (old_hash != nullptr) {
669 }
670
671 /* insert into hash table? */
672 if (new_hash != nullptr) {
673 v->hash_viewport_next = *new_hash;
675 v->hash_viewport_prev = new_hash;
676 *new_hash = v;
677 }
678}
679
680void ResetVehicleHash()
681{
682 for (Vehicle *v : Vehicle::Iterate()) { v->hash_tile_current = nullptr; }
683 _vehicle_viewport_hash.fill(nullptr);
684 _vehicle_tile_hash.fill(nullptr);
685}
686
687void ResetVehicleColourMap()
688{
689 for (Vehicle *v : Vehicle::Iterate()) { v->colourmap = PAL_NONE; }
690}
691
696using AutoreplaceMap = std::map<VehicleID, bool>;
697static AutoreplaceMap _vehicles_to_autoreplace;
698
699void InitializeVehicles()
700{
701 _vehicles_to_autoreplace.clear();
702 ResetVehicleHash();
703}
704
705uint CountVehiclesInChain(const Vehicle *v)
706{
707 uint count = 0;
708 do count++; while ((v = v->Next()) != nullptr);
709 return count;
710}
711
717{
718 switch (this->type) {
719 case VehicleType::Aircraft: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
721 return !this->IsArticulatedPart() && // tenders and other articulated parts
722 !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
724 case VehicleType::Ship: return true;
725 default: return false; // Only count company buildable vehicles
726 }
727}
728
734{
735 switch (this->type) {
739 case VehicleType::Ship: return true;
740 default: return false;
741 }
742}
743
750{
751 return Engine::Get(this->engine_type);
752}
753
760{
761 return this->GetEngine()->GetGRF();
762}
763
770{
771 return this->GetEngine()->GetGRFID();
772}
773
780{
781 this->date_of_last_service = std::max(this->date_of_last_service + interval, TimerGameEconomy::Date(0));
782 /* date_of_last_service_newgrf is not updated here as it must stay stable
783 * for vehicles outside of a depot. */
784}
785
794{
795 if (path_found) {
796 /* Route found, is the vehicle marked with "lost" flag? */
797 if (!this->vehicle_flags.Test(VehicleFlag::PathfinderLost)) return;
798
799 /* Clear the flag as the PF's problem was solved. */
801 SetWindowWidgetDirty(WindowClass::VehicleView, this->index, WID_VV_START_STOP);
803 /* Delete the news item. */
805 return;
806 }
807
808 /* Were we already lost? */
809 if (this->vehicle_flags.Test(VehicleFlag::PathfinderLost)) return;
810
811 /* It is first time the problem occurred, set the "lost" flag. */
813 SetWindowWidgetDirty(WindowClass::VehicleView, this->index, WID_VV_START_STOP);
815
816 /* Unbunching data is no longer valid. */
817 this->ResetDepotUnbunching();
818
819 /* Notify user about the event. */
820 AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
821 if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
822 AddVehicleAdviceNewsItem(AdviceType::VehicleLost, GetEncodedString(STR_NEWS_VEHICLE_IS_LOST, this->index), this->index);
823 }
824}
825
828{
829 if (CleaningPool()) return;
830
833 st->loading_vehicles.remove(this);
834
836 this->CancelReservation(StationID::Invalid(), st);
837 delete this->cargo_payment;
838 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
839 }
840
841 if (this->IsEngineCountable()) {
843 if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
845
848 }
849
850 Company::Get(this->owner)->freeunits[this->type].ReleaseID(this->unitnumber);
851
852 if (this->type == VehicleType::Aircraft && this->IsPrimaryVehicle()) {
853 Aircraft *a = Aircraft::From(this);
855 if (st != nullptr) {
856 const auto &layout = st->airport.GetFTA()->layout;
857 st->airport.blocks.Reset(layout[a->previous_pos].blocks | layout[a->pos].blocks);
858 }
859 }
860
861
862 if (this->type == VehicleType::Road && this->IsPrimaryVehicle()) {
864 if (!v->vehstatus.Test(VehState::Crashed) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
865 /* Leave the drive through roadstop, when you have not already left it. */
867 }
868
869 if (v->disaster_vehicle != VehicleID::Invalid()) ReleaseDisasterVehicle(v->disaster_vehicle);
870 }
871
872 if (this->Previous() == nullptr) {
873 InvalidateWindowData(WindowClass::VehicleDepot, this->tile);
874 }
875
876 if (this->IsPrimaryVehicle()) {
877 CloseWindowById(WindowClass::VehicleView, this->index);
878 CloseWindowById(WindowClass::VehicleOrders, this->index);
879 CloseWindowById(WindowClass::VehicleRefit, this->index);
880 CloseWindowById(WindowClass::VehicleDetails, this->index);
881 CloseWindowById(WindowClass::VehicleTimetable, this->index);
882 SetWindowDirty(WindowClass::Company, this->owner);
884 }
886
887 this->cargo.Truncate();
890
891 StopGlobalFollowVehicle(this);
892}
893
895{
896 if (CleaningPool()) {
897 this->cargo.OnCleanPool();
898 return;
899 }
900
901 /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
902 * it may happen that vehicle chain is deleted when visible */
903 if (!this->vehstatus.Test(VehState::Hidden)) this->MarkAllViewportsDirty();
904
905 Vehicle *v = this->Next();
906 this->SetNext(nullptr);
907
908 delete v;
909
910 UpdateVehicleTileHash(this, true);
911 UpdateVehicleViewportHash(this, INVALID_COORD, 0, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
912 if (this->type != VehicleType::Effect) {
915 }
916}
917
923{
924 /* Vehicle should stop in the depot if it was in 'stopping' state */
925 _vehicles_to_autoreplace[v->index] = !v->vehstatus.Test(VehState::Stopped);
926
927 /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
928 * stopping in the depot, so we stop it to ensure that it will not reserve
929 * the path out of the depot before we might autoreplace it to a different
930 * engine. The new engine would not own the reserved path we store that we
931 * stopped the vehicle, so autoreplace can start it again */
933}
934
939{
940 if (_game_mode != GameMode::Normal) return;
941
942 /* Run the calendar day proc for every DAY_TICKS vehicle starting at TimerGameCalendar::date_fract. */
944 Vehicle *v = Vehicle::Get(i);
945 if (v == nullptr) continue;
946 v->OnNewCalendarDay();
947 }
948}
949
956{
957 if (_game_mode != GameMode::Normal) return;
958
959 /* Run the economy day proc for every DAY_TICKS vehicle starting at TimerGameEconomy::date_fract. */
961 Vehicle *v = Vehicle::Get(i);
962 if (v == nullptr) continue;
963
964 /* Call the 32-day callback if needed */
965 if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
966 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
967 if (callback != CALLBACK_FAILED) {
968 if (HasBit(callback, 0)) {
969 TriggerVehicleRandomisation(v, VehicleRandomTrigger::Callback32); // Trigger vehicle trigger 10
970 }
971
972 /* After a vehicle trigger, the graphics and properties of the vehicle could change.
973 * Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */
974 if (callback != 0) v->First()->MarkDirty();
975
976 if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
977 }
978 }
979
980 /* This is called once per day for each vehicle, but not in the first tick of the day */
981 v->OnNewEconomyDay();
982 }
983}
984
985void CallVehicleTicks()
986{
987 _vehicles_to_autoreplace.clear();
988
990
991 {
992 PerformanceMeasurer framerate(PerformanceElement::GameLoopEconomy);
994 }
999
1000 for (Vehicle *v : Vehicle::Iterate()) {
1001 [[maybe_unused]] VehicleID vehicle_index = v->index;
1002
1003 /* Vehicle could be deleted in this tick */
1004 if (!v->Tick()) {
1005 assert(Vehicle::Get(vehicle_index) == nullptr);
1006 continue;
1007 }
1008
1009 assert(Vehicle::Get(vehicle_index) == v);
1010
1011 switch (v->type) {
1012 default: break;
1013
1014 case VehicleType::Train:
1015 case VehicleType::Road:
1017 case VehicleType::Ship: {
1018 Vehicle *front = v->First();
1019
1020 if (v->vcache.cached_cargo_age_period != 0) {
1022 if (--v->cargo_age_counter == 0) {
1023 v->cargo.AgeCargo();
1025 }
1026 }
1027
1028 /* Do not play any sound when crashed */
1029 if (front->vehstatus.Test(VehState::Crashed)) continue;
1030
1031 /* Do not play any sound when in depot or tunnel */
1032 if (v->vehstatus.Test(VehState::Hidden)) continue;
1033
1034 /* Do not play any sound when stopped */
1035 if (front->vehstatus.Test(VehState::Stopped) && (front->type != VehicleType::Train || front->cur_speed == 0)) continue;
1036
1037 /* Update motion counter for animation purposes. */
1038 v->motion_counter += front->cur_speed;
1039
1040 /* Check vehicle type specifics */
1041 switch (v->type) {
1042 case VehicleType::Train:
1043 if (!Train::From(v)->IsEngine()) continue;
1044 break;
1045
1046 case VehicleType::Road:
1047 if (!RoadVehicle::From(v)->IsFrontEngine()) continue;
1048 break;
1049
1051 if (!Aircraft::From(v)->IsNormalAircraft()) continue;
1052 break;
1053
1054 default:
1055 break;
1056 }
1057
1058 /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
1059 if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
1060
1061 /* Play an alternating running sound every 16 ticks */
1062 if (GB(v->tick_counter, 0, 4) == 0) {
1063 /* Play running sound when speed > 0 and not braking */
1064 bool running = (front->cur_speed > 0) && !front->vehstatus.Any({VehState::Stopped, VehState::TrainSlowing});
1066 }
1067
1068 break;
1069 }
1070 }
1071 }
1072
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 AutoRestoreBackup cur_company(_current_company, 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
1120static void DoDrawVehicle(const Vehicle *v)
1121{
1122 PaletteID pal = PAL_NONE;
1123
1125
1126 /* Check whether the vehicle shall be transparent due to the game state */
1127 bool shadowed = v->vehstatus.Test(VehState::Shadow);
1128
1129 if (v->type == VehicleType::Effect) {
1130 /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
1131 * However, transparent smoke and bubbles look weird, so always hide them. */
1133 if (to != TransparencyOption::Invalid && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
1134 }
1135
1137 for (uint i = 0; i < v->sprite_cache.sprite_seq.count; ++i) {
1138 PaletteID pal2 = v->sprite_cache.sprite_seq.seq[i].pal;
1139 if (!pal2 || v->vehstatus.Test(VehState::Crashed)) pal2 = pal;
1140 AddSortableSpriteToDraw(v->sprite_cache.sprite_seq.seq[i].sprite, pal2, v->x_pos, v->y_pos, v->z_pos, v->bounds, shadowed);
1141 }
1143}
1144
1150{
1151 /* The bounding rectangle */
1152 const int l = dpi->left;
1153 const int r = dpi->left + dpi->width;
1154 const int t = dpi->top;
1155 const int b = dpi->top + dpi->height;
1156
1157 /* Border size of MAX_VEHICLE_PIXEL_xy */
1158 const int xb = MAX_VEHICLE_PIXEL_X * ZOOM_BASE;
1159 const int yb = MAX_VEHICLE_PIXEL_Y * ZOOM_BASE;
1160
1161 /* The hash area to scan */
1162 uint xl, xu, yl, yu;
1163
1164 if (static_cast<uint>(dpi->width + xb) < GEN_HASHX_SIZE) {
1165 xl = GetViewportHashX(l - xb);
1166 xu = GetViewportHashX(r);
1167 } else {
1168 /* scan whole hash row */
1169 xl = 0;
1170 xu = GEN_HASHX_MASK;
1171 }
1172
1173 if (static_cast<uint>(dpi->height + yb) < GEN_HASHY_SIZE) {
1174 yl = GetViewportHashY(t - yb);
1175 yu = GetViewportHashY(b);
1176 } else {
1177 /* scan whole column */
1178 yl = 0;
1179 yu = GEN_HASHY_MASK;
1180 }
1181
1182 for (uint y = yl;; y = (y + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1183 for (uint x = xl;; x = (x + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1184 const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
1185
1186 while (v != nullptr) {
1187
1188 if (!v->vehstatus.Test(VehState::Hidden) &&
1189 l <= v->coord.right + xb &&
1190 t <= v->coord.bottom + yb &&
1191 r >= v->coord.left - xb &&
1192 b >= v->coord.top - yb)
1193 {
1194 /*
1195 * This vehicle can potentially be drawn as part of this viewport and
1196 * needs to be revalidated, as the sprite may not be correct.
1197 */
1199 VehicleSpriteSeq seq;
1201
1202 if (seq.IsValid() && v->sprite_cache.sprite_seq != seq) {
1203 v->sprite_cache.sprite_seq = seq;
1204 /*
1205 * A sprite change may also result in a bounding box change,
1206 * so we need to update the bounding box again before we
1207 * check to see if the vehicle should be drawn. Note that
1208 * we can't interfere with the viewport hash at this point,
1209 * so we keep the original hash on the assumption there will
1210 * not be a significant change in the top and left coordinates
1211 * of the vehicle.
1212 */
1214
1215 }
1216
1218 }
1219
1220 if (l <= v->coord.right &&
1221 t <= v->coord.bottom &&
1222 r >= v->coord.left &&
1223 b >= v->coord.top) DoDrawVehicle(v);
1224 }
1225
1226 v = v->hash_viewport_next;
1227 }
1228
1229 if (x == xu) break;
1230 }
1231
1232 if (y == yu) break;
1233 }
1234}
1235
1243Vehicle *CheckClickOnVehicle(const Viewport &vp, int x, int y)
1244{
1245 Vehicle *found = nullptr;
1246 uint dist, best_dist = UINT_MAX;
1247
1248 x -= vp.left;
1249 y -= vp.top;
1250 if (!IsInsideMM(x, 0, vp.width) || !IsInsideMM(y, 0, vp.height)) return nullptr;
1251
1252 x = ScaleByZoom(x, vp.zoom) + vp.virtual_left;
1253 y = ScaleByZoom(y, vp.zoom) + vp.virtual_top;
1254
1255 /* Border size of MAX_VEHICLE_PIXEL_xy */
1256 const int xb = MAX_VEHICLE_PIXEL_X * ZOOM_BASE;
1257 const int yb = MAX_VEHICLE_PIXEL_Y * ZOOM_BASE;
1258
1259 /* The hash area to scan */
1260 uint xl = GetViewportHashX(x - xb);
1261 uint xu = GetViewportHashX(x);
1262 uint yl = GetViewportHashY(y - yb);
1263 uint yu = GetViewportHashY(y);
1264
1265 for (uint hy = yl;; hy = (hy + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1266 for (uint hx = xl;; hx = (hx + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1267 Vehicle *v = _vehicle_viewport_hash[hx + hy]; // already masked & 0xFFF
1268
1269 while (v != nullptr) {
1270 if (!v->vehstatus.Any({VehState::Hidden, VehState::Unclickable}) &&
1271 x >= v->coord.left && x <= v->coord.right &&
1272 y >= v->coord.top && y <= v->coord.bottom) {
1273
1274 dist = std::max(
1275 abs(((v->coord.left + v->coord.right) >> 1) - x),
1276 abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1277 );
1278
1279 if (dist < best_dist) {
1280 found = v;
1281 best_dist = dist;
1282 }
1283 }
1284 v = v->hash_viewport_next;
1285 }
1286 if (hx == xu) break;
1287 }
1288 if (hy == yu) break;
1289 }
1290
1291 return found;
1292}
1293
1299{
1300 v->value -= v->value >> 8;
1301 SetWindowDirty(WindowClass::VehicleDetails, v->index);
1302}
1303
1304static const uint8_t _breakdown_chance[64] = {
1305 3, 3, 3, 3, 3, 3, 3, 3,
1306 4, 4, 5, 5, 6, 6, 7, 7,
1307 8, 8, 9, 9, 10, 10, 11, 11,
1308 12, 13, 13, 13, 13, 14, 15, 16,
1309 17, 19, 21, 25, 28, 31, 34, 37,
1310 40, 44, 48, 52, 56, 60, 64, 68,
1311 72, 80, 90, 100, 110, 120, 130, 140,
1312 150, 170, 190, 210, 230, 250, 250, 250,
1313};
1314
1320{
1321 /* Vehicles in the menu don't break down. */
1322 if (_game_mode == GameMode::Menu) return;
1323
1324 /* If both breakdowns and automatic servicing are disabled, we don't decrease reliability or break down. */
1325 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::None && _settings_game.order.no_servicing_if_no_breakdowns) return;
1326
1327 /* With Reduced breakdowns, vehicles (un)loading at stations don't lose reliability. */
1328 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::Reduced && v->current_order.IsType(OT_LOADING)) return;
1329
1330 /* Decrease reliability. */
1331 int rel, rel_old;
1332 v->reliability = rel = std::max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
1333 if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WindowClass::VehicleDetails, v->index);
1334
1335 /* Some vehicles lose reliability but won't break down. */
1336 /* Breakdowns are disabled. */
1337 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::None) return;
1338 /* The vehicle is already broken down. */
1339 if (v->breakdown_ctr != 0) return;
1340 /* The vehicle is stopped or going very slow. */
1341 if (v->cur_speed < 5) return;
1342 /* The vehicle has been manually stopped. */
1343 if (v->vehstatus.Test(VehState::Stopped)) return;
1344
1345 /* Time to consider breaking down. */
1346
1347 uint32_t r = Random();
1348
1349 /* Increase chance of failure. */
1350 int chance = v->breakdown_chance + 1;
1351 if (Chance16I(1, 25, r)) chance += 25;
1353
1354 /* Calculate reliability value to use in comparison. */
1355 rel = v->reliability;
1356 if (v->type == VehicleType::Ship) rel += 0x6666;
1357
1358 /* Reduce the chance if the player has chosen the Reduced setting. */
1359 if (_settings_game.difficulty.vehicle_breakdowns == VehicleBreakdowns::Reduced) rel += 0x6666;
1360
1361 /* Check the random chance and inform the vehicle of the result. */
1362 if (_breakdown_chance[ClampTo<uint16_t>(rel) >> 10] <= v->breakdown_chance) {
1363 v->breakdown_ctr = GB(r, 16, 6) + 0x3F;
1364 v->breakdown_delay = GB(r, 24, 7) + 0x80;
1365 v->breakdown_chance = 0;
1366 }
1367}
1368
1376{
1377 /* Possible states for Vehicle::breakdown_ctr
1378 * 0 - vehicle is running normally
1379 * 1 - vehicle is currently broken down
1380 * 2 - vehicle is going to break down now
1381 * >2 - vehicle is counting down to the actual breakdown event */
1382 switch (this->breakdown_ctr) {
1383 case 0:
1384 return false;
1385
1386 case 2:
1387 this->breakdown_ctr = 1;
1388
1389 if (this->breakdowns_since_last_service != 255) {
1391 }
1392
1393 if (this->type == VehicleType::Aircraft) {
1394 /* Aircraft just need this flag, the rest is handled elsewhere */
1396 } else {
1397 this->cur_speed = 0;
1398
1399 if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
1400 bool train_or_ship = this->type == VehicleType::Train || this->type == VehicleType::Ship;
1401 SndPlayVehicleFx((_settings_game.game_creation.landscape != LandscapeType::Toyland) ?
1404 }
1405
1406 if (!this->vehstatus.Test(VehState::Hidden) && !EngInfo(this->engine_type)->misc_flags.Test(EngineMiscFlag::NoBreakdownSmoke)) {
1408 if (u != nullptr) u->animation_state = this->breakdown_delay * 2;
1409 }
1410 }
1411
1412 this->MarkDirty(); // Update graphics after speed is zeroed
1413 SetWindowDirty(WindowClass::VehicleView, this->index);
1414 SetWindowDirty(WindowClass::VehicleDetails, this->index);
1415
1416 [[fallthrough]];
1417 case 1:
1418 /* Aircraft breakdowns end only when arriving at the airport */
1419 if (this->type == VehicleType::Aircraft) return false;
1420
1421 /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
1422 if ((this->tick_counter & (this->type == VehicleType::Train ? 3 : 1)) == 0) {
1423 if (--this->breakdown_delay == 0) {
1424 this->breakdown_ctr = 0;
1425 this->MarkDirty();
1426 SetWindowDirty(WindowClass::VehicleView, this->index);
1427 }
1428 }
1429 return true;
1430
1431 default:
1432 if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
1433 return false;
1434 }
1435}
1436
1448
1454{
1455 if (v->age < CalendarTime::MAX_DATE) v->age++;
1456
1457 if (!v->IsPrimaryVehicle() && (v->type != VehicleType::Train || !Train::From(v)->IsEngine())) return;
1458
1459 auto age = v->age - v->max_age;
1460 for (int32_t i = 0; i <= 4; i++) {
1462 v->reliability_spd_dec <<= 1;
1463 break;
1464 }
1465 }
1466
1467 SetWindowDirty(WindowClass::VehicleDetails, v->index);
1468
1469 /* Don't warn if warnings are disabled */
1470 if (!_settings_client.gui.old_vehicle_warn) return;
1471
1472 /* 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 */
1473 if (v->Previous() != nullptr || v->owner != _local_company || v->vehstatus.Any({VehState::Crashed, VehState::Stopped})) return;
1474
1475 const Company *c = Company::Get(v->owner);
1476 /* Don't warn if a renew is active */
1477 if (c->settings.engine_renew && v->GetEngine()->company_avail.Any()) return;
1478 /* Don't warn if a replacement is active */
1480
1481 StringID str;
1483 str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1485 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1487 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1488 } else {
1489 return;
1490 }
1491
1493}
1494
1504uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
1505{
1506 int count = 0;
1507 int max = 0;
1508 int cars = 0;
1509 int unloading = 0;
1510 bool loading = false;
1511
1512 bool is_loading = front->current_order.IsType(OT_LOADING);
1513
1514 /* The station may be nullptr when the (colour) string does not need to be set. */
1516 assert(colour == nullptr || (st != nullptr && is_loading));
1517
1518 bool order_no_load = is_loading && front->current_order.GetLoadType() == OrderLoadType::NoLoad;
1519 bool order_full_load = is_loading && front->current_order.IsFullLoadOrder();
1520
1521 /* Count up max and used */
1522 for (const Vehicle *v = front; v != nullptr; v = v->Next()) {
1523 count += v->cargo.StoredCount();
1524 max += v->cargo_cap;
1525 if (v->cargo_cap != 0 && colour != nullptr) {
1526 unloading += v->vehicle_flags.Test(VehicleFlag::CargoUnloading) ? 1 : 0;
1527 loading |= !order_no_load &&
1528 (order_full_load || st->goods[v->cargo_type].HasRating()) &&
1530 cars++;
1531 }
1532 }
1533
1534 if (colour != nullptr) {
1535 if (unloading == 0 && loading) {
1536 *colour = STR_PERCENT_UP;
1537 } else if (unloading == 0 && !loading) {
1538 *colour = STR_PERCENT_NONE;
1539 } else if (cars == unloading || !loading) {
1540 *colour = STR_PERCENT_DOWN;
1541 } else {
1542 *colour = STR_PERCENT_UP_DOWN;
1543 }
1544 }
1545
1546 /* Train without capacity */
1547 if (max == 0) return 100;
1548
1549 /* Return the percentage */
1550 if (count * 2 < max) {
1551 /* Less than 50%; round up, so that 0% means really empty. */
1552 return CeilDiv(count * 100, max);
1553 } else {
1554 /* More than 50%; round down, so that 100% means really full. */
1555 return (count * 100) / max;
1556 }
1557}
1558
1564{
1565 /* Always work with the front of the vehicle */
1566 assert(v == v->First());
1567
1568 switch (v->type) {
1569 case VehicleType::Train: {
1570 Train *t = Train::From(v);
1571 SetWindowClassesDirty(WindowClass::TrainList);
1572 /* Clear path reservation */
1573 SetDepotReservation(t->tile, false);
1574 if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
1575
1577 t->wait_counter = 0;
1581 break;
1582 }
1583
1584 case VehicleType::Road:
1585 SetWindowClassesDirty(WindowClass::RoadVehicleList);
1586 break;
1587
1588 case VehicleType::Ship: {
1589 SetWindowClassesDirty(WindowClass::ShipList);
1590 Ship *ship = Ship::From(v);
1591 ship->state = Track::Depot;
1592 ship->UpdateCache();
1593 ship->UpdateViewport(true, true);
1594 SetWindowDirty(WindowClass::VehicleDepot, v->tile);
1595 break;
1596 }
1597
1599 SetWindowClassesDirty(WindowClass::AircraftList);
1601 break;
1602 default: NOT_REACHED();
1603 }
1604 if (v->type != VehicleType::Train) {
1605 /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
1606 * 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 */
1607 InvalidateWindowData(WindowClass::VehicleDepot, v->tile);
1608 }
1609 SetWindowDirty(WindowClass::VehicleDepot, v->tile);
1610
1612 v->cur_speed = 0;
1613
1615
1616 /* Store that the vehicle entered a depot this tick */
1618
1619 /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
1620 TriggerVehicleRandomisation(v, VehicleRandomTrigger::Depot);
1621 v->MarkDirty();
1622
1623 InvalidateWindowData(WindowClass::VehicleView, v->index);
1624
1625 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1626 const Order *real_order = v->GetOrder(v->cur_real_order_index);
1627
1628 /* Test whether we are heading for this depot. If not, do nothing.
1629 * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
1631 real_order != nullptr && !real_order->GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot) &&
1633 /* We are heading for another depot, keep driving. */
1634 return;
1635 }
1636
1637 if (v->current_order.IsRefit()) {
1638 AutoRestoreBackup cur_company(_current_company, v->owner);
1639 CommandCost cost = ExtractCommandCost(Command<Commands::RefitVehicle>::Do(DoCommandFlag::Execute, v->index, v->current_order.GetRefitCargo(), 0xFF, false, false, 0));
1640
1641 if (cost.Failed()) {
1642 _vehicles_to_autoreplace[v->index] = false;
1643 if (v->owner == _local_company) {
1644 /* Notify the user that we stopped the vehicle */
1645 AddVehicleAdviceNewsItem(AdviceType::RefitFailed, GetEncodedString(STR_NEWS_ORDER_REFIT_FAILED, v->index), v->index);
1646 }
1647 } else if (cost.GetCost() != 0) {
1648 v->profit_this_year -= cost.GetCost() << 8;
1649 if (v->owner == _local_company) {
1651 }
1652 }
1653 }
1654
1656 /* Part of orders */
1658 UpdateVehicleTimetable(v, true);
1660 }
1662 /* Vehicles are always stopped on entering depots. Do not restart this one. */
1663 _vehicles_to_autoreplace[v->index] = false;
1664 /* Invalidate last_loading_station. As the link from the station
1665 * before the stop to the station after the stop can't be predicted
1666 * we shouldn't construct it when the vehicle visits the next stop. */
1667 v->last_loading_station = StationID::Invalid();
1668
1669 /* Clear unbunching data. */
1671
1672 /* Announce that the vehicle is waiting to players and AIs. */
1673 if (v->owner == _local_company) {
1674 AddVehicleAdviceNewsItem(AdviceType::VehicleWaiting, GetEncodedString(STR_NEWS_TRAIN_IS_WAITING + to_underlying(v->type), v->index), v->index);
1675 }
1676 AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
1677 }
1678
1679 /* If we've entered our unbunching depot, record the round trip duration. */
1682 if (v->round_trip_time == 0) {
1683 /* This might be our first round trip. */
1684 v->round_trip_time = measured_round_trip;
1685 } else {
1686 /* If we have a previous trip, smooth the effects of outlier trip calculations caused by jams or other interference. */
1687 v->round_trip_time = Clamp(measured_round_trip, (v->round_trip_time / 2), ClampTo<TimerGameTick::Ticks>(v->round_trip_time * 2));
1688 }
1689 }
1690
1692 }
1693}
1694
1695
1701{
1702 UpdateVehicleTileHash(this, false);
1703}
1704
1709void Vehicle::UpdateBoundingBoxCoordinates(bool update_cache) const
1710{
1711 Rect new_coord;
1712 this->sprite_cache.sprite_seq.GetBounds(&new_coord);
1713
1714 /* z-bounds are not used. */
1715 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);
1716 new_coord.left += pt.x;
1717 new_coord.top += pt.y;
1718 new_coord.right += pt.x + 2 * ZOOM_BASE;
1719 new_coord.bottom += pt.y + 2 * ZOOM_BASE;
1720
1721 extern bool _draw_bounding_boxes;
1722 if (_draw_bounding_boxes) {
1723 int x = this->x_pos + this->bounds.origin.x;
1724 int y = this->y_pos + this->bounds.origin.y;
1725 int z = this->z_pos + this->bounds.origin.z;
1726 new_coord.left = std::min(new_coord.left, RemapCoords(x + bounds.extent.x, y, z).x);
1727 new_coord.right = std::max(new_coord.right, RemapCoords(x, y + bounds.extent.y, z).x + 1);
1728 new_coord.top = std::min(new_coord.top, RemapCoords(x, y, z + bounds.extent.z).y);
1729 new_coord.bottom = std::max(new_coord.bottom, RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1);
1730 }
1731
1732 if (update_cache) {
1733 /*
1734 * If the old coordinates are invalid, set the cache to the new coordinates for correct
1735 * behaviour the next time the coordinate cache is checked.
1736 */
1737 this->sprite_cache.old_coord = this->coord.left == INVALID_COORD ? new_coord : this->coord;
1738 }
1739 else {
1740 /* Extend the bounds of the existing cached bounding box so the next dirty window is correct */
1741 this->sprite_cache.old_coord.left = std::min(this->sprite_cache.old_coord.left, this->coord.left);
1742 this->sprite_cache.old_coord.top = std::min(this->sprite_cache.old_coord.top, this->coord.top);
1743 this->sprite_cache.old_coord.right = std::max(this->sprite_cache.old_coord.right, this->coord.right);
1744 this->sprite_cache.old_coord.bottom = std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom);
1745 }
1746
1747 this->coord = new_coord;
1748}
1749
1755{
1756 /* If the existing cache is invalid we should ignore it, as it will be set to the current coords by UpdateBoundingBoxCoordinates */
1757 bool ignore_cached_coords = this->sprite_cache.old_coord.left == INVALID_COORD;
1758
1759 this->UpdateBoundingBoxCoordinates(true);
1760
1761 if (ignore_cached_coords) {
1762 UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, INVALID_COORD, INVALID_COORD);
1763 } else {
1764 UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
1765 }
1766
1767 if (dirty) {
1768 if (ignore_cached_coords) {
1769 this->sprite_cache.is_viewport_candidate = this->MarkAllViewportsDirty();
1770 } else {
1771 this->sprite_cache.is_viewport_candidate = ::MarkAllViewportsDirty(
1772 std::min(this->sprite_cache.old_coord.left, this->coord.left),
1773 std::min(this->sprite_cache.old_coord.top, this->coord.top),
1774 std::max(this->sprite_cache.old_coord.right, this->coord.right),
1775 std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom));
1776 }
1777 }
1778}
1779
1784{
1785 if (this->type != VehicleType::Effect) this->UpdatePosition();
1786 this->UpdateViewport(true);
1787}
1788
1794{
1795 return ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
1796}
1797
1804{
1805 static constexpr DirectionIndexArray<Coord2D<int8_t>> delta_coord{{{
1806 {-1, -1}, // N
1807 {-1, 0}, // NE
1808 {-1, 1}, // E
1809 {0, 1}, // SE
1810 {1, 1}, // S
1811 {1, 0}, // SW
1812 {1, -1}, // W
1813 {0, -1}, // NW
1814 }}};
1815
1816 const Coord2D<int8_t> &coord = delta_coord[v->GetMovingDirection()];
1817 int x = v->x_pos + coord.x;
1818 int y = v->y_pos + coord.y;
1819
1821 gp.x = x;
1822 gp.y = y;
1823 gp.old_tile = v->tile;
1824 gp.new_tile = TileVirtXY(x, y);
1825 return gp;
1826}
1827
1828static const Direction _new_direction_table[] = {
1832};
1833
1834Direction GetDirectionTowards(const Vehicle *v, int x, int y)
1835{
1836 int i = 0;
1837
1838 if (y >= v->y_pos) {
1839 if (y != v->y_pos) i += 3;
1840 i += 3;
1841 }
1842
1843 if (x >= v->x_pos) {
1844 if (x != v->x_pos) i++;
1845 i++;
1846 }
1847
1848 Direction dir = v->GetMovingDirection();
1849
1850 DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
1851 if (dirdiff == DirDiff::Same) return dir;
1852 return ChangeDir(dir, LimitDirDiff(dirdiff));
1853}
1854
1865{
1866 return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
1867}
1868
1875{
1876 for (auto it = std::begin(this->used_bitmap); it != std::end(this->used_bitmap); ++it) {
1877 BitmapStorage available = ~(*it);
1878 if (available == 0) continue;
1879 return static_cast<UnitID>(std::distance(std::begin(this->used_bitmap), it) * BITMAP_SIZE + FindFirstBit(available) + 1);
1880 }
1881 return static_cast<UnitID>(this->used_bitmap.size() * BITMAP_SIZE + 1);
1882}
1883
1890{
1891 if (index == 0 || index == UINT16_MAX) return index;
1892
1893 index--;
1894
1895 size_t slot = index / BITMAP_SIZE;
1896 if (slot >= this->used_bitmap.size()) this->used_bitmap.resize(slot + 1);
1897 SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
1898
1899 return index + 1;
1900}
1901
1907{
1908 if (index == 0 || index == UINT16_MAX) return;
1909
1910 index--;
1911
1912 assert(index / BITMAP_SIZE < this->used_bitmap.size());
1913 ClrBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
1914}
1915
1922{
1923 /* Check whether it is allowed to build another vehicle. */
1924 uint max_veh;
1925 switch (type) {
1926 case VehicleType::Train: max_veh = _settings_game.vehicle.max_trains; break;
1927 case VehicleType::Road: max_veh = _settings_game.vehicle.max_roadveh; break;
1928 case VehicleType::Ship: max_veh = _settings_game.vehicle.max_ships; break;
1929 case VehicleType::Aircraft: max_veh = _settings_game.vehicle.max_aircraft; break;
1930 default: NOT_REACHED();
1931 }
1932
1934 if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
1935
1936 return c->freeunits[type].NextID();
1937}
1938
1939
1950{
1951 assert(IsCompanyBuildableVehicleType(type));
1952
1953 if (!Company::IsValidID(_local_company)) return false;
1954
1955 UnitID max;
1956 switch (type) {
1957 case VehicleType::Train:
1958 if (!HasAnyRailTypesAvail(_local_company)) return false;
1959 max = _settings_game.vehicle.max_trains;
1960 break;
1961 case VehicleType::Road:
1962 if (!HasAnyRoadTypesAvail(_local_company, subtype)) return false;
1963 max = _settings_game.vehicle.max_roadveh;
1964 break;
1965 case VehicleType::Ship: max = _settings_game.vehicle.max_ships; break;
1966 case VehicleType::Aircraft: max = _settings_game.vehicle.max_aircraft; break;
1967 default: NOT_REACHED();
1968 }
1969
1970 /* We can build vehicle infrastructure when we may build the vehicle type */
1971 if (max > 0) {
1972 /* Can we actually build the vehicle type? */
1973 for (const Engine *e : Engine::IterateType(type)) {
1974 if (type == VehicleType::Road && GetRoadTramType(e->VehInfo<RoadVehicleInfo>().roadtype) != subtype) continue;
1975 if (e->company_avail.Test(_local_company)) return true;
1976 }
1977 return false;
1978 }
1979
1980 /* We should be able to build infrastructure when we have the actual vehicle type */
1981 for (const Vehicle *v : Vehicle::Iterate()) {
1982 if (v->type == VehicleType::Road && GetRoadTramType(RoadVehicle::From(v)->roadtype) != subtype) continue;
1983 if (v->owner == _local_company && v->type == type) return true;
1984 }
1985
1986 return false;
1987}
1988
1989
1997LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
1998{
1999 CargoType cargo_type = v == nullptr ? INVALID_CARGO : v->cargo_type;
2000 const Engine *e = Engine::Get(engine_type);
2001 switch (e->type) {
2002 default: NOT_REACHED();
2003 case VehicleType::Train:
2004 if (v != nullptr && parent_engine_type != EngineID::Invalid() && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->VehInfo<RailVehicleInfo>().railveh_type != RailVehicleType::Wagon))) {
2005 /* Wagonoverrides use the colour scheme of the front engine.
2006 * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
2007 engine_type = parent_engine_type;
2008 e = Engine::Get(engine_type);
2009 /* Note: Luckily cargo_type is not needed for engines */
2010 }
2011
2012 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
2013 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
2014 assert(IsValidCargoType(cargo_type));
2016 if (!CargoSpec::Get(cargo_type)->is_freight) {
2017 if (parent_engine_type == EngineID::Invalid()) {
2019 } else {
2020 bool is_mu = EngInfo(parent_engine_type)->misc_flags.Test(EngineMiscFlag::RailIsMU);
2021 switch (RailVehInfo(parent_engine_type)->engclass) {
2022 default: NOT_REACHED();
2028 }
2029 }
2030 } else {
2032 }
2033 } else {
2034 bool is_mu = e->info.misc_flags.Test(EngineMiscFlag::RailIsMU);
2035
2036 switch (e->VehInfo<RailVehicleInfo>().engclass) {
2037 default: NOT_REACHED();
2043 }
2044 }
2045
2046 case VehicleType::Road:
2047 /* Always use the livery of the front */
2048 if (v != nullptr && parent_engine_type != EngineID::Invalid()) {
2049 engine_type = parent_engine_type;
2050 e = Engine::Get(engine_type);
2051 cargo_type = v->First()->cargo_type;
2052 }
2053 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
2054 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
2055 assert(IsValidCargoType(cargo_type));
2056
2057 /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
2059 /* Tram */
2061 } else {
2062 /* Bus or truck */
2064 }
2065
2066 case VehicleType::Ship:
2067 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
2068 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
2069 assert(IsValidCargoType(cargo_type));
2071
2073 switch (e->VehInfo<AircraftVehicleInfo>().subtype) {
2074 case AIR_HELI: return LiveryScheme::Helicopter;
2076 case AIR_CTOL | AIR_FAST: return LiveryScheme::LargePlane;
2077 default: NOT_REACHED();
2078 }
2079 }
2080}
2081
2091const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, uint8_t livery_setting)
2092{
2093 const Company *c = Company::Get(company);
2095
2096 if (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company)) {
2097 if (v != nullptr) {
2098 const Group *g = Group::GetIfValid(v->First()->group_id);
2099 if (g != nullptr) {
2100 /* Traverse parents until we find a livery or reach the top */
2101 while (!g->livery.in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary}) && g->parent != GroupID::Invalid()) {
2102 g = Group::Get(g->parent);
2103 }
2104 if (g->livery.in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) return &g->livery;
2105 }
2106 }
2107
2108 /* The default livery is always available for use, but its in_use flag determines
2109 * whether any _other_ liveries are in use. */
2110 if (c->livery[LiveryScheme::Default].in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) {
2111 /* Determine the livery scheme to use */
2112 scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
2113 }
2114 }
2115
2116 return &c->livery[scheme];
2117}
2118
2119
2120static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
2121{
2122 PaletteID map = (v != nullptr) ? v->colourmap : PAL_NONE;
2123
2124 /* Return cached value if any */
2125 if (map != PAL_NONE) return map;
2126
2127 const Engine *e = Engine::Get(engine_type);
2128
2129 /* Check if we should use the colour map callback */
2131 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
2132 /* Failure means "use the default two-colour" */
2133 if (callback != CALLBACK_FAILED) {
2134 static_assert(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
2135 map = GB(callback, 0, 14);
2136 /* If bit 14 is set, then the company colours are applied to the
2137 * map else it's returned as-is. */
2138 if (!HasBit(callback, 14)) {
2139 /* Update cache */
2140 if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2141 return map;
2142 }
2143 }
2144 }
2145
2146 bool twocc = e->info.misc_flags.Test(EngineMiscFlag::Uses2CC);
2147
2148 if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
2149
2150 /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
2151 if (!Company::IsValidID(company)) return map;
2152
2153 const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
2154
2155 map += livery->GetRecolourOffset(twocc);
2156
2157 /* Update cache */
2158 if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2159 return map;
2160}
2161
2168PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
2169{
2170 return GetEngineColourMap(engine_type, company, EngineID::Invalid(), nullptr);
2171}
2172
2179{
2180 if (v->IsGroundVehicle()) {
2181 return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
2182 }
2183
2184 return GetEngineColourMap(v->engine_type, v->owner, EngineID::Invalid(), v);
2185}
2186
2191{
2192 if (this->IsGroundVehicle()) {
2193 GroundVehicleFlags &gv_flags = this->GetGroundVehicleFlags();
2195 /* Do not delete orders, only skip them */
2198 InvalidateVehicleOrder(this, 0);
2199 return;
2200 }
2201 }
2202
2203 auto orders = this->Orders();
2205 while (cur != INVALID_VEH_ORDER_ID) {
2206 if (this->cur_implicit_order_index == this->cur_real_order_index) break;
2207
2208 if (orders[cur].IsType(OT_IMPLICIT)) {
2210 /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2211 } else {
2212 /* Skip non-implicit orders, e.g. service-orders */
2213 if (cur < this->orders->GetNext(cur)) {
2215 } else {
2216 /* Wrapped around. */
2217 this->cur_implicit_order_index = 0;
2218 }
2219 cur = this->orders->GetNext(cur);
2220 }
2221 }
2222}
2223
2229{
2231
2233 if (this->current_order.IsType(OT_GOTO_STATION) &&
2234 this->current_order.GetDestination() == this->last_station_visited) {
2236
2237 /* Now both order indices point to the destination station, and we can start loading */
2238 this->current_order.MakeLoading(true);
2239 UpdateVehicleTimetable(this, true);
2240
2241 /* Furthermore add the Non Stop flag to mark that this station
2242 * is the actual destination of the vehicle, which is (for example)
2243 * necessary to be known for HandleTrainLoading to determine
2244 * whether the train is lost or not; not marking a train lost
2245 * that arrives at random stations is bad. */
2247
2248 } else {
2249 /* We weren't scheduled to stop here. Insert an implicit order
2250 * to show that we are stopping here.
2251 * While only groundvehicles have implicit orders, e.g. aircraft might still enter
2252 * the 'wrong' terminal when skipping orders etc. */
2253 Order *in_list = this->GetOrder(this->cur_implicit_order_index);
2254 if (this->IsGroundVehicle() &&
2255 (in_list == nullptr || !in_list->IsType(OT_IMPLICIT) ||
2256 in_list->GetDestination() != this->last_station_visited)) {
2257 bool suppress_implicit_orders = this->GetGroundVehicleFlags().Test(GroundVehicleFlag::SuppressImplicitOrders);
2258 /* Do not create consecutive duplicates of implicit orders */
2259 const Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : nullptr);
2260 if (prev_order == nullptr ||
2261 (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
2262 prev_order->GetDestination() != this->last_station_visited) {
2263
2264 /* Prefer deleting implicit orders instead of inserting new ones,
2265 * so test whether the right order follows later. In case of only
2266 * implicit orders treat the last order in the list like an
2267 * explicit one, except if the overall number of orders surpasses
2268 * IMPLICIT_ORDER_ONLY_CAP. */
2269 int target_index = this->cur_implicit_order_index;
2270 bool found = false;
2271 while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) {
2272 const Order *order = this->GetOrder(target_index);
2273 if (order == nullptr) break; // No orders.
2274 if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
2275 found = true;
2276 break;
2277 }
2278 target_index++;
2279 if (target_index >= this->orders->GetNumOrders()) {
2280 if (this->GetNumManualOrders() == 0 &&
2282 break;
2283 }
2284 target_index = 0;
2285 }
2286 if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop.
2287 }
2288
2289 if (found) {
2290 if (suppress_implicit_orders) {
2291 /* Skip to the found order */
2292 this->cur_implicit_order_index = target_index;
2293 InvalidateVehicleOrder(this, 0);
2294 } else {
2295 /* Delete all implicit orders up to the station we just reached */
2296 const Order *order = this->GetOrder(this->cur_implicit_order_index);
2297 while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
2298 if (order->IsType(OT_IMPLICIT)) {
2300 } else {
2301 /* Skip non-implicit orders, e.g. service-orders */
2303 }
2304 order = this->GetOrder(this->cur_implicit_order_index);
2305
2306 /* Wrapped around. */
2307 if (order == nullptr) {
2308 this->cur_implicit_order_index = 0;
2309 order = this->GetOrder(this->cur_implicit_order_index);
2310 }
2311 assert(order != nullptr);
2312 }
2313 }
2314 } else if (!suppress_implicit_orders &&
2315 (this->orders == nullptr ? OrderList::CanAllocateItem() : this->orders->GetNumOrders() < MAX_VEH_ORDER_ID)) {
2316 /* Insert new implicit order */
2317 Order implicit_order{};
2318 implicit_order.MakeImplicit(this->last_station_visited);
2319 InsertOrder(this, std::move(implicit_order), this->cur_implicit_order_index);
2321
2322 /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
2323 * Reenable it for this vehicle */
2325 }
2326 }
2327 }
2328 this->current_order.MakeLoading(false);
2329 }
2330
2331 if (this->last_loading_station != StationID::Invalid() &&
2333 (this->current_order.GetLoadType() != OrderLoadType::NoLoad ||
2334 this->current_order.GetUnloadType() != OrderUnloadType::NoUnload)) {
2335 IncreaseStats(Station::Get(this->last_loading_station), this, this->last_station_visited, travel_time);
2336 }
2337
2338 PrepareUnload(this);
2339
2341 SetWindowWidgetDirty(WindowClass::VehicleView, this->index, WID_VV_START_STOP);
2342 SetWindowDirty(WindowClass::VehicleDetails, this->index);
2343 SetWindowDirty(WindowClass::StationView, this->last_station_visited);
2344
2346 this->cur_speed = 0;
2347 this->MarkDirty();
2348}
2349
2357{
2358 for (Vehicle *v = this; v != nullptr; v = v->next) {
2360 if (cargo.ActionCount(VehicleCargoList::MoveToAction::Load) > 0) {
2361 Debug(misc, 1, "cancelling cargo reservation");
2362 cargo.Return(UINT_MAX, &st->goods[v->cargo_type].GetOrCreateData().cargo, next, v->tile);
2363 }
2364 cargo.KeepAll();
2365 }
2366}
2367
2373{
2374 assert(this->current_order.IsType(OT_LOADING));
2375
2376 delete this->cargo_payment;
2377 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
2378
2379 /* Only update the timetable if the vehicle was supposed to stop here. */
2380 if (this->current_order.GetNonStopType().Any()) UpdateVehicleTimetable(this, false);
2381
2382 if (this->current_order.GetLoadType() != OrderLoadType::NoLoad ||
2383 this->current_order.GetUnloadType() != OrderUnloadType::NoUnload) {
2384 if (this->current_order.CanLeaveWithCargo(this->last_loading_station != StationID::Invalid())) {
2385 /* Refresh next hop stats to make sure we've done that at least once
2386 * during the stop and that refit_cap == cargo_cap for each vehicle in
2387 * the consist. */
2388 this->ResetRefitCaps();
2389 LinkRefresher::Run(this);
2390
2391 /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
2394 } else {
2395 /* if the vehicle couldn't load and had to unload or transfer everything
2396 * set the last loading station to invalid as it will leave empty. */
2397 this->last_loading_station = StationID::Invalid();
2398 }
2399 }
2400
2401 this->current_order.MakeLeaveStation();
2403 this->CancelReservation(StationID::Invalid(), st);
2404 st->loading_vehicles.remove(this);
2405
2408
2409 if (this->type == VehicleType::Train && !this->vehstatus.Test(VehState::Crashed)) {
2410 /* Trigger station animation (trains only) */
2411 TileIndex tile = this->GetMovingFront()->tile;
2414 TriggerStationAnimation(st, tile, StationAnimationTrigger::VehicleDeparts);
2415 }
2416
2418 }
2419 if (this->type == VehicleType::Road && !this->vehstatus.Test(VehState::Crashed)) {
2420 /* Trigger road stop animation */
2421 if (IsStationRoadStopTile(this->tile)) {
2423 TriggerRoadStopAnimation(st, this->tile, StationAnimationTrigger::VehicleDeparts);
2424 }
2425 }
2426
2427
2428 this->MarkDirty();
2429}
2430
2435{
2436 for (Vehicle *v = this; v != nullptr; v = v->Next()) v->refit_cap = v->cargo_cap;
2437}
2438
2443{
2444 Company::Get(this->owner)->freeunits[this->type].ReleaseID(this->unitnumber);
2445 this->unitnumber = 0;
2446}
2447
2454{
2455 switch (this->current_order.GetType()) {
2456 case OT_LOADING: {
2457 TimerGameTick::Ticks wait_time = std::max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2458
2459 /* Not the first call for this tick, or still loading */
2460 if (mode || !this->vehicle_flags.Test(VehicleFlag::LoadingFinished) || this->current_order_time < wait_time) return;
2461
2462 this->PlayLeaveStationSound();
2463
2464 this->LeaveStation();
2465
2466 /* Only advance to next order if we just loaded at the current one */
2467 const Order *order = this->GetOrder(this->cur_implicit_order_index);
2468 if (order == nullptr ||
2469 (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2470 order->GetDestination() != this->last_station_visited) {
2471 return;
2472 }
2473 break;
2474 }
2475
2476 case OT_DUMMY: break;
2477
2478 default: return;
2479 }
2480
2482}
2483
2489{
2490 return std::ranges::any_of(this->Orders(), [](const Order &o) {
2491 return o.IsType(OT_GOTO_STATION) && o.IsFullLoadOrder();
2492 });
2493}
2494
2500{
2501 return std::ranges::any_of(this->Orders(), [](const Order &o) { return o.IsType(OT_CONDITIONAL); });
2502}
2503
2509{
2510 return std::ranges::any_of(this->Orders(), [](const Order &o) {
2511 return o.IsType(OT_GOTO_DEPOT) && o.GetDepotActionType().Test(OrderDepotActionFlag::Unbunch);
2512 });
2513}
2514
2521{
2522 /* If we are headed for the first order, we must wrap around back to the last order. */
2523 bool is_first_order = (v->GetOrder(v->cur_implicit_order_index) == v->GetFirstOrder());
2524 const Order *previous_order = (is_first_order) ? v->GetLastOrder() : v->GetOrder(v->cur_implicit_order_index - 1);
2525
2526 if (previous_order == nullptr || !previous_order->IsType(OT_GOTO_DEPOT)) return false;
2527 return previous_order->GetDepotActionType().Test(OrderDepotActionFlag::Unbunch);
2528}
2529
2534{
2535 /* Don't do anything if this is not our unbunching order. */
2536 if (!PreviousOrderIsUnbunching(this)) return;
2537
2538 /* Set the start point for this round trip time. */
2540
2541 /* Tell the timetable we are now "on time." */
2542 this->lateness_counter = 0;
2543 SetWindowDirty(WindowClass::VehicleTimetable, this->index);
2544
2545 /* Find the average travel time of vehicles that we share orders with. */
2546 int num_vehicles = 0;
2547 TimerGameTick::Ticks total_travel_time = 0;
2548
2549 Vehicle *u = this->FirstShared();
2550 for (; u != nullptr; u = u->NextShared()) {
2551 /* Ignore vehicles that are manually stopped or crashed. */
2552 if (u->vehstatus.Any({VehState::Stopped, VehState::Crashed})) continue;
2553
2554 num_vehicles++;
2555 total_travel_time += u->round_trip_time;
2556 }
2557
2558 /* Make sure we cannot divide by 0. */
2559 num_vehicles = std::max(num_vehicles, 1);
2560
2561 /* Calculate the separation by finding the average travel time, then calculating equal separation (minimum 1 tick) between vehicles. */
2562 TimerGameTick::Ticks separation = std::max((total_travel_time / num_vehicles / num_vehicles), 1);
2563 TimerGameTick::TickCounter next_departure = TimerGameTick::counter + separation;
2564
2565 /* Set the departure time of all vehicles that we share orders with. */
2566 u = this->FirstShared();
2567 for (; u != nullptr; u = u->NextShared()) {
2568 /* Ignore vehicles that are manually stopped or crashed. */
2569 if (u->vehstatus.Any({VehState::Stopped, VehState::Crashed})) continue;
2570
2571 u->depot_unbunching_next_departure = next_departure;
2572 InvalidateWindowData(WindowClass::VehicleView, u->index);
2573 }
2574}
2575
2581{
2582 assert(this->IsInDepot());
2583
2584 /* Don't bother if there are no vehicles sharing orders. */
2585 if (!this->IsOrderListShared()) return false;
2586
2587 /* Don't do anything if there aren't enough orders. */
2588 if (this->GetNumOrders() <= 1) return false;
2589
2590 /* Don't do anything if this is not our unbunching order. */
2591 if (!PreviousOrderIsUnbunching(this)) return false;
2592
2594};
2595
2603{
2604 CommandCost ret = CheckOwnership(this->owner);
2605 if (ret.Failed()) return ret;
2606
2607 if (this->vehstatus.Test(VehState::Crashed)) return CMD_ERROR;
2608 if (this->IsStoppedInDepot()) return CMD_ERROR;
2609
2610 /* No matter why we're headed to the depot, unbunching data is no longer valid. */
2612
2613 if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2614 bool halt_in_depot = this->current_order.GetDepotActionType().Test(OrderDepotActionFlag::Halt);
2615 if (command.Test(DepotCommandFlag::Service) == halt_in_depot) {
2616 /* We called with a different DEPOT_SERVICE setting.
2617 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2618 * Note: the if is (true for requesting service == true for ordered to stop in depot) */
2619 if (flags.Test(DoCommandFlag::Execute)) {
2620 this->current_order.SetDepotOrderType({});
2621 this->current_order.SetDepotActionType(halt_in_depot ? OrderDepotActionFlags{} : OrderDepotActionFlag::Halt);
2622 InvalidateWindowData(WindowClass::VehicleView, this->index);
2623 }
2624 return CommandCost();
2625 }
2626
2627 if (command.Test(DepotCommandFlag::DontCancel)) return CMD_ERROR; // Requested no cancellation of depot orders
2628 if (flags.Test(DoCommandFlag::Execute)) {
2629 /* If the orders to 'goto depot' are in the orders list (forced servicing),
2630 * then skip to the next order; effectively cancelling this forced service */
2631 if (this->current_order.GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders)) this->IncrementRealOrderIndex();
2632
2633 if (this->IsGroundVehicle()) {
2635 }
2636
2637 this->current_order.MakeDummy();
2638 InvalidateWindowData(WindowClass::VehicleView, this->index);
2639 }
2640 return CommandCost();
2641 }
2642
2643 ClosestDepot closest_depot = this->FindClosestDepot();
2644 static constexpr VehicleTypeIndexArray<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};
2645 if (!closest_depot.found) return CommandCost(no_depot[this->type]);
2646
2647 if (flags.Test(DoCommandFlag::Execute)) {
2648 if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2649
2650 if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2652 }
2653
2654 this->SetDestTile(closest_depot.location);
2655 this->current_order.MakeGoToDepot(closest_depot.destination.ToDepotID(), {});
2656 if (!command.Test(DepotCommandFlag::Service)) this->current_order.SetDepotActionType(OrderDepotActionFlag::Halt);
2657 InvalidateWindowData(WindowClass::VehicleView, this->index);
2658
2659 /* If there is no depot in front and the train is not already reversing, reverse automatically (trains only) */
2660 if (this->type == VehicleType::Train && (closest_depot.reverse ^ Train::From(this)->flags.Test(VehicleRailFlag::Reversing))) {
2661 Command<Commands::ReverseTrainDirection>::Do(DoCommandFlag::Execute, this->index, false);
2662 }
2663
2664 if (this->type == VehicleType::Aircraft) {
2665 Aircraft *a = Aircraft::From(this);
2666 if (a->state == FLYING && a->targetairport != closest_depot.destination) {
2667 /* The aircraft is now heading for a different hangar than the next in the orders */
2669 }
2670 }
2671 }
2672
2673 return CommandCost();
2674
2675}
2676
2681void Vehicle::UpdateVisualEffect(bool allow_power_change)
2682{
2683 bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2684 const Engine *e = this->GetEngine();
2685
2686 /* Evaluate properties */
2687 uint8_t visual_effect;
2688 switch (e->type) {
2689 case VehicleType::Train: visual_effect = e->VehInfo<RailVehicleInfo>().visual_effect; break;
2690 case VehicleType::Road: visual_effect = e->VehInfo<RoadVehicleInfo>().visual_effect; break;
2691 case VehicleType::Ship: visual_effect = e->VehInfo<ShipVehicleInfo>().visual_effect; break;
2692 default: visual_effect = 1 << VE_DISABLE_EFFECT; break;
2693 }
2694
2695 /* Check powered wagon / visual effect callback */
2697 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2698
2699 if (callback != CALLBACK_FAILED) {
2700 if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2701
2702 callback = GB(callback, 0, 8);
2703 /* Avoid accidentally setting 'visual_effect' to the default value
2704 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2705 if (callback == VE_DEFAULT) {
2706 assert(HasBit(callback, VE_DISABLE_EFFECT));
2707 SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2708 }
2709 visual_effect = callback;
2710 }
2711 }
2712
2713 /* Apply default values */
2714 if (visual_effect == VE_DEFAULT ||
2715 (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2716 /* Only train engines have default effects.
2717 * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2719 if (visual_effect == VE_DEFAULT) {
2720 visual_effect = 1 << VE_DISABLE_EFFECT;
2721 } else {
2722 SetBit(visual_effect, VE_DISABLE_EFFECT);
2723 }
2724 } else {
2725 if (visual_effect == VE_DEFAULT) {
2726 /* Also set the offset */
2727 visual_effect = (VE_OFFSET_CENTRE - (e->VehInfo<RailVehicleInfo>().engclass == EngineClass::Steam ? 4 : 0)) << VE_OFFSET_START;
2728 }
2730 }
2731 }
2732
2733 this->vcache.cached_vis_effect = visual_effect;
2734
2735 if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2736 ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2737 ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GRFBug::VehPoweredWagon, false);
2738 }
2739}
2740
2743 1, 1, 1, 0, -1, -1, -1, 0
2744};
2745
2751{
2752 std::array<int32_t, 4> regs100;
2753 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v, regs100);
2754 if (callback == CALLBACK_FAILED) return;
2755
2756 uint count = GB(callback, 0, 2);
2757 assert(count <= std::size(regs100));
2758 bool auto_center = HasBit(callback, 13);
2759 bool auto_rotate = !HasBit(callback, 14);
2760
2761 int8_t l_center = 0;
2762 if (auto_center) {
2763 /* For road vehicles: Compute offset from vehicle position to vehicle center */
2764 if (v->type == VehicleType::Road) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2765 } else {
2766 /* For trains: Compute offset from vehicle position to sprite position */
2768 }
2769
2770 Direction l_dir = v->direction;
2771 if (v->type == VehicleType::Train && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) l_dir = ReverseDir(l_dir);
2772 Direction t_dir = ChangeDir(l_dir, DirDiff::Right90);
2773
2774 int8_t x_center = _vehicle_smoke_pos[l_dir] * l_center;
2775 int8_t y_center = _vehicle_smoke_pos[t_dir] * l_center;
2776
2777 for (uint i = 0; i < count; i++) {
2778 int32_t reg = regs100[i];
2779 uint type = GB(reg, 0, 8);
2780 int8_t x = GB(reg, 8, 8);
2781 int8_t y = GB(reg, 16, 8);
2782 int8_t z = GB(reg, 24, 8);
2783
2784 if (auto_rotate) {
2785 int8_t l = x;
2786 int8_t t = y;
2787 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2788 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2789 }
2790
2791 if (type >= 0xF0) {
2792 switch (type) {
2793 case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2794 case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2795 case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2796 case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2797 default: break;
2798 }
2799 }
2800 }
2801}
2802
2808static bool IsBridgeAboveVehicle(const Vehicle *v)
2809{
2810 if (IsBridgeTile(v->tile)) {
2811 /* If the vehicle is 'on' a bridge tile, check the real position of the vehicle. If it's different then the
2812 * vehicle is on the middle of the bridge, which cannot have a bridge above. */
2813 TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
2814 if (tile != v->tile) return false;
2815 }
2816 return IsBridgeAbove(v->tile);
2817}
2818
2819
2829
2835{
2836 assert(this->IsPrimaryVehicle());
2837 bool sound = false;
2838
2839 /* Do not show any smoke when:
2840 * - vehicle smoke is disabled by the player
2841 * - the vehicle is slowing down or stopped (by the player)
2842 * - the vehicle is moving very slowly
2843 */
2844 if (_settings_game.vehicle.smoke_amount == 0 ||
2845 this->vehstatus.Any({VehState::TrainSlowing, VehState::Stopped}) ||
2846 this->cur_speed < 2) {
2847 return;
2848 }
2849
2850 /* Use the speed as limited by underground and orders. */
2851 uint max_speed = this->GetCurrentMaxSpeed();
2852
2853 if (this->type == VehicleType::Train) {
2854 const Train *t = Train::From(this);
2855 const Train *moving_front = t->GetMovingFront();
2856 /* For trains, do not show any smoke when:
2857 * - the train is reversing
2858 * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2859 */
2861 (IsRailStationTile(moving_front->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(moving_front->tile)) &&
2862 t->cur_speed >= max_speed)) {
2863 return;
2864 }
2865 }
2866
2867 const Vehicle *v = this;
2868
2869 do {
2873 if (advanced) {
2874 effect_offset = VE_OFFSET_CENTRE;
2875 effect_model = static_cast<VisualEffectSpawnModel>(GB(v->vcache.cached_vis_effect, 0, VE_ADVANCED_EFFECT));
2876 if (effect_model >= VisualEffectSpawnModel::End) effect_model = VisualEffectSpawnModel::None; // unknown spawning model
2877 } else {
2879 assert(to_underlying(effect_model) != to_underlying(VE_TYPE_DEFAULT)); // should have been resolved by UpdateVisualEffect
2883 }
2884
2885 /* Show no smoke when:
2886 * - Smoke has been disabled for this vehicle
2887 * - The vehicle is not visible
2888 * - The vehicle is under a bridge
2889 * - The vehicle is on a depot tile
2890 * - The vehicle is on a tunnel tile
2891 * - The vehicle is a train engine that is currently unpowered */
2892 if (effect_model == VisualEffectSpawnModel::None ||
2895 IsDepotTile(v->tile) ||
2896 IsTunnelTile(v->tile) ||
2897 (v->type == VehicleType::Train &&
2898 !HasPowerOnRail(Train::From(v)->railtypes, GetTileRailType(v->tile)))) {
2899 continue;
2900 }
2901
2902 EffectVehicleType evt = EV_END;
2903 switch (effect_model) {
2905 /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2906 * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2907 * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2908 * REGULATION:
2909 * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2910 if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2911 evt = EV_STEAM_SMOKE;
2912 }
2913 break;
2914
2916 /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2917 * when smoke emission stops.
2918 * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2919 * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2920 * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2921 * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2922 * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2923 * maximum speed no diesel_smoke is emitted.
2924 * REGULATION:
2925 * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2926 * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2927 int power_weight_effect = 0;
2928 if (v->type == VehicleType::Train) {
2929 power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2930 }
2931 if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2932 Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2933 evt = EV_DIESEL_SMOKE;
2934 }
2935 break;
2936 }
2937
2939 /* Electric train's spark - more often occurs when train is departing (more load)
2940 * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2941 * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2942 * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2943 * REGULATION:
2944 * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2945 if (GB(v->tick_counter, 0, 2) == 0 &&
2946 Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2947 evt = EV_ELECTRIC_SPARK;
2948 }
2949 break;
2950
2951 default:
2952 NOT_REACHED();
2953 }
2954
2955 if (evt != EV_END && advanced) {
2956 sound = true;
2958 } else if (evt != EV_END) {
2959 sound = true;
2960
2961 /* The effect offset is relative to a point 4 units behind the vehicle's
2962 * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2963 * correction factor. */
2964 if (v->type == VehicleType::Train) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2965
2966 int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2967 int y = _vehicle_smoke_pos[ChangeDir(v->direction, DirDiff::Right90)] * effect_offset;
2968
2969 if (v->type == VehicleType::Train && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) {
2970 x = -x;
2971 y = -y;
2972 }
2973
2974 CreateEffectVehicleRel(v, x, y, 10, evt);
2975 }
2976 } while ((v = v->Next()) != nullptr);
2977
2978 if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2979}
2980
2986{
2987 assert(this != next);
2988
2989 if (this->next != nullptr) {
2990 /* We had an old next vehicle. Update the first and previous pointers */
2991 for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
2992 v->first = this->next;
2993 }
2994 this->next->previous = nullptr;
2995 }
2996
2997 this->next = next;
2998
2999 if (this->next != nullptr) {
3000 /* A new next vehicle. Update the first and previous pointers */
3001 if (this->next->previous != nullptr) this->next->previous->next = nullptr;
3002 this->next->previous = this;
3003 for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
3004 v->first = this->first;
3005 }
3006 }
3007
3008 /* Update last vehicle of the entire chain. */
3009 Vehicle *new_last = this;
3010 while (new_last->Next() != nullptr) new_last = new_last->Next();
3011 for (Vehicle *v = this->first; v!= nullptr; v = v->Next()) {
3012 v->last = new_last;
3013 }
3014}
3015
3022{
3023 assert(this->previous_shared == nullptr && this->next_shared == nullptr);
3024
3025 if (shared_chain->orders == nullptr) {
3026 assert(shared_chain->previous_shared == nullptr);
3027 assert(shared_chain->next_shared == nullptr);
3028 this->orders = shared_chain->orders = OrderList::Create(shared_chain);
3029 }
3030
3031 this->next_shared = shared_chain->next_shared;
3032 this->previous_shared = shared_chain;
3033
3034 shared_chain->next_shared = this;
3035
3036 if (this->next_shared != nullptr) this->next_shared->previous_shared = this;
3037
3038 shared_chain->orders->AddVehicle(this);
3039}
3040
3045{
3046 /* Remember if we were first and the old window number before RemoveVehicle()
3047 * as this changes first if needed. */
3048 bool were_first = (this->FirstShared() == this);
3050
3051 this->orders->RemoveVehicle(this);
3052
3053 if (!were_first) {
3054 /* We are not the first shared one, so only relink our previous one. */
3055 this->previous_shared->next_shared = this->NextShared();
3056 }
3057
3058 if (this->next_shared != nullptr) this->next_shared->previous_shared = this->previous_shared;
3059
3060
3061 if (this->orders->GetNumVehicles() == 1) {
3062 /* When there is only one vehicle, remove the shared order list window. */
3065 } else if (were_first) {
3066 /* If we were the first one, update to the new first one.
3067 * Note: FirstShared() is already the new first */
3068 InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.ToWindowNumber(), this->FirstShared()->index.base() | (1U << 31));
3069 }
3070
3071 this->next_shared = nullptr;
3072 this->previous_shared = nullptr;
3073}
3074
3076static const IntervalTimer<TimerGameEconomy> _economy_vehicles_yearly({TimerGameEconomy::Trigger::Year, TimerGameEconomy::Priority::Vehicle}, [](auto)
3077{
3078 for (Vehicle *v : Vehicle::Iterate()) {
3079 if (v->IsPrimaryVehicle()) {
3080 /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
3081 Money profit = v->GetDisplayProfitThisYear();
3082 if (v->economy_age >= VEHICLE_PROFIT_MIN_AGE && profit < 0) {
3085 GetEncodedString(TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_VEHICLE_UNPROFITABLE_PERIOD : STR_NEWS_VEHICLE_UNPROFITABLE_YEAR, v->index, profit),
3086 v->index);
3087 }
3088 AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
3089 }
3090
3092 v->profit_this_year = 0;
3093 SetWindowDirty(WindowClass::VehicleDetails, v->index);
3094 }
3095 }
3097 SetWindowClassesDirty(WindowClass::TrainList);
3098 SetWindowClassesDirty(WindowClass::ShipList);
3099 SetWindowClassesDirty(WindowClass::RoadVehicleList);
3100 SetWindowClassesDirty(WindowClass::AircraftList);
3101});
3102
3112bool CanVehicleUseStation(EngineID engine_type, const Station *st)
3113{
3114 const Engine *e = Engine::GetIfValid(engine_type);
3115 assert(e != nullptr);
3116
3117 switch (e->type) {
3118 case VehicleType::Train:
3120
3121 case VehicleType::Road:
3122 /* For road vehicles we need the vehicle to know whether it can actually
3123 * use the station, but if it doesn't have facilities for RVs it is
3124 * certainly not possible that the station can be used. */
3126
3127 case VehicleType::Ship:
3129
3133
3134 default:
3135 return false;
3136 }
3137}
3138
3145bool CanVehicleUseStation(const Vehicle *v, const Station *st)
3146{
3147 if (v->type == VehicleType::Road) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != nullptr;
3148
3149 return CanVehicleUseStation(v->engine_type, st);
3150}
3151
3159{
3160 switch (v->type) {
3161 case VehicleType::Train:
3162 return STR_ERROR_NO_RAIL_STATION;
3163
3164 case VehicleType::Road: {
3165 const RoadVehicle *rv = RoadVehicle::From(v);
3166 RoadStop *rs = st->GetPrimaryRoadStop(rv->IsBus() ? RoadStopType::Bus : RoadStopType::Truck);
3167
3168 StringID err = rv->IsBus() ? STR_ERROR_NO_BUS_STATION : STR_ERROR_NO_TRUCK_STATION;
3169
3170 for (; rs != nullptr; rs = rs->next) {
3171 /* Articulated vehicles cannot use bay road stops, only drive-through. Make sure the vehicle can actually use this bay stop */
3173 err = STR_ERROR_NO_STOP_ARTICULATED_VEHICLE;
3174 continue;
3175 }
3176
3177 /* Bay stop errors take precedence, but otherwise the vehicle may not be compatible with the roadtype/tramtype of this station tile.
3178 * We give bay stop errors precedence because they are usually a bus sent to a tram station or vice versa. */
3179 if (!HasTileAnyRoadType(rs->xy, rv->compatible_roadtypes) && err != STR_ERROR_NO_STOP_ARTICULATED_VEHICLE) {
3180 err = RoadTypeIsRoad(rv->roadtype) ? STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE : STR_ERROR_NO_STOP_COMPATIBLE_TRAM_TYPE;
3181 continue;
3182 }
3183 }
3184
3185 return err;
3186 }
3187
3188 case VehicleType::Ship:
3189 return STR_ERROR_NO_DOCK;
3190
3192 if (!st->facilities.Test(StationFacility::Airport)) return STR_ERROR_NO_AIRPORT;
3193 if (v->GetEngine()->VehInfo<AircraftVehicleInfo>().subtype & AIR_CTOL) {
3194 return STR_ERROR_AIRPORT_NO_PLANES;
3195 } else {
3196 return STR_ERROR_AIRPORT_NO_HELICOPTERS;
3197 }
3198
3199 default:
3200 return INVALID_STRING_ID;
3201 }
3202}
3203
3210{
3211 assert(this->IsGroundVehicle());
3212 if (this->type == VehicleType::Train) {
3213 return &Train::From(this)->gcache;
3214 } else {
3215 return &RoadVehicle::From(this)->gcache;
3216 }
3217}
3218
3225{
3226 assert(this->IsGroundVehicle());
3227 if (this->type == VehicleType::Train) {
3228 return &Train::From(this)->gcache;
3229 } else {
3230 return &RoadVehicle::From(this)->gcache;
3231 }
3232}
3233
3240{
3241 assert(this->IsGroundVehicle());
3242 if (this->type == VehicleType::Train) {
3243 return Train::From(this)->gv_flags;
3244 } else {
3245 return RoadVehicle::From(this)->gv_flags;
3246 }
3247}
3248
3255{
3256 assert(this->IsGroundVehicle());
3257 if (this->type == VehicleType::Train) {
3258 return Train::From(this)->gv_flags;
3259 } else {
3260 return RoadVehicle::From(this)->gv_flags;
3261 }
3262}
3263
3272void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8_t num_vehicles)
3273{
3274 if (v->type == VehicleType::Train) {
3275 Train *u = Train::From(v);
3276 /* Only include whole vehicles, so start with the first articulated part */
3277 u = u->GetFirstEnginePart();
3278
3279 /* Include num_vehicles vehicles, not counting articulated parts */
3280 for (; u != nullptr && num_vehicles > 0; num_vehicles--) {
3281 do {
3282 /* Include current vehicle in the selection. */
3283 include(set, u->index);
3284
3285 /* If the vehicle is multiheaded, add the other part too. */
3286 if (u->IsMultiheaded()) include(set, u->other_multiheaded_part->index);
3287
3288 u = u->Next();
3289 } while (u != nullptr && u->IsArticulatedPart());
3290 }
3291 }
3292}
3293
3299{
3300 uint32_t max_weight = 0;
3301
3302 for (const Vehicle *u = this; u != nullptr; u = u->Next()) {
3303 max_weight += u->GetMaxWeight();
3304 }
3305
3306 return max_weight;
3307}
3308
3314{
3315 uint32_t max_weight = GetDisplayMaxWeight();
3316 if (max_weight == 0) return 0;
3317 return GetGroundVehicleCache()->cached_power * 10u / max_weight;
3318}
3319
3327{
3328 while (true) {
3329 if (v1 == nullptr && v2 == nullptr) return true;
3330 if (v1 == nullptr || v2 == nullptr) return false;
3331 if (v1->GetEngine() != v2->GetEngine()) return false;
3332 v1 = v1->GetNextVehicle();
3333 v2 = v2->GetNextVehicle();
3334 }
3335}
3336
3344{
3345 return std::ranges::equal(v1->Orders(), v2->Orders(), [](const Order &o1, const Order &o2) { return o1.Equals(o2); });
3346}
3347
3349struct VehicleSubcoordData : Coord2D<uint8_t> {
3351};
3352
3358 {{{ // NE
3359 {{15, 8}, Direction::NE}, // TRACK_X
3360 {}, // TRACK_Y
3361 {}, // TRACK_UPPER
3362 {{15, 8}, Direction::E}, // TRACK_LOWER
3363 {{15, 7}, Direction::N}, // TRACK_LEFT
3364 {}, // TRACK_RIGHT
3365 }}},
3366 {{{ // SE
3367 {}, // TRACK_X
3368 {{8, 0}, Direction::SE}, // TRACK_Y
3369 {{7, 0}, Direction::E}, // TRACK_UPPER
3370 {}, // TRACK_LOWER
3371 {{8, 0}, Direction::S}, // TRACK_LEFT
3372 {}, // TRACK_RIGHT
3373 }}},
3374 {{{ // SW
3375 {{0, 8}, Direction::SW}, // TRACK_X
3376 {}, // TRACK_Y
3377 {{0, 7}, Direction::W}, // TRACK_UPPER
3378 {}, // TRACK_LOWER
3379 {}, // TRACK_LEFT
3380 {{0, 8}, Direction::S}, // TRACK_RIGHT
3381 }}},
3382 {{{ // NW
3383 {}, // TRACK_X
3384 {{8, 15}, Direction::NW}, // TRACK_Y
3385 {}, // TRACK_UPPER
3386 {{8, 15}, Direction::W}, // TRACK_LOWER
3387 {}, // TRACK_LEFT
3388 {{7, 15}, Direction::N}, // TRACK_RIGHT
3389 }}},
3390}}};
3391
3400{
3401 const VehicleSubcoordData &b = _vehicle_subcoord[enterdir][track];
3402 gp.x = (gp.x & ~TILE_UNIT_MASK) | b.x;
3403 gp.y = (gp.y & ~TILE_UNIT_MASK) | b.y;
3404 return b.dir;
3405}
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:78
@ None
Tile is not animated.
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.
@ End
We are looking for this amount of GRFs.
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
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:110
EnumBitSet< CargoType, uint64_t > CargoTypes
Bitset of CargoType elements.
Definition cargo_type.h:113
CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
@ Passengers
Passengers.
Definition cargotype.h:51
bool IsCargoInClass(CargoType cargo, CargoClasses cc)
Does cargo c have cargo class cc?
Definition cargotype.h:238
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:231
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this bit 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.
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:73
GrfID GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:183
CompanyMask company_avail
Bit for each company whether the engine is available for that company.
Definition engine_base.h:42
VehicleType type
Vehicle type, ie VehicleType::Road, VehicleType::Train, etc.
Definition engine_base.h:64
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:96
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:51
UnitID UseID(UnitID index)
Use a unit number.
Definition vehicle.cpp:1889
void ReleaseID(UnitID index)
Release a unit number.
Definition vehicle.cpp:1906
UnitID NextID() const
Find first unused unit number.
Definition vehicle.cpp:1874
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:502
Iterator(int32_t x, int32_t y, uint max_dist)
Iterator constructor.
Definition vehicle.cpp:462
void Increment()
Advance the internal state to the next potential vehicle.
Definition vehicle.cpp:492
void SkipFalseMatches()
Advance the internal state until it reaches a vehicle within the search area.
Definition vehicle.cpp:520
Iterator(TileIndex tile)
Iterator constructor.
Definition vehicle.cpp:530
void Increment()
Advance the internal state to the next potential vehicle.
Definition vehicle.cpp:540
void SkipFalseMatches()
Advance the internal state until it reaches a vehicle on the correct tile or the end.
Definition vehicle.cpp:548
Iterate over all vehicles on a tile.
Functions related to commands.
CommandCost & ExtractCommandCost(Tret &ret)
Extract the CommandCost from a command proc result.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
EnumBitSet< DoCommandFlag, uint16_t > DoCommandFlags
Bitset of DoCommandFlag elements.
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 LimitDirDiff(DirDiff d)
Limit a direction difference to up to 45 degrees.
DirDiff
Enumeration for the difference between two directions.
@ Same
Both directions faces to the same direction.
@ Right90
Angle of 90 degrees right.
EnumIndexArray< T, DiagDirection, DiagDirection::End > DiagDirectionIndexArray
Array with DiagDirection as index.
Direction
Defines the 8 directions on the map.
@ Invalid
Flag for an invalid direction.
@ SW
Southwest.
@ NW
Northwest.
@ NE
Northeast.
@ SE
Southeast.
EnumIndexArray< T, Direction, Direction::End > DirectionIndexArray
Array with Direction as index.
DiagDirection
Enumeration for diagonal directions.
@ Invalid
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:1925
void PrepareUnload(Vehicle *front_v)
Prepare the vehicle to be unloaded.
Definition economy.cpp:1252
Base classes related to the economy.
@ NewVehicles
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
@ Maglev
Maglev engine.
Definition engine_type.h:43
@ Steam
Steam rail engine.
Definition engine_type.h:39
@ Diesel
Diesel rail engine.
Definition engine_type.h:40
@ Electric
Electric rail engine.
Definition engine_type.h:41
@ Monorail
Mono rail engine.
Definition engine_type.h:42
@ Wagon
simple wagon, not motorized
Definition engine_type.h:34
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
Functions related to errors.
@ 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.
@ GameLoopRoadVehicles
Time spend processing road vehicles.
@ GameLoopShips
Time spent processing ships.
@ GameLoopAircraft
Time spent processing aircraft.
@ GameLoopTrains
Time spent processing trains.
@ GameLoopEconomy
Time spent processing cargo movement.
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:1037
@ Normal
The most basic (normal) sprite.
Definition gfx_type.h:405
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
@ Company
Destination is a company.
Definition goal_type.h:56
@ Next
Next button.
Definition goal_type.h:35
@ Previous
Previous button.
Definition goal_type.h:34
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 EnumIndexArray< const TileTypeProcs *, TileType, TileType::MaxSize > _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
@ PassengerTram
Passenger trams.
Definition livery.h:55
@ SmallPlane
Small aeroplanes.
Definition livery.h:51
@ PassengerWagonMaglev
Passenger wagons attached to maglev engines.
Definition livery.h:38
@ Helicopter
Helicopters.
Definition livery.h:50
@ PassengerWagonElectric
Passenger wagons attached to electric engines.
Definition livery.h:36
@ Maglev
Maglev engines.
Definition livery.h:31
@ Steam
Steam engines.
Definition livery.h:27
@ PassengerShip
Passenger ships.
Definition livery.h:46
@ EMU
EMUs and their passenger wagons.
Definition livery.h:33
@ Bus
Buses.
Definition livery.h:42
@ Truck
Trucks.
Definition livery.h:43
@ Diesel
Diesel engines.
Definition livery.h:28
@ Default
Default scheme.
Definition livery.h:24
@ PassengerWagonDiesel
Passenger wagons attached to diesel engines.
Definition livery.h:35
@ FreightShip
Freight ships.
Definition livery.h:47
@ Electric
Electric engines.
Definition livery.h:29
@ PassengerWagonMonorail
Passenger wagons attached to monorail engines.
Definition livery.h:37
@ Monorail
Monorail engines.
Definition livery.h:30
@ FreightTram
Freight trams.
Definition livery.h:56
@ PassengerWagonSteam
Passenger wagons attached to steam engines.
Definition livery.h:34
@ LargePlane
Large aeroplanes.
Definition livery.h:52
@ FreightWagon
Freight wagons.
Definition livery.h:39
@ DMU
DMUs and their passenger wagons.
Definition livery.h:32
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:582
void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost)
Display animated income or costs on the map.
Definition misc_gui.cpp:508
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:1889
@ 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(GrfID grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
GRFConfig * GetGRFConfig(GrfID 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.
Label< struct GrfIDTag > GrfID
The unique identifier of a NewGRF.
Definition newgrf_type.h:17
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.
@ 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:75
@ Normal
A game normally paused.
Definition openttd.h:72
@ Normal
Playing a game.
Definition openttd.h:20
@ Menu
In the main menu.
Definition openttd.h:19
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
EnumBitSet< OrderDepotActionFlag, uint8_t > OrderDepotActionFlags
Bitset of OrderDepotActionFlag elements.
Definition order_type.h:126
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:120
@ NearestDepot
Send the vehicle to the nearest depot.
Definition order_type.h:121
@ Unbunch
Service the vehicle and then unbunch it.
Definition order_type.h:122
@ PartOfOrders
This depot order is because of a regular order.
Definition order_type.h:110
@ Service
This depot order is because of the servicing limit.
Definition order_type.h:109
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:379
void SetDepotReservation(Tile t, bool b)
Set the reservation state of the depot.
Definition rail_map.h:268
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:38
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:656
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:1762
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1793
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.
StrongType::Typedef< uint32_t, struct StringIDTag, StrongType::Compare, StrongType::Integer > StringID
Numeric value that represents a string, independent of the selected language.
static constexpr 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:75
uint8_t pos
Next desired position of the aircraft.
Definition aircraft.h:77
uint8_t state
State of the airport.
Definition aircraft.h:80
bool IsNormalAircraft() const
Check if the aircraft type is a normal flying device; eg not a rotor or a shadow.
Definition aircraft.h:123
uint8_t previous_pos
Previous desired position of the aircraft.
Definition aircraft.h:78
StationID targetairport
Airport to go to next.
Definition aircraft.h:79
@ Airplanes
Can planes land on this airport type?
Definition airport.h:165
@ Helicopters
Can helicopters land on this airport type?
Definition airport.h:166
std::vector< AirportFTA > layout
state machine for airport
Definition airport.h:195
Flags flags
Flags for this airport type.
Definition airport.h:198
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 upon destruction of this object to prevent stack v...
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:141
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
VehicleTypeIndexArray< GroupStatistics > group_all
NOSAVE: Statistics for the ALL_GROUP group.
A coordinate with two dimensions.
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.
GrfID grfid
grfid that introduced this entity.
uint16_t local_id
id defined by the grf file for this entity
Dynamic data of a loaded NewGRF.
Definition newgrf.h:124
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.
GroundVehicleFlags gv_flags
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:76
Livery livery
Custom colour scheme for vehicles in this group.
Definition group.h:82
GroupID parent
Parent group.
Definition group.h:88
Information about a particular livery.
Definition livery.h:82
Flags in_use
Livery flags.
Definition livery.h:92
uint8_t GetRecolourOffset(bool use_secondary=true) const
Get offset for recolour palette.
Definition livery.h:101
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
RailVehicleType railveh_type
Type of rail vehicle.
Definition engine_type.h:76
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:233
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:124
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition vehicle.cpp:152
Vehicle sub-coordinate data for moving into a new tile.
Definition vehicle.cpp:3349
Direction dir
new direction.
Definition vehicle.cpp:3350
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.
Direction direction
facing
void ShiftDates(TimerGameEconomy::Date interval)
Shift all dates by given interval.
Definition vehicle.cpp:779
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:749
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:301
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:2372
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:3021
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:2508
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:2602
void ReleaseUnitNumber()
Release the vehicle's unit number.
Definition vehicle.cpp:2442
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:1709
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:2453
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:2356
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:716
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:166
void UpdateVisualEffect(bool allow_power_change=true)
Update the cached visual effect.
Definition vehicle.cpp:2681
void LeaveUnbunchingDepot()
Leave an unbunching depot and calculate the next departure time for shared order vehicles.
Definition vehicle.cpp:2533
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).
Vehicle(VehicleID index, VehicleType type=VehicleType::Invalid)
Vehicle constructor.
Definition vehicle.cpp:380
void PreDestructor()
Destroy all stuff that (still) needs the virtual functions to work properly.
Definition vehicle.cpp:827
TimerGameTick::TickCounter last_loading_tick
Last TimerGameTick::counter tick that the vehicle has stopped at a station and could possibly leave w...
void HandlePathfindingResult(bool path_found)
Handle the pathfinding result, especially the lost status.
Definition vehicle.cpp:793
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:759
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:3313
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:1754
Money value
Value of the vehicle.
bool MarkAllViewportsDirty() const
Marks viewports dirty where the vehicle's image is.
Definition vehicle.cpp:1793
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.
SpriteBounds bounds
Bounding box of vehicle.
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition vehicle.cpp:3209
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:2488
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:2228
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:894
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:733
TimerGameCalendar::Date age
Age in calendar days.
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition vehicle.cpp:2580
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:2985
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:3298
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition vehicle.cpp:3044
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds,...
Definition vehicle.cpp:1375
void UpdatePositionAndViewport()
Update the position of the vehicle, and update the viewport.
Definition vehicle.cpp:1783
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:211
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition vehicle.cpp:2499
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1700
GroundVehicleFlags & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition vehicle.cpp:3239
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:2434
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:2834
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:293
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition vehicle.cpp:2190
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.
GrfID GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition vehicle.cpp:769
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:1864
EnumBitSet< VehicleEnterTileState, uint8_t > VehicleEnterTileStates
Bitset of VehicleEnterTileState elements.
Definition tile_cmd.h:31
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 uint TILE_UNIT_MASK
For masking in/out the inner-tile world coordinate units.
Definition tile_type.h:16
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:540
EnumBitSet< Track, uint8_t > TrackBits
Bitset of Track elements.
Definition track_type.h:43
Track
These are used to specify a single track.
Definition track_type.h:19
@ Depot
Special flag indicating a vehicle is inside a depot.
Definition track_type.h:30
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.
@ 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:338
constexpr uint TILE_HASH_MASK
Definition vehicle.cpp:401
static uint GetTileHash(uint x, uint y)
Compute hash for tile coordinate.
Definition vehicle.cpp:448
static const uint GEN_HASHX_MASK
Definition vehicle.cpp:111
static const uint GEN_HASHY_MASK
Definition vehicle.cpp:112
static void VehicleEnteredDepotThisTick(Vehicle *v)
Adds a vehicle to the list of vehicles that visited a depot this tick.
Definition vehicle.cpp:922
static void SpawnAdvancedVisualEffect(const Vehicle *v)
Call CBID_VEHICLE_SPAWN_VISUAL_EFFECT and spawn requested effects.
Definition vehicle.cpp:2750
constexpr uint TOTAL_TILE_HASH_SIZE
Definition vehicle.cpp:402
static const uint GEN_HASHY_INC
Definition vehicle.cpp:106
static uint GetTileHash1D(uint p)
Compute hash for 1D tile coordinate.
Definition vehicle.cpp:416
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:364
static constexpr DirectionIndexArray< int8_t > _vehicle_smoke_pos
Vehicle smoke effect position offsets.
Definition vehicle.cpp:2742
static const uint GEN_HASHY_BITS
Definition vehicle.cpp:72
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:188
static const IntervalTimer< TimerGameEconomy > _economy_vehicles_yearly({TimerGameEconomy::Trigger::Year, TimerGameEconomy::Priority::Vehicle}, [](auto) { for(Vehicle *v :Vehicle::Iterate()) { if(v->IsPrimaryVehicle()) { Money profit=v->GetDisplayProfitThisYear();if(v->economy_age >=VEHICLE_PROFIT_MIN_AGE &&profit< 0) { if(_settings_client.gui.vehicle_income_warn &&v->owner==_local_company) { AddVehicleAdviceNewsItem(AdviceType::VehicleUnprofitable, GetEncodedString(TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_VEHICLE_UNPROFITABLE_PERIOD :STR_NEWS_VEHICLE_UNPROFITABLE_YEAR, v->index, profit), v->index);} AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));} v->profit_last_year=v->profit_this_year;v->profit_this_year=0;SetWindowDirty(WindowClass::VehicleDetails, v->index);} } GroupStatistics::UpdateProfits();SetWindowClassesDirty(WindowClass::TrainList);SetWindowClassesDirty(WindowClass::ShipList);SetWindowClassesDirty(WindowClass::RoadVehicleList);SetWindowClassesDirty(WindowClass::AircraftList);})
Yearly callback for vehicles.
static const uint GEN_HASHY_BUCKET_BITS
Definition vehicle.cpp:78
static void RunEconomyVehicleDayProc()
Increases the day counter for all vehicles and calls 1-day and 32-day handlers.
Definition vehicle.cpp:955
constexpr uint TILE_HASH_SIZE
Definition vehicle.cpp:400
static const uint GEN_HASHY_SIZE
Definition vehicle.cpp:100
constexpr uint TILE_HASH_BITS
Definition vehicle.cpp:399
static uint ComposeTileHash(uint hx, uint hy)
Compose two 1D hashes into 2D hash.
Definition vehicle.cpp:437
static constexpr DiagDirectionIndexArray< TrackIndexArray< VehicleSubcoordData > > _vehicle_subcoord
Table of subtile coordinates and direction for each combination of chosen track and tile enter direct...
Definition vehicle.cpp:3357
static const uint GEN_HASHX_BUCKET_BITS
Definition vehicle.cpp:77
VisualEffectSpawnModel
Models for spawning visual effects.
Definition vehicle.cpp:2821
@ Steam
Steam model.
Definition vehicle.cpp:2823
@ None
No visual effect.
Definition vehicle.cpp:2822
@ Diesel
Diesel model.
Definition vehicle.cpp:2824
@ Electric
Electric model.
Definition vehicle.cpp:2825
static uint IncTileHash1D(uint h)
Increment 1D hash to next bucket.
Definition vehicle.cpp:426
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3112
static const uint GEN_HASHX_BITS
Definition vehicle.cpp:71
Vehicle * CheckClickOnVehicle(const Viewport &vp, int x, int y)
Find the vehicle close to the clicked coordinates.
Definition vehicle.cpp:1243
static const uint GEN_HASHX_INC
Definition vehicle.cpp:105
static const uint GEN_HASHX_SIZE
Definition vehicle.cpp:99
std::map< VehicleID, bool > AutoreplaceMap
List of vehicles that should check for autoreplace this tick.
Definition vehicle.cpp:696
static bool IsBridgeAboveVehicle(const Vehicle *v)
Test if a bridge is above a vehicle.
Definition vehicle.cpp:2808
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:409
static bool PreviousOrderIsUnbunching(const Vehicle *v)
Check if the previous order is a depot unbunching order.
Definition vehicle.cpp:2520
static void DoDrawVehicle(const Vehicle *v)
Add vehicle sprite for drawing to the screen.
Definition vehicle.cpp:1120
@ 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.
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:338
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:558
bool VehiclesHaveSameEngineList(const Vehicle *v1, const Vehicle *v2)
Checks if two vehicle chains have the same list of engines.
Definition vehicle.cpp:3326
bool VehiclesHaveSameOrderList(const Vehicle *v1, const Vehicle *v2)
Checks if two vehicles have the same list of orders.
Definition vehicle.cpp:3343
SpriteID GetEnginePalette(EngineID engine_type, CompanyID company)
Get the colour map for an engine.
Definition vehicle.cpp:2168
void VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition vehicle.cpp:1563
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:3272
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition vehicle.cpp:1921
void RunVehicleCalendarDayProc()
Age all vehicles, spreading out the action using the current TimerGameCalendar::date_fract.
Definition vehicle.cpp:938
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition vehicle.cpp:188
CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
Tests if a vehicle interacts with the specified track bits.
Definition vehicle.cpp:606
LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
Determines the LiveryScheme for a vehicle.
Definition vehicle.cpp:1997
void CheckVehicleBreakdown(Vehicle *v)
Periodic check for a vehicle to maybe break down.
Definition vehicle.cpp:1319
void ViewportAddVehicles(DrawPixelInfo *dpi)
Add the vehicle sprites that should be drawn at a part of the screen.
Definition vehicle.cpp:1149
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition vehicle.cpp:1803
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:3158
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:1298
void EconomyAgeVehicle(Vehicle *v)
Update economy age of a vehicle.
Definition vehicle.cpp:1441
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:2091
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore=nullptr)
Finds vehicle in tunnel / bridge.
Definition vehicle.cpp:582
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition vehicle.cpp:1453
Direction VehicleEnterTileCoordinates(GetNewVehiclePosResult &gp, DiagDirection enterdir, Track track)
Lookup new subposition coordinates and direction to use when entering a new tile, applying the subcoo...
Definition vehicle.cpp:3399
SpriteID GetVehiclePalette(const Vehicle *v)
Get the colour map for a vehicle.
Definition vehicle.cpp:2178
uint8_t CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1504
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:1949
@ 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
EnumBitSet< DepotCommandFlag, uint8_t > DepotCommandFlags
Bitset of DepotCommandFlag elements.
@ OnMap
Vehicle drawn in viewport.
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
VehicleType
Available vehicle types.
@ Ship
Ship vehicle type.
@ Effect
Effect vehicle type (smoke, explosions, sparks, bubbles).
@ Aircraft
Aircraft vehicle type.
@ Road
Road vehicle type.
@ Disaster
Disaster vehicle type.
@ 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).
EnumBitSet< GroundVehicleFlag, uint16_t > GroundVehicleFlags
Bitset of GroundVehicleFlag elements.
EnumIndexArray< T, VehicleType, Tend > VehicleTypeIndexArray
Array with VehicleType as index.
@ SuppressImplicitOrders
Disable insertion and removal of automatic orders until the vehicle completes the real order.
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.
@ VehicleSharedOrders
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:765
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:664
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:775
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:1204
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3226
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:3318
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:3212
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3196
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:3336
@ 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