OpenTTD Source 20260311-master-g511d3794ce
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_badge.h"
16#include "newgrf_cargo.h"
17#include "newgrf_spritegroup.h"
19#include "vehicle_func.h"
20#include "core/random_func.hpp"
22#include "aircraft.h"
23#include "station_base.h"
24#include "company_base.h"
25#include "newgrf_railtype.h"
26#include "newgrf_roadtype.h"
27#include "ship.h"
28
29#include "safeguards.h"
30
31void SetWagonOverrideSprites(EngineID engine, CargoType cargo, const SpriteGroup *group, std::span<EngineID> engine_ids)
32{
33 Engine *e = Engine::Get(engine);
34
35 assert(cargo < NUM_CARGO + 2); // Include SpriteGroupCargo::SG_DEFAULT and SpriteGroupCargo::SG_PURCHASE pseudo cargoes.
36
37 WagonOverride *wo = &e->overrides.emplace_back();
38 wo->group = group;
39 wo->cargo = cargo;
40 wo->engines.assign(engine_ids.begin(), engine_ids.end());
41}
42
43const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoType cargo, EngineID overriding_engine)
44{
45 const Engine *e = Engine::Get(engine);
46
47 for (const WagonOverride &wo : e->overrides) {
48 if (wo.cargo != cargo && wo.cargo != CargoGRFFileProps::SG_DEFAULT) continue;
49 if (std::ranges::find(wo.engines, overriding_engine) != wo.engines.end()) return wo.group;
50 }
51 return nullptr;
52}
53
54void SetCustomEngineSprites(EngineID engine, CargoType cargo, const SpriteGroup *group)
55{
56 Engine *e = Engine::Get(engine);
57
58 if (e->grf_prop.GetSpriteGroup(cargo) != nullptr) {
59 GrfMsg(6, "SetCustomEngineSprites: engine {} cargo {} already has group -- replacing", engine, cargo);
60 }
61 e->grf_prop.SetSpriteGroup(cargo, group);
62}
63
64
71void SetEngineGRF(EngineID engine, const GRFFile *file)
72{
73 Engine *e = Engine::Get(engine);
74 e->grf_prop.SetGRFFile(file);
75}
76
77
78static int MapOldSubType(const Vehicle *v)
79{
80 switch (v->type) {
81 case VEH_TRAIN:
82 if (Train::From(v)->IsEngine()) return 0;
83 if (Train::From(v)->IsFreeWagon()) return 4;
84 return 2;
85 case VEH_ROAD:
86 case VEH_SHIP: return 0;
87 case VEH_AIRCRAFT:
88 case VEH_DISASTER: return v->subtype;
89 case VEH_EFFECT: return v->subtype << 1;
90 default: NOT_REACHED();
91 }
92}
93
94
97 AMS_TTDP_HANGAR,
98 AMS_TTDP_TO_HANGAR,
99 AMS_TTDP_TO_PAD1,
100 AMS_TTDP_TO_PAD2,
101 AMS_TTDP_TO_PAD3,
102 AMS_TTDP_TO_ENTRY_2_AND_3,
103 AMS_TTDP_TO_ENTRY_2_AND_3_AND_H,
104 AMS_TTDP_TO_JUNCTION,
105 AMS_TTDP_LEAVE_RUNWAY,
106 AMS_TTDP_TO_INWAY,
107 AMS_TTDP_TO_RUNWAY,
108 AMS_TTDP_TO_OUTWAY,
109 AMS_TTDP_WAITING,
110 AMS_TTDP_TAKEOFF,
111 AMS_TTDP_TO_TAKEOFF,
112 AMS_TTDP_CLIMBING,
113 AMS_TTDP_FLIGHT_APPROACH,
114 AMS_TTDP_UNUSED_0x11,
115 AMS_TTDP_FLIGHT_TO_TOWER,
116 AMS_TTDP_UNUSED_0x13,
117 AMS_TTDP_FLIGHT_FINAL,
118 AMS_TTDP_FLIGHT_DESCENT,
119 AMS_TTDP_BRAKING,
120 AMS_TTDP_HELI_TAKEOFF_AIRPORT,
121 AMS_TTDP_HELI_TO_TAKEOFF_AIRPORT,
122 AMS_TTDP_HELI_LAND_AIRPORT,
123 AMS_TTDP_HELI_TAKEOFF_HELIPORT,
124 AMS_TTDP_HELI_TO_TAKEOFF_HELIPORT,
125 AMS_TTDP_HELI_LAND_HELIPORT,
126};
127
128
135static uint8_t MapAircraftMovementState(const Aircraft *v)
136{
137 const Station *st = GetTargetAirportIfValid(v);
138 if (st == nullptr) return AMS_TTDP_FLIGHT_TO_TOWER;
139
140 const AirportFTAClass *afc = st->airport.GetFTA();
141 AirportMovingDataFlags amdflag = afc->MovingData(v->pos)->flags;
142
143 switch (v->state) {
144 case HANGAR:
145 /* The international airport is a special case as helicopters can land in
146 * front of the hangar. Helicopters also change their air.state to
147 * AirportMovingDataFlag::HeliLower some time before actually descending. */
148
149 /* This condition only occurs for helicopters, during descent,
150 * to a landing by the hangar of an international airport. */
151 if (amdflag.Test(AirportMovingDataFlag::HeliLower)) return AMS_TTDP_HELI_LAND_AIRPORT;
152
153 /* This condition only occurs for helicopters, before starting descent,
154 * to a landing by the hangar of an international airport. */
155 if (amdflag.Test(AirportMovingDataFlag::SlowTurn)) return AMS_TTDP_FLIGHT_TO_TOWER;
156
157 /* The final two conditions apply to helicopters or aircraft.
158 * Has reached hangar? */
159 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_HANGAR;
160
161 /* Still moving towards hangar. */
162 return AMS_TTDP_TO_HANGAR;
163
164 case TERM1:
165 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_TO_PAD1;
166 return AMS_TTDP_TO_JUNCTION;
167
168 case TERM2:
169 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_TO_PAD2;
170 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
171
172 case TERM3:
173 case TERM4:
174 case TERM5:
175 case TERM6:
176 case TERM7:
177 case TERM8:
178 /* TTDPatch only has 3 terminals, so treat these states the same */
179 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_TO_PAD3;
180 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
181
182 case HELIPAD1:
183 case HELIPAD2:
184 case HELIPAD3:
185 /* Will only occur for helicopters.*/
186 if (amdflag.Test(AirportMovingDataFlag::HeliLower)) return AMS_TTDP_HELI_LAND_AIRPORT; // Descending.
187 if (amdflag.Test(AirportMovingDataFlag::SlowTurn)) return AMS_TTDP_FLIGHT_TO_TOWER; // Still hasn't started descent.
188 return AMS_TTDP_TO_JUNCTION; // On the ground.
189
190 case TAKEOFF: // Moving to takeoff position.
191 return AMS_TTDP_TO_OUTWAY;
192
193 case STARTTAKEOFF: // Accelerating down runway.
194 return AMS_TTDP_TAKEOFF;
195
196 case ENDTAKEOFF: // Ascent
197 return AMS_TTDP_CLIMBING;
198
199 case HELITAKEOFF: // Helicopter is moving to take off position.
200 if (afc->delta_z == 0) {
201 return amdflag.Test(AirportMovingDataFlag::HeliRaise) ?
202 AMS_TTDP_HELI_TAKEOFF_AIRPORT : AMS_TTDP_TO_JUNCTION;
203 } else {
204 return AMS_TTDP_HELI_TAKEOFF_HELIPORT;
205 }
206
207 case FLYING:
208 return amdflag.Test(AirportMovingDataFlag::Hold) ? AMS_TTDP_FLIGHT_APPROACH : AMS_TTDP_FLIGHT_TO_TOWER;
209
210 case LANDING: // Descent
211 return AMS_TTDP_FLIGHT_DESCENT;
212
213 case ENDLANDING: // On the runway braking
214 if (amdflag.Test(AirportMovingDataFlag::Brake)) return AMS_TTDP_BRAKING;
215 /* Landed - moving off runway */
216 return AMS_TTDP_TO_INWAY;
217
218 case HELILANDING:
219 case HELIENDLANDING: // Helicoptor is descending.
221 return afc->delta_z == 0 ?
222 AMS_TTDP_HELI_LAND_AIRPORT : AMS_TTDP_HELI_LAND_HELIPORT;
223 } else {
224 return AMS_TTDP_FLIGHT_TO_TOWER;
225 }
226
227 default:
228 return AMS_TTDP_HANGAR;
229 }
230}
231
232
235 AMA_TTDP_IN_HANGAR,
236 AMA_TTDP_ON_PAD1,
237 AMA_TTDP_ON_PAD2,
238 AMA_TTDP_ON_PAD3,
239 AMA_TTDP_HANGAR_TO_PAD1,
240 AMA_TTDP_HANGAR_TO_PAD2,
241 AMA_TTDP_HANGAR_TO_PAD3,
242 AMA_TTDP_LANDING_TO_PAD1,
243 AMA_TTDP_LANDING_TO_PAD2,
244 AMA_TTDP_LANDING_TO_PAD3,
245 AMA_TTDP_PAD1_TO_HANGAR,
246 AMA_TTDP_PAD2_TO_HANGAR,
247 AMA_TTDP_PAD3_TO_HANGAR,
248 AMA_TTDP_PAD1_TO_TAKEOFF,
249 AMA_TTDP_PAD2_TO_TAKEOFF,
250 AMA_TTDP_PAD3_TO_TAKEOFF,
251 AMA_TTDP_HANGAR_TO_TAKEOFF,
252 AMA_TTDP_LANDING_TO_HANGAR,
253 AMA_TTDP_IN_FLIGHT,
254};
255
256
264static uint8_t MapAircraftMovementAction(const Aircraft *v)
265{
266 switch (v->state) {
267 case HANGAR:
268 return (v->cur_speed > 0) ? AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_IN_HANGAR;
269
270 case TERM1:
271 case HELIPAD1:
272 return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD1 : AMA_TTDP_LANDING_TO_PAD1;
273
274 case TERM2:
275 case HELIPAD2:
276 return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD2 : AMA_TTDP_LANDING_TO_PAD2;
277
278 case TERM3:
279 case TERM4:
280 case TERM5:
281 case TERM6:
282 case TERM7:
283 case TERM8:
284 case HELIPAD3:
285 return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD3 : AMA_TTDP_LANDING_TO_PAD3;
286
287 case TAKEOFF: // Moving to takeoff position
288 case STARTTAKEOFF: // Accelerating down runway
289 case ENDTAKEOFF: // Ascent
290 case HELITAKEOFF:
291 /* @todo Need to find which terminal (or hangar) we've come from. How? */
292 return AMA_TTDP_PAD1_TO_TAKEOFF;
293
294 case FLYING:
295 return AMA_TTDP_IN_FLIGHT;
296
297 case LANDING: // Descent
298 case ENDLANDING: // On the runway braking
299 case HELILANDING:
300 case HELIENDLANDING:
301 /* @todo Need to check terminal we're landing to. Is it known yet? */
302 return (v->current_order.IsType(OT_GOTO_DEPOT)) ?
303 AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_LANDING_TO_PAD1;
304
305 default:
306 return AMA_TTDP_IN_HANGAR;
307 }
308}
309
310
311/* virtual */ uint32_t VehicleScopeResolver::GetRandomBits() const
312{
313 return this->v == nullptr ? 0 : this->v->random_bits;
314}
315
316/* virtual */ uint32_t VehicleScopeResolver::GetRandomTriggers() const
317{
318 return this->v == nullptr ? 0 : this->v->waiting_random_triggers.base();
319}
320
321
323{
324 switch (scope) {
325 case VSG_SCOPE_SELF: return &this->self_scope;
326 case VSG_SCOPE_PARENT: return &this->parent_scope;
327 case VSG_SCOPE_RELATIVE: {
328 int32_t count = GB(relative, 0, 4);
329 if (this->self_scope.v != nullptr && (relative != this->cached_relative_count || count == 0)) {
330 /* Note: This caching only works as long as the VSG_SCOPE_RELATIVE cannot be used in
331 * VarAct2 with procedure calls. */
332 if (count == 0) count = this->GetRegister(0x100);
333
334 const Vehicle *v = nullptr;
335 switch (GB(relative, 6, 2)) {
336 default: NOT_REACHED();
337 case 0x00: // count back (away from the engine), starting at this vehicle
338 v = this->self_scope.v;
339 break;
340 case 0x01: // count forward (toward the engine), starting at this vehicle
341 v = this->self_scope.v;
342 count = -count;
343 break;
344 case 0x02: // count back, starting at the engine
345 v = this->parent_scope.v;
346 break;
347 case 0x03: { // count back, starting at the first vehicle in this chain of vehicles with the same ID, as for vehicle variable 41
348 const Vehicle *self = this->self_scope.v;
349 for (const Vehicle *u = self->First(); u != self; u = u->Next()) {
350 if (u->engine_type != self->engine_type) {
351 v = nullptr;
352 } else {
353 if (v == nullptr) v = u;
354 }
355 }
356 if (v == nullptr) v = self;
357 break;
358 }
359 }
360 this->relative_scope.SetVehicle(v->Move(count));
361 }
362 return &this->relative_scope;
363 }
364 default: return ResolverObject::GetScope(scope, relative);
365 }
366}
367
377static const Livery *LiveryHelper(EngineID engine, const Vehicle *v)
378{
379 const Livery *l;
380
381 if (v == nullptr) {
382 if (!Company::IsValidID(_current_company)) return nullptr;
383 l = GetEngineLivery(engine, _current_company, EngineID::Invalid(), nullptr, LIT_ALL);
384 } else if (v->IsGroundVehicle()) {
386 } else {
387 l = GetEngineLivery(v->engine_type, v->owner, EngineID::Invalid(), v, LIT_ALL);
388 }
389
390 return l;
391}
392
400static uint32_t PositionHelper(const Vehicle *v, bool consecutive)
401{
402 const Vehicle *u;
403 uint8_t chain_before = 0;
404 uint8_t chain_after = 0;
405
406 for (u = v->First(); u != v; u = u->Next()) {
407 chain_before++;
408 if (consecutive && u->engine_type != v->engine_type) chain_before = 0;
409 }
410
411 while (u->Next() != nullptr && (!consecutive || u->Next()->engine_type == v->engine_type)) {
412 chain_after++;
413 u = u->Next();
414 }
415
416 return chain_before | chain_after << 8 | (chain_before + chain_after + consecutive) << 16;
417}
418
419static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, uint8_t variable, uint32_t parameter, bool &available)
420{
421 /* Calculated vehicle parameters */
422 switch (variable) {
423 case 0x25: // Get engine GRF ID
424 return v->GetGRFID();
425
426 case 0x40: // Get length of consist
430 }
432
433 case 0x41: // Get length of same consecutive wagons
437 }
439
440 case 0x42: { // Consist cargo information
442 std::array<uint8_t, NUM_CARGO> common_cargoes{};
443 uint8_t cargo_classes = 0;
444 uint8_t user_def_data = 0;
445
446 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
447 if (v->type == VEH_TRAIN) user_def_data |= Train::From(u)->tcache.user_def_data;
448
449 /* Skip empty engines */
450 if (!u->GetEngine()->CanCarryCargo()) continue;
451
452 cargo_classes |= CargoSpec::Get(u->cargo_type)->classes.base();
453 common_cargoes[u->cargo_type]++;
454 }
455
456 /* Pick the most common cargo type */
457 auto cargo_it = std::max_element(std::begin(common_cargoes), std::end(common_cargoes));
458 /* Return INVALID_CARGO if nothing is carried */
459 CargoType common_cargo_type = (*cargo_it == 0) ? INVALID_CARGO : static_cast<CargoType>(std::distance(std::begin(common_cargoes), cargo_it));
460
461 /* Count subcargo types of common_cargo_type */
462 std::array<uint8_t, UINT8_MAX + 1> common_subtypes{};
463 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
464 /* Skip empty engines and engines not carrying common_cargo_type */
465 if (u->cargo_type != common_cargo_type || !u->GetEngine()->CanCarryCargo()) continue;
466
467 common_subtypes[u->cargo_subtype]++;
468 }
469
470 /* Pick the most common subcargo type*/
471 auto subtype_it = std::max_element(std::begin(common_subtypes), std::end(common_subtypes));
472 /* Return UINT8_MAX if nothing is carried */
473 uint8_t common_subtype = (*subtype_it == 0) ? UINT8_MAX : static_cast<uint8_t>(std::distance(std::begin(common_subtypes), subtype_it));
474
475 /* Note: We have to store the untranslated cargotype in the cache as the cache can be read by different NewGRFs,
476 * which will need different translations */
477 v->grf_cache.consist_cargo_information = cargo_classes | (common_cargo_type << 8) | (common_subtype << 16) | (user_def_data << 24);
479 }
480
481 /* The cargo translation is specific to the accessing GRF, and thus cannot be cached. */
482 CargoType common_cargo_type = (v->grf_cache.consist_cargo_information >> 8) & 0xFF;
483
484 /* Note:
485 * - Unlike everywhere else the cargo translation table is only used since grf version 8, not 7.
486 * - For translating the cargo type we need to use the GRF which is resolving the variable, which
487 * is object->ro.grffile.
488 * In case of CBID_TRAIN_ALLOW_WAGON_ATTACH this is not the same as v->GetGRF().
489 * - The grffile == nullptr case only happens if this function is called for default vehicles.
490 * And this is only done by CheckCaches().
491 */
492 const GRFFile *grffile = object->ro.grffile;
493 uint8_t common_bitnum = (common_cargo_type == INVALID_CARGO) ? 0xFF :
494 (grffile == nullptr || grffile->grf_version < 8) ? CargoSpec::Get(common_cargo_type)->bitnum : grffile->cargo_map[common_cargo_type];
495
496 return (v->grf_cache.consist_cargo_information & 0xFFFF00FF) | common_bitnum << 8;
497 }
498
499 case 0x43: // Company information
503 }
505
506 case 0x44: // Aircraft information
507 if (v->type != VEH_AIRCRAFT || !Aircraft::From(v)->IsNormalAircraft()) return UINT_MAX;
508
509 {
510 const Vehicle *w = v->Next();
511 assert(w != nullptr);
512 uint16_t altitude = ClampTo<uint16_t>(v->z_pos - w->z_pos); // Aircraft height - shadow height
513 uint8_t airporttype = ATP_TTDP_LARGE;
514
516
517 if (st != nullptr && st->airport.tile != INVALID_TILE) {
518 airporttype = st->airport.GetSpec()->ttd_airport_type;
519 }
520
521 return (ClampTo<uint8_t>(altitude) << 8) | airporttype;
522 }
523
524 case 0x45: { // Curvature info
525 /* Format: xxxTxBxF
526 * F - previous wagon to current wagon, 0 if vehicle is first
527 * B - current wagon to next wagon, 0 if wagon is last
528 * T - previous wagon to next wagon, 0 in an S-bend
529 */
530 if (!v->IsGroundVehicle()) return 0;
531
532 const Vehicle *u_p = v->Previous();
533 const Vehicle *u_n = v->Next();
534 DirDiff f = (u_p == nullptr) ? DIRDIFF_SAME : DirDifference(u_p->direction, v->direction);
535 DirDiff b = (u_n == nullptr) ? DIRDIFF_SAME : DirDifference(v->direction, u_n->direction);
536 DirDiff t = ChangeDirDiff(f, b);
537
538 return ((t > DIRDIFF_REVERSE ? t | 8 : t) << 16) |
539 ((b > DIRDIFF_REVERSE ? b | 8 : b) << 8) |
540 ( f > DIRDIFF_REVERSE ? f | 8 : f);
541 }
542
543 case 0x46: // Motion counter
544 return v->motion_counter;
545
546 case 0x47: { // Vehicle cargo info
547 /* Format: ccccwwtt
548 * tt - the cargo type transported by the vehicle,
549 * translated if a translation table has been installed.
550 * ww - cargo unit weight in 1/16 tons, same as cargo prop. 0F.
551 * cccc - the cargo class value of the cargo transported by the vehicle.
552 */
553 const CargoSpec *cs = CargoSpec::Get(v->cargo_type);
554
555 /* Note:
556 * For translating the cargo type we need to use the GRF which is resolving the variable, which
557 * is object->ro.grffile.
558 * In case of CBID_TRAIN_ALLOW_WAGON_ATTACH this is not the same as v->GetGRF().
559 */
560 return (cs->classes.base() << 16) | (cs->weight << 8) | object->ro.grffile->cargo_map[v->cargo_type];
561 }
562
563 case 0x48: return v->GetEngine()->flags.base(); // Vehicle Type Info
564 case 0x49: return v->build_year.base();
565
566 case 0x4A:
567 switch (v->type) {
568 case VEH_TRAIN: {
570 const RailTypeInfo *rti = GetRailTypeInfo(rt);
571 return (rti->flags.Test(RailTypeFlag::Catenary) ? 0x200 : 0) |
572 (HasPowerOnRail(Train::From(v)->railtypes, rt) ? 0x100 : 0) |
574 }
575
576 case VEH_ROAD: {
577 RoadType rt = GetRoadType(v->tile, GetRoadTramType(RoadVehicle::From(v)->roadtype));
578 const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
579 return (rti->flags.Test(RoadTypeFlag::Catenary) ? 0x200 : 0) |
580 0x100 |
582 }
583
584 default:
585 return 0;
586 }
587
588 case 0x4B: // Long date of last service
589 return v->date_of_last_service_newgrf.base();
590
591 case 0x4C: // Current maximum speed in NewGRF units
592 if (!v->IsPrimaryVehicle()) return 0;
593 return v->GetCurrentMaxSpeed();
594
595 case 0x4D: // Position within articulated vehicle
597 uint8_t artic_before = 0;
598 for (const Vehicle *u = v; u->IsArticulatedPart(); u = u->Previous()) artic_before++;
599 uint8_t artic_after = 0;
600 for (const Vehicle *u = v; u->HasArticulatedPart(); u = u->Next()) artic_after++;
601 v->grf_cache.position_in_vehicle = artic_before | artic_after << 8;
603 }
605
606 /* Variables which use the parameter */
607 case 0x60: // Count consist's engine ID occurrence
608 if (v->type != VEH_TRAIN) return v->GetEngine()->grf_prop.local_id == parameter ? 1 : 0;
609
610 {
611 uint count = 0;
612 for (; v != nullptr; v = v->Next()) {
613 if (v->GetEngine()->grf_prop.local_id == parameter) count++;
614 }
615 return count;
616 }
617
618 case 0x61: // Get variable of n-th vehicle in chain [signed number relative to vehicle]
619 if (!v->IsGroundVehicle() || parameter == 0x61) {
620 /* Not available */
621 break;
622 }
623
624 /* Only allow callbacks that don't change properties to avoid circular dependencies. */
628 Vehicle *u = v->Move(object->ro.GetRegister(0x10F));
629 if (u == nullptr) return 0; // available, but zero
630
631 if (parameter == 0x5F) {
632 /* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */
633 return (u->random_bits << 8) | u->waiting_random_triggers.base();
634 } else {
635 return VehicleGetVariable(u, object, parameter, object->ro.GetRegister(0x10E), available);
636 }
637 }
638 /* Not available */
639 break;
640
641 case 0x62: { // Curvature/position difference for n-th vehicle in chain [signed number relative to vehicle]
642 /* Format: zzyyxxFD
643 * zz - Signed difference of z position between the selected and this vehicle.
644 * yy - Signed difference of y position between the selected and this vehicle.
645 * xx - Signed difference of x position between the selected and this vehicle.
646 * F - Flags, bit 7 corresponds to VehState::Hidden.
647 * D - Dir difference, like in 0x45.
648 */
649 if (!v->IsGroundVehicle()) return 0;
650
651 const Vehicle *u = v->Move((int8_t)parameter);
652 if (u == nullptr) return 0;
653
654 /* Get direction difference. */
655 bool prev = (int8_t)parameter < 0;
656 uint32_t ret = prev ? DirDifference(u->direction, v->direction) : DirDifference(v->direction, u->direction);
657 if (ret > DIRDIFF_REVERSE) ret |= 0x08;
658
659 if (u->vehstatus.Test(VehState::Hidden)) ret |= 0x80;
660
661 /* Get position difference. */
662 ret |= ((prev ? u->x_pos - v->x_pos : v->x_pos - u->x_pos) & 0xFF) << 8;
663 ret |= ((prev ? u->y_pos - v->y_pos : v->y_pos - u->y_pos) & 0xFF) << 16;
664 ret |= ((prev ? u->z_pos - v->z_pos : v->z_pos - u->z_pos) & 0xFF) << 24;
665
666 return ret;
667 }
668
669 case 0x63:
670 /* Tile compatibility wrt. arbitrary track-type
671 * Format:
672 * bit 0: Type 'parameter' is known.
673 * bit 1: Engines with type 'parameter' are compatible with this tile.
674 * bit 2: Engines with type 'parameter' are powered on this tile.
675 * bit 3: This tile has type 'parameter' or it is considered equivalent (alternate labels).
676 */
677 switch (v->type) {
678 case VEH_TRAIN: {
679 RailType param_type = GetRailTypeTranslation(parameter, object->ro.grffile);
680 if (param_type == INVALID_RAILTYPE) return 0x00;
681 RailType tile_type = GetTileRailType(v->tile);
682 if (tile_type == param_type) return 0x0F;
683 return (HasPowerOnRail(param_type, tile_type) ? 0x04 : 0x00) |
684 (IsCompatibleRail(param_type, tile_type) ? 0x02 : 0x00) |
685 0x01;
686 }
687 case VEH_ROAD: {
688 RoadTramType rtt = GetRoadTramType(RoadVehicle::From(v)->roadtype);
689 RoadType param_type = GetRoadTypeTranslation(rtt, parameter, object->ro.grffile);
690 if (param_type == INVALID_ROADTYPE) return 0x00;
691 RoadType tile_type = GetRoadType(v->tile, rtt);
692 if (tile_type == param_type) return 0x0F;
693 return (HasPowerOnRoad(param_type, tile_type) ? 0x06 : 0x00) |
694 0x01;
695 }
696 default: return 0x00;
697 }
698
699 case 0x64: { // Count consist's badge ID occurrence
700 if (v->type != VEH_TRAIN) return GetBadgeVariableResult(*object->ro.grffile, v->GetEngine()->badges, parameter);
701
702 /* Look up badge index. */
703 if (parameter >= std::size(object->ro.grffile->badge_list)) return UINT_MAX;
704 BadgeID index = object->ro.grffile->badge_list[parameter];
705
706 /* Count number of vehicles that contain this badge index. */
707 uint count = 0;
708 for (; v != nullptr; v = v->Next()) {
709 const auto &badges = v->GetEngine()->badges;
710 if (std::ranges::find(badges, index) != std::end(badges)) count++;
711 }
712
713 return count;
714 }
715
716 case 0x65:
717 if (v->type == VEH_TRAIN) {
718 RailType rt = GetRailType(v->tile);
719 return GetBadgeVariableResult(*object->ro.grffile, GetRailTypeInfo(rt)->badges, parameter);
720 }
721 if (v->type == VEH_ROAD) {
722 RoadType rt = GetRoadType(v->tile, GetRoadTramType(RoadVehicle::From(v)->roadtype));
723 return GetBadgeVariableResult(*object->ro.grffile, GetRoadTypeInfo(rt)->badges, parameter);
724 }
725 return UINT_MAX;
726
727 case 0x7A: return GetBadgeVariableResult(*object->ro.grffile, v->GetEngine()->badges, parameter);
728
729 case 0xFE:
730 case 0xFF: {
731 uint16_t modflags = 0;
732
733 if (v->type == VEH_TRAIN) {
734 const Train *t = Train::From(v);
735 bool is_powered_wagon = t->flags.Test(VehicleRailFlag::PoweredWagon);
736 const Train *u = is_powered_wagon ? t->First() : t; // for powered wagons the engine defines the type of engine (i.e. railtype)
737 RailType railtype = GetRailType(v->tile);
738 bool powered = t->IsEngine() || is_powered_wagon;
739 bool has_power = HasPowerOnRail(u->railtypes, railtype);
740
741 if (powered && has_power) SetBit(modflags, 5);
742 if (powered && !has_power) SetBit(modflags, 6);
743 if (t->flags.Test(VehicleRailFlag::Reversed)) SetBit(modflags, 8);
744 }
747
748 return variable == 0xFE ? modflags : GB(modflags, 8, 8);
749 }
750 }
751
752 /*
753 * General vehicle properties
754 *
755 * Some parts of the TTD Vehicle structure are omitted for various reasons
756 * (see http://marcin.ttdpatch.net/sv1codec/TTD-locations.html#_VehicleArray)
757 */
758 switch (variable - 0x80) {
759 case 0x00: return v->type + 0x10;
760 case 0x01: return MapOldSubType(v);
761 case 0x02: break; // not implemented
762 case 0x03: break; // not implemented
763 case 0x04: return v->index.base();
764 case 0x05: return GB(v->index.base(), 8, 8);
765 case 0x06: break; // not implemented
766 case 0x07: break; // not implemented
767 case 0x08: break; // not implemented
768 case 0x09: break; // not implemented
769 case 0x0A: return v->current_order.MapOldOrder();
770 case 0x0B: return v->current_order.GetDestination().value;
771 case 0x0C: return v->GetNumOrders();
772 case 0x0D: return v->cur_real_order_index;
773 case 0x0E: break; // not implemented
774 case 0x0F: break; // not implemented
775 case 0x10:
776 case 0x11: {
777 uint ticks;
778 if (v->current_order.IsType(OT_LOADING)) {
779 ticks = v->load_unload_ticks;
780 } else {
781 switch (v->type) {
782 case VEH_TRAIN: ticks = Train::From(v)->wait_counter; break;
783 case VEH_AIRCRAFT: ticks = Aircraft::From(v)->turn_counter; break;
784 default: ticks = 0; break;
785 }
786 }
787 return (variable - 0x80) == 0x10 ? ticks : GB(ticks, 8, 8);
788 }
791 case 0x14: return v->GetServiceInterval();
792 case 0x15: return GB(v->GetServiceInterval(), 8, 8);
793 case 0x16: return v->last_station_visited.base();
794 case 0x17: return v->tick_counter;
795 case 0x18:
796 case 0x19: {
797 uint max_speed;
798 switch (v->type) {
799 case VEH_AIRCRAFT:
800 max_speed = Aircraft::From(v)->GetSpeedOldUnits(); // Convert to old units.
801 break;
802
803 default:
804 max_speed = v->vcache.cached_max_speed;
805 break;
806 }
807 return (variable - 0x80) == 0x18 ? max_speed : GB(max_speed, 8, 8);
808 }
809 case 0x1A: return v->x_pos;
810 case 0x1B: return GB(v->x_pos, 8, 8);
811 case 0x1C: return v->y_pos;
812 case 0x1D: return GB(v->y_pos, 8, 8);
813 case 0x1E: return v->z_pos;
814 case 0x1F: return object->rotor_in_gui ? DIR_W : v->direction; // for rotors the spriteset contains animation frames, so NewGRF need a different way to tell the helicopter orientation.
815 case 0x20: break; // not implemented
816 case 0x21: break; // not implemented
817 case 0x22: break; // not implemented
818 case 0x23: break; // not implemented
819 case 0x24: break; // not implemented
820 case 0x25: break; // not implemented
821 case 0x26: break; // not implemented
822 case 0x27: break; // not implemented
823 case 0x28: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
824 case 0x29: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
825 case 0x2A: break; // not implemented
826 case 0x2B: break; // not implemented
827 case 0x2C: break; // not implemented
828 case 0x2D: break; // not implemented
829 case 0x2E: break; // not implemented
830 case 0x2F: break; // not implemented
831 case 0x30: break; // not implemented
832 case 0x31: break; // not implemented
833 case 0x32: return v->vehstatus.base();
834 case 0x33: return 0; // non-existent high byte of vehstatus
835 case 0x34: return v->type == VEH_AIRCRAFT ? (v->cur_speed * 10) / 128 : v->cur_speed;
836 case 0x35: return GB(v->type == VEH_AIRCRAFT ? (v->cur_speed * 10) / 128 : v->cur_speed, 8, 8);
837 case 0x36: return v->subspeed;
838 case 0x37: return v->acceleration;
839 case 0x38: break; // not implemented
840 case 0x39: return v->cargo_type;
841 case 0x3A: return v->cargo_cap;
842 case 0x3B: return GB(v->cargo_cap, 8, 8);
843 case 0x3C: return ClampTo<uint16_t>(v->cargo.StoredCount());
844 case 0x3D: return GB(ClampTo<uint16_t>(v->cargo.StoredCount()), 8, 8);
845 case 0x3E: return v->cargo.GetFirstStation().base();
846 case 0x3F: return ClampTo<uint8_t>(v->cargo.PeriodsInTransit());
847 case 0x40: return ClampTo<uint16_t>(v->age);
848 case 0x41: return GB(ClampTo<uint16_t>(v->age), 8, 8);
849 case 0x42: return ClampTo<uint16_t>(v->max_age);
850 case 0x43: return GB(ClampTo<uint16_t>(v->max_age), 8, 8);
852 case 0x45: return v->unitnumber;
853 case 0x46: return v->GetEngine()->grf_prop.local_id;
854 case 0x47: return GB(v->GetEngine()->grf_prop.local_id, 8, 8);
855 case 0x48:
856 if (v->type != VEH_TRAIN || v->spritenum != CUSTOM_VEHICLE_SPRITENUM) return v->spritenum;
858
859 case 0x49: return v->day_counter;
860 case 0x4A: return v->breakdowns_since_last_service;
861 case 0x4B: return v->breakdown_ctr;
862 case 0x4C: return v->breakdown_delay;
863 case 0x4D: return v->breakdown_chance;
864 case 0x4E: return v->reliability;
865 case 0x4F: return GB(v->reliability, 8, 8);
866 case 0x50: return v->reliability_spd_dec;
867 case 0x51: return GB(v->reliability_spd_dec, 8, 8);
868 case 0x52: return ClampTo<int32_t>(v->GetDisplayProfitThisYear());
869 case 0x53: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 8, 24);
870 case 0x54: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 16, 16);
871 case 0x55: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 24, 8);
872 case 0x56: return ClampTo<int32_t>(v->GetDisplayProfitLastYear());
873 case 0x57: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 8, 24);
874 case 0x58: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 16, 16);
875 case 0x59: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 24, 8);
876 case 0x5A: return (v->Next() == nullptr ? VehicleID::Invalid() : v->Next()->index).base();
877 case 0x5B: break; // not implemented
878 case 0x5C: return ClampTo<int32_t>(v->value);
879 case 0x5D: return GB(ClampTo<int32_t>(v->value), 8, 24);
880 case 0x5E: return GB(ClampTo<int32_t>(v->value), 16, 16);
881 case 0x5F: return GB(ClampTo<int32_t>(v->value), 24, 8);
882 case 0x60: break; // not implemented
883 case 0x61: break; // not implemented
884 case 0x62: break; // vehicle specific, see below
885 case 0x63: break; // not implemented
886 case 0x64: break; // vehicle specific, see below
887 case 0x65: break; // vehicle specific, see below
888 case 0x66: break; // vehicle specific, see below
889 case 0x67: break; // vehicle specific, see below
890 case 0x68: break; // vehicle specific, see below
891 case 0x69: break; // vehicle specific, see below
892 case 0x6A: break; // not implemented
893 case 0x6B: break; // not implemented
894 case 0x6C: break; // not implemented
895 case 0x6D: break; // not implemented
896 case 0x6E: break; // not implemented
897 case 0x6F: break; // not implemented
898 case 0x70: break; // not implemented
899 case 0x71: break; // not implemented
900 case 0x72: return v->cargo_subtype;
901 case 0x73: break; // vehicle specific, see below
902 case 0x74: break; // vehicle specific, see below
903 case 0x75: break; // vehicle specific, see below
904 case 0x76: break; // vehicle specific, see below
905 case 0x77: break; // vehicle specific, see below
906 case 0x78: break; // not implemented
907 case 0x79: break; // not implemented
908 case 0x7A: return v->random_bits;
909 case 0x7B: return v->waiting_random_triggers.base();
910 case 0x7C: break; // vehicle specific, see below
911 case 0x7D: break; // vehicle specific, see below
912 case 0x7E: break; // not implemented
913 case 0x7F: break; // vehicle specific, see below
914 }
915
916 /* Vehicle specific properties */
917 switch (v->type) {
918 case VEH_TRAIN: {
919 Train *t = Train::From(v);
920 switch (variable - 0x80) {
921 case 0x62: return t->track;
922 case 0x66: return t->railtypes.GetNthSetBit(0).value_or(RailType::INVALID_RAILTYPE);
923 case 0x73: return 0x80 + VEHICLE_LENGTH - t->gcache.cached_veh_length;
924 case 0x74: return t->gcache.cached_power;
925 case 0x75: return GB(t->gcache.cached_power, 8, 24);
926 case 0x76: return GB(t->gcache.cached_power, 16, 16);
927 case 0x77: return GB(t->gcache.cached_power, 24, 8);
928 case 0x7C: return t->First()->index.base();
929 case 0x7D: return GB(t->First()->index.base(), 8, 8);
930 case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
931 }
932 break;
933 }
934
935 case VEH_ROAD: {
937 switch (variable - 0x80) {
938 case 0x62: return rv->state;
939 case 0x64: return rv->blocked_ctr;
940 case 0x65: return GB(rv->blocked_ctr, 8, 8);
941 case 0x66: return rv->overtaking;
942 case 0x67: return rv->overtaking_ctr;
943 case 0x68: return rv->crashed_ctr;
944 case 0x69: return GB(rv->crashed_ctr, 8, 8);
945 }
946 break;
947 }
948
949 case VEH_SHIP: {
950 Ship *s = Ship::From(v);
951 switch (variable - 0x80) {
952 case 0x62: return s->state;
953 }
954 break;
955 }
956
957 case VEH_AIRCRAFT: {
958 Aircraft *a = Aircraft::From(v);
959 switch (variable - 0x80) {
960 case 0x62: return MapAircraftMovementState(a); // Current movement state
961 case 0x63: return a->targetairport.base(); // Airport to which the action refers
962 case 0x66: return MapAircraftMovementAction(a); // Current movement action
963 }
964 break;
965 }
966
967 default: break;
968 }
969
970 Debug(grf, 1, "Unhandled vehicle variable 0x{:X}, type 0x{:X}", variable, (uint)v->type);
971
972 available = false;
973 return UINT_MAX;
974}
975
976/* virtual */ uint32_t VehicleScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
977{
978 if (this->v == nullptr) {
979 /* Vehicle does not exist, so we're in a purchase list */
980 switch (variable) {
981 case 0x43: return GetCompanyInfo(_current_company, LiveryHelper(this->self_type, nullptr)); // Owner information
982 case 0x46: return 0; // Motion counter
983 case 0x47: { // Vehicle cargo info
984 const Engine *e = Engine::Get(this->self_type);
985 CargoType cargo_type = e->GetDefaultCargoType();
986 if (IsValidCargoType(cargo_type)) {
987 const CargoSpec *cs = CargoSpec::Get(cargo_type);
988 return (cs->classes.base() << 16) | (cs->weight << 8) | this->ro.grffile->cargo_map[cargo_type];
989 } else {
990 return 0x000000FF;
991 }
992 }
993 case 0x48: return Engine::Get(this->self_type)->flags.base(); // Vehicle Type Info
994 case 0x49: return TimerGameCalendar::year.base(); // 'Long' format build year
995 case 0x4B: return TimerGameCalendar::date.base(); // Long date of last service
996
997 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, Engine::Get(this->self_type)->badges, parameter);
998
1002 case 0xC6: return Engine::Get(this->self_type)->grf_prop.local_id;
1003 case 0xC7: return GB(Engine::Get(this->self_type)->grf_prop.local_id, 8, 8);
1004 case 0xDA: return VehicleID::Invalid().base(); // Next vehicle
1005 case 0xF2: return 0; // Cargo subtype
1006 }
1007
1008 available = false;
1009 return UINT_MAX;
1010 }
1011
1012 return VehicleGetVariable(const_cast<Vehicle*>(this->v), this, variable, parameter, available);
1013}
1014
1015
1017{
1018 const Vehicle *v = this->self_scope.v;
1019
1020 if (v == nullptr) {
1021 if (!group.loading.empty()) return group.loading[0];
1022 if (!group.loaded.empty()) return group.loaded[0];
1023 return nullptr;
1024 }
1025
1026 const Order &order = v->First()->current_order;
1027 bool not_loading = order.GetUnloadType() == OrderUnloadType::NoUnload && order.GetLoadType() == OrderLoadType::NoLoad;
1028 bool in_motion = !order.IsType(OT_LOADING) || not_loading;
1029
1030 uint totalsets = static_cast<uint>(in_motion ? group.loaded.size() : group.loading.size());
1031
1032 if (totalsets == 0) return nullptr;
1033
1034 uint set = (v->cargo.StoredCount() * totalsets) / std::max<uint16_t>(1u, v->cargo_cap);
1035 set = std::min(set, totalsets - 1);
1036
1037 return in_motion ? group.loaded[set] : group.loading[set];
1038}
1039
1041{
1042 switch (Engine::Get(this->self_scope.self_type)->type) {
1043 case VEH_TRAIN: return GSF_TRAINS;
1044 case VEH_ROAD: return GSF_ROADVEHICLES;
1045 case VEH_SHIP: return GSF_SHIPS;
1046 case VEH_AIRCRAFT: return GSF_AIRCRAFT;
1047 default: return GSF_INVALID;
1048 }
1049}
1050
1052{
1053 return Engine::Get(this->self_scope.self_type)->grf_prop.local_id;
1054}
1055
1061static const GRFFile *GetEngineGrfFile(EngineID engine_type)
1062{
1063 const Engine *e = Engine::Get(engine_type);
1064 return (e != nullptr) ? e->GetGRF() : nullptr;
1065}
1066
1077VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle *v, WagonOverride wagon_override, bool rotor_in_gui,
1079 : SpecializedResolverObject<VehicleRandomTriggers>(GetEngineGrfFile(engine_type), callback, callback_param1, callback_param2),
1080 self_scope(*this, engine_type, v, rotor_in_gui),
1081 parent_scope(*this, engine_type, ((v != nullptr) ? v->First() : v), rotor_in_gui),
1082 relative_scope(*this, engine_type, v, rotor_in_gui),
1084{
1085 if (wagon_override == WO_SELF) {
1086 this->root_spritegroup = GetWagonOverrideSpriteSet(engine_type, CargoGRFFileProps::SG_DEFAULT, engine_type);
1087 } else {
1088 if (wagon_override != WO_NONE && v != nullptr && v->IsGroundVehicle()) {
1089 assert(v->engine_type == engine_type); // overrides make little sense with fake scopes
1090
1091 /* For trains we always use cached value, except for callbacks because the override spriteset
1092 * to use may be different than the one cached. It happens for callback 0x15 (refit engine),
1093 * as v->cargo_type is temporary changed to the new type */
1094 if (wagon_override == WO_CACHED && v->type == VEH_TRAIN) {
1096 } else {
1097 this->root_spritegroup = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->GetGroundVehicleCache()->first_engine);
1098 }
1099 }
1100
1101 if (this->root_spritegroup == nullptr) {
1102 const Engine *e = Engine::Get(engine_type);
1103 CargoType cargo = v != nullptr ? v->cargo_type : CargoGRFFileProps::SG_PURCHASE;
1105 }
1106 }
1107}
1108
1109static void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result)
1110{
1112 result->Clear();
1113
1114 bool sprite_stack = EngInfo(engine)->misc_flags.Test(EngineMiscFlag::SpriteStack);
1115 uint max_stack = sprite_stack ? static_cast<uint>(std::size(result->seq)) : 1;
1116 for (uint stack = 0; stack < max_stack; ++stack) {
1117 object.callback_param1 = image_type | (stack << 8);
1118 const auto *group = object.Resolve<ResultSpriteGroup>();
1119 int32_t reg100 = sprite_stack ? object.GetRegister(0x100) : 0;
1120 if (group != nullptr && group->num_sprites != 0) {
1121 result->seq[result->count].sprite = group->sprite + (direction % group->num_sprites);
1122 result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring
1123 result->count++;
1124 }
1125 if (!HasBit(reg100, 31)) break;
1126 }
1127}
1128
1129void GetCustomVehicleSprite(const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result)
1130{
1131 GetCustomEngineSprite(v->engine_type, v, direction, image_type, result);
1132}
1133
1134void GetCustomVehicleIcon(EngineID engine, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result)
1135{
1136 GetCustomEngineSprite(engine, nullptr, direction, image_type, result);
1137}
1138
1139static void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result)
1140{
1141 const Engine *e = Engine::Get(engine);
1142
1143 /* Only valid for helicopters */
1144 assert(e->type == VEH_AIRCRAFT);
1145 assert(!(e->VehInfo<AircraftVehicleInfo>().subtype & AIR_CTOL));
1146
1147 /* We differ from TTDPatch by resolving the sprite using the primary vehicle 'v', and not using the rotor vehicle 'v->Next()->Next()'.
1148 * TTDPatch copies some variables between the vehicles each time, to somehow synchronize the rotor vehicle with the primary vehicle.
1149 * We use 'rotor_in_gui' to replicate when the variables differ.
1150 * But some other variables like 'rotor state' and 'rotor speed' are not available in OpenTTD, while they are in TTDPatch. */
1151 bool rotor_in_gui = image_type != EIT_ON_MAP;
1153 result->Clear();
1154 uint rotor_pos = v == nullptr || rotor_in_gui ? 0 : v->Next()->Next()->state;
1155
1156 bool sprite_stack = e->info.misc_flags.Test(EngineMiscFlag::SpriteStack);
1157 uint max_stack = sprite_stack ? static_cast<uint>(std::size(result->seq)) : 1;
1158 for (uint stack = 0; stack < max_stack; ++stack) {
1159 object.callback_param1 = image_type | (stack << 8);
1160 const auto *group = object.Resolve<ResultSpriteGroup>();
1161 int32_t reg100 = sprite_stack ? object.GetRegister(0x100) : 0;
1162 if (group != nullptr && group->num_sprites != 0) {
1163 result->seq[result->count].sprite = group->sprite + (rotor_pos % group->num_sprites);
1164 result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring
1165 result->count++;
1166 }
1167 if (!HasBit(reg100, 31)) break;
1168 }
1169}
1170
1171void GetCustomRotorSprite(const struct Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result)
1172{
1173 GetRotorOverrideSprite(v->engine_type, v, image_type, result);
1174}
1175
1176void GetCustomRotorIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
1177{
1178 GetRotorOverrideSprite(engine, nullptr, image_type, result);
1179}
1180
1187{
1188 assert(v->type == VEH_TRAIN);
1189 return Train::From(v)->tcache.cached_override != nullptr;
1190}
1191
1202uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, std::span<int32_t> regs100)
1203{
1204 VehicleResolverObject object(engine, v, VehicleResolverObject::WO_UNCACHED, false, callback, param1, param2);
1205 return object.ResolveCallback(regs100);
1206}
1207
1219uint16_t GetVehicleCallbackParent(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, const Vehicle *parent, std::span<int32_t> regs100)
1220{
1221 VehicleResolverObject object(engine, v, VehicleResolverObject::WO_NONE, false, callback, param1, param2);
1222 object.parent_scope.SetVehicle(parent);
1223 return object.ResolveCallback(regs100);
1224}
1225
1226
1227/* Callback 36 handlers */
1228int GetVehicleProperty(const Vehicle *v, PropertyID property, int orig_value, bool is_signed)
1229{
1230 return GetEngineProperty(v->engine_type, property, orig_value, v, is_signed);
1231}
1232
1233
1234int GetEngineProperty(EngineID engine, PropertyID property, int orig_value, const Vehicle *v, bool is_signed)
1235{
1236 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_MODIFY_PROPERTY, property, 0, engine, v);
1237 if (callback != CALLBACK_FAILED) {
1238 if (is_signed) {
1239 /* Sign extend 15 bit integer */
1240 return static_cast<int16_t>(callback << 1) / 2;
1241 } else {
1242 return callback;
1243 }
1244 }
1245
1246 return orig_value;
1247}
1248
1256{
1258 if (p == CALLBACK_FAILED) return std::nullopt;
1259
1260 const uint16_t PROBABILITY_RANGE = 100;
1261 return p + RandomRange(PROBABILITY_RANGE) >= PROBABILITY_RANGE;
1262}
1263
1264static void DoTriggerVehicleRandomisation(Vehicle *v, VehicleRandomTrigger trigger, uint16_t base_random_bits, bool first)
1265{
1266 /* We can't trigger a non-existent vehicle... */
1267 assert(v != nullptr);
1268
1270 v->waiting_random_triggers.Set(trigger); // store now for var 5F
1271 object.SetWaitingRandomTriggers(v->waiting_random_triggers);
1272
1273 object.ResolveRerandomisation();
1274
1275 /* Store remaining triggers. */
1276 v->waiting_random_triggers.Reset(object.GetUsedRandomTriggers());
1277
1278 /* Rerandomise bits. Scopes other than SELF are invalid for rerandomisation. For bug-to-bug-compatibility with TTDP we ignore the scope. */
1279 uint16_t new_random_bits = Random();
1280 uint32_t reseed = object.GetReseedSum();
1281 v->random_bits &= ~reseed;
1282 v->random_bits |= (first ? new_random_bits : base_random_bits) & reseed;
1283
1284 switch (trigger) {
1286 /* All vehicles in chain get ANY_NEW_CARGO trigger now.
1287 * So we call it for the first one and they will recurse.
1288 * Indexing part of vehicle random bits needs to be
1289 * same for all triggered vehicles in the chain (to get
1290 * all the random-cargo wagons carry the same cargo,
1291 * i.e.), so we give them all the NEW_CARGO triggered
1292 * vehicle's portion of random bits. */
1293 assert(first);
1294 DoTriggerVehicleRandomisation(v->First(), VehicleRandomTrigger::AnyNewCargo, new_random_bits, false);
1295 break;
1296
1298 /* We now trigger the next vehicle in chain recursively.
1299 * The random bits portions may be different for each
1300 * vehicle in chain. */
1301 if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), trigger, 0, true);
1302 break;
1303
1305 /* We now trigger the next vehicle in chain
1306 * recursively. The random bits portions must be same
1307 * for each vehicle in chain, so we give them all
1308 * first chained vehicle's portion of random bits. */
1309 if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), trigger, first ? new_random_bits : base_random_bits, false);
1310 break;
1311
1313 /* Now pass the trigger recursively to the next vehicle
1314 * in chain. */
1315 assert(!first);
1316 if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), trigger, base_random_bits, false);
1317 break;
1318
1320 /* Do not do any recursion */
1321 break;
1322 }
1323}
1324
1325void TriggerVehicleRandomisation(Vehicle *v, VehicleRandomTrigger trigger)
1326{
1328 DoTriggerVehicleRandomisation(v, trigger, 0, true);
1330}
1331
1332/* Functions for changing the order of vehicle purchase lists */
1333
1334struct ListOrderChange {
1336 uint16_t target;
1337
1338 ListOrderChange(EngineID engine, uint16_t target) : engine(engine), target(target) {}
1339};
1340
1341static std::vector<ListOrderChange> _list_order_changes;
1342
1349void AlterVehicleListOrder(EngineID engine, uint16_t target)
1350{
1351 /* Add the list order change to a queue */
1352 _list_order_changes.emplace_back(engine, target);
1353}
1354
1361static bool EnginePreSort(const EngineID &a, const EngineID &b)
1362{
1363 const Engine &engine_a = *Engine::Get(a);
1364 const Engine &engine_b = *Engine::Get(b);
1365
1366 /* 1. Sort by engine type */
1367 if (engine_a.type != engine_b.type) return static_cast<int>(engine_a.type) < static_cast<int>(engine_b.type);
1368
1369 /* 2. Sort by scope-GRFID */
1370 if (engine_a.grf_prop.grfid != engine_b.grf_prop.grfid) return engine_a.grf_prop.grfid < engine_b.grf_prop.grfid;
1371
1372 /* 3. Sort by local ID */
1373 return static_cast<int>(engine_a.grf_prop.local_id) < static_cast<int>(engine_b.grf_prop.local_id);
1374}
1375
1380{
1381 /* Build a list of EngineIDs. EngineIDs are sequential from 0 up to the number of pool items with no gaps. */
1382 std::vector<EngineID> ordering(Engine::GetNumItems());
1383 std::iota(std::begin(ordering), std::end(ordering), EngineID::Begin());
1384
1385 /* Pre-sort engines by scope-grfid and local index */
1386 std::ranges::sort(ordering, EnginePreSort);
1387
1388 /* Apply Insertion-Sort operations */
1389 for (const ListOrderChange &loc : _list_order_changes) {
1390 EngineID source = loc.engine;
1391
1392 Engine *engine_source = Engine::Get(source);
1393 if (engine_source->grf_prop.local_id == loc.target) continue;
1394
1395 EngineID target = _engine_mngr.GetID(engine_source->type, loc.target, engine_source->grf_prop.grfid);
1396 if (target == EngineID::Invalid()) continue;
1397
1398 auto it_source = std::ranges::find(ordering, source);
1399 auto it_target = std::ranges::find(ordering, target);
1400
1401 assert(it_source != std::end(ordering) && it_target != std::end(ordering));
1402 assert(it_source != it_target);
1403
1404 /* Move just this item to before the target. */
1405 Slide(it_source, std::next(it_source), it_target);
1406 }
1407
1408 /* Store final sort-order */
1409 for (uint16_t index = 0; const EngineID &eid : ordering) {
1410 Engine::Get(eid)->list_position = index;
1411 ++index;
1412 }
1413
1414 /* Clear out the queue */
1415 _list_order_changes.clear();
1416 _list_order_changes.shrink_to_fit();
1417}
1418
1424{
1426
1427 /* These variables we have to check; these are the ones with a cache. */
1428 static const int cache_entries[][2] = {
1432 { 0x43, NCVV_COMPANY_INFORMATION },
1433 { 0x4D, NCVV_POSITION_IN_VEHICLE },
1434 };
1435 static_assert(NCVV_END == lengthof(cache_entries));
1436
1437 /* Resolve all the variables, so their caches are set. */
1438 for (const auto &cache_entry : cache_entries) {
1439 /* Only resolve when the cache isn't valid. */
1440 if (HasBit(v->grf_cache.cache_valid, cache_entry[1])) continue;
1441 bool stub;
1442 ro.GetScope(VSG_SCOPE_SELF)->GetVariable(cache_entry[0], 0, stub);
1443 }
1444
1445 /* Make sure really all bits are set. */
1446 assert(v->grf_cache.cache_valid == (1 << NCVV_END) - 1);
1447}
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
@ HELITAKEOFF
Helicopter wants to leave the airport.
Definition airport.h:76
@ TERM4
Heading for terminal 4.
Definition airport.h:68
@ STARTTAKEOFF
Airplane has arrived at a runway for take-off.
Definition airport.h:74
@ HELIPAD2
Heading for helipad 2.
Definition airport.h:72
@ ENDTAKEOFF
Airplane has reached end-point of the take-off runway.
Definition airport.h:75
@ TERM5
Heading for terminal 5.
Definition airport.h:69
@ TERM6
Heading for terminal 6.
Definition airport.h:70
@ TERM3
Heading for terminal 3.
Definition airport.h:67
@ TERM8
Heading for terminal 8.
Definition airport.h:83
@ HELIPAD3
Heading for helipad 3.
Definition airport.h:84
@ HELIPAD1
Heading for helipad 1.
Definition airport.h:71
@ TERM2
Heading for terminal 2.
Definition airport.h:66
@ HANGAR
Heading for hangar.
Definition airport.h:64
@ FLYING
Vehicle is flying in the air.
Definition airport.h:77
@ TAKEOFF
Airplane wants to leave the airport.
Definition airport.h:73
@ HELILANDING
Helicopter wants to land.
Definition airport.h:80
@ ENDLANDING
Airplane wants to finish landing.
Definition airport.h:79
@ HELIENDLANDING
Helicopter wants to finish landing.
Definition airport.h:81
@ TERM1
Heading for terminal 1.
Definition airport.h:65
@ LANDING
Airplane wants to land.
Definition airport.h:78
@ TERM7
Heading for terminal 7.
Definition airport.h:82
@ 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.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:108
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:73
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:71
EngineFlags flags
Flags of the engine.
Definition engine_base.h:57
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:62
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:94
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:115
RailTypeFlags flags
Bit mask of rail type flags.
Definition rail.h:200
RoadTypeFlags flags
Bit mask of road type flags.
Definition road.h:101
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.
@ DIRDIFF_REVERSE
One direction is the opposite of the other one.
@ DIRDIFF_SAME
Both directions faces to the same direction.
Direction
Defines the 8 directions on the map.
@ DIR_W
West.
@ 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.
GrfSpecFeature
Definition newgrf.h:71
@ GSF_INVALID
An invalid spec feature.
Definition newgrf.h:102
@ 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.
@ VSG_SCOPE_SELF
Resolved object itself.
@ VSG_SCOPE_PARENT
Related object of the resolved one.
@ VSG_SCOPE_RELATIVE
Relative position (vehicles only).
@ 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:352
bool HasPowerOnRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType got power on a tile with a given RailType.
Definition rail.h:377
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:301
@ 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:25
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:32
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:230
@ 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:215
RoadType GetRoadType(Tile t, RoadTramType rtt)
Get the road type for the given RoadTramType.
Definition road_map.h:175
RoadTramType
The different types of road type.
Definition road_type.h:37
RoadType
The different roadtypes we support.
Definition road_type.h:23
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:28
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:271
Information about a aircraft vehicle.
uint8_t subtype
Type of aircraft.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:73
uint8_t pos
Next desired position of the aircraft.
Definition aircraft.h:75
uint8_t state
State of the airport.
Definition aircraft.h:78
uint8_t turn_counter
Ticks between each turn to prevent > 45 degree turns.
Definition aircraft.h:81
StationID targetairport
Airport to go to next.
Definition aircraft.h:77
Finite sTate mAchine (FTA) of an airport.
Definition airport.h:158
const AirportMovingData * MovingData(uint8_t position) const
Get movement data at a position.
Definition airport.h:183
uint8_t delta_z
Z adjustment for helicopter pads.
Definition airport.h:196
AirportMovingDataFlags flags
special flags when moving towards the destination.
Definition airport.h:138
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:74
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:81
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:138
uint8_t weight
Weight of a single unit of this cargo type in 1/16 ton (62.5 kg).
Definition cargotype.h:79
EngineMiscFlags misc_flags
Miscellaneous flags.
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced 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:117
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoType -> local ID).
Definition newgrf.h:139
std::vector< BadgeID > badge_list
Badge translation table (local index -> global index).
Definition newgrf.h:141
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:79
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.
const SpriteGroup * root_spritegroup
Root SpriteGroup to use for resolving.
virtual ScopeResolver * GetScope(VarSpriteGroupScope scope=VSG_SCOPE_SELF, uint8_t relative=0)
Get a resolver for the scope.
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=VSG_SCOPE_SELF, uint8_t relative=0) override
Get a resolver for the scope.
WagonOverride
Application of 'wagon overrides'.
@ WO_NONE
Resolve no wagon overrides.
@ WO_SELF
Resolve self-override (helicopter rotors and such).
@ WO_UNCACHED
Resolve wagon overrides.
@ WO_CACHED
Resolve wagon overrides using TrainCache::cached_override.
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.
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:747
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.
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition vehicle.cpp:767
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition vehicle.cpp:3186
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.
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
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:2086
@ 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).
EngineImageType
Visualisation contexts of vehicles and engines.
@ EIT_ON_MAP
Vehicle drawn in viewport.
@ 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.
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.