OpenTTD Source 20260721-master-g25ec12c62d
newgrf_engine.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "debug.h"
12#include "train.h"
13#include "roadveh.h"
14#include "company_func.h"
15#include "newgrf.h"
16#include "newgrf_badge.h"
17#include "newgrf_cargo.h"
18#include "newgrf_spritegroup.h"
20#include "vehicle_func.h"
21#include "core/random_func.hpp"
23#include "aircraft.h"
24#include "station_base.h"
25#include "company_base.h"
26#include "newgrf_railtype.h"
27#include "newgrf_roadtype.h"
28#include "ship.h"
29
30#include "safeguards.h"
31
32void SetWagonOverrideSprites(EngineID engine, CargoType cargo, const SpriteGroup *group, std::span<EngineID> engine_ids)
33{
34 Engine *e = Engine::Get(engine);
35
36 assert(cargo < NUM_CARGO + 2); // Include SpriteGroupCargo::SG_DEFAULT and SpriteGroupCargo::SG_PURCHASE pseudo cargoes.
37
38 WagonOverride *wo = &e->overrides.emplace_back();
39 wo->group = group;
40 wo->cargo = cargo;
41 wo->engines.assign(engine_ids.begin(), engine_ids.end());
42}
43
44const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoType cargo, EngineID overriding_engine)
45{
46 const Engine *e = Engine::Get(engine);
47
48 for (const WagonOverride &wo : e->overrides) {
49 if (wo.cargo != cargo && wo.cargo != CargoGRFFileProps::SG_DEFAULT) continue;
50 if (std::ranges::find(wo.engines, overriding_engine) != wo.engines.end()) return wo.group;
51 }
52 return nullptr;
53}
54
55void SetCustomEngineSprites(EngineID engine, CargoType cargo, const SpriteGroup *group)
56{
57 Engine *e = Engine::Get(engine);
58
59 if (e->grf_prop.GetSpriteGroup(cargo) != nullptr) {
60 GrfMsg(6, "SetCustomEngineSprites: engine {} cargo {} already has group -- replacing", engine, cargo);
61 }
62 e->grf_prop.SetSpriteGroup(cargo, group);
63}
64
65
72void SetEngineGRF(EngineID engine, const GRFFile *file)
73{
74 Engine *e = Engine::Get(engine);
75 e->grf_prop.SetGRFFile(file);
76}
77
78
79static int MapOldSubType(const Vehicle *v)
80{
81 switch (v->type) {
83 if (Train::From(v)->IsEngine()) return 0;
84 if (Train::From(v)->IsFreeWagon()) return 4;
85 return 2;
87 case VehicleType::Ship: return 0;
89 case VehicleType::Disaster: return v->subtype;
90 case VehicleType::Effect: return v->subtype << 1;
91 default: NOT_REACHED();
92 }
93}
94
95
98 AMS_TTDP_HANGAR,
99 AMS_TTDP_TO_HANGAR,
100 AMS_TTDP_TO_PAD1,
101 AMS_TTDP_TO_PAD2,
102 AMS_TTDP_TO_PAD3,
103 AMS_TTDP_TO_ENTRY_2_AND_3,
104 AMS_TTDP_TO_ENTRY_2_AND_3_AND_H,
105 AMS_TTDP_TO_JUNCTION,
106 AMS_TTDP_LEAVE_RUNWAY,
107 AMS_TTDP_TO_INWAY,
108 AMS_TTDP_TO_RUNWAY,
109 AMS_TTDP_TO_OUTWAY,
110 AMS_TTDP_WAITING,
111 AMS_TTDP_TAKEOFF,
112 AMS_TTDP_TO_TAKEOFF,
113 AMS_TTDP_CLIMBING,
114 AMS_TTDP_FLIGHT_APPROACH,
115 AMS_TTDP_UNUSED_0x11,
116 AMS_TTDP_FLIGHT_TO_TOWER,
117 AMS_TTDP_UNUSED_0x13,
118 AMS_TTDP_FLIGHT_FINAL,
119 AMS_TTDP_FLIGHT_DESCENT,
120 AMS_TTDP_BRAKING,
121 AMS_TTDP_HELI_TAKEOFF_AIRPORT,
122 AMS_TTDP_HELI_TO_TAKEOFF_AIRPORT,
123 AMS_TTDP_HELI_LAND_AIRPORT,
124 AMS_TTDP_HELI_TAKEOFF_HELIPORT,
125 AMS_TTDP_HELI_TO_TAKEOFF_HELIPORT,
126 AMS_TTDP_HELI_LAND_HELIPORT,
127};
128
129
136static uint8_t MapAircraftMovementState(const Aircraft *v)
137{
138 const Station *st = GetTargetAirportIfValid(v);
139 if (st == nullptr) return AMS_TTDP_FLIGHT_TO_TOWER;
140
141 const AirportFTAClass *afc = st->airport.GetFTA();
142 AirportMovingDataFlags amdflag = afc->MovingData(v->pos)->flags;
143
144 switch (v->state) {
145 case HANGAR:
146 /* The international airport is a special case as helicopters can land in
147 * front of the hangar. Helicopters also change their air.state to
148 * AirportMovingDataFlag::HeliLower some time before actually descending. */
149
150 /* This condition only occurs for helicopters, during descent,
151 * to a landing by the hangar of an international airport. */
152 if (amdflag.Test(AirportMovingDataFlag::HeliLower)) return AMS_TTDP_HELI_LAND_AIRPORT;
153
154 /* This condition only occurs for helicopters, before starting descent,
155 * to a landing by the hangar of an international airport. */
156 if (amdflag.Test(AirportMovingDataFlag::SlowTurn)) return AMS_TTDP_FLIGHT_TO_TOWER;
157
158 /* The final two conditions apply to helicopters or aircraft.
159 * Has reached hangar? */
160 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_HANGAR;
161
162 /* Still moving towards hangar. */
163 return AMS_TTDP_TO_HANGAR;
164
165 case TERM1:
166 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_TO_PAD1;
167 return AMS_TTDP_TO_JUNCTION;
168
169 case TERM2:
170 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_TO_PAD2;
171 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
172
173 case TERM3:
174 case TERM4:
175 case TERM5:
176 case TERM6:
177 case TERM7:
178 case TERM8:
179 /* TTDPatch only has 3 terminals, so treat these states the same */
180 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_TO_PAD3;
181 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
182
183 case HELIPAD1:
184 case HELIPAD2:
185 case HELIPAD3:
186 /* Will only occur for helicopters.*/
187 if (amdflag.Test(AirportMovingDataFlag::HeliLower)) return AMS_TTDP_HELI_LAND_AIRPORT; // Descending.
188 if (amdflag.Test(AirportMovingDataFlag::SlowTurn)) return AMS_TTDP_FLIGHT_TO_TOWER; // Still hasn't started descent.
189 return AMS_TTDP_TO_JUNCTION; // On the ground.
190
191 case TAKEOFF: // Moving to takeoff position.
192 return AMS_TTDP_TO_OUTWAY;
193
194 case STARTTAKEOFF: // Accelerating down runway.
195 return AMS_TTDP_TAKEOFF;
196
197 case ENDTAKEOFF: // Ascent
198 return AMS_TTDP_CLIMBING;
199
200 case HELITAKEOFF: // Helicopter is moving to take off position.
201 if (afc->delta_z == 0) {
202 return amdflag.Test(AirportMovingDataFlag::HeliRaise) ?
203 AMS_TTDP_HELI_TAKEOFF_AIRPORT : AMS_TTDP_TO_JUNCTION;
204 } else {
205 return AMS_TTDP_HELI_TAKEOFF_HELIPORT;
206 }
207
208 case FLYING:
209 return amdflag.Test(AirportMovingDataFlag::Hold) ? AMS_TTDP_FLIGHT_APPROACH : AMS_TTDP_FLIGHT_TO_TOWER;
210
211 case LANDING: // Descent
212 return AMS_TTDP_FLIGHT_DESCENT;
213
214 case ENDLANDING: // On the runway braking
215 if (amdflag.Test(AirportMovingDataFlag::Brake)) return AMS_TTDP_BRAKING;
216 /* Landed - moving off runway */
217 return AMS_TTDP_TO_INWAY;
218
219 case HELILANDING:
220 case HELIENDLANDING: // Helicoptor is descending.
222 return afc->delta_z == 0 ?
223 AMS_TTDP_HELI_LAND_AIRPORT : AMS_TTDP_HELI_LAND_HELIPORT;
224 } else {
225 return AMS_TTDP_FLIGHT_TO_TOWER;
226 }
227
228 default:
229 return AMS_TTDP_HANGAR;
230 }
231}
232
233
236 AMA_TTDP_IN_HANGAR,
237 AMA_TTDP_ON_PAD1,
238 AMA_TTDP_ON_PAD2,
239 AMA_TTDP_ON_PAD3,
240 AMA_TTDP_HANGAR_TO_PAD1,
241 AMA_TTDP_HANGAR_TO_PAD2,
242 AMA_TTDP_HANGAR_TO_PAD3,
243 AMA_TTDP_LANDING_TO_PAD1,
244 AMA_TTDP_LANDING_TO_PAD2,
245 AMA_TTDP_LANDING_TO_PAD3,
246 AMA_TTDP_PAD1_TO_HANGAR,
247 AMA_TTDP_PAD2_TO_HANGAR,
248 AMA_TTDP_PAD3_TO_HANGAR,
249 AMA_TTDP_PAD1_TO_TAKEOFF,
250 AMA_TTDP_PAD2_TO_TAKEOFF,
251 AMA_TTDP_PAD3_TO_TAKEOFF,
252 AMA_TTDP_HANGAR_TO_TAKEOFF,
253 AMA_TTDP_LANDING_TO_HANGAR,
254 AMA_TTDP_IN_FLIGHT,
255};
256
257
265static uint8_t MapAircraftMovementAction(const Aircraft *v)
266{
267 switch (v->state) {
268 case HANGAR:
269 return (v->cur_speed > 0) ? AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_IN_HANGAR;
270
271 case TERM1:
272 case HELIPAD1:
273 return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD1 : AMA_TTDP_LANDING_TO_PAD1;
274
275 case TERM2:
276 case HELIPAD2:
277 return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD2 : AMA_TTDP_LANDING_TO_PAD2;
278
279 case TERM3:
280 case TERM4:
281 case TERM5:
282 case TERM6:
283 case TERM7:
284 case TERM8:
285 case HELIPAD3:
286 return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD3 : AMA_TTDP_LANDING_TO_PAD3;
287
288 case TAKEOFF: // Moving to takeoff position
289 case STARTTAKEOFF: // Accelerating down runway
290 case ENDTAKEOFF: // Ascent
291 case HELITAKEOFF:
292 /* @todo Need to find which terminal (or hangar) we've come from. How? */
293 return AMA_TTDP_PAD1_TO_TAKEOFF;
294
295 case FLYING:
296 return AMA_TTDP_IN_FLIGHT;
297
298 case LANDING: // Descent
299 case ENDLANDING: // On the runway braking
300 case HELILANDING:
301 case HELIENDLANDING:
302 /* @todo Need to check terminal we're landing to. Is it known yet? */
303 return (v->current_order.IsType(OT_GOTO_DEPOT)) ?
304 AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_LANDING_TO_PAD1;
305
306 default:
307 return AMA_TTDP_IN_HANGAR;
308 }
309}
310
311
312/* virtual */ uint32_t VehicleScopeResolver::GetRandomBits() const
313{
314 return this->v == nullptr ? 0 : this->v->random_bits;
315}
316
317/* virtual */ uint32_t VehicleScopeResolver::GetRandomTriggers() const
318{
319 return this->v == nullptr ? 0 : this->v->waiting_random_triggers.base();
320}
321
322
324{
325 switch (scope) {
326 case VarSpriteGroupScope::Self: return &this->self_scope;
327 case VarSpriteGroupScope::Parent: return &this->parent_scope;
329 int32_t count = GB(relative, 0, 4);
330 if (this->self_scope.v != nullptr && (relative != this->cached_relative_count || count == 0)) {
331 /* Note: This caching only works as long as the VarSpriteGroupScope::Relative cannot be used in
332 * VarAct2 with procedure calls. */
333 if (count == 0) count = this->GetRegister(0x100);
334
335 const Vehicle *v = nullptr;
336 switch (GB(relative, 6, 2)) {
337 default: NOT_REACHED();
338 case 0x00: // count back (away from the engine), starting at this vehicle
339 v = this->self_scope.v;
340 break;
341 case 0x01: // count forward (toward the engine), starting at this vehicle
342 v = this->self_scope.v;
343 count = -count;
344 break;
345 case 0x02: // count back, starting at the engine
346 v = this->parent_scope.v;
347 break;
348 case 0x03: { // count back, starting at the first vehicle in this chain of vehicles with the same ID, as for vehicle variable 41
349 const Vehicle *self = this->self_scope.v;
350 for (const Vehicle *u = self->First(); u != self; u = u->Next()) {
351 if (u->engine_type != self->engine_type) {
352 v = nullptr;
353 } else {
354 if (v == nullptr) v = u;
355 }
356 }
357 if (v == nullptr) v = self;
358 break;
359 }
360 }
361 this->relative_scope.SetVehicle(v->Move(count));
362 }
363 return &this->relative_scope;
364 }
365 default: return ResolverObject::GetScope(scope, relative);
366 }
367}
368
378static const Livery *LiveryHelper(EngineID engine, const Vehicle *v)
379{
380 const Livery *l;
381
382 if (v == nullptr) {
383 if (!Company::IsValidID(_current_company)) return nullptr;
384 l = GetEngineLivery(engine, _current_company, EngineID::Invalid(), nullptr, LIT_ALL);
385 } else if (v->IsGroundVehicle()) {
387 } else {
388 l = GetEngineLivery(v->engine_type, v->owner, EngineID::Invalid(), v, LIT_ALL);
389 }
390
391 return l;
392}
393
401static uint32_t PositionHelper(const Vehicle *v, bool consecutive)
402{
403 const Vehicle *u;
404 uint8_t chain_before = 0;
405 uint8_t chain_after = 0;
406
407 for (u = v->First(); u != v; u = u->Next()) {
408 chain_before++;
409 if (consecutive && u->engine_type != v->engine_type) chain_before = 0;
410 }
411
412 while (u->Next() != nullptr && (!consecutive || u->Next()->engine_type == v->engine_type)) {
413 chain_after++;
414 u = u->Next();
415 }
416
417 return chain_before | chain_after << 8 | (chain_before + chain_after + consecutive) << 16;
418}
419
420static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, uint8_t variable, uint32_t parameter, bool &available)
421{
422 /* Calculated vehicle parameters */
423 switch (variable) {
424 case 0x25: // Get engine GRF ID
425 return FlattenNewGRFLabel(v->GetGRFID());
426
427 case 0x40: // Get length of consist
431 }
433
434 case 0x41: // Get length of same consecutive wagons
438 }
440
441 case 0x42: { // Consist cargo information
443 std::array<uint8_t, NUM_CARGO> common_cargoes{};
444 uint8_t cargo_classes = 0;
445 uint8_t user_def_data = 0;
446
447 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
448 if (v->type == VehicleType::Train) user_def_data |= Train::From(u)->tcache.user_def_data;
449
450 /* Skip empty engines */
451 if (!u->GetEngine()->CanCarryCargo()) continue;
452
453 cargo_classes |= CargoSpec::Get(u->cargo_type)->classes.base();
454 common_cargoes[u->cargo_type]++;
455 }
456
457 /* Pick the most common cargo type */
458 auto cargo_it = std::max_element(std::begin(common_cargoes), std::end(common_cargoes));
459 /* Return INVALID_CARGO if nothing is carried */
460 CargoType common_cargo_type = (*cargo_it == 0) ? INVALID_CARGO : static_cast<CargoType>(std::distance(std::begin(common_cargoes), cargo_it));
461
462 /* Count subcargo types of common_cargo_type */
463 std::array<uint8_t, UINT8_MAX + 1> common_subtypes{};
464 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
465 /* Skip empty engines and engines not carrying common_cargo_type */
466 if (u->cargo_type != common_cargo_type || !u->GetEngine()->CanCarryCargo()) continue;
467
468 common_subtypes[u->cargo_subtype]++;
469 }
470
471 /* Pick the most common subcargo type*/
472 auto subtype_it = std::max_element(std::begin(common_subtypes), std::end(common_subtypes));
473 /* Return UINT8_MAX if nothing is carried */
474 uint8_t common_subtype = (*subtype_it == 0) ? UINT8_MAX : static_cast<uint8_t>(std::distance(std::begin(common_subtypes), subtype_it));
475
476 /* Note: We have to store the untranslated cargotype in the cache as the cache can be read by different NewGRFs,
477 * which will need different translations */
478 v->grf_cache.consist_cargo_information = cargo_classes | (common_cargo_type << 8) | (common_subtype << 16) | (user_def_data << 24);
480 }
481
482 /* The cargo translation is specific to the accessing GRF, and thus cannot be cached. */
483 CargoType common_cargo_type = static_cast<CargoType>(GB(v->grf_cache.consist_cargo_information, 8, 8));
484
485 /* Note:
486 * - Unlike everywhere else the cargo translation table is only used since grf version 8, not 7.
487 * - For translating the cargo type we need to use the GRF which is resolving the variable, which
488 * is object->ro.grffile.
489 * In case of CBID_TRAIN_ALLOW_WAGON_ATTACH this is not the same as v->GetGRF().
490 * - The grffile == nullptr case only happens if this function is called for default vehicles.
491 * And this is only done by CheckCaches().
492 */
493 const GRFFile *grffile = object->ro.grffile;
494 uint8_t common_bitnum = (common_cargo_type == INVALID_CARGO) ? 0xFF :
495 (grffile == nullptr || grffile->grf_version < 8) ? CargoSpec::Get(common_cargo_type)->bitnum : grffile->cargo_map[common_cargo_type];
496
497 return (v->grf_cache.consist_cargo_information & 0xFFFF00FF) | common_bitnum << 8;
498 }
499
500 case 0x43: // Company information
504 }
506
507 case 0x44: // Aircraft information
508 if (v->type != VehicleType::Aircraft || !Aircraft::From(v)->IsNormalAircraft()) return UINT_MAX;
509
510 {
511 const Vehicle *w = v->Next();
512 assert(w != nullptr);
513 uint16_t altitude = ClampTo<uint16_t>(v->z_pos - w->z_pos); // Aircraft height - shadow height
514 uint8_t airporttype = ATP_TTDP_LARGE;
515
517
518 if (st != nullptr && st->airport.tile != INVALID_TILE) {
519 airporttype = st->airport.GetSpec()->ttd_airport_type;
520 }
521
522 return (ClampTo<uint8_t>(altitude) << 8) | airporttype;
523 }
524
525 case 0x45: { // Curvature info
526 /* Format: xxxTxBxF
527 * F - previous wagon to current wagon, 0 if vehicle is first
528 * B - current wagon to next wagon, 0 if wagon is last
529 * T - previous wagon to next wagon, 0 in an S-bend
530 */
531 if (!v->IsGroundVehicle()) return 0;
532
533 const Vehicle *u_p = v->Previous();
534 const Vehicle *u_n = v->Next();
535 DirDiff f = (u_p == nullptr) ? DirDiff::Same : DirDifference(u_p->direction, v->direction);
536 DirDiff b = (u_n == nullptr) ? DirDiff::Same : DirDifference(v->direction, u_n->direction);
537 DirDiff t = ChangeDirDiff(f, b);
538
539 return ((t > DirDiff::Reverse ? to_underlying(t) | 8 : to_underlying(t)) << 16) |
540 ((b > DirDiff::Reverse ? to_underlying(b) | 8 : to_underlying(b)) << 8) |
541 ( f > DirDiff::Reverse ? to_underlying(f) | 8 : to_underlying(f));
542 }
543
544 case 0x46: // Motion counter
545 return v->motion_counter;
546
547 case 0x47: { // Vehicle cargo info
548 /* Format: ccccwwtt
549 * tt - the cargo type transported by the vehicle,
550 * translated if a translation table has been installed.
551 * ww - cargo unit weight in 1/16 tons, same as cargo prop. 0F.
552 * cccc - the cargo class value of the cargo transported by the vehicle.
553 */
554 const CargoSpec *cs = CargoSpec::Get(v->cargo_type);
555
556 /* Note:
557 * For translating the cargo type we need to use the GRF which is resolving the variable, which
558 * is object->ro.grffile.
559 * In case of CBID_TRAIN_ALLOW_WAGON_ATTACH this is not the same as v->GetGRF().
560 */
561 return (cs->classes.base() << 16) | (cs->weight << 8) | object->ro.grffile->cargo_map[v->cargo_type];
562 }
563
564 case 0x48: return v->GetEngine()->flags.base(); // Vehicle Type Info
565 case 0x49: return v->build_year.base();
566
567 case 0x4A:
568 switch (v->type) {
569 case VehicleType::Train: {
571 const RailTypeInfo *rti = GetRailTypeInfo(rt);
572 return (rti->flags.Test(RailTypeFlag::Catenary) ? 0x200 : 0) |
573 (HasPowerOnRail(Train::From(v)->railtypes, rt) ? 0x100 : 0) |
575 }
576
577 case VehicleType::Road: {
578 RoadType rt = GetRoadType(v->tile, GetRoadTramType(RoadVehicle::From(v)->roadtype));
579 const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
580 return (rti->flags.Test(RoadTypeFlag::Catenary) ? 0x200 : 0) |
581 0x100 |
583 }
584
585 default:
586 return 0;
587 }
588
589 case 0x4B: // Long date of last service
590 return v->date_of_last_service_newgrf.base();
591
592 case 0x4C: // Current maximum speed in NewGRF units
593 if (!v->IsPrimaryVehicle()) return 0;
594 return v->GetCurrentMaxSpeed();
595
596 case 0x4D: // Position within articulated vehicle
598 uint8_t artic_before = 0;
599 for (const Vehicle *u = v; u->IsArticulatedPart(); u = u->Previous()) artic_before++;
600 uint8_t artic_after = 0;
601 for (const Vehicle *u = v; u->HasArticulatedPart(); u = u->Next()) artic_after++;
602 v->grf_cache.position_in_vehicle = artic_before | artic_after << 8;
604 }
606
607 /* Variables which use the parameter */
608 case 0x60: // Count consist's engine ID occurrence
609 if (v->type != VehicleType::Train) return v->GetEngine()->grf_prop.local_id == parameter ? 1 : 0;
610
611 {
612 uint count = 0;
613 for (; v != nullptr; v = v->Next()) {
614 if (v->GetEngine()->grf_prop.local_id == parameter) count++;
615 }
616 return count;
617 }
618
619 case 0x61: // Get variable of n-th vehicle in chain [signed number relative to vehicle]
620 if (!v->IsGroundVehicle() || parameter == 0x61) {
621 /* Not available */
622 break;
623 }
624
625 /* Only allow callbacks that don't change properties to avoid circular dependencies. */
629 Vehicle *u = v->Move(object->ro.GetRegister(0x10F));
630 if (u == nullptr) return 0; // available, but zero
631
632 if (parameter == 0x5F) {
633 /* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */
634 return (u->random_bits << 8) | u->waiting_random_triggers.base();
635 } else {
636 return VehicleGetVariable(u, object, parameter, object->ro.GetRegister(0x10E), available);
637 }
638 }
639 /* Not available */
640 break;
641
642 case 0x62: { // Curvature/position difference for n-th vehicle in chain [signed number relative to vehicle]
643 /* Format: zzyyxxFD
644 * zz - Signed difference of z position between the selected and this vehicle.
645 * yy - Signed difference of y position between the selected and this vehicle.
646 * xx - Signed difference of x position between the selected and this vehicle.
647 * F - Flags, bit 7 corresponds to VehState::Hidden.
648 * D - Dir difference, like in 0x45.
649 */
650 if (!v->IsGroundVehicle()) return 0;
651
652 const Vehicle *u = v->Move(static_cast<int8_t>(parameter));
653 if (u == nullptr) return 0;
654
655 /* Get direction difference. */
656 bool prev = static_cast<int8_t>(parameter) < 0;
657 DirDiff dirdiff = prev ? DirDifference(u->direction, v->direction) : DirDifference(v->direction, u->direction);
658 uint32_t ret = to_underlying(dirdiff);
659 if (dirdiff > DirDiff::Reverse) ret |= 0x08;
660
661 if (u->vehstatus.Test(VehState::Hidden)) ret |= 0x80;
662
663 /* Get position difference. */
664 ret |= ((prev ? u->x_pos - v->x_pos : v->x_pos - u->x_pos) & 0xFF) << 8;
665 ret |= ((prev ? u->y_pos - v->y_pos : v->y_pos - u->y_pos) & 0xFF) << 16;
666 ret |= ((prev ? u->z_pos - v->z_pos : v->z_pos - u->z_pos) & 0xFF) << 24;
667
668 return ret;
669 }
670
671 case 0x63:
672 /* Tile compatibility wrt. arbitrary track-type
673 * Format:
674 * bit 0: Type 'parameter' is known.
675 * bit 1: Engines with type 'parameter' are compatible with this tile.
676 * bit 2: Engines with type 'parameter' are powered on this tile.
677 * bit 3: This tile has type 'parameter' or it is considered equivalent (alternate labels).
678 */
679 switch (v->type) {
680 case VehicleType::Train: {
681 RailType param_type = GetRailTypeTranslation(parameter, object->ro.grffile);
682 if (param_type == INVALID_RAILTYPE) return 0x00;
683 RailType tile_type = GetTileRailType(v->tile);
684 if (tile_type == param_type) return 0x0F;
685 return (HasPowerOnRail(param_type, tile_type) ? 0x04 : 0x00) |
686 (IsCompatibleRail(param_type, tile_type) ? 0x02 : 0x00) |
687 0x01;
688 }
689 case VehicleType::Road: {
690 RoadTramType rtt = GetRoadTramType(RoadVehicle::From(v)->roadtype);
691 RoadType param_type = GetRoadTypeTranslation(rtt, parameter, object->ro.grffile);
692 if (param_type == INVALID_ROADTYPE) return 0x00;
693 RoadType tile_type = GetRoadType(v->tile, rtt);
694 if (tile_type == param_type) return 0x0F;
695 return (HasPowerOnRoad(param_type, tile_type) ? 0x06 : 0x00) |
696 0x01;
697 }
698 default: return 0x00;
699 }
700
701 case 0x64: { // Count consist's badge ID occurrence
702 if (v->type != VehicleType::Train) return GetBadgeVariableResult(*object->ro.grffile, v->GetEngine()->badges, parameter);
703
704 /* Look up badge index. */
705 if (parameter >= std::size(object->ro.grffile->badge_list)) return UINT_MAX;
706 BadgeID index = object->ro.grffile->badge_list[parameter];
707
708 /* Count number of vehicles that contain this badge index. */
709 uint count = 0;
710 for (; v != nullptr; v = v->Next()) {
711 const auto &badges = v->GetEngine()->badges;
712 if (std::ranges::find(badges, index) != std::end(badges)) count++;
713 }
714
715 return count;
716 }
717
718 case 0x65:
719 if (v->type == VehicleType::Train) {
720 RailType rt = GetRailType(v->tile);
721 return GetBadgeVariableResult(*object->ro.grffile, GetRailTypeInfo(rt)->badges, parameter);
722 }
723 if (v->type == VehicleType::Road) {
724 RoadType rt = GetRoadType(v->tile, GetRoadTramType(RoadVehicle::From(v)->roadtype));
725 return GetBadgeVariableResult(*object->ro.grffile, GetRoadTypeInfo(rt)->badges, parameter);
726 }
727 return UINT_MAX;
728
729 case 0x7A: return GetBadgeVariableResult(*object->ro.grffile, v->GetEngine()->badges, parameter);
730
731 case 0xFE:
732 case 0xFF: {
733 uint16_t modflags = 0;
734
735 if (v->type == VehicleType::Train) {
736 const Train *t = Train::From(v);
737 bool is_powered_wagon = t->flags.Test(VehicleRailFlag::PoweredWagon);
738 const Train *u = is_powered_wagon ? t->First() : t; // for powered wagons the engine defines the type of engine (i.e. railtype)
739 RailType railtype = GetRailType(v->tile);
740 bool powered = t->IsEngine() || is_powered_wagon;
741 bool has_power = HasPowerOnRail(u->railtypes, railtype);
742
743 if (powered && has_power) SetBit(modflags, 5);
744 if (powered && !has_power) SetBit(modflags, 6);
745 if (t->flags.Test(VehicleRailFlag::Reversed)) SetBit(modflags, 8);
746 }
749 if (v->IsDrivingBackwards()) SetBit(modflags, 11);
750
751 return variable == 0xFE ? modflags : GB(modflags, 8, 8);
752 }
753 }
754
755 /*
756 * General vehicle properties
757 *
758 * Some parts of the TTD Vehicle structure are omitted for various reasons
759 * (see http://marcin.ttdpatch.net/sv1codec/TTD-locations.html#_VehicleArray)
760 */
761 switch (variable - 0x80) {
762 case 0x00: return to_underlying(v->type) + 0x10;
763 case 0x01: return MapOldSubType(v);
764 case 0x02: break; // not implemented
765 case 0x03: break; // not implemented
766 case 0x04: return v->index.base();
767 case 0x05: return GB(v->index.base(), 8, 8);
768 case 0x06: break; // not implemented
769 case 0x07: break; // not implemented
770 case 0x08: break; // not implemented
771 case 0x09: break; // not implemented
772 case 0x0A: return v->current_order.MapOldOrder();
773 case 0x0B: return v->current_order.GetDestination().value;
774 case 0x0C: return v->GetNumOrders();
775 case 0x0D: return v->cur_real_order_index;
776 case 0x0E: break; // not implemented
777 case 0x0F: break; // not implemented
778 case 0x10:
779 case 0x11: {
780 uint ticks;
781 if (v->current_order.IsType(OT_LOADING)) {
782 ticks = v->load_unload_ticks;
783 } else {
784 switch (v->type) {
785 case VehicleType::Train: ticks = Train::From(v)->wait_counter; break;
786 case VehicleType::Aircraft: ticks = Aircraft::From(v)->turn_counter; break;
787 default: ticks = 0; break;
788 }
789 }
790 return (variable - 0x80) == 0x10 ? ticks : GB(ticks, 8, 8);
791 }
794 case 0x14: return v->GetServiceInterval();
795 case 0x15: return GB(v->GetServiceInterval(), 8, 8);
796 case 0x16: return v->last_station_visited.base();
797 case 0x17: return v->tick_counter;
798 case 0x18:
799 case 0x19: {
800 uint max_speed;
801 switch (v->type) {
803 max_speed = Aircraft::From(v)->GetSpeedOldUnits(); // Convert to old units.
804 break;
805
806 default:
807 max_speed = v->vcache.cached_max_speed;
808 break;
809 }
810 return (variable - 0x80) == 0x18 ? max_speed : GB(max_speed, 8, 8);
811 }
812 case 0x1A: return v->x_pos;
813 case 0x1B: return GB(v->x_pos, 8, 8);
814 case 0x1C: return v->y_pos;
815 case 0x1D: return GB(v->y_pos, 8, 8);
816 case 0x1E: return v->z_pos;
817 case 0x1F: return to_underlying(object->rotor_in_gui ? Direction::W : v->direction); // for rotors the spriteset contains animation frames, so NewGRF need a different way to tell the helicopter orientation.
818 case 0x20: break; // not implemented
819 case 0x21: break; // not implemented
820 case 0x22: break; // not implemented
821 case 0x23: break; // not implemented
822 case 0x24: break; // not implemented
823 case 0x25: break; // not implemented
824 case 0x26: break; // not implemented
825 case 0x27: break; // not implemented
826 case 0x28: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
827 case 0x29: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
828 case 0x2A: break; // not implemented
829 case 0x2B: break; // not implemented
830 case 0x2C: break; // not implemented
831 case 0x2D: break; // not implemented
832 case 0x2E: break; // not implemented
833 case 0x2F: break; // not implemented
834 case 0x30: break; // not implemented
835 case 0x31: break; // not implemented
836 case 0x32: return v->vehstatus.base();
837 case 0x33: return 0; // non-existent high byte of vehstatus
838 case 0x34: return v->type == VehicleType::Aircraft ? (v->cur_speed * 10) / 128 : v->cur_speed;
839 case 0x35: return GB(v->type == VehicleType::Aircraft ? (v->cur_speed * 10) / 128 : v->cur_speed, 8, 8);
840 case 0x36: return v->subspeed;
841 case 0x37: return v->acceleration;
842 case 0x38: break; // not implemented
843 case 0x39: return v->cargo_type;
844 case 0x3A: return v->cargo_cap;
845 case 0x3B: return GB(v->cargo_cap, 8, 8);
846 case 0x3C: return ClampTo<uint16_t>(v->cargo.StoredCount());
847 case 0x3D: return GB(ClampTo<uint16_t>(v->cargo.StoredCount()), 8, 8);
848 case 0x3E: return v->cargo.GetFirstStation().base();
849 case 0x3F: return ClampTo<uint8_t>(v->cargo.PeriodsInTransit());
850 case 0x40: return ClampTo<uint16_t>(v->age);
851 case 0x41: return GB(ClampTo<uint16_t>(v->age), 8, 8);
852 case 0x42: return ClampTo<uint16_t>(v->max_age);
853 case 0x43: return GB(ClampTo<uint16_t>(v->max_age), 8, 8);
855 case 0x45: return v->unitnumber;
856 case 0x46: return v->GetEngine()->grf_prop.local_id;
857 case 0x47: return GB(v->GetEngine()->grf_prop.local_id, 8, 8);
858 case 0x48:
861
862 case 0x49: return v->day_counter;
863 case 0x4A: return v->breakdowns_since_last_service;
864 case 0x4B: return v->breakdown_ctr;
865 case 0x4C: return v->breakdown_delay;
866 case 0x4D: return v->breakdown_chance;
867 case 0x4E: return v->reliability;
868 case 0x4F: return GB(v->reliability, 8, 8);
869 case 0x50: return v->reliability_spd_dec;
870 case 0x51: return GB(v->reliability_spd_dec, 8, 8);
871 case 0x52: return ClampTo<int32_t>(v->GetDisplayProfitThisYear());
872 case 0x53: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 8, 24);
873 case 0x54: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 16, 16);
874 case 0x55: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 24, 8);
875 case 0x56: return ClampTo<int32_t>(v->GetDisplayProfitLastYear());
876 case 0x57: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 8, 24);
877 case 0x58: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 16, 16);
878 case 0x59: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 24, 8);
879 case 0x5A: return (v->Next() == nullptr ? VehicleID::Invalid() : v->Next()->index).base();
880 case 0x5B: break; // not implemented
881 case 0x5C: return ClampTo<int32_t>(v->value);
882 case 0x5D: return GB(ClampTo<int32_t>(v->value), 8, 24);
883 case 0x5E: return GB(ClampTo<int32_t>(v->value), 16, 16);
884 case 0x5F: return GB(ClampTo<int32_t>(v->value), 24, 8);
885 case 0x60: break; // not implemented
886 case 0x61: break; // not implemented
887 case 0x62: break; // vehicle specific, see below
888 case 0x63: break; // not implemented
889 case 0x64: break; // vehicle specific, see below
890 case 0x65: break; // vehicle specific, see below
891 case 0x66: break; // vehicle specific, see below
892 case 0x67: break; // vehicle specific, see below
893 case 0x68: break; // vehicle specific, see below
894 case 0x69: break; // vehicle specific, see below
895 case 0x6A: break; // not implemented
896 case 0x6B: break; // not implemented
897 case 0x6C: break; // not implemented
898 case 0x6D: break; // not implemented
899 case 0x6E: break; // not implemented
900 case 0x6F: break; // not implemented
901 case 0x70: break; // not implemented
902 case 0x71: break; // not implemented
903 case 0x72: return v->cargo_subtype;
904 case 0x73: break; // vehicle specific, see below
905 case 0x74: break; // vehicle specific, see below
906 case 0x75: break; // vehicle specific, see below
907 case 0x76: break; // vehicle specific, see below
908 case 0x77: break; // vehicle specific, see below
909 case 0x78: break; // not implemented
910 case 0x79: break; // not implemented
911 case 0x7A: return v->random_bits;
912 case 0x7B: return v->waiting_random_triggers.base();
913 case 0x7C: break; // vehicle specific, see below
914 case 0x7D: break; // vehicle specific, see below
915 case 0x7E: break; // not implemented
916 case 0x7F: break; // vehicle specific, see below
917 }
918
919 /* Vehicle specific properties */
920 switch (v->type) {
921 case VehicleType::Train: {
922 Train *t = Train::From(v);
923 switch (variable - 0x80) {
924 case 0x62: return t->track.base();
925 case 0x66: return t->railtypes.GetNthSetBit(0).value_or(RailType::INVALID_RAILTYPE);
926 case 0x73: return 0x80 + VEHICLE_LENGTH - t->gcache.cached_veh_length;
927 case 0x74: return t->gcache.cached_power;
928 case 0x75: return GB(t->gcache.cached_power, 8, 24);
929 case 0x76: return GB(t->gcache.cached_power, 16, 16);
930 case 0x77: return GB(t->gcache.cached_power, 24, 8);
931 case 0x7C: return t->First()->index.base();
932 case 0x7D: return GB(t->First()->index.base(), 8, 8);
933 case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
934 }
935 break;
936 }
937
938 case VehicleType::Road: {
940 switch (variable - 0x80) {
941 case 0x62: return rv->state;
942 case 0x64: return rv->blocked_ctr;
943 case 0x65: return GB(rv->blocked_ctr, 8, 8);
944 case 0x66: return rv->overtaking;
945 case 0x67: return rv->overtaking_ctr;
946 case 0x68: return rv->crashed_ctr;
947 case 0x69: return GB(rv->crashed_ctr, 8, 8);
948 }
949 break;
950 }
951
952 case VehicleType::Ship: {
953 Ship *s = Ship::From(v);
954 switch (variable - 0x80) {
955 case 0x62: return s->state.base();
956 }
957 break;
958 }
959
961 Aircraft *a = Aircraft::From(v);
962 switch (variable - 0x80) {
963 case 0x62: return MapAircraftMovementState(a); // Current movement state
964 case 0x63: return a->targetairport.base(); // Airport to which the action refers
965 case 0x66: return MapAircraftMovementAction(a); // Current movement action
966 }
967 break;
968 }
969
970 default: break;
971 }
972
973 Debug(grf, 1, "Unhandled vehicle variable 0x{:X}, type 0x{:X}", variable, (uint)v->type);
974
975 available = false;
976 return UINT_MAX;
977}
978
979/* virtual */ uint32_t VehicleScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
980{
981 if (this->v == nullptr) {
982 /* Vehicle does not exist, so we're in a purchase list */
983 switch (variable) {
984 case 0x43: return GetCompanyInfo(_current_company, LiveryHelper(this->self_type, nullptr)); // Owner information
985 case 0x46: return 0; // Motion counter
986 case 0x47: { // Vehicle cargo info
987 const Engine *e = Engine::Get(this->self_type);
988 CargoType cargo_type = e->GetDefaultCargoType();
989 if (IsValidCargoType(cargo_type)) {
990 const CargoSpec *cs = CargoSpec::Get(cargo_type);
991 return (cs->classes.base() << 16) | (cs->weight << 8) | this->ro.grffile->cargo_map[cargo_type];
992 } else {
993 return 0x000000FF;
994 }
995 }
996 case 0x48: return Engine::Get(this->self_type)->flags.base(); // Vehicle Type Info
997 case 0x49: return TimerGameCalendar::year.base(); // 'Long' format build year
998 case 0x4B: return TimerGameCalendar::date.base(); // Long date of last service
999
1000 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, Engine::Get(this->self_type)->badges, parameter);
1001
1005 case 0xC6: return Engine::Get(this->self_type)->grf_prop.local_id;
1006 case 0xC7: return GB(Engine::Get(this->self_type)->grf_prop.local_id, 8, 8);
1007 case 0xDA: return VehicleID::Invalid().base(); // Next vehicle
1008 case 0xF2: return 0; // Cargo subtype
1009 }
1010
1011 available = false;
1012 return UINT_MAX;
1013 }
1014
1015 return VehicleGetVariable(const_cast<Vehicle*>(this->v), this, variable, parameter, available);
1016}
1017
1018
1020{
1021 const Vehicle *v = this->self_scope.v;
1022
1023 if (v == nullptr) {
1024 if (!group.loading.empty()) return group.loading[0];
1025 if (!group.loaded.empty()) return group.loaded[0];
1026 return nullptr;
1027 }
1028
1029 const Order &order = v->First()->current_order;
1030 bool not_loading = order.GetUnloadType() == OrderUnloadType::NoUnload && order.GetLoadType() == OrderLoadType::NoLoad;
1031 bool in_motion = !order.IsType(OT_LOADING) || not_loading;
1032
1033 uint totalsets = static_cast<uint>(in_motion ? group.loaded.size() : group.loading.size());
1034
1035 if (totalsets == 0) return nullptr;
1036
1037 uint set = (v->cargo.StoredCount() * totalsets) / std::max<uint16_t>(1u, v->cargo_cap);
1038 set = std::min(set, totalsets - 1);
1039
1040 return in_motion ? group.loaded[set] : group.loading[set];
1041}
1042
1044{
1045 switch (Engine::Get(this->self_scope.self_type)->type) {
1050 default: return GrfSpecFeature::Invalid;
1051 }
1052}
1053
1055{
1056 return Engine::Get(this->self_scope.self_type)->grf_prop.local_id;
1057}
1058
1064static const GRFFile *GetEngineGrfFile(EngineID engine_type)
1065{
1066 const Engine *e = Engine::Get(engine_type);
1067 return (e != nullptr) ? e->GetGRF() : nullptr;
1068}
1069
1080VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle *v, WagonOverride wagon_override, bool rotor_in_gui,
1083 self_scope(*this, engine_type, v, rotor_in_gui),
1084 parent_scope(*this, engine_type, ((v != nullptr) ? v->First() : v), rotor_in_gui),
1085 relative_scope(*this, engine_type, v, rotor_in_gui),
1087{
1088 if (wagon_override == WagonOverride::Self) {
1089 this->root_spritegroup = GetWagonOverrideSpriteSet(engine_type, CargoGRFFileProps::SG_DEFAULT, engine_type);
1090 } else {
1091 if (wagon_override != WagonOverride::None && v != nullptr && v->IsGroundVehicle()) {
1092 assert(v->engine_type == engine_type); // overrides make little sense with fake scopes
1093
1094 /* For trains we always use cached value, except for callbacks because the override spriteset
1095 * to use may be different than the one cached. It happens for callback 0x15 (refit engine),
1096 * as v->cargo_type is temporary changed to the new type */
1097 if (wagon_override == WagonOverride::Cached && v->type == VehicleType::Train) {
1099 } else {
1100 this->root_spritegroup = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->GetGroundVehicleCache()->first_engine);
1101 }
1102 }
1103
1104 if (this->root_spritegroup == nullptr) {
1105 const Engine *e = Engine::Get(engine_type);
1106 CargoType cargo = v != nullptr ? v->cargo_type : CargoGRFFileProps::SG_PURCHASE;
1108 }
1109 }
1110}
1111
1112static void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result)
1113{
1115 result->Clear();
1116
1117 bool sprite_stack = EngInfo(engine)->misc_flags.Test(EngineMiscFlag::SpriteStack);
1118 uint max_stack = sprite_stack ? static_cast<uint>(std::size(result->seq)) : 1;
1119 for (uint stack = 0; stack < max_stack; ++stack) {
1120 object.callback_param1 = to_underlying(image_type) | (stack << 8);
1121 const auto *group = object.Resolve<ResultSpriteGroup>();
1122 int32_t reg100 = sprite_stack ? object.GetRegister(0x100) : 0;
1123 if (group != nullptr && group->num_sprites != 0) {
1124 result->seq[result->count].sprite = group->sprite + (to_underlying(direction) % group->num_sprites);
1125 result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring
1126 result->count++;
1127 }
1128 if (!HasBit(reg100, 31)) break;
1129 }
1130}
1131
1132void GetCustomVehicleSprite(const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result)
1133{
1134 GetCustomEngineSprite(v->engine_type, v, direction, image_type, result);
1135}
1136
1137void GetCustomVehicleIcon(EngineID engine, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result)
1138{
1139 GetCustomEngineSprite(engine, nullptr, direction, image_type, result);
1140}
1141
1142static void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result)
1143{
1144 const Engine *e = Engine::Get(engine);
1145
1146 /* Only valid for helicopters */
1147 assert(e->type == VehicleType::Aircraft);
1148 assert(!(e->VehInfo<AircraftVehicleInfo>().subtype & AIR_CTOL));
1149
1150 /* We differ from TTDPatch by resolving the sprite using the primary vehicle 'v', and not using the rotor vehicle 'v->Next()->Next()'.
1151 * TTDPatch copies some variables between the vehicles each time, to somehow synchronize the rotor vehicle with the primary vehicle.
1152 * We use 'rotor_in_gui' to replicate when the variables differ.
1153 * But some other variables like 'rotor state' and 'rotor speed' are not available in OpenTTD, while they are in TTDPatch. */
1154 bool rotor_in_gui = image_type != EngineImageType::OnMap;
1156 result->Clear();
1157 uint rotor_pos = v == nullptr || rotor_in_gui ? 0 : v->Next()->Next()->state;
1158
1159 bool sprite_stack = e->info.misc_flags.Test(EngineMiscFlag::SpriteStack);
1160 uint max_stack = sprite_stack ? static_cast<uint>(std::size(result->seq)) : 1;
1161 for (uint stack = 0; stack < max_stack; ++stack) {
1162 object.callback_param1 = to_underlying(image_type) | (stack << 8);
1163 const auto *group = object.Resolve<ResultSpriteGroup>();
1164 int32_t reg100 = sprite_stack ? object.GetRegister(0x100) : 0;
1165 if (group != nullptr && group->num_sprites != 0) {
1166 result->seq[result->count].sprite = group->sprite + (rotor_pos % group->num_sprites);
1167 result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring
1168 result->count++;
1169 }
1170 if (!HasBit(reg100, 31)) break;
1171 }
1172}
1173
1174void GetCustomRotorSprite(const struct Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result)
1175{
1176 GetRotorOverrideSprite(v->engine_type, v, image_type, result);
1177}
1178
1179void GetCustomRotorIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
1180{
1181 GetRotorOverrideSprite(engine, nullptr, image_type, result);
1182}
1183
1190{
1191 assert(v->type == VehicleType::Train);
1192 return Train::From(v)->tcache.cached_override != nullptr;
1193}
1194
1205uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, std::span<int32_t> regs100)
1206{
1207 VehicleResolverObject object(engine, v, VehicleResolverObject::WagonOverride::Uncached, false, callback, param1, param2);
1208 return object.ResolveCallback(regs100);
1209}
1210
1222uint16_t GetVehicleCallbackParent(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, const Vehicle *parent, std::span<int32_t> regs100)
1223{
1224 VehicleResolverObject object(engine, v, VehicleResolverObject::WagonOverride::None, false, callback, param1, param2);
1225 object.parent_scope.SetVehicle(parent);
1226 return object.ResolveCallback(regs100);
1227}
1228
1229
1230/* Callback 36 handlers */
1231int GetVehicleProperty(const Vehicle *v, PropertyID property, int orig_value, bool is_signed)
1232{
1233 return GetEngineProperty(v->engine_type, property, orig_value, v, is_signed);
1234}
1235
1236
1237int GetEngineProperty(EngineID engine, PropertyID property, int orig_value, const Vehicle *v, bool is_signed)
1238{
1239 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_MODIFY_PROPERTY, property, 0, engine, v);
1240 if (callback != CALLBACK_FAILED) {
1241 if (is_signed) {
1242 /* Sign extend 15 bit integer */
1243 return static_cast<int16_t>(callback << 1) / 2;
1244 } else {
1245 return callback;
1246 }
1247 }
1248
1249 return orig_value;
1250}
1251
1259{
1261 if (p == CALLBACK_FAILED) return std::nullopt;
1262
1263 const uint16_t PROBABILITY_RANGE = 100;
1264 return p + RandomRange(PROBABILITY_RANGE) >= PROBABILITY_RANGE;
1265}
1266
1267static void DoTriggerVehicleRandomisation(Vehicle *v, VehicleRandomTrigger trigger, uint16_t base_random_bits, bool first)
1268{
1269 /* We can't trigger a non-existent vehicle... */
1270 assert(v != nullptr);
1271
1273 v->waiting_random_triggers.Set(trigger); // store now for var 5F
1274 object.SetWaitingRandomTriggers(v->waiting_random_triggers);
1275
1276 object.ResolveRerandomisation();
1277
1278 /* Store remaining triggers. */
1279 v->waiting_random_triggers.Reset(object.GetUsedRandomTriggers());
1280
1281 /* Rerandomise bits. Scopes other than SELF are invalid for rerandomisation. For bug-to-bug-compatibility with TTDP we ignore the scope. */
1282 uint16_t new_random_bits = Random();
1283 uint32_t reseed = object.GetReseedSum();
1284 v->random_bits &= ~reseed;
1285 v->random_bits |= (first ? new_random_bits : base_random_bits) & reseed;
1286
1287 switch (trigger) {
1289 /* All vehicles in chain get ANY_NEW_CARGO trigger now.
1290 * So we call it for the first one and they will recurse.
1291 * Indexing part of vehicle random bits needs to be
1292 * same for all triggered vehicles in the chain (to get
1293 * all the random-cargo wagons carry the same cargo,
1294 * i.e.), so we give them all the NEW_CARGO triggered
1295 * vehicle's portion of random bits. */
1296 assert(first);
1297 DoTriggerVehicleRandomisation(v->First(), VehicleRandomTrigger::AnyNewCargo, new_random_bits, false);
1298 break;
1299
1301 /* We now trigger the next vehicle in chain recursively.
1302 * The random bits portions may be different for each
1303 * vehicle in chain. */
1304 if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), trigger, 0, true);
1305 break;
1306
1308 /* We now trigger the next vehicle in chain
1309 * recursively. The random bits portions must be same
1310 * for each vehicle in chain, so we give them all
1311 * first chained vehicle's portion of random bits. */
1312 if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), trigger, first ? new_random_bits : base_random_bits, false);
1313 break;
1314
1316 /* Now pass the trigger recursively to the next vehicle
1317 * in chain. */
1318 assert(!first);
1319 if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), trigger, base_random_bits, false);
1320 break;
1321
1323 /* Do not do any recursion */
1324 break;
1325 }
1326}
1327
1328void TriggerVehicleRandomisation(Vehicle *v, VehicleRandomTrigger trigger)
1329{
1331 DoTriggerVehicleRandomisation(v, trigger, 0, true);
1333}
1334
1335/* Functions for changing the order of vehicle purchase lists */
1336
1337struct ListOrderChange {
1339 uint16_t target;
1340
1341 ListOrderChange(EngineID engine, uint16_t target) : engine(engine), target(target) {}
1342};
1343
1344static std::vector<ListOrderChange> _list_order_changes;
1345
1352void AlterVehicleListOrder(EngineID engine, uint16_t target)
1353{
1354 /* Add the list order change to a queue */
1355 _list_order_changes.emplace_back(engine, target);
1356}
1357
1364static bool EnginePreSort(const EngineID &a, const EngineID &b)
1365{
1366 const Engine &engine_a = *Engine::Get(a);
1367 const Engine &engine_b = *Engine::Get(b);
1368
1369 /* 1. Sort by engine type */
1370 if (engine_a.type != engine_b.type) return static_cast<int>(engine_a.type) < static_cast<int>(engine_b.type);
1371
1372 /* 2. Sort by scope-GRFID */
1373 if (engine_a.grf_prop.grfid != engine_b.grf_prop.grfid) return engine_a.grf_prop.grfid < engine_b.grf_prop.grfid;
1374
1375 /* 3. Sort by local ID */
1376 return static_cast<int>(engine_a.grf_prop.local_id) < static_cast<int>(engine_b.grf_prop.local_id);
1377}
1378
1383{
1384 /* Build a list of EngineIDs. EngineIDs are sequential from 0 up to the number of pool items with no gaps. */
1385 std::vector<EngineID> ordering(Engine::GetNumItems());
1386 std::iota(std::begin(ordering), std::end(ordering), EngineID::Begin());
1387
1388 /* Pre-sort engines by scope-grfid and local index */
1389 std::ranges::sort(ordering, EnginePreSort);
1390
1391 /* Apply Insertion-Sort operations */
1392 for (const ListOrderChange &loc : _list_order_changes) {
1393 EngineID source = loc.engine;
1394
1395 Engine *engine_source = Engine::Get(source);
1396 if (engine_source->grf_prop.local_id == loc.target) continue;
1397
1398 EngineID target = _engine_mngr.GetID(engine_source->type, loc.target, engine_source->grf_prop.grfid);
1399 if (target == EngineID::Invalid()) continue;
1400
1401 auto it_source = std::ranges::find(ordering, source);
1402 auto it_target = std::ranges::find(ordering, target);
1403
1404 assert(it_source != std::end(ordering) && it_target != std::end(ordering));
1405 assert(it_source != it_target);
1406
1407 /* Move just this item to before the target. */
1408 Slide(it_source, std::next(it_source), it_target);
1409 }
1410
1411 /* Store final sort-order */
1412 for (uint16_t index = 0; const EngineID &eid : ordering) {
1413 Engine::Get(eid)->list_position = index;
1414 ++index;
1415 }
1416
1417 /* Clear out the queue */
1418 _list_order_changes.clear();
1419 _list_order_changes.shrink_to_fit();
1420}
1421
1427{
1429
1430 /* These variables we have to check; these are the ones with a cache. */
1431 static const int cache_entries[][2] = {
1435 { 0x43, NCVV_COMPANY_INFORMATION },
1436 { 0x4D, NCVV_POSITION_IN_VEHICLE },
1437 };
1438 static_assert(NCVV_END == lengthof(cache_entries));
1439
1440 /* Resolve all the variables, so their caches are set. */
1441 for (const auto &cache_entry : cache_entries) {
1442 /* Only resolve when the cache isn't valid. */
1443 if (HasBit(v->grf_cache.cache_valid, cache_entry[1])) continue;
1444 bool stub;
1445 ro.GetScope(VarSpriteGroupScope::Self)->GetVariable(cache_entry[0], 0, stub);
1446 }
1447
1448 /* Make sure really all bits are set. */
1449 assert(v->grf_cache.cache_valid == (1 << NCVV_END) - 1);
1450}
Base for aircraft.
Station * GetTargetAirportIfValid(const Aircraft *v)
Returns aircraft's target station if v->target_airport is a valid station with airport.
@ HeliRaise
Helicopter take-off.
Definition airport.h:54
@ HeliLower
Helicopter landing.
Definition airport.h:55
@ SlowTurn
Turn slowly (mostly used in the air).
Definition airport.h:50
@ Brake
Taxiing at the airport.
Definition airport.h:53
@ Hold
Holding pattern movement (above the airport).
Definition airport.h:56
@ ExactPosition
Go exactly to the destination coordinates.
Definition airport.h:52
EnumBitSet< AirportMovingDataFlag, uint16_t > AirportMovingDataFlags
Bitset of AirportMovingDataFlag elements.
Definition airport.h:60
@ HELITAKEOFF
Helicopter wants to leave the airport.
Definition airport.h:77
@ TERM4
Heading for terminal 4.
Definition airport.h:69
@ STARTTAKEOFF
Airplane has arrived at a runway for take-off.
Definition airport.h:75
@ HELIPAD2
Heading for helipad 2.
Definition airport.h:73
@ ENDTAKEOFF
Airplane has reached end-point of the take-off runway.
Definition airport.h:76
@ TERM5
Heading for terminal 5.
Definition airport.h:70
@ TERM6
Heading for terminal 6.
Definition airport.h:71
@ TERM3
Heading for terminal 3.
Definition airport.h:68
@ TERM8
Heading for terminal 8.
Definition airport.h:84
@ HELIPAD3
Heading for helipad 3.
Definition airport.h:85
@ HELIPAD1
Heading for helipad 1.
Definition airport.h:72
@ TERM2
Heading for terminal 2.
Definition airport.h:67
@ HANGAR
Heading for hangar.
Definition airport.h:65
@ FLYING
Vehicle is flying in the air.
Definition airport.h:78
@ TAKEOFF
Airplane wants to leave the airport.
Definition airport.h:74
@ HELILANDING
Helicopter wants to land.
Definition airport.h:81
@ ENDLANDING
Airplane wants to finish landing.
Definition airport.h:80
@ HELIENDLANDING
Helicopter wants to finish landing.
Definition airport.h:82
@ TERM1
Heading for terminal 1.
Definition airport.h:66
@ LANDING
Airplane wants to land.
Definition airport.h:79
@ TERM7
Heading for terminal 7.
Definition airport.h:83
@ BuiltAsPrototype
Vehicle is a prototype (accepted as exclusive preview).
@ CargoUnloading
Vehicle is unloading cargo.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:110
static constexpr CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:75
CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this bit set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
std::optional< Tvalue_type > GetNthSetBit(uint n) const
Get the value of the Nth set bit.
uint PeriodsInTransit() const
Returns average number of cargo aging periods in transit for a cargo entity.
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
CargoGRFFileProps grf_prop
Link to NewGRF.
Definition engine_base.h:73
EngineFlags flags
Flags of the engine.
Definition engine_base.h:59
VehicleType type
Vehicle type, ie VehicleType::Road, VehicleType::Train, etc.
Definition engine_base.h:64
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:96
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:117
RailTypeFlags flags
Bit mask of rail type flags.
Definition rail.h:202
RoadTypeFlags flags
Bit mask of road type flags.
Definition road.h:103
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static constexpr TimerGame< struct Calendar >::Year ORIGINAL_MAX_YEAR
static constexpr TimerGame< struct Calendar >::Year ORIGINAL_BASE_YEAR
static constexpr TimerGame< struct Calendar >::Date DAYS_TILL_ORIGINAL_BASE_YEAR
StationID GetFirstStation() const
Returns the first station of the first cargo packet in this list.
uint StoredCount() const
Returns sum of cargo on board the vehicle (ie not only reserved).
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
Some simple functions to help with accessing containers.
auto Slide(TIter first, TIter last, TIter position) -> std::pair< TIter, TIter >
Move elements between first and last to a new position, rotating elements in between as necessary.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
DirDiff DirDifference(Direction d0, Direction d1)
Calculate the difference between two directions.
DirDiff ChangeDirDiff(DirDiff d, DirDiff delta)
Applies two differences together.
DirDiff
Enumeration for the difference between two directions.
@ Reverse
One direction is the opposite of the other one.
@ Same
Both directions faces to the same direction.
Direction
Defines the 8 directions on the map.
@ AIR_CTOL
Conventional Take Off and Landing, i.e. planes.
@ SpriteStack
Draw vehicle by stacking multiple sprites.
PoolID< uint16_t, struct EngineIDTag, 64000, 0xFFFF > EngineID
Unique identification number of an engine.
Definition engine_type.h:26
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
static const uint8_t LIT_ALL
Show the liveries of all companies.
Definition livery.h:19
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
@ First
The first client ID.
Base for the NewGRF implementation.
constexpr uint32_t FlattenNewGRFLabel(T label)
Flatten a NewGRF related label to a 32 bits integer.
Definition newgrf.h:259
GrfSpecFeature
Definition newgrf.h:78
@ Trains
Trains feature.
Definition newgrf.h:79
@ RoadVehicles
Road vehicles feature.
Definition newgrf.h:80
@ Invalid
An invalid spec feature.
Definition newgrf.h:109
@ Ships
Ships feature.
Definition newgrf.h:81
@ Aircraft
Aircraft feature.
Definition newgrf.h:82
@ ATP_TTDP_LARGE
Same as AT_LARGE.
uint32_t GetBadgeVariableResult(const GRFFile &grffile, std::span< const BadgeID > badges, uint32_t parameter)
Test for a matching badge in a list of badges, returning the number of matching bits.
Functions related to NewGRF badges.
CallbackID
List of implemented NewGRF callbacks.
@ CBID_VEHICLE_BUILD_PROBABILITY
Called to determine probability during build.
@ 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_NO_CALLBACK
Set when using the callback resolve system, but not to resolve a callback.
@ CBID_VEHICLE_START_STOP_CHECK
Called when the company (or AI) tries to start or stop a vehicle.
@ CBID_RANDOM_TRIGGER
Set when calling a randomizing trigger (almost undocumented).
@ CBID_TRAIN_ALLOW_WAGON_ATTACH
Determine whether a wagon can be attached to an already existing train.
@ CBID_VEHICLE_MODIFY_PROPERTY
Called to modify various vehicle properties.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
Cargo support for NewGRFs.
uint32_t GetCompanyInfo(CompanyID owner, const Livery *l)
Returns company information like in vehicle var 43 or station var 43.
void SetEngineGRF(EngineID engine, const GRFFile *file)
Tie a GRFFile entry to an engine, to allow us to retrieve GRF parameters etc during a game.
static uint32_t PositionHelper(const Vehicle *v, bool consecutive)
Helper to get the position of a vehicle within a chain of vehicles.
static bool EnginePreSort(const EngineID &a, const EngineID &b)
Comparator function to sort engines via scope-GRFID and local ID.
void FillNewGRFVehicleCache(const Vehicle *v)
Fill the grf_cache of the given vehicle.
uint16_t GetVehicleCallbackParent(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, const Vehicle *parent, std::span< int32_t > regs100)
Evaluate a newgrf callback for vehicles with a different vehicle for parent scope.
TTDPAircraftMovementStates
TTDP style aircraft movement states for GRF Action 2 Var 0xE2.
bool UsesWagonOverride(const Vehicle *v)
Check if a wagon is currently using a wagon override.
static const Livery * LiveryHelper(EngineID engine, const Vehicle *v)
Determines the livery of an engine.
static uint8_t MapAircraftMovementState(const Aircraft *v)
Map OTTD aircraft movement states to TTDPatch style movement states (VarAction 2 Variable 0xE2).
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, std::span< int32_t > regs100)
Evaluate a newgrf callback for vehicles.
TTDPAircraftMovementActions
TTDP style aircraft movement action for GRF Action 2 Var 0xE6.
static uint8_t MapAircraftMovementAction(const Aircraft *v)
Map OTTD aircraft movement states to TTDPatch style movement actions (VarAction 2 Variable 0xE6) This...
std::optional< bool > TestVehicleBuildProbability(Vehicle *v, BuildProbabilityType type)
Test for vehicle build probability type.
void CommitVehicleListOrderChanges()
Determine default engine sorting and execute recorded ListOrderChanges from AlterVehicleListOrder.
static const GRFFile * GetEngineGrfFile(EngineID engine_type)
Get the grf file associated with an engine type.
void AlterVehicleListOrder(EngineID engine, uint16_t target)
Record a vehicle ListOrderChange.
BuildProbabilityType
Different types of modifications during the purchase of a vehicle to request the chance for using a N...
PropertyID
List of NewGRF properties used in Action 0 or Callback 0x36 (CBID_VEHICLE_MODIFY_PROPERTY).
uint8_t GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile)
Perform a reverse railtype lookup to get the GRF internal ID.
RailType GetRailTypeTranslation(uint8_t railtype, const GRFFile *grffile)
Translate an index to the GRF-local railtype-translation table into a RailType.
NewGRF handling of rail types.
uint8_t GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile)
Perform a reverse roadtype lookup to get the GRF internal ID.
RoadType GetRoadTypeTranslation(RoadTramType rtt, uint8_t tracktype, const GRFFile *grffile)
Translate an index to the GRF-local road/tramtype-translation table into a RoadType.
NewGRF handling of road types.
Action 2 handling.
VarSpriteGroupScope
Shared by deterministic and random groups.
@ Relative
Relative position (vehicles only).
@ Parent
Related object of the resolved one.
@ Self
Resolved object itself.
@ NoUnload
Totally no unloading will be done.
Definition order_type.h:71
@ NoLoad
Do not load anything.
Definition order_type.h:81
RailType GetTileRailType(Tile tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
Definition rail.cpp:39
bool IsCompatibleRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType can drive on a tile with a given RailType.
Definition rail.h:354
bool HasPowerOnRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType got power on a tile with a given RailType.
Definition rail.h:379
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:303
@ Catenary
Bit number for drawing a catenary.
Definition rail.h:28
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition rail_map.h:115
RailType
Enumeration for all possible railtypes.
Definition rail_type.h:26
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:33
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 HasPowerOnRoad(RoadType enginetype, RoadType tiletype)
Checks if an engine of the given RoadType got power on a tile with a given RoadType.
Definition road.h:232
@ Catenary
Bit number for adding catenary.
Definition road.h:25
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:217
RoadType GetRoadType(Tile t, RoadTramType rtt)
Get the road type for the given RoadTramType.
Definition road_map.h:175
RoadType
The different roadtypes we support.
Definition road_type.h:24
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:29
RoadTramType
The different types of road type.
Definition road_type.h:38
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
Base for ships.
Base classes/functions for stations.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:261
Information about a aircraft vehicle.
uint8_t subtype
Type of aircraft.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:75
uint8_t pos
Next desired position of the aircraft.
Definition aircraft.h:77
uint8_t state
State of the airport.
Definition aircraft.h:80
uint8_t turn_counter
Ticks between each turn to prevent > 45 degree turns.
Definition aircraft.h:83
StationID targetairport
Airport to go to next.
Definition aircraft.h:79
Finite sTate mAchine (FTA) of an airport.
Definition airport.h:161
const AirportMovingData * MovingData(uint8_t position) const
Get movement data at a position.
Definition airport.h:188
uint8_t delta_z
Z adjustment for helicopter pads.
Definition airport.h:201
AirportMovingDataFlags flags
special flags when moving towards the destination.
Definition airport.h:141
TTDPAirportType ttd_airport_type
ttdpatch airport type (Small/Large/Helipad/Oilrig)
const AirportFTAClass * GetFTA() const
Get the finite-state machine for this airport or the finite-state machine for the dummy airport in ca...
const AirportSpec * GetSpec() const
Get the AirportSpec that from the airport type of this airport.
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
VehicleFlags vehicle_flags
Used for gradual loading and other miscellaneous things (.
VehicleType type
Type of vehicle.
static constexpr CargoType SG_PURCHASE
Used in purchase lists before an item exists.
static constexpr CargoType SG_DEFAULT
Default type used when no more-specific cargo matches.
Specification of a cargo type.
Definition cargotype.h:77
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:84
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:141
uint8_t weight
Weight of a single unit of this cargo type in 1/16 ton (62.5 kg).
Definition cargotype.h:82
EngineMiscFlags misc_flags
Miscellaneous flags.
GrfID grfid
grfid that introduced this entity.
uint16_t local_id
id defined by the grf file for this entity
void SetGRFFile(const struct GRFFile *grffile)
Set the NewGRF file, and its grfid, associated with grf props.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:124
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoType -> local ID).
Definition newgrf.h:146
std::vector< BadgeID > badge_list
Badge translation table (local index -> global index).
Definition newgrf.h:148
EngineID first_engine
Cached EngineID of the front vehicle. EngineID::Invalid() for the front vehicle itself.
uint32_t cached_power
Total power of the consist (valid only for the first engine).
uint8_t cached_veh_length
Length of this vehicle in units of 1/VEHICLE_LENGTH of normal length. It is cached because this can b...
GroundVehicleCache gcache
Cache of often calculated values.
bool IsEngine() const
Check if a vehicle is an engine (can be first in a consist).
uint16_t target
GRF-local ID.
EngineID engine
Engine ID.
Information about a particular livery.
Definition livery.h:82
uint32_t position_in_vehicle
Cache for NewGRF var 4D.
uint32_t position_consist_length
Cache for NewGRF var 40.
uint32_t consist_cargo_information
Cache for NewGRF var 42. (Note: The cargotype is untranslated in the cache because the accessing GRF ...
uint8_t cache_valid
Bitset that indicates which cache values are valid.
uint32_t company_information
Cache for NewGRF var 43.
uint32_t position_same_id_length
Cache for NewGRF var 41.
If you change this, keep in mind that it is also saved in 2 other places:
Definition order_base.h:34
uint16_t MapOldOrder() const
Pack this order into a 16 bits integer as close to the TTD representation as possible.
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:100
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:67
OrderUnloadType GetUnloadType() const
How must the consist be unloaded?
Definition order_base.h:152
OrderLoadType GetLoadType() const
How must the consist be loaded?
Definition order_base.h:146
TileIndex tile
The base tile of the area.
static Engine * Get(auto index)
'Real' sprite groups contain a list of other result or callback sprite groups.
std::vector< const SpriteGroup * > loaded
List of loaded groups (can be SpriteIDs or Callback results).
std::vector< const SpriteGroup * > loading
List of loading groups (can be SpriteIDs or Callback results).
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
uint32_t callback_param2
Second parameter (var 18) of the callback.
int32_t GetRegister(uint i) const
Gets the value of a so-called newgrf "register".
CallbackID callback
Callback being resolved.
uint32_t callback_param1
First parameter (var 10) of the callback.
virtual ScopeResolver * GetScope(VarSpriteGroupScope scope=VarSpriteGroupScope::Self, uint8_t relative=0)
Get a resolver for the scope.
const SpriteGroup * root_spritegroup
Root SpriteGroup to use for resolving.
A result sprite group returns the first SpriteID and the number of sprites in the set.
Buses, trucks and trams belong to this class.
Definition roadveh.h:105
uint8_t state
Definition roadveh.h:107
uint16_t crashed_ctr
Animation counter when the vehicle has crashed.
Definition roadveh.h:112
uint8_t overtaking_ctr
The length of the current overtake attempt.
Definition roadveh.h:111
uint8_t overtaking
Set to RVSB_DRIVE_SIDE when overtaking, otherwise 0.
Definition roadveh.h:110
Interface to query and set values specific to a single VarSpriteGroupScope (action 2 scope).
virtual uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const
Get a variable value.
ResolverObject & ro
Surrounding resolver object.
All ships have this type.
Definition ship.h:32
TrackBits state
The "track" the ship is following.
Definition ship.h:34
Specialization of ResolverObject with type-safe access to RandomTriggers.
T * Next() const
Get next vehicle in the chain.
static Train * From(Vehicle *v)
T * First() const
Get the first vehicle in the chain.
Common wrapper for all the different sprite group types.
virtual ResolverResult Resolve(ResolverObject &object) const =0
Resolves a callback or rerandomisation callback to a NewGRF.
Station data structure.
Airport airport
Tile area the airport covers.
const struct SpriteGroup * cached_override
Cached wagon override spritegroup.
Definition train.h:77
uint8_t user_def_data
Cached property 0x25. Can be set by Callback 0x36.
Definition train.h:81
'Train' is either a loco or a wagon.
Definition train.h:97
RailTypes railtypes
On which rail types the train can run.
Definition train.h:108
TrackBits track
On which track the train currently is.
Definition train.h:110
VehicleRailFlags flags
Which flags has this train currently set.
Definition train.h:98
TrainCache tcache
Set of cached variables, recalculated on load and each time a vehicle is added to/removed from the co...
Definition train.h:102
uint16_t wait_counter
Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through sign...
Definition train.h:100
const struct SpriteGroup * GetFirstSpriteGroupOf(std::initializer_list< Tkey > indices) const
Get the first existing SpriteGroup from a list of options.
const SpriteGroup * GetSpriteGroup(Tkey index) const
Get the SpriteGroup at the specified index.
void SetSpriteGroup(Tkey index, const SpriteGroup *spritegroup)
Set the SpriteGroup at the specified index.
uint16_t cached_max_speed
Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
Resolver for a vehicle (chain).
VehicleScopeResolver self_scope
Scope resolver for the indicated vehicle.
ScopeResolver * GetScope(VarSpriteGroupScope scope=VarSpriteGroupScope::Self, uint8_t relative=0) override
Get a resolver for the scope.
WagonOverride
Application of 'wagon overrides'.
@ Cached
Resolve wagon overrides using TrainCache::cached_override.
@ None
Resolve no wagon overrides.
@ Uncached
Resolve wagon overrides.
@ Self
Resolve self-override (helicopter rotors and such).
VehicleScopeResolver parent_scope
Scope resolver for its parent vehicle.
GrfSpecFeature GetFeature() const override
Get the feature number being resolved for.
VehicleResolverObject(EngineID engine_type, const Vehicle *v, WagonOverride wagon_override, bool rotor_in_gui=false, CallbackID callback=CBID_NO_CALLBACK, uint32_t callback_param1=0, uint32_t callback_param2=0)
Resolver of a vehicle (chain).
const SpriteGroup * ResolveReal(const RealSpriteGroup &group) const override
Get the real sprites of the grf.
VehicleScopeResolver relative_scope
Scope resolver for an other vehicle in the chain.
uint32_t GetDebugID() const override
Get an identifier for the item being resolved.
uint8_t cached_relative_count
Relative position of the other vehicle.
Resolver for a vehicle scope.
uint32_t GetRandomTriggers() const override
Get the triggers.
bool rotor_in_gui
Helicopter rotor is drawn in GUI.
EngineID self_type
Type of the vehicle.
uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const override
Get a variable value.
uint32_t GetRandomBits() const override
Get a few random bits.
Sprite sequence for a vehicle part.
void Clear()
Clear all information.
Vehicle data structure.
Money GetDisplayProfitThisYear() const
Gets the profit vehicle had this year.
EngineID engine_type
The type of engine used for this vehicle.
int32_t z_pos
z coordinate.
Direction direction
facing
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition vehicle.cpp:748
VehicleCargoList cargo
The cargo this vehicle is carrying.
uint16_t cargo_cap
total capacity
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
uint8_t subtype
subtype (Filled with values from AircraftSubType/DisasterSubType/EffectVehicleType/GroundVehicleSubty...
uint16_t random_bits
Bits used for randomized variational spritegroups.
uint8_t day_counter
Increased by one for each day.
bool HasArticulatedPart() const
Check if an engine has an articulated part.
uint8_t breakdown_ctr
Counter for managing breakdown events.
uint8_t breakdown_delay
Counter for managing breakdown length.
bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
VehStates vehstatus
Status.
TimerGameCalendar::Date date_of_last_service_newgrf
Last calendar date the vehicle had a service at a depot, unchanged by the date cheat to protect again...
uint8_t subspeed
fractional speed
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
Vehicle * Move(int n)
Get the vehicle at offset n of this vehicle chain.
CargoType cargo_type
type of cargo this vehicle is carrying
uint8_t acceleration
used by train & aircraft
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Order current_order
The current order (+ status, like: loading).
Vehicle * Next() const
Get the next vehicle of this vehicle.
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
Money value
Value of the vehicle.
VehicleRandomTriggers waiting_random_triggers
Triggers to be yet matched before rerandomizing the random bits.
VehicleCache vcache
Cache of often used vehicle values.
uint32_t motion_counter
counter to occasionally play a vehicle sound.
NewGRFCache grf_cache
Cache of often used calculated NewGRF values.
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition vehicle.cpp:3208
virtual int GetCurrentMaxSpeed() const
Calculates the maximum speed of the vehicle under its current conditions.
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
uint16_t load_unload_ticks
Ticks to wait before starting next cycle.
Money GetDisplayProfitLastYear() const
Gets the profit vehicle had last year.
uint8_t spritenum
currently displayed sprite index 0xfd == custom sprite, 0xfe == custom second head sprite 0xff == res...
uint16_t cur_speed
current speed
uint8_t cargo_subtype
Used for livery refits (NewGRF variations).
TimerGameCalendar::Date age
Age in calendar days.
uint8_t breakdowns_since_last_service
Counter for the amount of breakdowns.
TimerGameCalendar::Date max_age
Maximum age.
uint16_t reliability
Reliability.
Vehicle * Previous() const
Get the previous vehicle of this vehicle.
uint16_t reliability_spd_dec
Reliability decrease speed.
uint8_t tick_counter
Increased by one for each tick.
TileIndex tile
Current tile index.
StationID last_station_visited
The last station we stopped at.
bool IsDrivingBackwards() const
Is this vehicle moving backwards?
void InvalidateNewGRFCacheOfChain()
Invalidates cached NewGRF variables of all vehicles in the chain (after the current vehicle).
uint8_t breakdown_chance
Current chance of breakdowns.
TimerGameCalendar::Year build_year
Year the vehicle has been built.
Owner owner
Which company owns the vehicle?
UnitID unitnumber
unit number, for display purposes only
GrfID GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition vehicle.cpp:768
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
Definition of the game-calendar-timer.
Base for the train class.
@ Reversed
Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle ...
Definition train.h:31
@ PoweredWagon
Wagon is powered.
Definition train.h:27
@ Flipped
Reverse the visible direction of the vehicle.
Definition train.h:28
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:2090
@ Hidden
Vehicle is not visible.
@ NCVV_COMPANY_INFORMATION
This bit will be set if the NewGRF var 43 currently stored is valid.
@ NCVV_CONSIST_CARGO_INFORMATION
This bit will be set if the NewGRF var 42 currently stored is valid.
@ NCVV_POSITION_CONSIST_LENGTH
This bit will be set if the NewGRF var 40 currently stored is valid.
@ NCVV_POSITION_SAME_ID_LENGTH
This bit will be set if the NewGRF var 41 currently stored is valid.
@ NCVV_POSITION_IN_VEHICLE
This bit will be set if the NewGRF var 4D currently stored is valid.
@ NCVV_END
End of the bits.
Functions related to vehicles.
@ CUSTOM_VEHICLE_SPRITENUM
Vehicle sprite from NewGRF.
@ CUSTOM_VEHICLE_SPRITENUM_REVERSED
Vehicle sprite from NewGRF with reverse driving direction (from articulation callback).
EnumBitSet< VehicleRandomTrigger, uint8_t > VehicleRandomTriggers
Bitset of VehicleRandomTrigger elements.
EngineImageType
Visualisation contexts of vehicles and engines.
@ OnMap
Vehicle drawn in viewport.
@ Ship
Ship vehicle type.
@ Effect
Effect vehicle type (smoke, explosions, sparks, bubbles).
@ Aircraft
Aircraft vehicle type.
@ Road
Road vehicle type.
@ Disaster
Disaster vehicle type.
@ Train
Train vehicle type.
VehicleRandomTrigger
Randomisation triggers for vehicles.
@ Callback32
All vehicles in consist: 32 day callback requested rerandomisation.
@ NewCargo
Affected vehicle only: Vehicle is loaded with cargo, after it was empty.
@ Depot
Front vehicle only: Consist arrived in depot.
@ AnyNewCargo
All vehicles in consist: Any vehicle in the consist received new cargo.
@ Empty
Front vehicle only: Entire consist is empty.
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.