OpenTTD Source 20250218-master-g53dd1258a7
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 <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "error.h"
12#include "roadveh.h"
13#include "ship.h"
14#include "spritecache.h"
15#include "timetable.h"
16#include "viewport_func.h"
17#include "news_func.h"
18#include "command_func.h"
19#include "company_func.h"
20#include "train.h"
21#include "aircraft.h"
22#include "newgrf_debug.h"
23#include "newgrf_sound.h"
24#include "newgrf_station.h"
25#include "group_gui.h"
26#include "strings_func.h"
27#include "zoom_func.h"
28#include "vehicle_func.h"
29#include "autoreplace_func.h"
30#include "autoreplace_gui.h"
31#include "station_base.h"
32#include "ai/ai.hpp"
33#include "depot_func.h"
34#include "network/network.h"
35#include "core/pool_func.hpp"
36#include "economy_base.h"
38#include "roadstop_base.h"
39#include "core/random_func.hpp"
40#include "core/backup_type.hpp"
42#include "order_backup.h"
43#include "sound_func.h"
44#include "effectvehicle_func.h"
45#include "effectvehicle_base.h"
46#include "vehiclelist.h"
47#include "bridge_map.h"
48#include "tunnel_map.h"
49#include "depot_map.h"
50#include "gamelog.h"
51#include "linkgraph/linkgraph.h"
52#include "linkgraph/refresh.h"
53#include "framerate_type.h"
54#include "autoreplace_cmd.h"
55#include "misc_cmd.h"
56#include "train_cmd.h"
57#include "vehicle_cmd.h"
58#include "newgrf_roadstop.h"
59#include "timer/timer.h"
63
64#include "table/strings.h"
65
66#include "safeguards.h"
67
68/* Number of bits in the hash to use from each vehicle coord */
69static const uint GEN_HASHX_BITS = 6;
70static const uint GEN_HASHY_BITS = 6;
71
72/* Size of each hash bucket */
73static const uint GEN_HASHX_BUCKET_BITS = 7;
74static const uint GEN_HASHY_BUCKET_BITS = 6;
75
76/* Compute hash for vehicle coord */
77#define GEN_HASHX(x) GB((x), GEN_HASHX_BUCKET_BITS + ZOOM_BASE_SHIFT, GEN_HASHX_BITS)
78#define GEN_HASHY(y) (GB((y), GEN_HASHY_BUCKET_BITS + ZOOM_BASE_SHIFT, GEN_HASHY_BITS) << GEN_HASHX_BITS)
79#define GEN_HASH(x, y) (GEN_HASHY(y) + GEN_HASHX(x))
80
81/* Maximum size until hash repeats */
82static const int GEN_HASHX_SIZE = 1 << (GEN_HASHX_BUCKET_BITS + GEN_HASHX_BITS + ZOOM_BASE_SHIFT);
83static const int GEN_HASHY_SIZE = 1 << (GEN_HASHY_BUCKET_BITS + GEN_HASHY_BITS + ZOOM_BASE_SHIFT);
84
85/* Increments to reach next bucket in hash table */
86static const int GEN_HASHX_INC = 1;
87static const int GEN_HASHY_INC = 1 << GEN_HASHX_BITS;
88
89/* Mask to wrap-around buckets */
90static const uint GEN_HASHX_MASK = (1 << GEN_HASHX_BITS) - 1;
91static const uint GEN_HASHY_MASK = ((1 << GEN_HASHY_BITS) - 1) << GEN_HASHX_BITS;
92
93
97
98
99
103void VehicleSpriteSeq::GetBounds(Rect *bounds) const
104{
105 bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
106 for (uint i = 0; i < this->count; ++i) {
107 const Sprite *spr = GetSprite(this->seq[i].sprite, SpriteType::Normal);
108 if (i == 0) {
109 bounds->left = spr->x_offs;
110 bounds->top = spr->y_offs;
111 bounds->right = spr->width + spr->x_offs - 1;
112 bounds->bottom = spr->height + spr->y_offs - 1;
113 } else {
114 if (spr->x_offs < bounds->left) bounds->left = spr->x_offs;
115 if (spr->y_offs < bounds->top) bounds->top = spr->y_offs;
116 int right = spr->width + spr->x_offs - 1;
117 int bottom = spr->height + spr->y_offs - 1;
118 if (right > bounds->right) bounds->right = right;
119 if (bottom > bounds->bottom) bounds->bottom = bottom;
120 }
121 }
122}
123
131void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const
132{
133 for (uint i = 0; i < this->count; ++i) {
134 PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal;
135 DrawSprite(this->seq[i].sprite, pal, x, y);
136 }
137}
138
145bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
146{
147 /* We can always generate the Company pointer when we have the vehicle.
148 * However this takes time and since the Company pointer is often present
149 * when this function is called then it's faster to pass the pointer as an
150 * argument rather than finding it again. */
151 assert(c == Company::Get(this->owner));
152
153 if (use_renew_setting && !c->settings.engine_renew) return false;
154 if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
155
156 /* Only engines need renewing */
157 if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
158
159 return true;
160}
161
168{
169 assert(v != nullptr);
170 SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
171
172 do {
177 /* Prevent vehicles from breaking down directly after exiting the depot. */
178 v->breakdown_chance /= 4;
179 if (_settings_game.difficulty.vehicle_breakdowns == 1) v->breakdown_chance = 0; // on reduced breakdown
180 v = v->Next();
181 } while (v != nullptr && v->HasEngineType());
182}
183
191{
192 /* Stopped or crashed vehicles will not move, as such making unmovable
193 * vehicles to go for service is lame. */
194 if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
195
196 /* Are we ready for the next service cycle? */
197 const Company *c = Company::Get(this->owner);
198
199 /* Service intervals can be measured in different units, which we handle individually. */
200 if (this->ServiceIntervalIsPercent()) {
201 /* Service interval is in percents. */
202 if (this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) return false;
204 /* Service interval is in minutes. */
205 if (this->date_of_last_service + (this->GetServiceInterval() * EconomyTime::DAYS_IN_ECONOMY_MONTH) >= TimerGameEconomy::date) return false;
206 } else {
207 /* Service interval is in days. */
208 if (this->date_of_last_service + this->GetServiceInterval() >= TimerGameEconomy::date) return false;
209 }
210
211 /* If we're servicing anyway, because we have not disabled servicing when
212 * there are no breakdowns or we are playing with breakdowns, bail out. */
215 return true;
216 }
217
218 /* Test whether there is some pending autoreplace.
219 * Note: We do this after the service-interval test.
220 * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
221 bool pending_replace = false;
222 Money needed_money = c->settings.engine_renew_money;
223 if (needed_money > GetAvailableMoney(c->index)) return false;
224
225 for (const Vehicle *v = this; v != nullptr; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : nullptr) {
226 bool replace_when_old = false;
227 EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
228
229 /* Check engine availability */
230 if (new_engine == EngineID::Invalid() || !Engine::Get(new_engine)->company_avail.Test(v->owner)) continue;
231 /* Is the vehicle old if we are not always replacing? */
232 if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
233
234 /* Check refittability */
235 CargoTypes available_cargo_types, union_mask;
236 GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
237 /* Is there anything to refit? */
238 if (union_mask != 0) {
240 CargoTypes cargo_mask = GetCargoTypesOfArticulatedVehicle(v, &cargo_type);
241 if (!HasAtMostOneBit(cargo_mask)) {
242 CargoTypes new_engine_default_cargoes = GetCargoTypesOfArticulatedParts(new_engine);
243 if ((cargo_mask & new_engine_default_cargoes) != cargo_mask) {
244 /* We cannot refit to mixed cargoes in an automated way */
245 continue;
246 }
247 /* engine_type is already a mixed cargo type which matches the incoming vehicle by default, no refit required */
248 } else {
249 /* Did the old vehicle carry anything? */
251 /* We can't refit the vehicle to carry the cargo we want */
252 if (!HasBit(available_cargo_types, cargo_type)) continue;
253 }
254 }
255 }
256
257 /* Check money.
258 * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
259 pending_replace = true;
260 needed_money += 2 * Engine::Get(new_engine)->GetCost();
261 if (needed_money > GetAvailableMoney(c->index)) return false;
262 }
263
264 return pending_replace;
265}
266
273{
274 if (this->HasDepotOrder()) return false;
275 if (this->current_order.IsType(OT_LOADING)) return false;
276 if (this->current_order.IsType(OT_GOTO_DEPOT) && (this->current_order.GetDepotOrderType() & ODTFB_SERVICE) == 0) return false;
277 return NeedsServicing();
278}
279
281{
282 assert((this->vehstatus & VS_CRASHED) == 0);
283 assert(this->Previous() == nullptr); // IsPrimaryVehicle fails for free-wagon-chains
284
285 uint pass = 0;
286 /* Stop the vehicle. */
287 if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
288 /* crash all wagons, and count passengers */
289 for (Vehicle *v = this; v != nullptr; v = v->Next()) {
290 /* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */
291 if (IsCargoInClass(v->cargo_type, CargoClass::Passengers)) pass += v->cargo.TotalCount();
292 v->vehstatus |= VS_CRASHED;
293 v->MarkAllViewportsDirty();
294 }
295
296 /* Dirty some windows */
301
302 delete this->cargo_payment;
303 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
304
305 return RandomRange(pass + 1); // Randomise deceased passengers.
306}
307
308
317void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBug bug_type, bool critical)
318{
319 const Engine *e = Engine::Get(engine);
320 GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
321
322 /* Missing GRF. Nothing useful can be done in this situation. */
323 if (grfconfig == nullptr) return;
324
325 if (!grfconfig->grf_bugs.Test(bug_type)) {
326 grfconfig->grf_bugs.Set(bug_type);
327 ShowErrorMessage(GetEncodedString(part1, grfconfig->GetName()),
328 GetEncodedString(part2, std::monostate{}, engine), WL_CRITICAL);
330 }
331
332 /* debug output */
333 Debug(grf, 0, "{}", StrMakeValid(GetString(part1, grfconfig->GetName())));
334
335 Debug(grf, 0, "{}", StrMakeValid(GetString(part2, std::monostate{}, engine)));
336}
337
344{
345 /* show a warning once for each engine in whole game and once for each GRF after each game load */
346 const Engine *engine = u->GetEngine();
347 uint32_t grfid = engine->grf_prop.grfid;
348 GRFConfig *grfconfig = GetGRFConfig(grfid);
349 if (_gamelog.GRFBugReverse(grfid, engine->grf_prop.local_id) || !grfconfig->grf_bugs.Test(GRFBug::VehLength)) {
350 ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GRFBug::VehLength, true);
351 }
352}
353
359{
360 this->type = type;
361 this->coord.left = INVALID_COORD;
363 this->group_id = DEFAULT_GROUP;
364 this->fill_percent_te_id = INVALID_TE_ID;
365 this->first = this;
366 this->colourmap = PAL_NONE;
367 this->cargo_age_counter = 1;
368 this->last_station_visited = StationID::Invalid();
369 this->last_loading_station = StationID::Invalid();
370}
371
372/* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
373 * lookup times at the expense of memory usage. */
374const int HASH_BITS = 7;
375const int HASH_SIZE = 1 << HASH_BITS;
376const int HASH_MASK = HASH_SIZE - 1;
377const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
378const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
379
380/* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
381 * Profiling results show that 0 is fastest. */
382const int HASH_RES = 0;
383
384static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
385
386static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
387{
388 for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
389 for (int x = xl; ; x = (x + 1) & HASH_MASK) {
390 Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
391 for (; v != nullptr; v = v->hash_tile_next) {
392 Vehicle *a = proc(v, data);
393 if (find_first && a != nullptr) return a;
394 }
395 if (x == xu) break;
396 }
397 if (y == yu) break;
398 }
399
400 return nullptr;
401}
402
403
415static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
416{
417 const int COLL_DIST = 6;
418
419 /* Hash area to scan is from xl,yl to xu,yu */
420 int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
421 int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
422 int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
423 int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
424
425 return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
426}
427
442void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
443{
444 VehicleFromPosXY(x, y, data, proc, false);
445}
446
458bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
459{
460 return VehicleFromPosXY(x, y, data, proc, true) != nullptr;
461}
462
473static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
474{
475 int x = GB(TileX(tile), HASH_RES, HASH_BITS);
476 int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
477
478 Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
479 for (; v != nullptr; v = v->hash_tile_next) {
480 if (v->tile != tile) continue;
481
482 Vehicle *a = proc(v, data);
483 if (find_first && a != nullptr) return a;
484 }
485
486 return nullptr;
487}
488
502void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
503{
504 VehicleFromPos(tile, data, proc, false);
505}
506
517bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
518{
519 return VehicleFromPos(tile, data, proc, true) != nullptr;
520}
521
528static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
529{
530 int z = *(int*)data;
531
532 if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return nullptr;
533 if (v->z_pos > z) return nullptr;
534
535 return v;
536}
537
544{
545 int z = GetTileMaxPixelZ(tile);
546
547 /* Value v is not safe in MP games, however, it is used to generate a local
548 * error message only (which may be different for different machines).
549 * Such a message does not affect MP synchronisation.
550 */
551 Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
552 if (v != nullptr) return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
553 return CommandCost();
554}
555
558{
559 if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return nullptr;
560 if (v == (const Vehicle *)data) return nullptr;
561
562 return v;
563}
564
573{
574 /* Value v is not safe in MP games, however, it is used to generate a local
575 * error message only (which may be different for different machines).
576 * Such a message does not affect MP synchronisation.
577 */
578 Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
579 if (v == nullptr) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
580
581 if (v != nullptr) return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
582 return CommandCost();
583}
584
585static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
586{
587 TrackBits rail_bits = *(TrackBits *)data;
588
589 if (v->type != VEH_TRAIN) return nullptr;
590
591 Train *t = Train::From(v);
592 if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return nullptr;
593
594 return v;
595}
596
606{
607 /* Value v is not safe in MP games, however, it is used to generate a local
608 * error message only (which may be different for different machines).
609 * Such a message does not affect MP synchronisation.
610 */
611 Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
612 if (v != nullptr) return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
613 return CommandCost();
614}
615
616static void UpdateVehicleTileHash(Vehicle *v, bool remove)
617{
618 Vehicle **old_hash = v->hash_tile_current;
619 Vehicle **new_hash;
620
621 if (remove) {
622 new_hash = nullptr;
623 } else {
624 int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
625 int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
626 new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
627 }
628
629 if (old_hash == new_hash) return;
630
631 /* Remove from the old position in the hash table */
632 if (old_hash != nullptr) {
635 }
636
637 /* Insert vehicle at beginning of the new position in the hash table */
638 if (new_hash != nullptr) {
639 v->hash_tile_next = *new_hash;
640 if (v->hash_tile_next != nullptr) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next;
641 v->hash_tile_prev = new_hash;
642 *new_hash = v;
643 }
644
645 /* Remember current hash position */
646 v->hash_tile_current = new_hash;
647}
648
649static Vehicle *_vehicle_viewport_hash[1 << (GEN_HASHX_BITS + GEN_HASHY_BITS)];
650
651static void UpdateVehicleViewportHash(Vehicle *v, int x, int y, int old_x, int old_y)
652{
653 Vehicle **old_hash, **new_hash;
654
655 new_hash = (x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GEN_HASH(x, y)];
656 old_hash = (old_x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
657
658 if (old_hash == new_hash) return;
659
660 /* remove from hash table? */
661 if (old_hash != nullptr) {
664 }
665
666 /* insert into hash table? */
667 if (new_hash != nullptr) {
668 v->hash_viewport_next = *new_hash;
670 v->hash_viewport_prev = new_hash;
671 *new_hash = v;
672 }
673}
674
675void ResetVehicleHash()
676{
677 for (Vehicle *v : Vehicle::Iterate()) { v->hash_tile_current = nullptr; }
678 memset(_vehicle_viewport_hash, 0, sizeof(_vehicle_viewport_hash));
679 memset(_vehicle_tile_hash, 0, sizeof(_vehicle_tile_hash));
680}
681
682void ResetVehicleColourMap()
683{
684 for (Vehicle *v : Vehicle::Iterate()) { v->colourmap = PAL_NONE; }
685}
686
691using AutoreplaceMap = std::map<VehicleID, bool>;
692static AutoreplaceMap _vehicles_to_autoreplace;
693
694void InitializeVehicles()
695{
696 _vehicles_to_autoreplace.clear();
697 ResetVehicleHash();
698}
699
700uint CountVehiclesInChain(const Vehicle *v)
701{
702 uint count = 0;
703 do count++; while ((v = v->Next()) != nullptr);
704 return count;
705}
706
712{
713 switch (this->type) {
714 case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
715 case VEH_TRAIN:
716 return !this->IsArticulatedPart() && // tenders and other articulated parts
717 !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
718 case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
719 case VEH_SHIP: return true;
720 default: return false; // Only count company buildable vehicles
721 }
722}
723
729{
730 switch (this->type) {
731 case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft();
732 case VEH_TRAIN:
733 case VEH_ROAD:
734 case VEH_SHIP: return true;
735 default: return false;
736 }
737}
738
745{
746 return Engine::Get(this->engine_type);
747}
748
755{
756 return this->GetEngine()->GetGRF();
757}
758
764uint32_t Vehicle::GetGRFID() const
765{
766 return this->GetEngine()->GetGRFID();
767}
768
774void Vehicle::ShiftDates(TimerGameEconomy::Date interval)
775{
776 this->date_of_last_service = std::max(this->date_of_last_service + interval, TimerGameEconomy::Date(0));
777 /* date_of_last_service_newgrf is not updated here as it must stay stable
778 * for vehicles outside of a depot. */
779}
780
789{
790 if (path_found) {
791 /* Route found, is the vehicle marked with "lost" flag? */
792 if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
793
794 /* Clear the flag as the PF's problem was solved. */
798 /* Delete the news item. */
800 return;
801 }
802
803 /* Were we already lost? */
804 if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
805
806 /* It is first time the problem occurred, set the "lost" flag. */
810
811 /* Unbunching data is no longer valid. */
812 this->ResetDepotUnbunching();
813
814 /* Notify user about the event. */
815 AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
817 SetDParam(0, this->index);
818 AddVehicleAdviceNewsItem(AdviceType::VehicleLost, STR_NEWS_VEHICLE_IS_LOST, this->index);
819 }
820}
821
824{
825 if (CleaningPool()) return;
826
829 st->loading_vehicles.remove(this);
830
832 this->CancelReservation(StationID::Invalid(), st);
833 delete this->cargo_payment;
834 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
835 }
836
837 if (this->IsEngineCountable()) {
839 if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
841
844 }
845
846 Company::Get(this->owner)->freeunits[this->type].ReleaseID(this->unitnumber);
847
848 if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
849 Aircraft *a = Aircraft::From(this);
851 if (st != nullptr) {
852 const auto &layout = st->airport.GetFTA()->layout;
853 st->airport.blocks.Reset(layout[a->previous_pos].blocks | layout[a->pos].blocks);
854 }
855 }
856
857
858 if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
860 if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
861 /* Leave the drive through roadstop, when you have not already left it. */
863 }
864
865 if (v->disaster_vehicle != VehicleID::Invalid()) ReleaseDisasterVehicle(v->disaster_vehicle);
866 }
867
868 if (this->Previous() == nullptr) {
870 }
871
872 if (this->IsPrimaryVehicle()) {
880 }
882
883 this->cargo.Truncate();
886
887 StopGlobalFollowVehicle(this);
888}
889
891{
892 if (CleaningPool()) {
893 this->cargo.OnCleanPool();
894 return;
895 }
896
897 /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
898 * it may happen that vehicle chain is deleted when visible */
899 if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty();
900
901 Vehicle *v = this->Next();
902 this->SetNext(nullptr);
903
904 delete v;
905
906 UpdateVehicleTileHash(this, true);
907 UpdateVehicleViewportHash(this, INVALID_COORD, 0, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
908 if (this->type != VEH_EFFECT) {
911 }
912}
913
919{
920 /* Vehicle should stop in the depot if it was in 'stopping' state */
921 _vehicles_to_autoreplace[v->index] = !(v->vehstatus & VS_STOPPED);
922
923 /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
924 * stopping in the depot, so we stop it to ensure that it will not reserve
925 * the path out of the depot before we might autoreplace it to a different
926 * engine. The new engine would not own the reserved path we store that we
927 * stopped the vehicle, so autoreplace can start it again */
928 v->vehstatus |= VS_STOPPED;
929}
930
935{
936 if (_game_mode != GM_NORMAL) return;
937
938 /* Run the calendar day proc for every DAY_TICKS vehicle starting at TimerGameCalendar::date_fract. */
940 Vehicle *v = Vehicle::Get(i);
941 if (v == nullptr) continue;
942 v->OnNewCalendarDay();
943 }
944}
945
952{
953 if (_game_mode != GM_NORMAL) return;
954
955 /* Run the economy day proc for every DAY_TICKS vehicle starting at TimerGameEconomy::date_fract. */
957 Vehicle *v = Vehicle::Get(i);
958 if (v == nullptr) continue;
959
960 /* Call the 32-day callback if needed */
961 if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
962 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
963 if (callback != CALLBACK_FAILED) {
964 if (HasBit(callback, 0)) {
965 TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
966 }
967
968 /* After a vehicle trigger, the graphics and properties of the vehicle could change.
969 * Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */
970 if (callback != 0) v->First()->MarkDirty();
971
972 if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
973 }
974 }
975
976 /* This is called once per day for each vehicle, but not in the first tick of the day */
977 v->OnNewEconomyDay();
978 }
979}
980
981void CallVehicleTicks()
982{
983 _vehicles_to_autoreplace.clear();
984
986
987 {
989 for (Station *st : Station::Iterate()) LoadUnloadStation(st);
990 }
995
996 for (Vehicle *v : Vehicle::Iterate()) {
997 [[maybe_unused]] VehicleID vehicle_index = v->index;
998
999 /* Vehicle could be deleted in this tick */
1000 if (!v->Tick()) {
1001 assert(Vehicle::Get(vehicle_index) == nullptr);
1002 continue;
1003 }
1004
1005 assert(Vehicle::Get(vehicle_index) == v);
1006
1007 switch (v->type) {
1008 default: break;
1009
1010 case VEH_TRAIN:
1011 case VEH_ROAD:
1012 case VEH_AIRCRAFT:
1013 case VEH_SHIP: {
1014 Vehicle *front = v->First();
1015
1016 if (v->vcache.cached_cargo_age_period != 0) {
1018 if (--v->cargo_age_counter == 0) {
1019 v->cargo.AgeCargo();
1021 }
1022 }
1023
1024 /* Do not play any sound when crashed */
1025 if (front->vehstatus & VS_CRASHED) continue;
1026
1027 /* Do not play any sound when in depot or tunnel */
1028 if (v->vehstatus & VS_HIDDEN) continue;
1029
1030 /* Do not play any sound when stopped */
1031 if ((front->vehstatus & VS_STOPPED) && (front->type != VEH_TRAIN || front->cur_speed == 0)) continue;
1032
1033 /* Update motion counter for animation purposes. */
1034 v->motion_counter += front->cur_speed;
1035
1036 /* Check vehicle type specifics */
1037 switch (v->type) {
1038 case VEH_TRAIN:
1039 if (!Train::From(v)->IsEngine()) continue;
1040 break;
1041
1042 case VEH_ROAD:
1043 if (!RoadVehicle::From(v)->IsFrontEngine()) continue;
1044 break;
1045
1046 case VEH_AIRCRAFT:
1047 if (!Aircraft::From(v)->IsNormalAircraft()) continue;
1048 break;
1049
1050 default:
1051 break;
1052 }
1053
1054 /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
1055 if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
1056
1057 /* Play an alternating running sound every 16 ticks */
1058 if (GB(v->tick_counter, 0, 4) == 0) {
1059 /* Play running sound when speed > 0 and not braking */
1060 bool running = (front->cur_speed > 0) && !(front->vehstatus & (VS_STOPPED | VS_TRAIN_SLOWING));
1062 }
1063
1064 break;
1065 }
1066 }
1067 }
1068
1070 for (auto &it : _vehicles_to_autoreplace) {
1071 Vehicle *v = Vehicle::Get(it.first);
1072 /* Autoreplace needs the current company set as the vehicle owner */
1073 cur_company.Change(v->owner);
1074
1075 /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
1076 * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
1077 * they are already leaving the depot again before being replaced. */
1078 if (it.second) v->vehstatus &= ~VS_STOPPED;
1079
1080 /* Store the position of the effect as the vehicle pointer will become invalid later */
1081 int x = v->x_pos;
1082 int y = v->y_pos;
1083 int z = v->z_pos;
1084
1089
1090 if (!IsLocalCompany()) continue;
1091
1092 if (res.Succeeded()) {
1093 ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
1094 continue;
1095 }
1096
1097 StringID error_message = res.GetErrorMessage();
1098 if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
1099
1100 if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
1101
1102 StringID message;
1103 if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
1104 message = error_message;
1105 } else {
1106 message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
1107 }
1108
1109 SetDParam(0, v->index);
1110 SetDParam(1, error_message);
1112 }
1113
1114 cur_company.Restore();
1115}
1116
1121static void DoDrawVehicle(const Vehicle *v)
1122{
1123 PaletteID pal = PAL_NONE;
1124
1126
1127 /* Check whether the vehicle shall be transparent due to the game state */
1128 bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
1129
1130 if (v->type == VEH_EFFECT) {
1131 /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
1132 * However, transparent smoke and bubbles look weird, so always hide them. */
1134 if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
1135 }
1136
1138 for (uint i = 0; i < v->sprite_cache.sprite_seq.count; ++i) {
1139 PaletteID pal2 = v->sprite_cache.sprite_seq.seq[i].pal;
1140 if (!pal2 || (v->vehstatus & VS_CRASHED)) pal2 = pal;
1142 v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
1143 }
1145}
1146
1152{
1153 /* The bounding rectangle */
1154 const int l = dpi->left;
1155 const int r = dpi->left + dpi->width;
1156 const int t = dpi->top;
1157 const int b = dpi->top + dpi->height;
1158
1159 /* Border size of MAX_VEHICLE_PIXEL_xy */
1160 const int xb = MAX_VEHICLE_PIXEL_X * ZOOM_BASE;
1161 const int yb = MAX_VEHICLE_PIXEL_Y * ZOOM_BASE;
1162
1163 /* The hash area to scan */
1164 int xl, xu, yl, yu;
1165
1166 if (dpi->width + xb < GEN_HASHX_SIZE) {
1167 xl = GEN_HASHX(l - xb);
1168 xu = GEN_HASHX(r);
1169 } else {
1170 /* scan whole hash row */
1171 xl = 0;
1172 xu = GEN_HASHX_MASK;
1173 }
1174
1175 if (dpi->height + yb < GEN_HASHY_SIZE) {
1176 yl = GEN_HASHY(t - yb);
1177 yu = GEN_HASHY(b);
1178 } else {
1179 /* scan whole column */
1180 yl = 0;
1181 yu = GEN_HASHY_MASK;
1182 }
1183
1184 for (int y = yl;; y = (y + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1185 for (int x = xl;; x = (x + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1186 const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
1187
1188 while (v != nullptr) {
1189
1190 if (!(v->vehstatus & VS_HIDDEN) &&
1191 l <= v->coord.right + xb &&
1192 t <= v->coord.bottom + yb &&
1193 r >= v->coord.left - xb &&
1194 b >= v->coord.top - yb)
1195 {
1196 /*
1197 * This vehicle can potentially be drawn as part of this viewport and
1198 * needs to be revalidated, as the sprite may not be correct.
1199 */
1201 VehicleSpriteSeq seq;
1202 v->GetImage(v->direction, EIT_ON_MAP, &seq);
1203
1204 if (seq.IsValid() && v->sprite_cache.sprite_seq != seq) {
1205 v->sprite_cache.sprite_seq = seq;
1206 /*
1207 * A sprite change may also result in a bounding box change,
1208 * so we need to update the bounding box again before we
1209 * check to see if the vehicle should be drawn. Note that
1210 * we can't interfere with the viewport hash at this point,
1211 * so we keep the original hash on the assumption there will
1212 * not be a significant change in the top and left coordinates
1213 * of the vehicle.
1214 */
1216
1217 }
1218
1220 }
1221
1222 if (l <= v->coord.right &&
1223 t <= v->coord.bottom &&
1224 r >= v->coord.left &&
1225 b >= v->coord.top) DoDrawVehicle(v);
1226 }
1227
1228 v = v->hash_viewport_next;
1229 }
1230
1231 if (x == xu) break;
1232 }
1233
1234 if (y == yu) break;
1235 }
1236}
1237
1245Vehicle *CheckClickOnVehicle(const Viewport *vp, int x, int y)
1246{
1247 Vehicle *found = nullptr;
1248 uint dist, best_dist = UINT_MAX;
1249
1250 if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)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 int xl = GEN_HASHX(x - xb);
1261 int xu = GEN_HASHX(x);
1262 int yl = GEN_HASHY(y - yb);
1263 int yu = GEN_HASHY(y);
1264
1265 for (int hy = yl;; hy = (hy + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1266 for (int 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 & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
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;
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
1315void CheckVehicleBreakdown(Vehicle *v)
1316{
1317 int rel, rel_old;
1318
1319 /* decrease reliability */
1322 v->reliability = rel = std::max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
1323 if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
1324 }
1325
1326 if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
1328 v->cur_speed < 5 || _game_mode == GM_MENU) {
1329 return;
1330 }
1331
1332 uint32_t r = Random();
1333
1334 /* increase chance of failure */
1335 int chance = v->breakdown_chance + 1;
1336 if (Chance16I(1, 25, r)) chance += 25;
1337 v->breakdown_chance = ClampTo<uint8_t>(chance);
1338
1339 /* calculate reliability value to use in comparison */
1340 rel = v->reliability;
1341 if (v->type == VEH_SHIP) rel += 0x6666;
1342
1343 /* reduced breakdowns? */
1344 if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
1345
1346 /* check if to break down */
1347 if (_breakdown_chance[ClampTo<uint16_t>(rel) >> 10] <= v->breakdown_chance) {
1348 v->breakdown_ctr = GB(r, 16, 6) + 0x3F;
1349 v->breakdown_delay = GB(r, 24, 7) + 0x80;
1350 v->breakdown_chance = 0;
1351 }
1352}
1353
1361{
1362 /* Possible states for Vehicle::breakdown_ctr
1363 * 0 - vehicle is running normally
1364 * 1 - vehicle is currently broken down
1365 * 2 - vehicle is going to break down now
1366 * >2 - vehicle is counting down to the actual breakdown event */
1367 switch (this->breakdown_ctr) {
1368 case 0:
1369 return false;
1370
1371 case 2:
1372 this->breakdown_ctr = 1;
1373
1374 if (this->breakdowns_since_last_service != 255) {
1376 }
1377
1378 if (this->type == VEH_AIRCRAFT) {
1379 /* Aircraft just need this flag, the rest is handled elsewhere */
1381 } else {
1382 this->cur_speed = 0;
1383
1384 if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
1385 bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP;
1386 SndPlayVehicleFx((_settings_game.game_creation.landscape != LandscapeType::Toyland) ?
1389 }
1390
1391 if (!(this->vehstatus & VS_HIDDEN) && !EngInfo(this->engine_type)->misc_flags.Test(EngineMiscFlag::NoBreakdownSmoke)) {
1393 if (u != nullptr) u->animation_state = this->breakdown_delay * 2;
1394 }
1395 }
1396
1397 this->MarkDirty(); // Update graphics after speed is zeroed
1400
1401 [[fallthrough]];
1402 case 1:
1403 /* Aircraft breakdowns end only when arriving at the airport */
1404 if (this->type == VEH_AIRCRAFT) return false;
1405
1406 /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
1407 if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
1408 if (--this->breakdown_delay == 0) {
1409 this->breakdown_ctr = 0;
1410 this->MarkDirty();
1412 }
1413 }
1414 return true;
1415
1416 default:
1417 if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
1418 return false;
1419 }
1420}
1421
1433
1439{
1440 if (v->age < CalendarTime::MAX_DATE) v->age++;
1441
1442 if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
1443
1444 auto age = v->age - v->max_age;
1445 for (int32_t i = 0; i <= 4; i++) {
1447 v->reliability_spd_dec <<= 1;
1448 break;
1449 }
1450 }
1451
1453
1454 /* Don't warn if warnings are disabled */
1456
1457 /* 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 */
1458 if (v->Previous() != nullptr || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0 || (v->vehstatus & VS_STOPPED) != 0) return;
1459
1460 const Company *c = Company::Get(v->owner);
1461 /* Don't warn if a renew is active */
1462 if (c->settings.engine_renew && v->GetEngine()->company_avail.Any()) return;
1463 /* Don't warn if a replacement is active */
1465
1466 StringID str;
1468 str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1470 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1472 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1473 } else {
1474 return;
1475 }
1476
1477 SetDParam(0, v->index);
1479}
1480
1490uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
1491{
1492 int count = 0;
1493 int max = 0;
1494 int cars = 0;
1495 int unloading = 0;
1496 bool loading = false;
1497
1498 bool is_loading = front->current_order.IsType(OT_LOADING);
1499
1500 /* The station may be nullptr when the (colour) string does not need to be set. */
1502 assert(colour == nullptr || (st != nullptr && is_loading));
1503
1504 bool order_no_load = is_loading && (front->current_order.GetLoadType() & OLFB_NO_LOAD);
1505 bool order_full_load = is_loading && (front->current_order.GetLoadType() & OLFB_FULL_LOAD);
1506
1507 /* Count up max and used */
1508 for (const Vehicle *v = front; v != nullptr; v = v->Next()) {
1509 count += v->cargo.StoredCount();
1510 max += v->cargo_cap;
1511 if (v->cargo_cap != 0 && colour != nullptr) {
1512 unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
1513 loading |= !order_no_load &&
1514 (order_full_load || st->goods[v->cargo_type].HasRating()) &&
1516 cars++;
1517 }
1518 }
1519
1520 if (colour != nullptr) {
1521 if (unloading == 0 && loading) {
1522 *colour = STR_PERCENT_UP;
1523 } else if (unloading == 0 && !loading) {
1524 *colour = STR_PERCENT_NONE;
1525 } else if (cars == unloading || !loading) {
1526 *colour = STR_PERCENT_DOWN;
1527 } else {
1528 *colour = STR_PERCENT_UP_DOWN;
1529 }
1530 }
1531
1532 /* Train without capacity */
1533 if (max == 0) return 100;
1534
1535 /* Return the percentage */
1536 if (count * 2 < max) {
1537 /* Less than 50%; round up, so that 0% means really empty. */
1538 return CeilDiv(count * 100, max);
1539 } else {
1540 /* More than 50%; round down, so that 100% means really full. */
1541 return (count * 100) / max;
1542 }
1543}
1544
1550{
1551 /* Always work with the front of the vehicle */
1552 assert(v == v->First());
1553
1554 switch (v->type) {
1555 case VEH_TRAIN: {
1556 Train *t = Train::From(v);
1558 /* Clear path reservation */
1559 SetDepotReservation(t->tile, false);
1561
1563 t->wait_counter = 0;
1564 t->force_proceed = TFP_NONE;
1565 ClrBit(t->flags, VRF_TOGGLE_REVERSE);
1567 break;
1568 }
1569
1570 case VEH_ROAD:
1572 break;
1573
1574 case VEH_SHIP: {
1576 Ship *ship = Ship::From(v);
1577 ship->state = TRACK_BIT_DEPOT;
1578 ship->UpdateCache();
1579 ship->UpdateViewport(true, true);
1581 break;
1582 }
1583
1584 case VEH_AIRCRAFT:
1587 break;
1588 default: NOT_REACHED();
1589 }
1591
1592 if (v->type != VEH_TRAIN) {
1593 /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
1594 * 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 */
1596 }
1598
1599 v->vehstatus |= VS_HIDDEN;
1600 v->cur_speed = 0;
1601
1603
1604 /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
1605 TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1606 v->MarkDirty();
1607
1609
1610 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1612
1613 const Order *real_order = v->GetOrder(v->cur_real_order_index);
1614
1615 /* Test whether we are heading for this depot. If not, do nothing.
1616 * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
1618 real_order != nullptr && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
1620 /* We are heading for another depot, keep driving. */
1621 return;
1622 }
1623
1624 if (v->current_order.IsRefit()) {
1625 Backup<CompanyID> cur_company(_current_company, v->owner);
1626 CommandCost cost = std::get<0>(Command<CMD_REFIT_VEHICLE>::Do(DoCommandFlag::Execute, v->index, v->current_order.GetRefitCargo(), 0xFF, false, false, 0));
1627 cur_company.Restore();
1628
1629 if (cost.Failed()) {
1630 _vehicles_to_autoreplace[v->index] = false;
1631 if (v->owner == _local_company) {
1632 /* Notify the user that we stopped the vehicle */
1633 SetDParam(0, v->index);
1634 AddVehicleAdviceNewsItem(AdviceType::RefitFailed, STR_NEWS_ORDER_REFIT_FAILED, v->index);
1635 }
1636 } else if (cost.GetCost() != 0) {
1637 v->profit_this_year -= cost.GetCost() << 8;
1638 if (v->owner == _local_company) {
1640 }
1641 }
1642 }
1643
1645 /* Part of orders */
1647 UpdateVehicleTimetable(v, true);
1649 }
1651 /* Vehicles are always stopped on entering depots. Do not restart this one. */
1652 _vehicles_to_autoreplace[v->index] = false;
1653 /* Invalidate last_loading_station. As the link from the station
1654 * before the stop to the station after the stop can't be predicted
1655 * we shouldn't construct it when the vehicle visits the next stop. */
1656 v->last_loading_station = StationID::Invalid();
1657
1658 /* Clear unbunching data. */
1660
1661 /* Announce that the vehicle is waiting to players and AIs. */
1662 if (v->owner == _local_company) {
1663 SetDParam(0, v->index);
1664 AddVehicleAdviceNewsItem(AdviceType::VehicleWaiting, STR_NEWS_TRAIN_IS_WAITING + v->type, v->index);
1665 }
1666 AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
1667 }
1668
1669 /* If we've entered our unbunching depot, record the round trip duration. */
1672 if (v->round_trip_time == 0) {
1673 /* This might be our first round trip. */
1674 v->round_trip_time = measured_round_trip;
1675 } else {
1676 /* If we have a previous trip, smooth the effects of outlier trip calculations caused by jams or other interference. */
1677 v->round_trip_time = Clamp(measured_round_trip, (v->round_trip_time / 2), ClampTo<TimerGameTick::Ticks>(v->round_trip_time * 2));
1678 }
1679 }
1680
1682 }
1683}
1684
1685
1691{
1692 UpdateVehicleTileHash(this, false);
1693}
1694
1699void Vehicle::UpdateBoundingBoxCoordinates(bool update_cache) const
1700{
1701 Rect new_coord;
1702 this->sprite_cache.sprite_seq.GetBounds(&new_coord);
1703
1704 Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
1705 new_coord.left += pt.x;
1706 new_coord.top += pt.y;
1707 new_coord.right += pt.x + 2 * ZOOM_BASE;
1708 new_coord.bottom += pt.y + 2 * ZOOM_BASE;
1709
1710 if (update_cache) {
1711 /*
1712 * If the old coordinates are invalid, set the cache to the new coordinates for correct
1713 * behaviour the next time the coordinate cache is checked.
1714 */
1715 this->sprite_cache.old_coord = this->coord.left == INVALID_COORD ? new_coord : this->coord;
1716 }
1717 else {
1718 /* Extend the bounds of the existing cached bounding box so the next dirty window is correct */
1719 this->sprite_cache.old_coord.left = std::min(this->sprite_cache.old_coord.left, this->coord.left);
1720 this->sprite_cache.old_coord.top = std::min(this->sprite_cache.old_coord.top, this->coord.top);
1721 this->sprite_cache.old_coord.right = std::max(this->sprite_cache.old_coord.right, this->coord.right);
1722 this->sprite_cache.old_coord.bottom = std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom);
1723 }
1724
1725 this->coord = new_coord;
1726}
1727
1733{
1734 /* If the existing cache is invalid we should ignore it, as it will be set to the current coords by UpdateBoundingBoxCoordinates */
1735 bool ignore_cached_coords = this->sprite_cache.old_coord.left == INVALID_COORD;
1736
1737 this->UpdateBoundingBoxCoordinates(true);
1738
1739 if (ignore_cached_coords) {
1740 UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, INVALID_COORD, INVALID_COORD);
1741 } else {
1742 UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top);
1743 }
1744
1745 if (dirty) {
1746 if (ignore_cached_coords) {
1748 } else {
1750 std::min(this->sprite_cache.old_coord.left, this->coord.left),
1751 std::min(this->sprite_cache.old_coord.top, this->coord.top),
1752 std::max(this->sprite_cache.old_coord.right, this->coord.right),
1753 std::max(this->sprite_cache.old_coord.bottom, this->coord.bottom));
1754 }
1755 }
1756}
1757
1762{
1763 this->UpdatePosition();
1764 this->UpdateViewport(true);
1765}
1766
1772{
1773 return ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
1774}
1775
1782{
1783 static const int8_t _delta_coord[16] = {
1784 -1,-1,-1, 0, 1, 1, 1, 0, /* x */
1785 -1, 0, 1, 1, 1, 0,-1,-1, /* y */
1786 };
1787
1788 int x = v->x_pos + _delta_coord[v->direction];
1789 int y = v->y_pos + _delta_coord[v->direction + 8];
1790
1792 gp.x = x;
1793 gp.y = y;
1794 gp.old_tile = v->tile;
1795 gp.new_tile = TileVirtXY(x, y);
1796 return gp;
1797}
1798
1799static const Direction _new_direction_table[] = {
1800 DIR_N, DIR_NW, DIR_W,
1803};
1804
1805Direction GetDirectionTowards(const Vehicle *v, int x, int y)
1806{
1807 int i = 0;
1808
1809 if (y >= v->y_pos) {
1810 if (y != v->y_pos) i += 3;
1811 i += 3;
1812 }
1813
1814 if (x >= v->x_pos) {
1815 if (x != v->x_pos) i++;
1816 i++;
1817 }
1818
1819 Direction dir = v->direction;
1820
1821 DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
1822 if (dirdiff == DIRDIFF_SAME) return dir;
1823 return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
1824}
1825
1836{
1837 return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
1838}
1839
1846{
1847 for (auto it = std::begin(this->used_bitmap); it != std::end(this->used_bitmap); ++it) {
1848 BitmapStorage available = ~(*it);
1849 if (available == 0) continue;
1850 return static_cast<UnitID>(std::distance(std::begin(this->used_bitmap), it) * BITMAP_SIZE + FindFirstBit(available) + 1);
1851 }
1852 return static_cast<UnitID>(this->used_bitmap.size() * BITMAP_SIZE + 1);
1853}
1854
1861{
1862 if (index == 0 || index == UINT16_MAX) return index;
1863
1864 index--;
1865
1866 size_t slot = index / BITMAP_SIZE;
1867 if (slot >= this->used_bitmap.size()) this->used_bitmap.resize(slot + 1);
1868 SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
1869
1870 return index + 1;
1871}
1872
1878{
1879 if (index == 0 || index == UINT16_MAX) return;
1880
1881 index--;
1882
1883 assert(index / BITMAP_SIZE < this->used_bitmap.size());
1884 ClrBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
1885}
1886
1893{
1894 /* Check whether it is allowed to build another vehicle. */
1895 uint max_veh;
1896 switch (type) {
1897 case VEH_TRAIN: max_veh = _settings_game.vehicle.max_trains; break;
1898 case VEH_ROAD: max_veh = _settings_game.vehicle.max_roadveh; break;
1899 case VEH_SHIP: max_veh = _settings_game.vehicle.max_ships; break;
1900 case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
1901 default: NOT_REACHED();
1902 }
1903
1905 if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
1906
1907 return c->freeunits[type].NextID();
1908}
1909
1910
1920{
1921 assert(IsCompanyBuildableVehicleType(type));
1922
1923 if (!Company::IsValidID(_local_company)) return false;
1924
1925 UnitID max;
1926 switch (type) {
1927 case VEH_TRAIN:
1928 if (!HasAnyRailTypesAvail(_local_company)) return false;
1930 break;
1931 case VEH_ROAD:
1932 if (!HasAnyRoadTypesAvail(_local_company, (RoadTramType)subtype)) return false;
1934 break;
1935 case VEH_SHIP: max = _settings_game.vehicle.max_ships; break;
1937 default: NOT_REACHED();
1938 }
1939
1940 /* We can build vehicle infrastructure when we may build the vehicle type */
1941 if (max > 0) {
1942 /* Can we actually build the vehicle type? */
1943 for (const Engine *e : Engine::IterateType(type)) {
1944 if (type == VEH_ROAD && GetRoadTramType(e->u.road.roadtype) != (RoadTramType)subtype) continue;
1945 if (e->company_avail.Test(_local_company)) return true;
1946 }
1947 return false;
1948 }
1949
1950 /* We should be able to build infrastructure when we have the actual vehicle type */
1951 for (const Vehicle *v : Vehicle::Iterate()) {
1952 if (v->type == VEH_ROAD && GetRoadTramType(RoadVehicle::From(v)->roadtype) != (RoadTramType)subtype) continue;
1953 if (v->owner == _local_company && v->type == type) return true;
1954 }
1955
1956 return false;
1957}
1958
1959
1967LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
1968{
1969 CargoType cargo_type = v == nullptr ? INVALID_CARGO : v->cargo_type;
1970 const Engine *e = Engine::Get(engine_type);
1971 switch (e->type) {
1972 default: NOT_REACHED();
1973 case VEH_TRAIN:
1974 if (v != nullptr && parent_engine_type != EngineID::Invalid() && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
1975 /* Wagonoverrides use the colour scheme of the front engine.
1976 * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
1977 engine_type = parent_engine_type;
1978 e = Engine::Get(engine_type);
1979 /* Note: Luckily cargo_type is not needed for engines */
1980 }
1981
1982 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
1983 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
1984 assert(IsValidCargoType(cargo_type));
1985 if (e->u.rail.railveh_type == RAILVEH_WAGON) {
1986 if (!CargoSpec::Get(cargo_type)->is_freight) {
1987 if (parent_engine_type == EngineID::Invalid()) {
1988 return LS_PASSENGER_WAGON_STEAM;
1989 } else {
1990 bool is_mu = EngInfo(parent_engine_type)->misc_flags.Test(EngineMiscFlag::RailIsMU);
1991 switch (RailVehInfo(parent_engine_type)->engclass) {
1992 default: NOT_REACHED();
1993 case EC_STEAM: return LS_PASSENGER_WAGON_STEAM;
1994 case EC_DIESEL: return is_mu ? LS_DMU : LS_PASSENGER_WAGON_DIESEL;
1995 case EC_ELECTRIC: return is_mu ? LS_EMU : LS_PASSENGER_WAGON_ELECTRIC;
1996 case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
1997 case EC_MAGLEV: return LS_PASSENGER_WAGON_MAGLEV;
1998 }
1999 }
2000 } else {
2001 return LS_FREIGHT_WAGON;
2002 }
2003 } else {
2004 bool is_mu = e->info.misc_flags.Test(EngineMiscFlag::RailIsMU);
2005
2006 switch (e->u.rail.engclass) {
2007 default: NOT_REACHED();
2008 case EC_STEAM: return LS_STEAM;
2009 case EC_DIESEL: return is_mu ? LS_DMU : LS_DIESEL;
2010 case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
2011 case EC_MONORAIL: return LS_MONORAIL;
2012 case EC_MAGLEV: return LS_MAGLEV;
2013 }
2014 }
2015
2016 case VEH_ROAD:
2017 /* Always use the livery of the front */
2018 if (v != nullptr && parent_engine_type != EngineID::Invalid()) {
2019 engine_type = parent_engine_type;
2020 e = Engine::Get(engine_type);
2021 cargo_type = v->First()->cargo_type;
2022 }
2023 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
2024 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
2025 assert(IsValidCargoType(cargo_type));
2026
2027 /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
2029 /* Tram */
2030 return IsCargoInClass(cargo_type, CargoClass::Passengers) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
2031 } else {
2032 /* Bus or truck */
2033 return IsCargoInClass(cargo_type, CargoClass::Passengers) ? LS_BUS : LS_TRUCK;
2034 }
2035
2036 case VEH_SHIP:
2037 if (!IsValidCargoType(cargo_type)) cargo_type = e->GetDefaultCargoType();
2038 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(CT_GOODS); // The vehicle does not carry anything, let's pick some freight cargo
2039 assert(IsValidCargoType(cargo_type));
2040 return IsCargoInClass(cargo_type, CargoClass::Passengers) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
2041
2042 case VEH_AIRCRAFT:
2043 switch (e->u.air.subtype) {
2044 case AIR_HELI: return LS_HELICOPTER;
2045 case AIR_CTOL: return LS_SMALL_PLANE;
2046 case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
2047 default: NOT_REACHED();
2048 }
2049 }
2050}
2051
2061const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, uint8_t livery_setting)
2062{
2063 const Company *c = Company::Get(company);
2064 LiveryScheme scheme = LS_DEFAULT;
2065
2066 if (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company)) {
2067 if (v != nullptr) {
2068 const Group *g = Group::GetIfValid(v->First()->group_id);
2069 if (g != nullptr) {
2070 /* Traverse parents until we find a livery or reach the top */
2071 while (g->livery.in_use == 0 && g->parent != GroupID::Invalid()) {
2072 g = Group::Get(g->parent);
2073 }
2074 if (g->livery.in_use != 0) return &g->livery;
2075 }
2076 }
2077
2078 /* The default livery is always available for use, but its in_use flag determines
2079 * whether any _other_ liveries are in use. */
2080 if (c->livery[LS_DEFAULT].in_use != 0) {
2081 /* Determine the livery scheme to use */
2082 scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
2083 }
2084 }
2085
2086 return &c->livery[scheme];
2087}
2088
2089
2090static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
2091{
2092 PaletteID map = (v != nullptr) ? v->colourmap : PAL_NONE;
2093
2094 /* Return cached value if any */
2095 if (map != PAL_NONE) return map;
2096
2097 const Engine *e = Engine::Get(engine_type);
2098
2099 /* Check if we should use the colour map callback */
2101 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
2102 /* Failure means "use the default two-colour" */
2103 if (callback != CALLBACK_FAILED) {
2104 static_assert(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
2105 map = GB(callback, 0, 14);
2106 /* If bit 14 is set, then the company colours are applied to the
2107 * map else it's returned as-is. */
2108 if (!HasBit(callback, 14)) {
2109 /* Update cache */
2110 if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2111 return map;
2112 }
2113 }
2114 }
2115
2116 bool twocc = e->info.misc_flags.Test(EngineMiscFlag::Uses2CC);
2117
2118 if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
2119
2120 /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
2121 if (!Company::IsValidID(company)) return map;
2122
2123 const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
2124
2125 map += livery->colour1;
2126 if (twocc) map += livery->colour2 * 16;
2127
2128 /* Update cache */
2129 if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
2130 return map;
2131}
2132
2140{
2141 return GetEngineColourMap(engine_type, company, EngineID::Invalid(), nullptr);
2142}
2143
2150{
2151 if (v->IsGroundVehicle()) {
2152 return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
2153 }
2154
2155 return GetEngineColourMap(v->engine_type, v->owner, EngineID::Invalid(), v);
2156}
2157
2162{
2163 if (this->IsGroundVehicle()) {
2164 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2165 if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
2166 /* Do not delete orders, only skip them */
2169 InvalidateVehicleOrder(this, 0);
2170 return;
2171 }
2172 }
2173
2174 const Order *order = this->GetOrder(this->cur_implicit_order_index);
2175 while (order != nullptr) {
2176 if (this->cur_implicit_order_index == this->cur_real_order_index) break;
2177
2178 if (order->IsType(OT_IMPLICIT)) {
2180 /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2181 order = this->GetOrder(this->cur_implicit_order_index);
2182 } else {
2183 /* Skip non-implicit orders, e.g. service-orders */
2184 order = order->next;
2186 }
2187
2188 /* Wrap around */
2189 if (order == nullptr) {
2190 order = this->GetOrder(0);
2191 this->cur_implicit_order_index = 0;
2192 }
2193 }
2194}
2195
2201{
2202 assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
2203
2205 if (this->current_order.IsType(OT_GOTO_STATION) &&
2206 this->current_order.GetDestination() == this->last_station_visited) {
2208
2209 /* Now both order indices point to the destination station, and we can start loading */
2210 this->current_order.MakeLoading(true);
2211 UpdateVehicleTimetable(this, true);
2212
2213 /* Furthermore add the Non Stop flag to mark that this station
2214 * is the actual destination of the vehicle, which is (for example)
2215 * necessary to be known for HandleTrainLoading to determine
2216 * whether the train is lost or not; not marking a train lost
2217 * that arrives at random stations is bad. */
2219
2220 } else {
2221 /* We weren't scheduled to stop here. Insert an implicit order
2222 * to show that we are stopping here.
2223 * While only groundvehicles have implicit orders, e.g. aircraft might still enter
2224 * the 'wrong' terminal when skipping orders etc. */
2225 Order *in_list = this->GetOrder(this->cur_implicit_order_index);
2226 if (this->IsGroundVehicle() &&
2227 (in_list == nullptr || !in_list->IsType(OT_IMPLICIT) ||
2228 in_list->GetDestination() != this->last_station_visited)) {
2229 bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
2230 /* Do not create consecutive duplicates of implicit orders */
2231 Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : nullptr);
2232 if (prev_order == nullptr ||
2233 (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
2234 prev_order->GetDestination() != this->last_station_visited) {
2235
2236 /* Prefer deleting implicit orders instead of inserting new ones,
2237 * so test whether the right order follows later. In case of only
2238 * implicit orders treat the last order in the list like an
2239 * explicit one, except if the overall number of orders surpasses
2240 * IMPLICIT_ORDER_ONLY_CAP. */
2241 int target_index = this->cur_implicit_order_index;
2242 bool found = false;
2243 while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) {
2244 const Order *order = this->GetOrder(target_index);
2245 if (order == nullptr) break; // No orders.
2246 if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
2247 found = true;
2248 break;
2249 }
2250 target_index++;
2251 if (target_index >= this->orders->GetNumOrders()) {
2252 if (this->GetNumManualOrders() == 0 &&
2254 break;
2255 }
2256 target_index = 0;
2257 }
2258 if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop.
2259 }
2260
2261 if (found) {
2262 if (suppress_implicit_orders) {
2263 /* Skip to the found order */
2264 this->cur_implicit_order_index = target_index;
2265 InvalidateVehicleOrder(this, 0);
2266 } else {
2267 /* Delete all implicit orders up to the station we just reached */
2268 const Order *order = this->GetOrder(this->cur_implicit_order_index);
2269 while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
2270 if (order->IsType(OT_IMPLICIT)) {
2272 /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
2273 order = this->GetOrder(this->cur_implicit_order_index);
2274 } else {
2275 /* Skip non-implicit orders, e.g. service-orders */
2276 order = order->next;
2278 }
2279
2280 /* Wrap around */
2281 if (order == nullptr) {
2282 order = this->GetOrder(0);
2283 this->cur_implicit_order_index = 0;
2284 }
2285 assert(order != nullptr);
2286 }
2287 }
2288 } else if (!suppress_implicit_orders &&
2289 ((this->orders == nullptr ? OrderList::CanAllocateItem() : this->orders->GetNumOrders() < MAX_VEH_ORDER_ID)) &&
2291 /* Insert new implicit order */
2292 Order *implicit_order = new Order();
2293 implicit_order->MakeImplicit(this->last_station_visited);
2294 InsertOrder(this, implicit_order, this->cur_implicit_order_index);
2296
2297 /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
2298 * Reenable it for this vehicle */
2299 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2301 }
2302 }
2303 }
2304 this->current_order.MakeLoading(false);
2305 }
2306
2307 if (this->last_loading_station != StationID::Invalid() &&
2309 ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2310 (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0)) {
2311 IncreaseStats(Station::Get(this->last_loading_station), this, this->last_station_visited, travel_time);
2312 }
2313
2314 PrepareUnload(this);
2315
2320
2322 this->cur_speed = 0;
2323 this->MarkDirty();
2324}
2325
2332{
2333 for (Vehicle *v = this; v != nullptr; v = v->next) {
2336 Debug(misc, 1, "cancelling cargo reservation");
2337 cargo.Return(UINT_MAX, &st->goods[v->cargo_type].GetOrCreateData().cargo, next, v->tile);
2338 }
2339 cargo.KeepAll();
2340 }
2341}
2342
2348{
2349 assert(this->current_order.IsType(OT_LOADING));
2350
2351 delete this->cargo_payment;
2352 assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment
2353
2354 /* Only update the timetable if the vehicle was supposed to stop here. */
2356
2357 if ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2358 (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
2359 if (this->current_order.CanLeaveWithCargo(this->last_loading_station != StationID::Invalid())) {
2360 /* Refresh next hop stats to make sure we've done that at least once
2361 * during the stop and that refit_cap == cargo_cap for each vehicle in
2362 * the consist. */
2363 this->ResetRefitCaps();
2364 LinkRefresher::Run(this);
2365
2366 /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
2369 } else {
2370 /* if the vehicle couldn't load and had to unload or transfer everything
2371 * set the last loading station to invalid as it will leave empty. */
2372 this->last_loading_station = StationID::Invalid();
2373 }
2374 }
2375
2378 this->CancelReservation(StationID::Invalid(), st);
2379 st->loading_vehicles.remove(this);
2380
2383
2384 if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
2385 /* Trigger station animation (trains only) */
2386 if (IsTileType(this->tile, MP_STATION)) {
2388 TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
2389 }
2390
2391 SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
2392 }
2393 if (this->type == VEH_ROAD && !(this->vehstatus & VS_CRASHED)) {
2394 /* Trigger road stop animation */
2395 if (IsStationRoadStopTile(this->tile)) {
2396 TriggerRoadStopRandomisation(st, this->tile, RSRT_VEH_DEPARTS);
2397 TriggerRoadStopAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
2398 }
2399 }
2400
2401
2402 this->MarkDirty();
2403}
2404
2409{
2410 for (Vehicle *v = this; v != nullptr; v = v->Next()) v->refit_cap = v->cargo_cap;
2411}
2412
2417{
2418 Company::Get(this->owner)->freeunits[this->type].ReleaseID(this->unitnumber);
2419 this->unitnumber = 0;
2420}
2421
2428{
2429 switch (this->current_order.GetType()) {
2430 case OT_LOADING: {
2431 TimerGameTick::Ticks wait_time = std::max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2432
2433 /* Not the first call for this tick, or still loading */
2434 if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
2435
2436 this->PlayLeaveStationSound();
2437
2438 this->LeaveStation();
2439
2440 /* Only advance to next order if we just loaded at the current one */
2441 const Order *order = this->GetOrder(this->cur_implicit_order_index);
2442 if (order == nullptr ||
2443 (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2444 order->GetDestination() != this->last_station_visited) {
2445 return;
2446 }
2447 break;
2448 }
2449
2450 case OT_DUMMY: break;
2451
2452 default: return;
2453 }
2454
2456}
2457
2463{
2464 for (Order *o : this->Orders()) {
2465 if (o->IsType(OT_GOTO_STATION) && o->GetLoadType() & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) return true;
2466 }
2467 return false;
2468}
2469
2475{
2476 for (Order *o : this->Orders()) {
2477 if (o->IsType(OT_CONDITIONAL)) return true;
2478 }
2479 return false;
2480}
2481
2487{
2488 for (Order *o : this->Orders()) {
2489 if (o->IsType(OT_GOTO_DEPOT) && o->GetDepotActionType() & ODATFB_UNBUNCH) return true;
2490 }
2491 return false;
2492}
2493
2499{
2500 /* If we are headed for the first order, we must wrap around back to the last order. */
2501 bool is_first_order = (v->GetOrder(v->cur_implicit_order_index) == v->GetFirstOrder());
2502 Order *previous_order = (is_first_order) ? v->GetLastOrder() : v->GetOrder(v->cur_implicit_order_index - 1);
2503
2504 if (previous_order == nullptr || !previous_order->IsType(OT_GOTO_DEPOT)) return false;
2505 return (previous_order->GetDepotActionType() & ODATFB_UNBUNCH) != 0;
2506}
2507
2512{
2513 /* Don't do anything if this is not our unbunching order. */
2514 if (!PreviousOrderIsUnbunching(this)) return;
2515
2516 /* Set the start point for this round trip time. */
2518
2519 /* Tell the timetable we are now "on time." */
2520 this->lateness_counter = 0;
2522
2523 /* Find the average travel time of vehicles that we share orders with. */
2524 int num_vehicles = 0;
2525 TimerGameTick::Ticks total_travel_time = 0;
2526
2527 Vehicle *u = this->FirstShared();
2528 for (; u != nullptr; u = u->NextShared()) {
2529 /* Ignore vehicles that are manually stopped or crashed. */
2530 if (u->vehstatus & (VS_STOPPED | VS_CRASHED)) continue;
2531
2532 num_vehicles++;
2533 total_travel_time += u->round_trip_time;
2534 }
2535
2536 /* Make sure we cannot divide by 0. */
2537 num_vehicles = std::max(num_vehicles, 1);
2538
2539 /* Calculate the separation by finding the average travel time, then calculating equal separation (minimum 1 tick) between vehicles. */
2540 TimerGameTick::Ticks separation = std::max((total_travel_time / num_vehicles / num_vehicles), 1);
2541 TimerGameTick::TickCounter next_departure = TimerGameTick::counter + separation;
2542
2543 /* Set the departure time of all vehicles that we share orders with. */
2544 u = this->FirstShared();
2545 for (; u != nullptr; u = u->NextShared()) {
2546 /* Ignore vehicles that are manually stopped or crashed. */
2547 if (u->vehstatus & (VS_STOPPED | VS_CRASHED)) continue;
2548
2549 u->depot_unbunching_next_departure = next_departure;
2551 }
2552}
2553
2559{
2560 assert(this->IsInDepot());
2561
2562 /* Don't bother if there are no vehicles sharing orders. */
2563 if (!this->IsOrderListShared()) return false;
2564
2565 /* Don't do anything if there aren't enough orders. */
2566 if (this->GetNumOrders() <= 1) return false;
2567
2568 /* Don't do anything if this is not our unbunching order. */
2569 if (!PreviousOrderIsUnbunching(this)) return false;
2570
2572};
2573
2581{
2582 CommandCost ret = CheckOwnership(this->owner);
2583 if (ret.Failed()) return ret;
2584
2585 if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
2586 if (this->IsStoppedInDepot()) return CMD_ERROR;
2587
2588 /* No matter why we're headed to the depot, unbunching data is no longer valid. */
2590
2591 if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2592 bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
2593 if (command.Test(DepotCommandFlag::Service) == halt_in_depot) {
2594 /* We called with a different DEPOT_SERVICE setting.
2595 * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2596 * Note: the if is (true for requesting service == true for ordered to stop in depot) */
2597 if (flags.Test(DoCommandFlag::Execute)) {
2601 }
2602 return CommandCost();
2603 }
2604
2605 if (command.Test(DepotCommandFlag::DontCancel)) return CMD_ERROR; // Requested no cancellation of depot orders
2606 if (flags.Test(DoCommandFlag::Execute)) {
2607 /* If the orders to 'goto depot' are in the orders list (forced servicing),
2608 * then skip to the next order; effectively cancelling this forced service */
2610
2611 if (this->IsGroundVehicle()) {
2612 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2614 }
2615
2616 this->current_order.MakeDummy();
2618 }
2619 return CommandCost();
2620 }
2621
2622 ClosestDepot closestDepot = this->FindClosestDepot();
2623 static const StringID no_depot[] = {STR_ERROR_UNABLE_TO_FIND_ROUTE_TO, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR};
2624 if (!closestDepot.found) return CommandCost(no_depot[this->type]);
2625
2626 if (flags.Test(DoCommandFlag::Execute)) {
2627 if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2628
2629 if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2630 uint16_t &gv_flags = this->GetGroundVehicleFlags();
2632 }
2633
2634 this->SetDestTile(closestDepot.location);
2635 this->current_order.MakeGoToDepot(closestDepot.destination.ToDepotID(), ODTF_MANUAL);
2638
2639 /* If there is no depot in front and the train is not already reversing, reverse automatically (trains only) */
2640 if (this->type == VEH_TRAIN && (closestDepot.reverse ^ HasBit(Train::From(this)->flags, VRF_REVERSING))) {
2642 }
2643
2644 if (this->type == VEH_AIRCRAFT) {
2645 Aircraft *a = Aircraft::From(this);
2646 if (a->state == FLYING && a->targetairport != closestDepot.destination) {
2647 /* The aircraft is now heading for a different hangar than the next in the orders */
2649 }
2650 }
2651 }
2652
2653 return CommandCost();
2654
2655}
2656
2661void Vehicle::UpdateVisualEffect(bool allow_power_change)
2662{
2663 bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2664 const Engine *e = this->GetEngine();
2665
2666 /* Evaluate properties */
2667 uint8_t visual_effect;
2668 switch (e->type) {
2669 case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
2670 case VEH_ROAD: visual_effect = e->u.road.visual_effect; break;
2671 case VEH_SHIP: visual_effect = e->u.ship.visual_effect; break;
2672 default: visual_effect = 1 << VE_DISABLE_EFFECT; break;
2673 }
2674
2675 /* Check powered wagon / visual effect callback */
2677 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2678
2679 if (callback != CALLBACK_FAILED) {
2680 if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2681
2682 callback = GB(callback, 0, 8);
2683 /* Avoid accidentally setting 'visual_effect' to the default value
2684 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2685 if (callback == VE_DEFAULT) {
2686 assert(HasBit(callback, VE_DISABLE_EFFECT));
2687 SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2688 }
2689 visual_effect = callback;
2690 }
2691 }
2692
2693 /* Apply default values */
2694 if (visual_effect == VE_DEFAULT ||
2695 (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2696 /* Only train engines have default effects.
2697 * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2698 if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
2699 if (visual_effect == VE_DEFAULT) {
2700 visual_effect = 1 << VE_DISABLE_EFFECT;
2701 } else {
2702 SetBit(visual_effect, VE_DISABLE_EFFECT);
2703 }
2704 } else {
2705 if (visual_effect == VE_DEFAULT) {
2706 /* Also set the offset */
2707 visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
2708 }
2709 SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
2710 }
2711 }
2712
2713 this->vcache.cached_vis_effect = visual_effect;
2714
2715 if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2717 ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GRFBug::VehPoweredWagon, false);
2718 }
2719}
2720
2721static const int8_t _vehicle_smoke_pos[8] = {
2722 1, 1, 1, 0, -1, -1, -1, 0
2723};
2724
2730{
2732 if (callback == CALLBACK_FAILED) return;
2733
2734 uint count = GB(callback, 0, 2);
2735 bool auto_center = HasBit(callback, 13);
2736 bool auto_rotate = !HasBit(callback, 14);
2737
2738 int8_t l_center = 0;
2739 if (auto_center) {
2740 /* For road vehicles: Compute offset from vehicle position to vehicle center */
2741 if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2742 } else {
2743 /* For trains: Compute offset from vehicle position to sprite position */
2744 if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2745 }
2746
2747 Direction l_dir = v->direction;
2748 if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir);
2749 Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
2750
2751 int8_t x_center = _vehicle_smoke_pos[l_dir] * l_center;
2752 int8_t y_center = _vehicle_smoke_pos[t_dir] * l_center;
2753
2754 for (uint i = 0; i < count; i++) {
2755 uint32_t reg = GetRegister(0x100 + i);
2756 uint type = GB(reg, 0, 8);
2757 int8_t x = GB(reg, 8, 8);
2758 int8_t y = GB(reg, 16, 8);
2759 int8_t z = GB(reg, 24, 8);
2760
2761 if (auto_rotate) {
2762 int8_t l = x;
2763 int8_t t = y;
2764 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2765 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2766 }
2767
2768 if (type >= 0xF0) {
2769 switch (type) {
2770 case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2771 case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2772 case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2773 case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2774 default: break;
2775 }
2776 }
2777 }
2778}
2779
2785{
2786 assert(this->IsPrimaryVehicle());
2787 bool sound = false;
2788
2789 /* Do not show any smoke when:
2790 * - vehicle smoke is disabled by the player
2791 * - the vehicle is slowing down or stopped (by the player)
2792 * - the vehicle is moving very slowly
2793 */
2795 this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
2796 this->cur_speed < 2) {
2797 return;
2798 }
2799
2800 /* Use the speed as limited by underground and orders. */
2801 uint max_speed = this->GetCurrentMaxSpeed();
2802
2803 if (this->type == VEH_TRAIN) {
2804 const Train *t = Train::From(this);
2805 /* For trains, do not show any smoke when:
2806 * - the train is reversing
2807 * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2808 */
2809 if (HasBit(t->flags, VRF_REVERSING) ||
2811 t->cur_speed >= max_speed)) {
2812 return;
2813 }
2814 }
2815
2816 const Vehicle *v = this;
2817
2818 do {
2821 VisualEffectSpawnModel effect_model = VESM_NONE;
2822 if (advanced) {
2823 effect_offset = VE_OFFSET_CENTRE;
2825 if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
2826 } else {
2828 assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
2829 static_assert((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
2830 static_assert((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL);
2831 static_assert((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
2832 }
2833
2834 /* Show no smoke when:
2835 * - Smoke has been disabled for this vehicle
2836 * - The vehicle is not visible
2837 * - The vehicle is under a bridge
2838 * - The vehicle is on a depot tile
2839 * - The vehicle is on a tunnel tile
2840 * - The vehicle is a train engine that is currently unpowered */
2841 if (effect_model == VESM_NONE ||
2842 v->vehstatus & VS_HIDDEN ||
2843 IsBridgeAbove(v->tile) ||
2844 IsDepotTile(v->tile) ||
2845 IsTunnelTile(v->tile) ||
2846 (v->type == VEH_TRAIN &&
2847 !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
2848 continue;
2849 }
2850
2851 EffectVehicleType evt = EV_END;
2852 switch (effect_model) {
2853 case VESM_STEAM:
2854 /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2855 * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2856 * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2857 * REGULATION:
2858 * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2859 if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2860 evt = EV_STEAM_SMOKE;
2861 }
2862 break;
2863
2864 case VESM_DIESEL: {
2865 /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2866 * when smoke emission stops.
2867 * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2868 * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2869 * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2870 * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2871 * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2872 * maximum speed no diesel_smoke is emitted.
2873 * REGULATION:
2874 * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2875 * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2876 int power_weight_effect = 0;
2877 if (v->type == VEH_TRAIN) {
2878 power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2879 }
2880 if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2881 Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2882 evt = EV_DIESEL_SMOKE;
2883 }
2884 break;
2885 }
2886
2887 case VESM_ELECTRIC:
2888 /* Electric train's spark - more often occurs when train is departing (more load)
2889 * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2890 * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2891 * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2892 * REGULATION:
2893 * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2894 if (GB(v->tick_counter, 0, 2) == 0 &&
2895 Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2896 evt = EV_ELECTRIC_SPARK;
2897 }
2898 break;
2899
2900 default:
2901 NOT_REACHED();
2902 }
2903
2904 if (evt != EV_END && advanced) {
2905 sound = true;
2907 } else if (evt != EV_END) {
2908 sound = true;
2909
2910 /* The effect offset is relative to a point 4 units behind the vehicle's
2911 * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2912 * correction factor. */
2913 if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2914
2915 int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2916 int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2917
2918 if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
2919 x = -x;
2920 y = -y;
2921 }
2922
2923 CreateEffectVehicleRel(v, x, y, 10, evt);
2924 }
2925 } while ((v = v->Next()) != nullptr);
2926
2927 if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2928}
2929
2935{
2936 assert(this != next);
2937
2938 if (this->next != nullptr) {
2939 /* We had an old next vehicle. Update the first and previous pointers */
2940 for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
2941 v->first = this->next;
2942 }
2943 this->next->previous = nullptr;
2944 }
2945
2946 this->next = next;
2947
2948 if (this->next != nullptr) {
2949 /* A new next vehicle. Update the first and previous pointers */
2950 if (this->next->previous != nullptr) this->next->previous->next = nullptr;
2951 this->next->previous = this;
2952 for (Vehicle *v = this->next; v != nullptr; v = v->Next()) {
2953 v->first = this->first;
2954 }
2955 }
2956}
2957
2964{
2965 assert(this->previous_shared == nullptr && this->next_shared == nullptr);
2966
2967 if (shared_chain->orders == nullptr) {
2968 assert(shared_chain->previous_shared == nullptr);
2969 assert(shared_chain->next_shared == nullptr);
2970 this->orders = shared_chain->orders = new OrderList(nullptr, shared_chain);
2971 }
2972
2973 this->next_shared = shared_chain->next_shared;
2974 this->previous_shared = shared_chain;
2975
2976 shared_chain->next_shared = this;
2977
2978 if (this->next_shared != nullptr) this->next_shared->previous_shared = this;
2979
2980 shared_chain->orders->AddVehicle(this);
2981}
2982
2987{
2988 /* Remember if we were first and the old window number before RemoveVehicle()
2989 * as this changes first if needed. */
2990 bool were_first = (this->FirstShared() == this);
2992
2993 this->orders->RemoveVehicle(this);
2994
2995 if (!were_first) {
2996 /* We are not the first shared one, so only relink our previous one. */
2997 this->previous_shared->next_shared = this->NextShared();
2998 }
2999
3000 if (this->next_shared != nullptr) this->next_shared->previous_shared = this->previous_shared;
3001
3002
3003 if (this->orders->GetNumVehicles() == 1) {
3004 /* When there is only one vehicle, remove the shared order list window. */
3007 } else if (were_first) {
3008 /* If we were the first one, update to the new first one.
3009 * Note: FirstShared() is already the new first */
3010 InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.ToWindowNumber(), this->FirstShared()->index.base() | (1U << 31));
3011 }
3012
3013 this->next_shared = nullptr;
3014 this->previous_shared = nullptr;
3015}
3016
3017static IntervalTimer<TimerGameEconomy> _economy_vehicles_yearly({TimerGameEconomy::YEAR, TimerGameEconomy::Priority::VEHICLE}, [](auto)
3018{
3019 for (Vehicle *v : Vehicle::Iterate()) {
3020 if (v->IsPrimaryVehicle()) {
3021 /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
3022 Money profit = v->GetDisplayProfitThisYear();
3023 if (v->economy_age >= VEHICLE_PROFIT_MIN_AGE && profit < 0) {
3025 SetDParam(0, v->index);
3026 SetDParam(1, profit);
3028 TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_VEHICLE_UNPROFITABLE_PERIOD : STR_NEWS_VEHICLE_UNPROFITABLE_YEAR,
3029 v->index);
3030 }
3031 AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
3032 }
3033
3035 v->profit_this_year = 0;
3037 }
3038 }
3044});
3045
3055bool CanVehicleUseStation(EngineID engine_type, const Station *st)
3056{
3057 const Engine *e = Engine::GetIfValid(engine_type);
3058 assert(e != nullptr);
3059
3060 switch (e->type) {
3061 case VEH_TRAIN:
3063
3064 case VEH_ROAD:
3065 /* For road vehicles we need the vehicle to know whether it can actually
3066 * use the station, but if it doesn't have facilities for RVs it is
3067 * certainly not possible that the station can be used. */
3069
3070 case VEH_SHIP:
3072
3073 case VEH_AIRCRAFT:
3076
3077 default:
3078 return false;
3079 }
3080}
3081
3088bool CanVehicleUseStation(const Vehicle *v, const Station *st)
3089{
3090 if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != nullptr;
3091
3092 return CanVehicleUseStation(v->engine_type, st);
3093}
3094
3102{
3103 switch (v->type) {
3104 case VEH_TRAIN:
3105 return STR_ERROR_NO_RAIL_STATION;
3106
3107 case VEH_ROAD: {
3108 const RoadVehicle *rv = RoadVehicle::From(v);
3109 RoadStop *rs = st->GetPrimaryRoadStop(rv->IsBus() ? RoadStopType::Bus : RoadStopType::Truck);
3110
3111 StringID err = rv->IsBus() ? STR_ERROR_NO_BUS_STATION : STR_ERROR_NO_TRUCK_STATION;
3112
3113 for (; rs != nullptr; rs = rs->next) {
3114 /* Articulated vehicles cannot use bay road stops, only drive-through. Make sure the vehicle can actually use this bay stop */
3116 err = STR_ERROR_NO_STOP_ARTICULATED_VEHICLE;
3117 continue;
3118 }
3119
3120 /* Bay stop errors take precedence, but otherwise the vehicle may not be compatible with the roadtype/tramtype of this station tile.
3121 * We give bay stop errors precedence because they are usually a bus sent to a tram station or vice versa. */
3122 if (!HasTileAnyRoadType(rs->xy, rv->compatible_roadtypes) && err != STR_ERROR_NO_STOP_ARTICULATED_VEHICLE) {
3123 err = RoadTypeIsRoad(rv->roadtype) ? STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE : STR_ERROR_NO_STOP_COMPATIBLE_TRAM_TYPE;
3124 continue;
3125 }
3126 }
3127
3128 return err;
3129 }
3130
3131 case VEH_SHIP:
3132 return STR_ERROR_NO_DOCK;
3133
3134 case VEH_AIRCRAFT:
3135 if (!st->facilities.Test(StationFacility::Airport)) return STR_ERROR_NO_AIRPORT;
3136 if (v->GetEngine()->u.air.subtype & AIR_CTOL) {
3137 return STR_ERROR_AIRPORT_NO_PLANES;
3138 } else {
3139 return STR_ERROR_AIRPORT_NO_HELICOPTERS;
3140 }
3141
3142 default:
3143 return INVALID_STRING_ID;
3144 }
3145}
3146
3153{
3154 assert(this->IsGroundVehicle());
3155 if (this->type == VEH_TRAIN) {
3156 return &Train::From(this)->gcache;
3157 } else {
3158 return &RoadVehicle::From(this)->gcache;
3159 }
3160}
3161
3168{
3169 assert(this->IsGroundVehicle());
3170 if (this->type == VEH_TRAIN) {
3171 return &Train::From(this)->gcache;
3172 } else {
3173 return &RoadVehicle::From(this)->gcache;
3174 }
3175}
3176
3183{
3184 assert(this->IsGroundVehicle());
3185 if (this->type == VEH_TRAIN) {
3186 return Train::From(this)->gv_flags;
3187 } else {
3188 return RoadVehicle::From(this)->gv_flags;
3189 }
3190}
3191
3197const uint16_t &Vehicle::GetGroundVehicleFlags() const
3198{
3199 assert(this->IsGroundVehicle());
3200 if (this->type == VEH_TRAIN) {
3201 return Train::From(this)->gv_flags;
3202 } else {
3203 return RoadVehicle::From(this)->gv_flags;
3204 }
3205}
3206
3215void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8_t num_vehicles)
3216{
3217 if (v->type == VEH_TRAIN) {
3218 Train *u = Train::From(v);
3219 /* Only include whole vehicles, so start with the first articulated part */
3220 u = u->GetFirstEnginePart();
3221
3222 /* Include num_vehicles vehicles, not counting articulated parts */
3223 for (; u != nullptr && num_vehicles > 0; num_vehicles--) {
3224 do {
3225 /* Include current vehicle in the selection. */
3226 include(set, u->index);
3227
3228 /* If the vehicle is multiheaded, add the other part too. */
3229 if (u->IsMultiheaded()) include(set, u->other_multiheaded_part->index);
3230
3231 u = u->Next();
3232 } while (u != nullptr && u->IsArticulatedPart());
3233 }
3234 }
3235}
3236
3242{
3243 uint32_t max_weight = 0;
3244
3245 for (const Vehicle *u = this; u != nullptr; u = u->Next()) {
3246 max_weight += u->GetMaxWeight();
3247 }
3248
3249 return max_weight;
3250}
3251
3257{
3258 uint32_t max_weight = GetDisplayMaxWeight();
3259 if (max_weight == 0) return 0;
3260 return GetGroundVehicleCache()->cached_power * 10u / max_weight;
3261}
3262
3270{
3271 while (true) {
3272 if (v1 == nullptr && v2 == nullptr) return true;
3273 if (v1 == nullptr || v2 == nullptr) return false;
3274 if (v1->GetEngine() != v2->GetEngine()) return false;
3275 v1 = v1->GetNextVehicle();
3276 v2 = v2->GetNextVehicle();
3277 }
3278}
3279
3287{
3288 const Order *o1 = v1->GetFirstOrder();
3289 const Order *o2 = v2->GetFirstOrder();
3290 while (true) {
3291 if (o1 == nullptr && o2 == nullptr) return true;
3292 if (o1 == nullptr || o2 == nullptr) return false;
3293 if (!o1->Equals(*o2)) return false;
3294 o1 = o1->next;
3295 o2 = o2->next;
3296 }
3297}
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:75
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.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
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.
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 HasAtMostOneBit(T value)
Test whether value has at most 1 bit set.
debug_inline 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 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 IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
bool IsCargoInClass(CargoType c, CargoClasses cc)
Does cargo c have cargo class cc?
Definition cargotype.h:236
@ Passengers
Passengers.
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:243
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
constexpr Timpl & Reset(Tvalue_type value)
Reset the value-th bit.
void OnCleanPool()
Empty the cargo list, but don't free the cargo packets; the cargo packets are cleaned by CargoPacket'...
@ MTA_LOAD
Load the cargo from the station.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
StringID GetErrorMessage() const
Returns the error message of a command.
static constexpr int DAYS_IN_ECONOMY_MONTH
Days in an economy month, when in wallclock timekeeping mode.
Enum-as-bit-set wrapper.
UnitID UseID(UnitID index)
Use a unit number.
Definition vehicle.cpp:1860
void ReleaseID(UnitID index)
Release a unit number.
Definition vehicle.cpp:1877
UnitID NextID() const
Find first unused unit number.
Definition vehicle.cpp:1845
bool GRFBugReverse(uint32_t grfid, uint16_t internal_id)
Logs GRF bug - rail vehicle has different length after reversing.
Definition gamelog.cpp:482
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
static void Run(Vehicle *v, bool allow_merge=true, bool is_full_loading=false)
Refresh all links the given vehicle will visit.
Definition refresh.cpp:26
static void Reset(PerformanceElement elem)
Store the previous accumulator value and reset for a new cycle of accumulating measurements.
RAII class for measuring simple elements of performance.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Date date
Current date in days (day counter).
static DateFract date_fract
Fractional part of the day.
static constexpr TimerGame< struct Economy >::Date MAX_DATE
The date of the last day of the max year.
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
static Date date
Current date in days (day counter).
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
static DateFract date_fract
Fractional part of the day.
uint64_t TickCounter
The type that the tick counter is stored in.
static TickCounter counter
Monotonic counter, in ticks, since start of game.
int32_t Ticks
The type to store ticks in.
static constexpr Date DateAtStartOfYear(Year year)
Calculate the date of the first day of a given year.
CargoList that is used for vehicles.
uint ActionCount(MoveToAction action) const
Returns the amount of cargo designated for a given purpose.
uint Truncate(uint max_move=UINT_MAX)
Truncates the cargo in this list to the given amount.
uint Return(uint max_move, StationCargoList *dest, StationID next_station, TileIndex current_tile)
Returns reserved cargo to the station and removes it from the cache.
void KeepAll()
Marks all cargo in the vehicle as to be kept.
void AgeCargo()
Ages the all cargo in this list.
uint StoredCount() const
Returns sum of cargo on board the vehicle (ie not only reserved).
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
void SubtractMoneyFromCompany(const CommandCost &cost)
Subtract money from the _current_company, if the company is valid.
Money GetAvailableMoney(CompanyID company)
Get the amount of money that a company has available, or INT64_MAX if there is no such valid company.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
bool IsLocalCompany()
Is the current company the local company?
Some simple functions to help with accessing containers.
bool include(Container &container, typename Container::const_reference &item)
Helper function to append an item to a container if it is not already contained.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Functions related to depots.
void DeleteDepotHighlightOfVehicle(const Vehicle *v)
Removes the highlight of a vehicle in a depot window.
Map related accessors for depots.
bool IsDepotTile(Tile tile)
Is the given tile a tile with a depot on it?
Definition depot_map.h:42
DirDiff DirDifference(Direction d0, Direction d1)
Calculate the difference between two directions.
Direction ReverseDir(Direction d)
Return the reverse of a direction.
Direction ChangeDir(Direction d, DirDiff delta)
Change a direction by a given difference.
DirDiff
Allow incrementing of Direction variables.
@ DIRDIFF_45LEFT
Angle of 45 degrees left.
@ DIRDIFF_REVERSE
One direction is the opposite of the other one.
@ DIRDIFF_45RIGHT
Angle of 45 degrees right.
@ DIRDIFF_SAME
Both directions faces to the same direction.
@ DIRDIFF_90RIGHT
Angle of 90 degrees right.
Direction
Defines the 8 directions on the map.
@ DIR_SW
Southwest.
@ DIR_NW
Northwest.
@ DIR_N
North.
@ DIR_SE
Southeast.
@ DIR_S
South.
@ DIR_NE
Northeast.
@ DIR_W
West.
@ DIR_E
East.
@ INVALID_DIAGDIR
Flag for an invalid DiagDirection.
void ReleaseDisasterVehicle(VehicleID vehicle)
Notify disasters that we are about to delete a vehicle.
void LoadUnloadStation(Station *st)
Load/unload the vehicles in this station according to the order they entered.
Definition economy.cpp:1949
void PrepareUnload(Vehicle *front_v)
Prepare the vehicle to be unloaded.
Definition economy.cpp:1277
Base classes related to the economy.
@ EXPENSES_NEW_VEHICLES
New vehicles.
EffectVehicle * CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular vehicle.
Base class for all effect vehicles.
Functions related to effect vehicles.
EffectVehicleType
Effect vehicle types.
@ EV_BREAKDOWN_SMOKE
Smoke of broken vehicles except aircraft.
@ EV_STEAM_SMOKE
Smoke of steam engines.
@ EV_DIESEL_SMOKE
Smoke of diesel engines.
@ EV_BREAKDOWN_SMOKE_AIRCRAFT
Smoke of broken aircraft.
@ EV_ELECTRIC_SPARK
Sparcs of electric engines.
@ AIR_CTOL
Conventional Take Off and Landing, i.e. planes.
Definition engine_type.h:99
@ 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)
@ EC_DIESEL
Diesel rail engine.
Definition engine_type.h:39
@ EC_STEAM
Steam rail engine.
Definition engine_type.h:38
@ EC_MAGLEV
Maglev engine.
Definition engine_type.h:42
@ EC_ELECTRIC
Electric rail engine.
Definition engine_type.h:40
@ EC_MONORAIL
Mono rail engine.
Definition engine_type.h:41
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:33
Functions related to errors.
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition error.h:27
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, const CommandCost &cc)
Display an error message in a window.
Types for recording game performance data.
@ PFE_GL_SHIPS
Time spent processing ships.
@ PFE_GL_AIRCRAFT
Time spent processing aircraft.
@ PFE_GL_ECONOMY
Time spent processing cargo movement.
@ PFE_GL_ROADVEHS
Time spend processing road vehicles.
@ PFE_GL_TRAINS
Time spent processing trains.
Gamelog _gamelog
Gamelog instance.
Definition gamelog.cpp:31
Functions to be called to log fundamental changes to the game.
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:988
@ Normal
The most basic (normal) sprite.
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
void MarkTilesDirty(bool cargo_change) const
Marks the tiles of the station as dirty.
Definition station.cpp:246
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
virtual void MarkDirty()
Marks the vehicles to be redrawn and updates cached variables.
void DeleteGroupHighlightOfVehicle(const Vehicle *v)
Removes the highlight of a vehicle in a group window.
Functions/definitions that have something to do with groups.
static constexpr GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition group_type.h:18
const TileTypeProcs *const _tile_type_procs[16]
Tile callback functions for each type of tile.
Definition landscape.cpp:65
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:79
@ Random
Randomise borders.
Declaration of link graph classes used for cargo distribution.
static const uint8_t LIT_ALL
Show the liveries of all companies.
Definition livery.h:18
LiveryScheme
List of different livery schemes.
Definition livery.h:21
static const uint8_t LIT_COMPANY
Show the liveries of your own company.
Definition livery.h:17
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:424
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:414
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:403
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
Miscellaneous command definitions.
void HideFillingPercent(TextEffectID *te_id)
Hide vehicle loading indicators.
Definition misc_gui.cpp:611
void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost)
Display animated income or costs on the map.
Definition misc_gui.cpp:538
bool _networking
are we in networking mode?
Definition network.cpp:65
Basic functions/variables used all over the place.
@ SAT_TRAIN_DEPARTS
Trigger platform when train leaves.
@ VisualEffect
Visual effects and wagon power (trains, road vehicles and ships)
@ ColourRemap
Change colour mapping of vehicle.
@ CBID_VEHICLE_SPAWN_VISUAL_EFFECT
Called to spawn visual effects for vehicles.
@ CBID_VEHICLE_COLOUR_MAPPING
Called to determine if a specific colour map should be used for a vehicle instead of the default live...
@ CBID_VEHICLE_32DAY_CALLBACK
Called for every vehicle every 32 days (not all on same date though).
@ CBID_VEHICLE_VISUAL_EFFECT
Visual effects and wagon power.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
GRFConfig * GetGRFConfig(uint32_t grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
GRFBug
Encountered GRF bugs.
@ VehPoweredWagon
Powered wagon changed poweredness state when not inside a depot.
@ VehLength
Length of rail vehicle changes when not inside a depot.
Functions/types related to NewGRF debugging.
GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
Get the GrfSpecFeature associated with the tile.
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
bool UsesWagonOverride(const Vehicle *v)
Check if a wagon is currently using a wagon override.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
NewGRF definitions and structures for road stops.
@ RSRT_VEH_DEPARTS
Trigger roadstop when road vehicle leaves.
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.
uint32_t GetRegister(uint i)
Gets the value of a so-called newgrf "register".
void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoType cargo_type)
Trigger station randomisation.
Header file for NewGRF stations.
@ SRT_TRAIN_DEPARTS
Trigger platform when train leaves.
Functions related to news.
void AddVehicleAdviceNewsItem(AdviceType advice_type, StringID string, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition news_func.h:40
void DeleteVehicleNews(VehicleID vid, AdviceType advice_type=AdviceType::Invalid)
Delete news with a given advice type about a vehicle.
@ VehicleLost
The vehicle has become lost.
@ VehicleWaiting
The vehicle is waiting in the depot.
@ AutorenewFailed
Autorenew or autoreplace failed.
@ VehicleOld
The vehicle is starting to get old.
@ VehicleUnprofitable
The vehicle is costing you money.
@ RefitFailed
The refit order failed to execute.
@ Error
A game paused because a (critical) error.
@ Normal
A game normally paused.
Functions related to order backups.
void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
Insert a new order but skip the validation.
void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
Delete an order but skip the parameter validation.
void InvalidateVehicleOrder(const Vehicle *v, int data)
Updates the widgets of a vehicle which contains the order-data.
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
@ OUFB_NO_UNLOAD
Totally no unloading will be done.
Definition order_type.h:72
@ ODTFB_PART_OF_ORDERS
This depot order is because of a regular order.
Definition order_type.h:112
@ ODTFB_SERVICE
This depot order is because of the servicing limit.
Definition order_type.h:111
@ ODTF_MANUAL
Manually initiated order.
Definition order_type.h:110
@ ODATFB_UNBUNCH
Service the vehicle and then unbunch it.
Definition order_type.h:122
@ ODATFB_NEAREST_DEPOT
Send the vehicle to the nearest depot.
Definition order_type.h:121
@ ODATFB_HALT
Service the vehicle and then halt it.
Definition order_type.h:120
@ ODATF_SERVICE_ONLY
Only service the vehicle.
Definition order_type.h:119
static const VehicleOrderID MAX_VEH_ORDER_ID
Last valid VehicleOrderID.
Definition order_type.h:42
@ OLFB_FULL_LOAD
Full load all cargoes of the consist.
Definition order_type.h:80
@ OLFB_NO_LOAD
Do not load anything.
Definition order_type.h:82
@ OLF_FULL_LOAD_ANY
Full load a single cargo of the consist.
Definition order_type.h:81
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:48
@ ONSF_NO_STOP_AT_ANY_STATION
The vehicle will not stop at any stations it passes including the destination.
Definition order_type.h:92
@ ONSF_STOP_EVERYWHERE
The vehicle will stop at any station it passes and the destination.
Definition order_type.h:89
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:196
RailType GetTileRailType(Tile tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
Definition rail.cpp:155
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:328
void SetDepotReservation(Tile t, bool b)
Set the reservation state of the depot.
Definition rail_map.h:270
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.
Definition of link refreshing utility.
bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt)
Test if any buildable RoadType is available for a company.
Definition road.cpp:143
bool HasTileAnyRoadType(Tile t, RoadTypes rts)
Check if a tile has one of the specified road types.
Definition road_map.h:222
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:58
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:57
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:650
Functions related to sound.
@ SND_3A_BREAKDOWN_TRAIN_SHIP_TOYLAND
58 == 0x3A Breakdown: train or ship (toyland)
Definition sound_type.h:105
@ SND_10_BREAKDOWN_TRAIN_SHIP
14 == 0x0E Breakdown: train or ship (non-toyland)
Definition sound_type.h:61
@ SND_0F_BREAKDOWN_ROADVEHICLE
13 == 0x0D Breakdown: road vehicle (non-toyland)
Definition sound_type.h:60
@ SND_35_BREAKDOWN_ROADVEHICLE_TOYLAND
53 == 0x35 Breakdown: road vehicle (toyland)
Definition sound_type.h:100
Functions to cache sprites in memory.
static const PaletteID PALETTE_RECOLOUR_START
First recolour sprite for company colours.
Definition sprites.h:1574
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1605
Base classes/functions for stations.
void IncreaseStats(Station *st, CargoType cargo, StationID next_station_id, uint capacity, uint usage, uint32_t time, EdgeUpdateMode mode)
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.
Definition of base types and functions in a cross-platform compatible way.
static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
Definition string.cpp:126
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:163
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:103
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition strings.cpp:420
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
uint8_t subtype
Type of aircraft.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:72
uint8_t pos
Next desired position of the aircraft.
Definition aircraft.h:74
uint8_t state
State of the airport.
Definition aircraft.h:77
bool IsNormalAircraft() const
Check if the aircraft type is a normal flying device; eg not a rotor or a shadow.
Definition aircraft.h:121
uint8_t previous_pos
Previous desired position of the aircraft.
Definition aircraft.h:75
StationID targetairport
Airport to go to next.
Definition aircraft.h:76
@ Airplanes
Can planes land on this airport type?
@ Helicopters
Can helicopters land on this airport type?
std::vector< AirportFTA > layout
state machine for airport
Definition airport.h:188
Flags flags
Flags for this airport type.
Definition airport.h:191
AirportBlocks blocks
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
const AirportFTAClass * GetFTA() const
Get the finite-state machine for this airport or the finite-state machine for the dummy airport in ca...
Class to backup a specific variable and restore it later.
void Restore()
Restore the variable.
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
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.
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.
uint16_t vehicle_flags
Used for gradual loading and other miscellaneous things (.
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
StationFacilities facilities
The facilities that this station has.
VehicleType type
Type of vehicle.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
GUISettings gui
settings related to the GUI
Structure to return information about the closest depot location, and whether it could be found.
DestinationID destination
The DestinationID as used for orders.
CompanySettings settings
settings specific for each company
uint32_t engine_renew_money
minimum amount of money before autorenew is used
int16_t engine_renew_months
months before/after the maximum vehicle age a vehicle should be renewed
bool engine_renew
is autorenew enabled
GroupStatistics group_all[VEH_COMPANY_END]
NOSAVE: Statistics for the ALL_GROUP group.
uint8_t vehicle_breakdowns
likelihood of vehicles breaking down
Data about how and where to blit pixels.
Definition gfx_type.h:156
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.
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:157
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.
CompanyMask company_avail
Bit for each company whether the engine is available for that company.
Definition engine_base.h:39
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:61
VariableGRFFileProps grf_prop
Properties related the the grf file.
Definition engine_base.h:83
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:48
Information about GRF, used in the game and (part of it) in savegames.
GRFBugs grf_bugs
NOSAVE: bugs in this GRF in this run,.
const char * GetName() const
Get the name of this grf.
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced this entity.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:112
bool lost_vehicle_warn
if a vehicle can't find its destination, show a warning
bool vehicle_income_warn
if a vehicle isn't generating income, show a warning
bool show_track_reservation
highlight reserved tracks.
uint8_t liveries
options for displaying company liveries, 0=none, 1=self, 2=all
bool old_vehicle_warn
if a vehicle is getting old, show a warning
LandscapeType landscape
the landscape we're currently in
DifficultySettings difficulty
settings related to the difficulty
GameCreationSettings game_creation
settings used during the creation of a game (map)
VehicleSettings vehicle
options for vehicles
OrderSettings order
settings related to orders
Position information of a vehicle after it moved.
TileIndex new_tile
Tile of the vehicle after moving.
int y
x and y position of the vehicle after moving
TileIndex old_tile
Current tile of the vehicle.
StationCargoList cargo
The cargo packets of cargo waiting in this station.
bool HasRating() const
Does this cargo have a rating at this station?
GoodsEntryData & GetOrCreateData()
Get optional cargo packet/flow data.
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).
bool IsMultiheaded() const
Check if the vehicle is a multiheaded engine.
static void CountVehicle(const Vehicle *v, int delta)
Update num_vehicle when adding or removing a vehicle.
static void VehicleReachedMinAge(const Vehicle *v)
Add a vehicle to the profit sum of its group.
static void CountEngine(const Vehicle *v, int delta)
Update num_engines when adding/removing an engine.
uint16_t num_vehicle
Number of vehicles.
Definition group.h:28
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:72
Livery livery
Custom colour scheme for vehicles in this group.
Definition group.h:78
GroupID parent
Parent group.
Definition group.h:83
Information about a particular livery.
Definition livery.h:78
Colours colour2
Second colour, for vehicles with 2CC support.
Definition livery.h:81
Colours colour1
First colour, for all vehicles.
Definition livery.h:80
uint8_t in_use
Bit 0 set if this livery should override the default livery first colour, Bit 1 for the second colour...
Definition livery.h:79
bool revalidate_before_draw
We need to do a GetImage() and check bounds before drawing this sprite.
VehicleSpriteSeq sprite_seq
Vehicle appearance.
bool is_viewport_candidate
This vehicle can potentially be drawn on a viewport.
Rect old_coord
Co-ordinates from the last valid bounding box.
static void ClearVehicle(const Vehicle *v)
Clear/update the (clone) vehicle from an order backup.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition order_base.h:258
uint GetNumVehicles() const
Return the number of vehicles that share this orders list.
Definition order_base.h:349
void RemoveVehicle(Vehicle *v)
Removes the vehicle from the shared order list.
void AddVehicle(Vehicle *v)
Adds the given vehicle to this shared order list.
Definition order_base.h:357
VehicleOrderID GetNumOrders() const
Get number of orders in the order list.
Definition order_base.h:318
bool no_servicing_if_no_breakdowns
don't send vehicles to depot when breakdowns are disabled
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition order_base.h:144
bool Equals(const Order &other) const
Does this order have the same type, flags and destination?
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:70
void SetNonStopType(OrderNonStopFlags non_stop_type)
Set whether we must stop at stations or not.
Definition order_base.h:161
CargoType GetRefitCargo() const
Get the cargo to to refit to.
Definition order_base.h:131
OrderType GetType() const
Get the type of order of this order.
Definition order_base.h:76
void SetDepotOrderType(OrderDepotTypeFlags depot_order_type)
Set the cause to go to the depot.
Definition order_base.h:165
OrderLoadFlags GetLoadType() const
How must the consist be loaded?
Definition order_base.h:136
void MakeDummy()
Makes this order a Dummy order.
Order * next
Pointer to next order. If nullptr, end of list.
Definition order_base.h:59
void SetDepotActionType(OrderDepotActionFlags depot_service_type)
Set what we are going to do in the depot.
Definition order_base.h:167
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition order_base.h:146
void MakeLeaveStation()
Makes this order a Leave Station order.
bool CanLeaveWithCargo(bool has_cargo) const
A vehicle can leave the current station with cargo if:
uint16_t GetTimetabledWait() const
Get the time in ticks a vehicle should wait at the destination or 0 if it's not timetabled.
Definition order_base.h:188
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.
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition order_base.h:140
bool IsRefit() const
Is this order a refit order.
Definition order_base.h:117
void MakeLoading(bool ordered)
Makes this order a Loading order.
void MakeGoToDepot(DestinationID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoType cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition order_cmd.cpp:90
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
Coordinates of a point in 2D.
static size_t GetPoolSize()
Returns first unused index.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Tindex index
Index of this pool item.
static bool CleaningPool()
Returns current state of pool cleaning - yes or no.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
static Titem * Get(auto index)
Returns Titem with given index.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Base class for all pools.
uint8_t visual_effect
Bitstuffed NewGRF visual effect data.
Definition engine_type.h:62
EngineClass engclass
Class of engine for this vehicle.
Definition engine_type.h:58
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:214
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:264
uint8_t visual_effect
Bitstuffed NewGRF visual effect data.
Buses, trucks and trams belong to this class.
Definition roadveh.h:98
uint8_t state
Definition roadveh.h:100
RoadTypes compatible_roadtypes
NOSAVE: Roadtypes this consist is powered on.
Definition roadveh.h:110
bool IsBus() const
Check whether a roadvehicle is a bus.
RoadType roadtype
NOSAVE: Roadtype of this vehicle.
Definition roadveh.h:108
VehicleID disaster_vehicle
NOSAVE: Disaster vehicle targetting this vehicle.
Definition roadveh.h:109
uint8_t visual_effect
Bitstuffed NewGRF visual effect data.
Definition engine_type.h:80
All ships have this type.
Definition ship.h:32
TrackBits state
The "track" the ship is following.
Definition ship.h:34
void UpdateCache()
Update the caches of this ship.
Definition ship_cmd.cpp:232
static bool IsValidID(auto index)
Tests whether given index is a valid index for station of this type.
static Station * Get(auto index)
Gets station with given index.
static Station * GetIfValid(auto index)
Returns station if the index is a valid index for this station type.
T * Next() const
Get next vehicle in the chain.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
void UpdateViewport(bool force_update, bool update_delta)
Update vehicle sprite- and position caches.
T * GetFirstEnginePart()
Get the first part of an articulated engine.
Data structure describing a sprite.
Definition spritecache.h:17
uint16_t width
Width of the sprite.
Definition spritecache.h:19
uint16_t height
Height of the sprite.
Definition spritecache.h:18
int16_t y_offs
Number of pixels to shift the sprite downwards.
Definition spritecache.h:21
int16_t x_offs
Number of pixels to shift the sprite to the right.
Definition spritecache.h:20
Station data structure.
GoodsEntry goods[NUM_CARGO]
Goods at this station.
Airport airport
Tile area the airport covers.
VehicleEnterTileProc * vehicle_enter_tile_proc
Called when a vehicle enters a tile.
Definition tile_cmd.h:171
'Train' is either a loco or a wagon.
Definition train.h:89
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:92
uint8_t cached_vis_effect
Visual effect to show (see VisualEffect)
uint16_t cached_cargo_age_period
Number of ticks before carried cargo is aged.
The information about a vehicle list.
Definition vehiclelist.h:32
WindowNumber ToWindowNumber() const
Pack a VehicleListIdentifier in 32 bits so it can be used as unique WindowNumber.
UnitID max_ships
max ships in game per company
UnitID max_trains
max trains in game per company
uint8_t smoke_amount
amount of smoke/sparks locomotives produce
UnitID max_aircraft
max planes in game per company
UnitID max_roadveh
max trucks in game per company
Sprite sequence for a vehicle part.
bool IsValid() const
Check whether the sequence contains any sprites.
void GetBounds(Rect *bounds) const
Determine shared bounds of all sprites.
Definition vehicle.cpp:103
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition vehicle.cpp:131
Vehicle data structure.
Money GetDisplayProfitThisYear() const
Gets the profit vehicle had this year.
CargoPayment * cargo_payment
The cargo payment we're currently in.
EngineID engine_type
The type of engine used for this vehicle.
uint16_t cargo_age_counter
Ticks till cargo is aged next.
int32_t z_pos
z coordinate.
uint16_t & GetGroundVehicleFlags()
Access the ground vehicle flags of the vehicle.
Definition vehicle.cpp:3182
Direction direction
facing
void ShiftDates(TimerGameEconomy::Date interval)
Shift all dates by given interval.
Definition vehicle.cpp:774
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:744
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:280
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:2347
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition vehicle.cpp:2963
VehicleCargoList cargo
The cargo this vehicle is carrying.
uint8_t x_extent
x-extent of vehicle bounding box
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:2486
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.
uint8_t subtype
subtype (Filled with values from AircraftSubType/DisasterSubType/EffectVehicleType/GroundVehicleSubty...
CommandCost SendToDepot(DoCommandFlags flags, DepotCommandFlags command)
Send this vehicle to the depot using the given command(s).
Definition vehicle.cpp:2580
void ReleaseUnitNumber()
Release the vehicle's unit number.
Definition vehicle.cpp:2416
void UpdateBoundingBoxCoordinates(bool update_cache) const
Update the bounding box co-ordinates of the vehicle.
Definition vehicle.cpp:1699
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:2427
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.
uint8_t z_extent
z-extent of vehicle bounding box
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:2331
Money profit_last_year
Profit last year << 8, low 8 bits are fract.
Order * GetFirstOrder() const
Get the first order of the vehicles order list.
bool IsEngineCountable() const
Check if a vehicle is counted in num_engines in each company struct.
Definition vehicle.cpp:711
virtual ~Vehicle()
We want to 'destruct' the right class.
Definition vehicle.cpp:890
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:145
void UpdateVisualEffect(bool allow_power_change=true)
Update the cached visual effect.
Definition vehicle.cpp:2661
void LeaveUnbunchingDepot()
Leave an unbunching depot and calculate the next departure time for shared order vehicles.
Definition vehicle.cpp:2511
int8_t y_offs
y offset for vehicle sprite
CargoType cargo_type
type of cargo this vehicle is carrying
debug_inline bool IsFrontEngine() const
Check if the vehicle is a front engine.
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).
int8_t x_bb_offs
x offset of vehicle bounding box
Order current_order
The current order (+ status, like: loading)
void PreDestructor()
Destroy all stuff that (still) needs the virtual functions to work properly.
Definition vehicle.cpp:823
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:788
Vehicle * Next() const
Get the next vehicle of this vehicle.
int8_t x_offs
x offset for vehicle sprite
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:754
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:3256
uint8_t y_extent
y-extent of vehicle bounding box
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:1732
Money value
Value of the vehicle.
bool MarkAllViewportsDirty() const
Marks viewports dirty where the vehicle's image is.
Definition vehicle.cpp:1771
uint16_t refit_cap
Capacity left over from before last refit.
uint8_t vehstatus
Status.
VehicleCache vcache
Cache of often used vehicle values.
uint32_t motion_counter
counter to occasionally play a vehicle sound.
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition vehicle.cpp:764
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition vehicle.cpp:3152
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.
int8_t y_bb_offs
y offset of vehicle bounding box
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:2462
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:2200
Order * GetLastOrder() const
Returns the last order of a vehicle, or nullptr if it doesn't exists.
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.
bool HasEngineType() const
Check whether Vehicle::engine_type has any meaning.
Definition vehicle.cpp:728
TimerGameCalendar::Date age
Age in calendar days.
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition vehicle.cpp:2558
TextEffectID fill_percent_te_id
a text-effect id to a loading indicator object
IterateWrapper Orders() const
Returns an iterable ensemble of orders of a vehicle.
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition vehicle.cpp:2934
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:3241
Vehicle * FirstShared() const
Get the first vehicle of this vehicle chain.
void RemoveFromShared()
Removes the vehicle from the shared order list.
Definition vehicle.cpp:2986
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds,...
Definition vehicle.cpp:1360
debug_inline bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
void UpdatePositionAndViewport()
Update the position of the vehicle, and update the viewport.
Definition vehicle.cpp:1761
Vehicle(VehicleType type=VEH_INVALID)
Vehicle constructor.
Definition vehicle.cpp:358
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:190
bool HasConditionalOrder() const
Check if the current vehicle has a conditional order.
Definition vehicle.cpp:2474
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1690
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:2408
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:2784
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:272
void DeleteUnreachedImplicitOrders()
Delete all implicit orders which were not reached.
Definition vehicle.cpp:2161
Vehicle ** hash_viewport_prev
NOSAVE: Previous vehicle in the visual location hash.
virtual void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
Gets the sprite to show for the given direction.
Vehicle * hash_viewport_next
NOSAVE: Next vehicle in the visual location hash.
Data structure for viewport, display of a part of the world.
int top
Screen coordinate top edge of the viewport.
int width
Screen width of the viewport.
ZoomLevel zoom
The zoom level of the viewport.
int virtual_top
Virtual top coordinate.
int virtual_left
Virtual left coordinate.
int left
Screen coordinate left edge of the viewport.
int height
Screen height of the viewport.
VehicleEnterTileStatus
The returned bits of VehicleEnterTile.
Definition tile_cmd.h:21
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition tile_map.h:312
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
static const int MAX_VEHICLE_PIXEL_Y
Maximum height of a vehicle in pixels in ZOOM_BASE.
Definition tile_type.h:22
static const uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
static const int MAX_VEHICLE_PIXEL_X
Maximum width of a vehicle in pixels in ZOOM_BASE.
Definition tile_type.h:21
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.
Functions related to time tabling.
void UpdateVehicleTimetable(Vehicle *v, bool travelling)
Update the timetable for the vehicle.
bool TracksOverlap(TrackBits bits)
Checks if the given tracks overlap, ie form a crossing.
Definition track_func.h:645
TrackBits
Allow incrementing of Track variables.
Definition track_type.h:35
@ TRACK_BIT_DEPOT
Bitflag for a depot.
Definition track_type.h:53
Base for the train class.
@ VRF_LEAVING_STATION
Train is just leaving a station.
Definition train.h:33
@ VRF_TOGGLE_REVERSE
Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle ...
Definition train.h:31
@ VRF_REVERSE_DIRECTION
Reverse the visible direction of the vehicle.
Definition train.h:28
@ CCF_ARRANGE
Valid changes for arranging the consist in a depot.
Definition train.h:52
@ TFP_NONE
Normal operation.
Definition train.h:38
Command definitions related to trains.
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
TransparencyOption
Transparency option bits: which position in _transparency_opt stands for which transparency.
@ TO_INVALID
Invalid transparency option.
uint16_t UnitID
Type for the company global vehicle unit number.
Map accessors for tunnels.
bool IsTunnelTile(Tile t)
Is this a tunnel (entrance)?
Definition tunnel_map.h:34
PaletteID GetVehiclePalette(const Vehicle *v)
Get the colour map for a vehicle.
Definition vehicle.cpp:2149
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:317
bool CanBuildVehicleInfrastructure(VehicleType type, uint8_t subtype)
Check whether we can build infrastructure for the given vehicle type.
Definition vehicle.cpp:1919
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:543
bool VehiclesHaveSameEngineList(const Vehicle *v1, const Vehicle *v2)
Checks if two vehicle chains have the same list of engines.
Definition vehicle.cpp:3269
bool VehiclesHaveSameOrderList(const Vehicle *v1, const Vehicle *v2)
Checks if two vehicles have the same list of orders.
Definition vehicle.cpp:3286
static void SpawnAdvancedVisualEffect(const Vehicle *v)
Call CBID_VEHICLE_SPAWN_VISUAL_EFFECT and spawn requested effects.
Definition vehicle.cpp:2729
static Vehicle * GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
Procedure called for every vehicle found in tunnel/bridge in the hash map.
Definition vehicle.cpp:557
void VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition vehicle.cpp:1549
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:3215
bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
Checks whether a vehicle in on a specific location.
Definition vehicle.cpp:458
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition vehicle.cpp:1892
void RunVehicleCalendarDayProc()
Age all vehicles, spreading out the action using the current TimerGameCalendar::date_fract.
Definition vehicle.cpp:934
static Vehicle * VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
Helper function for FindVehicleOnPos/HasVehicleOnPos.
Definition vehicle.cpp:473
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:343
const 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:2061
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:167
CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
Tests if a vehicle interacts with the specified track bits.
Definition vehicle.cpp:605
void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition vehicle.cpp:442
static void RunEconomyVehicleDayProc()
Increases the day counter for all vehicles and calls 1-day and 32-day handlers.
Definition vehicle.cpp:951
LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
Determines the LiveryScheme for a vehicle.
Definition vehicle.cpp:1967
VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
Call the tile callback function for a vehicle entering a tile.
Definition vehicle.cpp:1835
void ViewportAddVehicles(DrawPixelInfo *dpi)
Add the vehicle sprites that should be drawn at a part of the screen.
Definition vehicle.cpp:1151
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition vehicle.cpp:1781
bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Checks whether a vehicle is on a specific location.
Definition vehicle.cpp:517
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition vehicle.cpp:502
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:3101
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:1426
static Vehicle * EnsureNoVehicleProcZ(Vehicle *v, void *data)
Callback that returns 'real' vehicles lower or at height *(int*)data .
Definition vehicle.cpp:528
uint8_t CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
Calculates how full a vehicle is.
Definition vehicle.cpp:1490
Vehicle * CheckClickOnVehicle(const Viewport *vp, int x, int y)
Find the vehicle close to the clicked coordinates.
Definition vehicle.cpp:1245
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
Finds vehicle in tunnel / bridge.
Definition vehicle.cpp:572
PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
Get the colour map for an engine.
Definition vehicle.cpp:2139
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3055
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition vehicle.cpp:1438
static Vehicle * VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
Helper function for FindVehicleOnPos/HasVehicleOnPos.
Definition vehicle.cpp:415
void VehicleEnteredDepotThisTick(Vehicle *v)
Adds a vehicle to the list of vehicles that visited a depot this tick.
Definition vehicle.cpp:918
std::map< VehicleID, bool > AutoreplaceMap
List of vehicles that should check for autoreplace this tick.
Definition vehicle.cpp:691
static bool PreviousOrderIsUnbunching(const Vehicle *v)
Check if the previous order is a depot unbunching order.
Definition vehicle.cpp:2498
static void DoDrawVehicle(const Vehicle *v)
Add vehicle sprite for drawing to the screen.
Definition vehicle.cpp:1121
@ VE_TYPE_DEFAULT
Use default from engine class.
@ VE_TYPE_COUNT
Number of bits used for the effect type.
@ VE_OFFSET_CENTRE
Value of offset corresponding to a position above the centre of the vehicle.
@ VE_TYPE_ELECTRIC
Electric sparks.
@ VE_TYPE_START
First bit used for the type of effect.
@ VE_OFFSET_COUNT
Number of bits used for the offset.
@ VE_ADVANCED_EFFECT
Flag for advanced effects.
@ VE_DISABLE_EFFECT
Flag to disable visual effect.
@ VE_TYPE_STEAM
Steam plumes.
@ VE_TYPE_DIESEL
Diesel fumes.
@ VE_DEFAULT
Default value to indicate that visual effect should be based on engine class.
@ VE_OFFSET_START
First bit that contains the offset (0 = front, 8 = centre, 15 = rear)
@ VE_DISABLE_WAGON_POWER
Flag to disable wagon power.
VisualEffectSpawnModel
Models for spawning visual effects.
@ VESM_ELECTRIC
Electric model.
@ VESM_STEAM
Steam model.
@ VESM_DIESEL
Diesel model.
@ VESM_NONE
No visual effect.
@ VS_UNCLICKABLE
Vehicle is not clickable by the user (shadow vehicles).
@ VS_TRAIN_SLOWING
Train is slowing down.
@ VS_AIRCRAFT_BROKEN
Aircraft is broken down.
@ VS_SHADOW
Vehicle is a shadow vehicle.
@ VS_STOPPED
Vehicle is stopped by the player.
@ VS_HIDDEN
Vehicle is not visible.
@ VS_CRASHED
Vehicle is crashed.
@ VS_DEFPAL
Use default vehicle palette.
@ VF_STOP_LOADING
Don't load anymore during the next load cycle.
@ VF_CARGO_UNLOADING
Vehicle is unloading cargo.
@ VF_PATHFINDER_LOST
Vehicle's pathfinder is lost.
@ VF_LOADING_FINISHED
Vehicle has finished loading.
static const int32_t INVALID_COORD
Sentinel for an invalid coordinate.
Command definitions for vehicles.
Functions related to vehicles.
static const TimerGameEconomy::Date VEHICLE_PROFIT_MIN_AGE
Only vehicles older than this have a meaningful profit.
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
@ VIWD_MODIFY_ORDERS
Other order modifications.
Definition vehicle_gui.h:36
WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition vehicle_gui.h:97
@ EIT_ON_MAP
Vehicle drawn in viewport.
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_DISASTER
Disaster vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_EFFECT
Effect vehicle type (smoke, explosions, sparks, bubbles)
@ VEH_TRAIN
Train vehicle type.
@ DontCancel
Don't cancel current goto depot command if any.
@ Service
The vehicle will leave the depot right after arrival (service only)
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
Functions and type for generating vehicle lists.
@ VL_SHARED_ORDERS
Index is the first vehicle of the shared orders.
Definition vehiclelist.h:24
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition viewport.cpp:767
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:671
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:777
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:1137
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3125
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:3217
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:3112
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3099
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:3234
@ WC_ROADVEH_LIST
Road vehicle list; Window numbers:
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
@ WC_SHIPS_LIST
Ships list; Window numbers:
@ WC_STATION_VIEW
Station view; Window numbers:
@ WC_TRAINS_LIST
Trains list; Window numbers:
@ WC_VEHICLE_REFIT
Vehicle refit; Window numbers:
@ WC_VEHICLE_DETAILS
Vehicle details; Window numbers:
@ WC_COMPANY
Company view; Window numbers:
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
@ WC_VEHICLE_TIMETABLE
Vehicle timetable; Window numbers:
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers:
Functions related to zooming.
int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZOOM_LVL_MIN) When shifting right,...
Definition zoom_func.h:22