OpenTTD Source 20250328-master-gc3457cd4c0
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 <http://www.gnu.org/licenses/>.
6 */
7
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 != SpriteGroupCargo::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
95/* TTDP style aircraft movement states for GRF Action 2 Var 0xE2 */
96enum TTDPAircraftMovementStates : uint8_t {
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
133static uint8_t MapAircraftMovementState(const Aircraft *v)
134{
135 const Station *st = GetTargetAirportIfValid(v);
136 if (st == nullptr) return AMS_TTDP_FLIGHT_TO_TOWER;
137
138 const AirportFTAClass *afc = st->airport.GetFTA();
139 AirportMovingDataFlags amdflag = afc->MovingData(v->pos)->flags;
140
141 switch (v->state) {
142 case HANGAR:
143 /* The international airport is a special case as helicopters can land in
144 * front of the hangar. Helicopters also change their air.state to
145 * AirportMovingDataFlag::HeliLower some time before actually descending. */
146
147 /* This condition only occurs for helicopters, during descent,
148 * to a landing by the hangar of an international airport. */
149 if (amdflag.Test(AirportMovingDataFlag::HeliLower)) return AMS_TTDP_HELI_LAND_AIRPORT;
150
151 /* This condition only occurs for helicopters, before starting descent,
152 * to a landing by the hangar of an international airport. */
153 if (amdflag.Test(AirportMovingDataFlag::SlowTurn)) return AMS_TTDP_FLIGHT_TO_TOWER;
154
155 /* The final two conditions apply to helicopters or aircraft.
156 * Has reached hangar? */
157 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_HANGAR;
158
159 /* Still moving towards hangar. */
160 return AMS_TTDP_TO_HANGAR;
161
162 case TERM1:
163 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_TO_PAD1;
164 return AMS_TTDP_TO_JUNCTION;
165
166 case TERM2:
167 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_TO_PAD2;
168 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
169
170 case TERM3:
171 case TERM4:
172 case TERM5:
173 case TERM6:
174 case TERM7:
175 case TERM8:
176 /* TTDPatch only has 3 terminals, so treat these states the same */
177 if (amdflag.Test(AirportMovingDataFlag::ExactPosition)) return AMS_TTDP_TO_PAD3;
178 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H;
179
180 case HELIPAD1:
181 case HELIPAD2:
182 case HELIPAD3:
183 /* Will only occur for helicopters.*/
184 if (amdflag.Test(AirportMovingDataFlag::HeliLower)) return AMS_TTDP_HELI_LAND_AIRPORT; // Descending.
185 if (amdflag.Test(AirportMovingDataFlag::SlowTurn)) return AMS_TTDP_FLIGHT_TO_TOWER; // Still hasn't started descent.
186 return AMS_TTDP_TO_JUNCTION; // On the ground.
187
188 case TAKEOFF: // Moving to takeoff position.
189 return AMS_TTDP_TO_OUTWAY;
190
191 case STARTTAKEOFF: // Accelerating down runway.
192 return AMS_TTDP_TAKEOFF;
193
194 case ENDTAKEOFF: // Ascent
195 return AMS_TTDP_CLIMBING;
196
197 case HELITAKEOFF: // Helicopter is moving to take off position.
198 if (afc->delta_z == 0) {
199 return amdflag.Test(AirportMovingDataFlag::HeliRaise) ?
200 AMS_TTDP_HELI_TAKEOFF_AIRPORT : AMS_TTDP_TO_JUNCTION;
201 } else {
202 return AMS_TTDP_HELI_TAKEOFF_HELIPORT;
203 }
204
205 case FLYING:
206 return amdflag.Test(AirportMovingDataFlag::Hold) ? AMS_TTDP_FLIGHT_APPROACH : AMS_TTDP_FLIGHT_TO_TOWER;
207
208 case LANDING: // Descent
209 return AMS_TTDP_FLIGHT_DESCENT;
210
211 case ENDLANDING: // On the runway braking
212 if (amdflag.Test(AirportMovingDataFlag::Brake)) return AMS_TTDP_BRAKING;
213 /* Landed - moving off runway */
214 return AMS_TTDP_TO_INWAY;
215
216 case HELILANDING:
217 case HELIENDLANDING: // Helicoptor is descending.
219 return afc->delta_z == 0 ?
220 AMS_TTDP_HELI_LAND_AIRPORT : AMS_TTDP_HELI_LAND_HELIPORT;
221 } else {
222 return AMS_TTDP_FLIGHT_TO_TOWER;
223 }
224
225 default:
226 return AMS_TTDP_HANGAR;
227 }
228}
229
230
231/* TTDP style aircraft movement action for GRF Action 2 Var 0xE6 */
232enum TTDPAircraftMovementActions : uint8_t {
233 AMA_TTDP_IN_HANGAR,
234 AMA_TTDP_ON_PAD1,
235 AMA_TTDP_ON_PAD2,
236 AMA_TTDP_ON_PAD3,
237 AMA_TTDP_HANGAR_TO_PAD1,
238 AMA_TTDP_HANGAR_TO_PAD2,
239 AMA_TTDP_HANGAR_TO_PAD3,
240 AMA_TTDP_LANDING_TO_PAD1,
241 AMA_TTDP_LANDING_TO_PAD2,
242 AMA_TTDP_LANDING_TO_PAD3,
243 AMA_TTDP_PAD1_TO_HANGAR,
244 AMA_TTDP_PAD2_TO_HANGAR,
245 AMA_TTDP_PAD3_TO_HANGAR,
246 AMA_TTDP_PAD1_TO_TAKEOFF,
247 AMA_TTDP_PAD2_TO_TAKEOFF,
248 AMA_TTDP_PAD3_TO_TAKEOFF,
249 AMA_TTDP_HANGAR_TO_TAKOFF,
250 AMA_TTDP_LANDING_TO_HANGAR,
251 AMA_TTDP_IN_FLIGHT,
252};
253
254
260static uint8_t MapAircraftMovementAction(const Aircraft *v)
261{
262 switch (v->state) {
263 case HANGAR:
264 return (v->cur_speed > 0) ? AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_IN_HANGAR;
265
266 case TERM1:
267 case HELIPAD1:
268 return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD1 : AMA_TTDP_LANDING_TO_PAD1;
269
270 case TERM2:
271 case HELIPAD2:
272 return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD2 : AMA_TTDP_LANDING_TO_PAD2;
273
274 case TERM3:
275 case TERM4:
276 case TERM5:
277 case TERM6:
278 case TERM7:
279 case TERM8:
280 case HELIPAD3:
281 return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD3 : AMA_TTDP_LANDING_TO_PAD3;
282
283 case TAKEOFF: // Moving to takeoff position
284 case STARTTAKEOFF: // Accelerating down runway
285 case ENDTAKEOFF: // Ascent
286 case HELITAKEOFF:
287 /* @todo Need to find which terminal (or hangar) we've come from. How? */
288 return AMA_TTDP_PAD1_TO_TAKEOFF;
289
290 case FLYING:
291 return AMA_TTDP_IN_FLIGHT;
292
293 case LANDING: // Descent
294 case ENDLANDING: // On the runway braking
295 case HELILANDING:
296 case HELIENDLANDING:
297 /* @todo Need to check terminal we're landing to. Is it known yet? */
298 return (v->current_order.IsType(OT_GOTO_DEPOT)) ?
299 AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_LANDING_TO_PAD1;
300
301 default:
302 return AMA_TTDP_IN_HANGAR;
303 }
304}
305
306
307/* virtual */ uint32_t VehicleScopeResolver::GetRandomBits() const
308{
309 return this->v == nullptr ? 0 : this->v->random_bits;
310}
311
312/* virtual */ uint32_t VehicleScopeResolver::GetTriggers() const
313{
314 return this->v == nullptr ? 0 : this->v->waiting_triggers;
315}
316
317
319{
320 switch (scope) {
321 case VSG_SCOPE_SELF: return &this->self_scope;
322 case VSG_SCOPE_PARENT: return &this->parent_scope;
323 case VSG_SCOPE_RELATIVE: {
324 int32_t count = GB(relative, 0, 4);
325 if (this->self_scope.v != nullptr && (relative != this->cached_relative_count || count == 0)) {
326 /* Note: This caching only works as long as the VSG_SCOPE_RELATIVE cannot be used in
327 * VarAct2 with procedure calls. */
328 if (count == 0) count = GetRegister(0x100);
329
330 const Vehicle *v = nullptr;
331 switch (GB(relative, 6, 2)) {
332 default: NOT_REACHED();
333 case 0x00: // count back (away from the engine), starting at this vehicle
334 v = this->self_scope.v;
335 break;
336 case 0x01: // count forward (toward the engine), starting at this vehicle
337 v = this->self_scope.v;
338 count = -count;
339 break;
340 case 0x02: // count back, starting at the engine
341 v = this->parent_scope.v;
342 break;
343 case 0x03: { // count back, starting at the first vehicle in this chain of vehicles with the same ID, as for vehicle variable 41
344 const Vehicle *self = this->self_scope.v;
345 for (const Vehicle *u = self->First(); u != self; u = u->Next()) {
346 if (u->engine_type != self->engine_type) {
347 v = nullptr;
348 } else {
349 if (v == nullptr) v = u;
350 }
351 }
352 if (v == nullptr) v = self;
353 break;
354 }
355 }
356 this->relative_scope.SetVehicle(v->Move(count));
357 }
358 return &this->relative_scope;
359 }
360 default: return ResolverObject::GetScope(scope, relative);
361 }
362}
363
373static const Livery *LiveryHelper(EngineID engine, const Vehicle *v)
374{
375 const Livery *l;
376
377 if (v == nullptr) {
378 if (!Company::IsValidID(_current_company)) return nullptr;
379 l = GetEngineLivery(engine, _current_company, EngineID::Invalid(), nullptr, LIT_ALL);
380 } else if (v->IsGroundVehicle()) {
382 } else {
383 l = GetEngineLivery(v->engine_type, v->owner, EngineID::Invalid(), v, LIT_ALL);
384 }
385
386 return l;
387}
388
396static uint32_t PositionHelper(const Vehicle *v, bool consecutive)
397{
398 const Vehicle *u;
399 uint8_t chain_before = 0;
400 uint8_t chain_after = 0;
401
402 for (u = v->First(); u != v; u = u->Next()) {
403 chain_before++;
404 if (consecutive && u->engine_type != v->engine_type) chain_before = 0;
405 }
406
407 while (u->Next() != nullptr && (!consecutive || u->Next()->engine_type == v->engine_type)) {
408 chain_after++;
409 u = u->Next();
410 }
411
412 return chain_before | chain_after << 8 | (chain_before + chain_after + consecutive) << 16;
413}
414
415static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, uint8_t variable, uint32_t parameter, bool &available)
416{
417 /* Calculated vehicle parameters */
418 switch (variable) {
419 case 0x25: // Get engine GRF ID
420 return v->GetGRFID();
421
422 case 0x40: // Get length of consist
426 }
428
429 case 0x41: // Get length of same consecutive wagons
433 }
435
436 case 0x42: { // Consist cargo information
438 std::array<uint8_t, NUM_CARGO> common_cargoes{};
439 uint8_t cargo_classes = 0;
440 uint8_t user_def_data = 0;
441
442 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
443 if (v->type == VEH_TRAIN) user_def_data |= Train::From(u)->tcache.user_def_data;
444
445 /* Skip empty engines */
446 if (!u->GetEngine()->CanCarryCargo()) continue;
447
448 cargo_classes |= CargoSpec::Get(u->cargo_type)->classes.base();
449 common_cargoes[u->cargo_type]++;
450 }
451
452 /* Pick the most common cargo type */
453 auto cargo_it = std::max_element(std::begin(common_cargoes), std::end(common_cargoes));
454 /* Return INVALID_CARGO if nothing is carried */
455 CargoType common_cargo_type = (*cargo_it == 0) ? INVALID_CARGO : static_cast<CargoType>(std::distance(std::begin(common_cargoes), cargo_it));
456
457 /* Count subcargo types of common_cargo_type */
458 std::array<uint8_t, UINT8_MAX + 1> common_subtypes{};
459 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
460 /* Skip empty engines and engines not carrying common_cargo_type */
461 if (u->cargo_type != common_cargo_type || !u->GetEngine()->CanCarryCargo()) continue;
462
463 common_subtypes[u->cargo_subtype]++;
464 }
465
466 /* Pick the most common subcargo type*/
467 auto subtype_it = std::max_element(std::begin(common_subtypes), std::end(common_subtypes));
468 /* Return UINT8_MAX if nothing is carried */
469 uint8_t common_subtype = (*subtype_it == 0) ? UINT8_MAX : static_cast<uint8_t>(std::distance(std::begin(common_subtypes), subtype_it));
470
471 /* Note: We have to store the untranslated cargotype in the cache as the cache can be read by different NewGRFs,
472 * which will need different translations */
473 v->grf_cache.consist_cargo_information = cargo_classes | (common_cargo_type << 8) | (common_subtype << 16) | (user_def_data << 24);
475 }
476
477 /* The cargo translation is specific to the accessing GRF, and thus cannot be cached. */
478 CargoType common_cargo_type = (v->grf_cache.consist_cargo_information >> 8) & 0xFF;
479
480 /* Note:
481 * - Unlike everywhere else the cargo translation table is only used since grf version 8, not 7.
482 * - For translating the cargo type we need to use the GRF which is resolving the variable, which
483 * is object->ro.grffile.
484 * In case of CBID_TRAIN_ALLOW_WAGON_ATTACH this is not the same as v->GetGRF().
485 * - The grffile == nullptr case only happens if this function is called for default vehicles.
486 * And this is only done by CheckCaches().
487 */
488 const GRFFile *grffile = object->ro.grffile;
489 uint8_t common_bitnum = (common_cargo_type == INVALID_CARGO) ? 0xFF :
490 (grffile == nullptr || grffile->grf_version < 8) ? CargoSpec::Get(common_cargo_type)->bitnum : grffile->cargo_map[common_cargo_type];
491
492 return (v->grf_cache.consist_cargo_information & 0xFFFF00FF) | common_bitnum << 8;
493 }
494
495 case 0x43: // Company information
499 }
501
502 case 0x44: // Aircraft information
503 if (v->type != VEH_AIRCRAFT || !Aircraft::From(v)->IsNormalAircraft()) return UINT_MAX;
504
505 {
506 const Vehicle *w = v->Next();
507 assert(w != nullptr);
508 uint16_t altitude = ClampTo<uint16_t>(v->z_pos - w->z_pos); // Aircraft height - shadow height
509 uint8_t airporttype = ATP_TTDP_LARGE;
510
512
513 if (st != nullptr && st->airport.tile != INVALID_TILE) {
514 airporttype = st->airport.GetSpec()->ttd_airport_type;
515 }
516
517 return (ClampTo<uint8_t>(altitude) << 8) | airporttype;
518 }
519
520 case 0x45: { // Curvature info
521 /* Format: xxxTxBxF
522 * F - previous wagon to current wagon, 0 if vehicle is first
523 * B - current wagon to next wagon, 0 if wagon is last
524 * T - previous wagon to next wagon, 0 in an S-bend
525 */
526 if (!v->IsGroundVehicle()) return 0;
527
528 const Vehicle *u_p = v->Previous();
529 const Vehicle *u_n = v->Next();
530 DirDiff f = (u_p == nullptr) ? DIRDIFF_SAME : DirDifference(u_p->direction, v->direction);
531 DirDiff b = (u_n == nullptr) ? DIRDIFF_SAME : DirDifference(v->direction, u_n->direction);
532 DirDiff t = ChangeDirDiff(f, b);
533
534 return ((t > DIRDIFF_REVERSE ? t | 8 : t) << 16) |
535 ((b > DIRDIFF_REVERSE ? b | 8 : b) << 8) |
536 ( f > DIRDIFF_REVERSE ? f | 8 : f);
537 }
538
539 case 0x46: // Motion counter
540 return v->motion_counter;
541
542 case 0x47: { // Vehicle cargo info
543 /* Format: ccccwwtt
544 * tt - the cargo type transported by the vehicle,
545 * translated if a translation table has been installed.
546 * ww - cargo unit weight in 1/16 tons, same as cargo prop. 0F.
547 * cccc - the cargo class value of the cargo transported by the vehicle.
548 */
549 const CargoSpec *cs = CargoSpec::Get(v->cargo_type);
550
551 /* Note:
552 * For translating the cargo type we need to use the GRF which is resolving the variable, which
553 * is object->ro.grffile.
554 * In case of CBID_TRAIN_ALLOW_WAGON_ATTACH this is not the same as v->GetGRF().
555 */
556 return (cs->classes.base() << 16) | (cs->weight << 8) | object->ro.grffile->cargo_map[v->cargo_type];
557 }
558
559 case 0x48: return v->GetEngine()->flags.base(); // Vehicle Type Info
560 case 0x49: return v->build_year.base();
561
562 case 0x4A:
563 switch (v->type) {
564 case VEH_TRAIN: {
566 const RailTypeInfo *rti = GetRailTypeInfo(rt);
567 return (rti->flags.Test(RailTypeFlag::Catenary) ? 0x200 : 0) |
568 (HasPowerOnRail(Train::From(v)->railtype, rt) ? 0x100 : 0) |
569 GetReverseRailTypeTranslation(rt, object->ro.grffile);
570 }
571
572 case VEH_ROAD: {
573 RoadType rt = GetRoadType(v->tile, GetRoadTramType(RoadVehicle::From(v)->roadtype));
574 const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
575 return (rti->flags.Test(RoadTypeFlag::Catenary) ? 0x200 : 0) |
576 0x100 |
577 GetReverseRoadTypeTranslation(rt, object->ro.grffile);
578 }
579
580 default:
581 return 0;
582 }
583
584 case 0x4B: // Long date of last service
585 return v->date_of_last_service_newgrf.base();
586
587 case 0x4C: // Current maximum speed in NewGRF units
588 if (!v->IsPrimaryVehicle()) return 0;
589 return v->GetCurrentMaxSpeed();
590
591 case 0x4D: // Position within articulated vehicle
593 uint8_t artic_before = 0;
594 for (const Vehicle *u = v; u->IsArticulatedPart(); u = u->Previous()) artic_before++;
595 uint8_t artic_after = 0;
596 for (const Vehicle *u = v; u->HasArticulatedPart(); u = u->Next()) artic_after++;
597 v->grf_cache.position_in_vehicle = artic_before | artic_after << 8;
599 }
601
602 /* Variables which use the parameter */
603 case 0x60: // Count consist's engine ID occurrence
604 if (v->type != VEH_TRAIN) return v->GetEngine()->grf_prop.local_id == parameter ? 1 : 0;
605
606 {
607 uint count = 0;
608 for (; v != nullptr; v = v->Next()) {
609 if (v->GetEngine()->grf_prop.local_id == parameter) count++;
610 }
611 return count;
612 }
613
614 case 0x61: // Get variable of n-th vehicle in chain [signed number relative to vehicle]
615 if (!v->IsGroundVehicle() || parameter == 0x61) {
616 /* Not available */
617 break;
618 }
619
620 /* Only allow callbacks that don't change properties to avoid circular dependencies. */
624 Vehicle *u = v->Move((int32_t)GetRegister(0x10F));
625 if (u == nullptr) return 0; // available, but zero
626
627 if (parameter == 0x5F) {
628 /* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */
629 return (u->random_bits << 8) | u->waiting_triggers;
630 } else {
631 return VehicleGetVariable(u, object, parameter, GetRegister(0x10E), available);
632 }
633 }
634 /* Not available */
635 break;
636
637 case 0x62: { // Curvature/position difference for n-th vehicle in chain [signed number relative to vehicle]
638 /* Format: zzyyxxFD
639 * zz - Signed difference of z position between the selected and this vehicle.
640 * yy - Signed difference of y position between the selected and this vehicle.
641 * xx - Signed difference of x position between the selected and this vehicle.
642 * F - Flags, bit 7 corresponds to VehState::Hidden.
643 * D - Dir difference, like in 0x45.
644 */
645 if (!v->IsGroundVehicle()) return 0;
646
647 const Vehicle *u = v->Move((int8_t)parameter);
648 if (u == nullptr) return 0;
649
650 /* Get direction difference. */
651 bool prev = (int8_t)parameter < 0;
652 uint32_t ret = prev ? DirDifference(u->direction, v->direction) : DirDifference(v->direction, u->direction);
653 if (ret > DIRDIFF_REVERSE) ret |= 0x08;
654
655 if (u->vehstatus.Test(VehState::Hidden)) ret |= 0x80;
656
657 /* Get position difference. */
658 ret |= ((prev ? u->x_pos - v->x_pos : v->x_pos - u->x_pos) & 0xFF) << 8;
659 ret |= ((prev ? u->y_pos - v->y_pos : v->y_pos - u->y_pos) & 0xFF) << 16;
660 ret |= ((prev ? u->z_pos - v->z_pos : v->z_pos - u->z_pos) & 0xFF) << 24;
661
662 return ret;
663 }
664
665 case 0x63:
666 /* Tile compatibility wrt. arbitrary track-type
667 * Format:
668 * bit 0: Type 'parameter' is known.
669 * bit 1: Engines with type 'parameter' are compatible with this tile.
670 * bit 2: Engines with type 'parameter' are powered on this tile.
671 * bit 3: This tile has type 'parameter' or it is considered equivalent (alternate labels).
672 */
673 switch (v->type) {
674 case VEH_TRAIN: {
675 RailType param_type = GetRailTypeTranslation(parameter, object->ro.grffile);
676 if (param_type == INVALID_RAILTYPE) return 0x00;
677 RailType tile_type = GetTileRailType(v->tile);
678 if (tile_type == param_type) return 0x0F;
679 return (HasPowerOnRail(param_type, tile_type) ? 0x04 : 0x00) |
680 (IsCompatibleRail(param_type, tile_type) ? 0x02 : 0x00) |
681 0x01;
682 }
683 case VEH_ROAD: {
684 RoadTramType rtt = GetRoadTramType(RoadVehicle::From(v)->roadtype);
685 RoadType param_type = GetRoadTypeTranslation(rtt, parameter, object->ro.grffile);
686 if (param_type == INVALID_ROADTYPE) return 0x00;
687 RoadType tile_type = GetRoadType(v->tile, rtt);
688 if (tile_type == param_type) return 0x0F;
689 return (HasPowerOnRoad(param_type, tile_type) ? 0x06 : 0x00) |
690 0x01;
691 }
692 default: return 0x00;
693 }
694
695 case 0x64: { // Count consist's badge ID occurrence
696 if (v->type != VEH_TRAIN) return GetBadgeVariableResult(*object->ro.grffile, v->GetEngine()->badges, parameter);
697
698 /* Look up badge index. */
699 if (parameter >= std::size(object->ro.grffile->badge_list)) return UINT_MAX;
700 BadgeID index = object->ro.grffile->badge_list[parameter];
701
702 /* Count number of vehicles that contain this badge index. */
703 uint count = 0;
704 for (; v != nullptr; v = v->Next()) {
705 const auto &badges = v->GetEngine()->badges;
706 if (std::ranges::find(badges, index) != std::end(badges)) count++;
707 }
708
709 return count;
710 }
711
712 case 0x7A: return GetBadgeVariableResult(*object->ro.grffile, v->GetEngine()->badges, parameter);
713
714 case 0xFE:
715 case 0xFF: {
716 uint16_t modflags = 0;
717
718 if (v->type == VEH_TRAIN) {
719 const Train *t = Train::From(v);
720 bool is_powered_wagon = HasBit(t->flags, VRF_POWEREDWAGON);
721 const Train *u = is_powered_wagon ? t->First() : t; // for powered wagons the engine defines the type of engine (i.e. railtype)
722 RailType railtype = GetRailType(v->tile);
723 bool powered = t->IsEngine() || is_powered_wagon;
724 bool has_power = HasPowerOnRail(u->railtype, railtype);
725
726 if (powered && has_power) SetBit(modflags, 5);
727 if (powered && !has_power) SetBit(modflags, 6);
728 if (HasBit(t->flags, VRF_TOGGLE_REVERSE)) SetBit(modflags, 8);
729 }
732
733 return variable == 0xFE ? modflags : GB(modflags, 8, 8);
734 }
735 }
736
737 /*
738 * General vehicle properties
739 *
740 * Some parts of the TTD Vehicle structure are omitted for various reasons
741 * (see http://marcin.ttdpatch.net/sv1codec/TTD-locations.html#_VehicleArray)
742 */
743 switch (variable - 0x80) {
744 case 0x00: return v->type + 0x10;
745 case 0x01: return MapOldSubType(v);
746 case 0x02: break; // not implemented
747 case 0x03: break; // not implemented
748 case 0x04: return v->index.base();
749 case 0x05: return GB(v->index.base(), 8, 8);
750 case 0x06: break; // not implemented
751 case 0x07: break; // not implemented
752 case 0x08: break; // not implemented
753 case 0x09: break; // not implemented
754 case 0x0A: return v->current_order.MapOldOrder();
755 case 0x0B: return v->current_order.GetDestination().value;
756 case 0x0C: return v->GetNumOrders();
757 case 0x0D: return v->cur_real_order_index;
758 case 0x0E: break; // not implemented
759 case 0x0F: break; // not implemented
760 case 0x10:
761 case 0x11: {
762 uint ticks;
763 if (v->current_order.IsType(OT_LOADING)) {
764 ticks = v->load_unload_ticks;
765 } else {
766 switch (v->type) {
767 case VEH_TRAIN: ticks = Train::From(v)->wait_counter; break;
768 case VEH_AIRCRAFT: ticks = Aircraft::From(v)->turn_counter; break;
769 default: ticks = 0; break;
770 }
771 }
772 return (variable - 0x80) == 0x10 ? ticks : GB(ticks, 8, 8);
773 }
774 case 0x12: return ClampTo<uint16_t>(v->date_of_last_service_newgrf - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR);
775 case 0x13: return GB(ClampTo<uint16_t>(v->date_of_last_service_newgrf - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR), 8, 8);
776 case 0x14: return v->GetServiceInterval();
777 case 0x15: return GB(v->GetServiceInterval(), 8, 8);
778 case 0x16: return v->last_station_visited.base();
779 case 0x17: return v->tick_counter;
780 case 0x18:
781 case 0x19: {
782 uint max_speed;
783 switch (v->type) {
784 case VEH_AIRCRAFT:
785 max_speed = Aircraft::From(v)->GetSpeedOldUnits(); // Convert to old units.
786 break;
787
788 default:
789 max_speed = v->vcache.cached_max_speed;
790 break;
791 }
792 return (variable - 0x80) == 0x18 ? max_speed : GB(max_speed, 8, 8);
793 }
794 case 0x1A: return v->x_pos;
795 case 0x1B: return GB(v->x_pos, 8, 8);
796 case 0x1C: return v->y_pos;
797 case 0x1D: return GB(v->y_pos, 8, 8);
798 case 0x1E: return v->z_pos;
799 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.
800 case 0x20: break; // not implemented
801 case 0x21: break; // not implemented
802 case 0x22: break; // not implemented
803 case 0x23: break; // not implemented
804 case 0x24: break; // not implemented
805 case 0x25: break; // not implemented
806 case 0x26: break; // not implemented
807 case 0x27: break; // not implemented
808 case 0x28: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
809 case 0x29: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
810 case 0x2A: break; // not implemented
811 case 0x2B: break; // not implemented
812 case 0x2C: break; // not implemented
813 case 0x2D: break; // not implemented
814 case 0x2E: break; // not implemented
815 case 0x2F: break; // not implemented
816 case 0x30: break; // not implemented
817 case 0x31: break; // not implemented
818 case 0x32: return v->vehstatus.base();
819 case 0x33: return 0; // non-existent high byte of vehstatus
820 case 0x34: return v->type == VEH_AIRCRAFT ? (v->cur_speed * 10) / 128 : v->cur_speed;
821 case 0x35: return GB(v->type == VEH_AIRCRAFT ? (v->cur_speed * 10) / 128 : v->cur_speed, 8, 8);
822 case 0x36: return v->subspeed;
823 case 0x37: return v->acceleration;
824 case 0x38: break; // not implemented
825 case 0x39: return v->cargo_type;
826 case 0x3A: return v->cargo_cap;
827 case 0x3B: return GB(v->cargo_cap, 8, 8);
828 case 0x3C: return ClampTo<uint16_t>(v->cargo.StoredCount());
829 case 0x3D: return GB(ClampTo<uint16_t>(v->cargo.StoredCount()), 8, 8);
830 case 0x3E: return v->cargo.GetFirstStation().base();
831 case 0x3F: return ClampTo<uint8_t>(v->cargo.PeriodsInTransit());
832 case 0x40: return ClampTo<uint16_t>(v->age);
833 case 0x41: return GB(ClampTo<uint16_t>(v->age), 8, 8);
834 case 0x42: return ClampTo<uint16_t>(v->max_age);
835 case 0x43: return GB(ClampTo<uint16_t>(v->max_age), 8, 8);
837 case 0x45: return v->unitnumber;
838 case 0x46: return v->GetEngine()->grf_prop.local_id;
839 case 0x47: return GB(v->GetEngine()->grf_prop.local_id, 8, 8);
840 case 0x48:
841 if (v->type != VEH_TRAIN || v->spritenum != 0xFD) return v->spritenum;
842 return HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION) ? 0xFE : 0xFD;
843
844 case 0x49: return v->day_counter;
845 case 0x4A: return v->breakdowns_since_last_service;
846 case 0x4B: return v->breakdown_ctr;
847 case 0x4C: return v->breakdown_delay;
848 case 0x4D: return v->breakdown_chance;
849 case 0x4E: return v->reliability;
850 case 0x4F: return GB(v->reliability, 8, 8);
851 case 0x50: return v->reliability_spd_dec;
852 case 0x51: return GB(v->reliability_spd_dec, 8, 8);
853 case 0x52: return ClampTo<int32_t>(v->GetDisplayProfitThisYear());
854 case 0x53: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 8, 24);
855 case 0x54: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 16, 16);
856 case 0x55: return GB(ClampTo<int32_t>(v->GetDisplayProfitThisYear()), 24, 8);
857 case 0x56: return ClampTo<int32_t>(v->GetDisplayProfitLastYear());
858 case 0x57: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 8, 24);
859 case 0x58: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 16, 16);
860 case 0x59: return GB(ClampTo<int32_t>(v->GetDisplayProfitLastYear()), 24, 8);
861 case 0x5A: return (v->Next() == nullptr ? VehicleID::Invalid() : v->Next()->index).base();
862 case 0x5B: break; // not implemented
863 case 0x5C: return ClampTo<int32_t>(v->value);
864 case 0x5D: return GB(ClampTo<int32_t>(v->value), 8, 24);
865 case 0x5E: return GB(ClampTo<int32_t>(v->value), 16, 16);
866 case 0x5F: return GB(ClampTo<int32_t>(v->value), 24, 8);
867 case 0x60: break; // not implemented
868 case 0x61: break; // not implemented
869 case 0x62: break; // vehicle specific, see below
870 case 0x63: break; // not implemented
871 case 0x64: break; // vehicle specific, see below
872 case 0x65: break; // vehicle specific, see below
873 case 0x66: break; // vehicle specific, see below
874 case 0x67: break; // vehicle specific, see below
875 case 0x68: break; // vehicle specific, see below
876 case 0x69: break; // vehicle specific, see below
877 case 0x6A: break; // not implemented
878 case 0x6B: break; // not implemented
879 case 0x6C: break; // not implemented
880 case 0x6D: break; // not implemented
881 case 0x6E: break; // not implemented
882 case 0x6F: break; // not implemented
883 case 0x70: break; // not implemented
884 case 0x71: break; // not implemented
885 case 0x72: return v->cargo_subtype;
886 case 0x73: break; // vehicle specific, see below
887 case 0x74: break; // vehicle specific, see below
888 case 0x75: break; // vehicle specific, see below
889 case 0x76: break; // vehicle specific, see below
890 case 0x77: break; // vehicle specific, see below
891 case 0x78: break; // not implemented
892 case 0x79: break; // not implemented
893 case 0x7A: return v->random_bits;
894 case 0x7B: return v->waiting_triggers;
895 case 0x7C: break; // vehicle specific, see below
896 case 0x7D: break; // vehicle specific, see below
897 case 0x7E: break; // not implemented
898 case 0x7F: break; // vehicle specific, see below
899 }
900
901 /* Vehicle specific properties */
902 switch (v->type) {
903 case VEH_TRAIN: {
904 Train *t = Train::From(v);
905 switch (variable - 0x80) {
906 case 0x62: return t->track;
907 case 0x66: return t->railtype;
908 case 0x73: return 0x80 + VEHICLE_LENGTH - t->gcache.cached_veh_length;
909 case 0x74: return t->gcache.cached_power;
910 case 0x75: return GB(t->gcache.cached_power, 8, 24);
911 case 0x76: return GB(t->gcache.cached_power, 16, 16);
912 case 0x77: return GB(t->gcache.cached_power, 24, 8);
913 case 0x7C: return t->First()->index.base();
914 case 0x7D: return GB(t->First()->index.base(), 8, 8);
915 case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
916 }
917 break;
918 }
919
920 case VEH_ROAD: {
922 switch (variable - 0x80) {
923 case 0x62: return rv->state;
924 case 0x64: return rv->blocked_ctr;
925 case 0x65: return GB(rv->blocked_ctr, 8, 8);
926 case 0x66: return rv->overtaking;
927 case 0x67: return rv->overtaking_ctr;
928 case 0x68: return rv->crashed_ctr;
929 case 0x69: return GB(rv->crashed_ctr, 8, 8);
930 }
931 break;
932 }
933
934 case VEH_SHIP: {
935 Ship *s = Ship::From(v);
936 switch (variable - 0x80) {
937 case 0x62: return s->state;
938 }
939 break;
940 }
941
942 case VEH_AIRCRAFT: {
943 Aircraft *a = Aircraft::From(v);
944 switch (variable - 0x80) {
945 case 0x62: return MapAircraftMovementState(a); // Current movement state
946 case 0x63: return a->targetairport.base(); // Airport to which the action refers
947 case 0x66: return MapAircraftMovementAction(a); // Current movement action
948 }
949 break;
950 }
951
952 default: break;
953 }
954
955 Debug(grf, 1, "Unhandled vehicle variable 0x{:X}, type 0x{:X}", variable, (uint)v->type);
956
957 available = false;
958 return UINT_MAX;
959}
960
961/* virtual */ uint32_t VehicleScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
962{
963 if (this->v == nullptr) {
964 /* Vehicle does not exist, so we're in a purchase list */
965 switch (variable) {
966 case 0x43: return GetCompanyInfo(_current_company, LiveryHelper(this->self_type, nullptr)); // Owner information
967 case 0x46: return 0; // Motion counter
968 case 0x47: { // Vehicle cargo info
969 const Engine *e = Engine::Get(this->self_type);
970 CargoType cargo_type = e->GetDefaultCargoType();
971 if (IsValidCargoType(cargo_type)) {
972 const CargoSpec *cs = CargoSpec::Get(cargo_type);
973 return (cs->classes.base() << 16) | (cs->weight << 8) | this->ro.grffile->cargo_map[cargo_type];
974 } else {
975 return 0x000000FF;
976 }
977 }
978 case 0x48: return Engine::Get(this->self_type)->flags.base(); // Vehicle Type Info
979 case 0x49: return TimerGameCalendar::year.base(); // 'Long' format build year
980 case 0x4B: return TimerGameCalendar::date.base(); // Long date of last service
981
982 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, Engine::Get(this->self_type)->badges, parameter);
983
984 case 0x92: return ClampTo<uint16_t>(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date of last service
985 case 0x93: return GB(ClampTo<uint16_t>(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR), 8, 8);
987 case 0xC6: return Engine::Get(this->self_type)->grf_prop.local_id;
988 case 0xC7: return GB(Engine::Get(this->self_type)->grf_prop.local_id, 8, 8);
989 case 0xDA: return VehicleID::Invalid().base(); // Next vehicle
990 case 0xF2: return 0; // Cargo subtype
991 }
992
993 available = false;
994 return UINT_MAX;
995 }
996
997 return VehicleGetVariable(const_cast<Vehicle*>(this->v), this, variable, parameter, available);
998}
999
1000
1002{
1003 const Vehicle *v = this->self_scope.v;
1004
1005 if (v == nullptr) {
1006 if (!group->loading.empty()) return group->loading[0];
1007 if (!group->loaded.empty()) return group->loaded[0];
1008 return nullptr;
1009 }
1010
1011 const Order &order = v->First()->current_order;
1012 bool not_loading = (order.GetUnloadType() & OUFB_NO_UNLOAD) && (order.GetLoadType() & OLFB_NO_LOAD);
1013 bool in_motion = !order.IsType(OT_LOADING) || not_loading;
1014
1015 uint totalsets = in_motion ? (uint)group->loaded.size() : (uint)group->loading.size();
1016
1017 if (totalsets == 0) return nullptr;
1018
1019 uint set = (v->cargo.StoredCount() * totalsets) / std::max<uint16_t>(1u, v->cargo_cap);
1020 set = std::min(set, totalsets - 1);
1021
1022 return in_motion ? group->loaded[set] : group->loading[set];
1023}
1024
1026{
1027 switch (Engine::Get(this->self_scope.self_type)->type) {
1028 case VEH_TRAIN: return GSF_TRAINS;
1029 case VEH_ROAD: return GSF_ROADVEHICLES;
1030 case VEH_SHIP: return GSF_SHIPS;
1031 case VEH_AIRCRAFT: return GSF_AIRCRAFT;
1032 default: return GSF_INVALID;
1033 }
1034}
1035
1037{
1038 return Engine::Get(this->self_scope.self_type)->grf_prop.local_id;
1039}
1040
1046static const GRFFile *GetEngineGrfFile(EngineID engine_type)
1047{
1048 const Engine *e = Engine::Get(engine_type);
1049 return (e != nullptr) ? e->GetGRF() : nullptr;
1050}
1051
1062VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle *v, WagonOverride wagon_override, bool rotor_in_gui,
1063 CallbackID callback, uint32_t callback_param1, uint32_t callback_param2)
1064 : ResolverObject(GetEngineGrfFile(engine_type), callback, callback_param1, callback_param2),
1065 self_scope(*this, engine_type, v, rotor_in_gui),
1066 parent_scope(*this, engine_type, ((v != nullptr) ? v->First() : v), rotor_in_gui),
1067 relative_scope(*this, engine_type, v, rotor_in_gui),
1068 cached_relative_count(0)
1069{
1070 if (wagon_override == WO_SELF) {
1071 this->root_spritegroup = GetWagonOverrideSpriteSet(engine_type, SpriteGroupCargo::SG_DEFAULT, engine_type);
1072 } else {
1073 if (wagon_override != WO_NONE && v != nullptr && v->IsGroundVehicle()) {
1074 assert(v->engine_type == engine_type); // overrides make little sense with fake scopes
1075
1076 /* For trains we always use cached value, except for callbacks because the override spriteset
1077 * to use may be different than the one cached. It happens for callback 0x15 (refit engine),
1078 * as v->cargo_type is temporary changed to the new type */
1079 if (wagon_override == WO_CACHED && v->type == VEH_TRAIN) {
1080 this->root_spritegroup = Train::From(v)->tcache.cached_override;
1081 } else {
1082 this->root_spritegroup = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->GetGroundVehicleCache()->first_engine);
1083 }
1084 }
1085
1086 if (this->root_spritegroup == nullptr) {
1087 const Engine *e = Engine::Get(engine_type);
1088 CargoType cargo = v != nullptr ? v->cargo_type : SpriteGroupCargo::SG_PURCHASE;
1089 this->root_spritegroup = e->grf_prop.GetSpriteGroup(cargo);
1091 }
1092 }
1093}
1094
1095
1096
1097void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result)
1098{
1100 result->Clear();
1101
1102 bool sprite_stack = EngInfo(engine)->misc_flags.Test(EngineMiscFlag::SpriteStack);
1103 uint max_stack = sprite_stack ? static_cast<uint>(std::size(result->seq)) : 1;
1104 for (uint stack = 0; stack < max_stack; ++stack) {
1105 object.ResetState();
1106 object.callback_param1 = image_type | (stack << 8);
1107 const SpriteGroup *group = object.Resolve();
1108 uint32_t reg100 = sprite_stack ? GetRegister(0x100) : 0;
1109 if (group != nullptr && group->GetNumResults() != 0) {
1110 result->seq[result->count].sprite = group->GetResult() + (direction % group->GetNumResults());
1111 result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring
1112 result->count++;
1113 }
1114 if (!HasBit(reg100, 31)) break;
1115 }
1116}
1117
1118
1119void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result)
1120{
1121 const Engine *e = Engine::Get(engine);
1122
1123 /* Only valid for helicopters */
1124 assert(e->type == VEH_AIRCRAFT);
1125 assert(!(e->u.air.subtype & AIR_CTOL));
1126
1127 /* We differ from TTDPatch by resolving the sprite using the primary vehicle 'v', and not using the rotor vehicle 'v->Next()->Next()'.
1128 * TTDPatch copies some variables between the vehicles each time, to somehow synchronize the rotor vehicle with the primary vehicle.
1129 * We use 'rotor_in_gui' to replicate when the variables differ.
1130 * But some other variables like 'rotor state' and 'rotor speed' are not available in OpenTTD, while they are in TTDPatch. */
1131 bool rotor_in_gui = image_type != EIT_ON_MAP;
1133 result->Clear();
1134 uint rotor_pos = v == nullptr || rotor_in_gui ? 0 : v->Next()->Next()->state;
1135
1136 bool sprite_stack = e->info.misc_flags.Test(EngineMiscFlag::SpriteStack);
1137 uint max_stack = sprite_stack ? static_cast<uint>(std::size(result->seq)) : 1;
1138 for (uint stack = 0; stack < max_stack; ++stack) {
1139 object.ResetState();
1140 object.callback_param1 = image_type | (stack << 8);
1141 const SpriteGroup *group = object.Resolve();
1142 uint32_t reg100 = sprite_stack ? GetRegister(0x100) : 0;
1143 if (group != nullptr && group->GetNumResults() != 0) {
1144 result->seq[result->count].sprite = group->GetResult() + (rotor_pos % group->GetNumResults());
1145 result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring
1146 result->count++;
1147 }
1148 if (!HasBit(reg100, 31)) break;
1149 }
1150}
1151
1152
1159{
1160 assert(v->type == VEH_TRAIN);
1161 return Train::From(v)->tcache.cached_override != nullptr;
1162}
1163
1173uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v)
1174{
1175 VehicleResolverObject object(engine, v, VehicleResolverObject::WO_UNCACHED, false, callback, param1, param2);
1176 return object.ResolveCallback();
1177}
1178
1189uint16_t GetVehicleCallbackParent(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, const Vehicle *parent)
1190{
1191 VehicleResolverObject object(engine, v, VehicleResolverObject::WO_NONE, false, callback, param1, param2);
1192 object.parent_scope.SetVehicle(parent);
1193 return object.ResolveCallback();
1194}
1195
1196
1197/* Callback 36 handlers */
1198int GetVehicleProperty(const Vehicle *v, PropertyID property, int orig_value, bool is_signed)
1199{
1200 return GetEngineProperty(v->engine_type, property, orig_value, v, is_signed);
1201}
1202
1203
1204int GetEngineProperty(EngineID engine, PropertyID property, int orig_value, const Vehicle *v, bool is_signed)
1205{
1206 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_MODIFY_PROPERTY, property, 0, engine, v);
1207 if (callback != CALLBACK_FAILED) {
1208 if (is_signed) {
1209 /* Sign extend 15 bit integer */
1210 return static_cast<int16_t>(callback << 1) / 2;
1211 } else {
1212 return callback;
1213 }
1214 }
1215
1216 return orig_value;
1217}
1218
1225bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type)
1226{
1227 uint16_t p = GetVehicleCallback(CBID_VEHICLE_BUILD_PROBABILITY, to_underlying(type), 0, engine, v);
1228 if (p == CALLBACK_FAILED) return false;
1229
1230 const uint16_t PROBABILITY_RANGE = 100;
1231 return p + RandomRange(PROBABILITY_RANGE) >= PROBABILITY_RANGE;
1232}
1233
1234static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, uint16_t base_random_bits, bool first)
1235{
1236 /* We can't trigger a non-existent vehicle... */
1237 assert(v != nullptr);
1238
1240 object.waiting_triggers = v->waiting_triggers | trigger;
1241 v->waiting_triggers = object.waiting_triggers; // store now for var 5F
1242
1243 const SpriteGroup *group = object.Resolve();
1244 if (group == nullptr) return;
1245
1246 /* Store remaining triggers. */
1247 v->waiting_triggers = object.GetRemainingTriggers();
1248
1249 /* Rerandomise bits. Scopes other than SELF are invalid for rerandomisation. For bug-to-bug-compatibility with TTDP we ignore the scope. */
1250 uint16_t new_random_bits = Random();
1251 uint32_t reseed = object.GetReseedSum();
1252 v->random_bits &= ~reseed;
1253 v->random_bits |= (first ? new_random_bits : base_random_bits) & reseed;
1254
1255 switch (trigger) {
1256 case VEHICLE_TRIGGER_NEW_CARGO:
1257 /* All vehicles in chain get ANY_NEW_CARGO trigger now.
1258 * So we call it for the first one and they will recurse.
1259 * Indexing part of vehicle random bits needs to be
1260 * same for all triggered vehicles in the chain (to get
1261 * all the random-cargo wagons carry the same cargo,
1262 * i.e.), so we give them all the NEW_CARGO triggered
1263 * vehicle's portion of random bits. */
1264 assert(first);
1265 DoTriggerVehicle(v->First(), VEHICLE_TRIGGER_ANY_NEW_CARGO, new_random_bits, false);
1266 break;
1267
1268 case VEHICLE_TRIGGER_DEPOT:
1269 /* We now trigger the next vehicle in chain recursively.
1270 * The random bits portions may be different for each
1271 * vehicle in chain. */
1272 if (v->Next() != nullptr) DoTriggerVehicle(v->Next(), trigger, 0, true);
1273 break;
1274
1275 case VEHICLE_TRIGGER_EMPTY:
1276 /* We now trigger the next vehicle in chain
1277 * recursively. The random bits portions must be same
1278 * for each vehicle in chain, so we give them all
1279 * first chained vehicle's portion of random bits. */
1280 if (v->Next() != nullptr) DoTriggerVehicle(v->Next(), trigger, first ? new_random_bits : base_random_bits, false);
1281 break;
1282
1283 case VEHICLE_TRIGGER_ANY_NEW_CARGO:
1284 /* Now pass the trigger recursively to the next vehicle
1285 * in chain. */
1286 assert(!first);
1287 if (v->Next() != nullptr) DoTriggerVehicle(v->Next(), VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false);
1288 break;
1289
1290 case VEHICLE_TRIGGER_CALLBACK_32:
1291 /* Do not do any recursion */
1292 break;
1293 }
1294}
1295
1296void TriggerVehicle(Vehicle *v, VehicleTrigger trigger)
1297{
1298 if (trigger == VEHICLE_TRIGGER_DEPOT) {
1299 /* store that the vehicle entered a depot this tick */
1301 }
1302
1304 DoTriggerVehicle(v, trigger, 0, true);
1306}
1307
1308/* Functions for changing the order of vehicle purchase lists */
1309
1316
1317static std::vector<ListOrderChange> _list_order_changes;
1318
1325void AlterVehicleListOrder(EngineID engine, uint16_t target)
1326{
1327 /* Add the list order change to a queue */
1328 _list_order_changes.emplace_back(engine, target);
1329}
1330
1337static bool EnginePreSort(const EngineID &a, const EngineID &b)
1338{
1339 const Engine &engine_a = *Engine::Get(a);
1340 const Engine &engine_b = *Engine::Get(b);
1341
1342 /* 1. Sort by engine type */
1343 if (engine_a.type != engine_b.type) return static_cast<int>(engine_a.type) < static_cast<int>(engine_b.type);
1344
1345 /* 2. Sort by scope-GRFID */
1346 if (engine_a.grf_prop.grfid != engine_b.grf_prop.grfid) return engine_a.grf_prop.grfid < engine_b.grf_prop.grfid;
1347
1348 /* 3. Sort by local ID */
1349 return static_cast<int>(engine_a.grf_prop.local_id) < static_cast<int>(engine_b.grf_prop.local_id);
1350}
1351
1356{
1357 /* Build a list of EngineIDs. EngineIDs are sequential from 0 up to the number of pool items with no gaps. */
1358 std::vector<EngineID> ordering(Engine::GetNumItems());
1359 std::iota(std::begin(ordering), std::end(ordering), EngineID::Begin());
1360
1361 /* Pre-sort engines by scope-grfid and local index */
1362 std::ranges::sort(ordering, EnginePreSort);
1363
1364 /* Apply Insertion-Sort operations */
1365 for (const ListOrderChange &loc : _list_order_changes) {
1366 EngineID source = loc.engine;
1367
1368 Engine *engine_source = Engine::Get(source);
1369 if (engine_source->grf_prop.local_id == loc.target) continue;
1370
1371 EngineID target = _engine_mngr.GetID(engine_source->type, loc.target, engine_source->grf_prop.grfid);
1372 if (target == EngineID::Invalid()) continue;
1373
1374 auto it_source = std::ranges::find(ordering, source);
1375 auto it_target = std::ranges::find(ordering, target);
1376
1377 assert(it_source != std::end(ordering) && it_target != std::end(ordering));
1378 assert(it_source != it_target);
1379
1380 /* Move just this item to before the target. */
1381 Slide(it_source, std::next(it_source), it_target);
1382 }
1383
1384 /* Store final sort-order */
1385 for (uint16_t index = 0; const EngineID &eid : ordering) {
1386 Engine::Get(eid)->list_position = index;
1387 ++index;
1388 }
1389
1390 /* Clear out the queue */
1391 _list_order_changes.clear();
1392 _list_order_changes.shrink_to_fit();
1393}
1394
1400{
1402
1403 /* These variables we have to check; these are the ones with a cache. */
1404 static const int cache_entries[][2] = {
1408 { 0x43, NCVV_COMPANY_INFORMATION },
1409 { 0x4D, NCVV_POSITION_IN_VEHICLE },
1410 };
1411 static_assert(NCVV_END == lengthof(cache_entries));
1412
1413 /* Resolve all the variables, so their caches are set. */
1414 for (const auto &cache_entry : cache_entries) {
1415 /* Only resolve when the cache isn't valid. */
1416 if (HasBit(v->grf_cache.cache_valid, cache_entry[1])) continue;
1417 bool stub;
1418 ro.GetScope(VSG_SCOPE_SELF)->GetVariable(cache_entry[0], 0, stub);
1419 }
1420
1421 /* Make sure really all bits are set. */
1422 assert(v->grf_cache.cache_valid == (1 << NCVV_END) - 1);
1423}
Base for aircraft.
Station * GetTargetAirportIfValid(const Aircraft *v)
Returns aircraft's target station if v->target_airport is a valid station with airport.
@ SlowTurn
Turn slowly (mostly used in the air).
Definition airport.h:50
@ HeliLower
Helicopter landing.
Definition airport.h:55
@ Hold
Holding pattern movement (above the airport).
Definition airport.h:56
@ Brake
Taxiing at the airport.
Definition airport.h:53
@ HeliRaise
Helicopter take-off.
Definition airport.h:54
@ 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.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:75
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.
uint PeriodsInTransit() const
Returns average number of cargo aging periods in transit for a cargo entity.
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:118
RailTypeFlags flags
Bit mask of rail type flags.
Definition rail.h:202
RoadTypeFlags flags
Bit mask of road type flags.
Definition road.h:118
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
The maximum year of the original TTD.
static constexpr TimerGame< struct Calendar >::Year ORIGINAL_BASE_YEAR
The minimum starting year/base year of the original TTD.
static constexpr TimerGame< struct Calendar >::Date DAYS_TILL_ORIGINAL_BASE_YEAR
The date of the first day of the 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
Allow incrementing of Direction variables.
@ 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.
Definition engine_type.h:99
@ SpriteStack
Draw vehicle by stacking multiple sprites.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
@ Random
Randomise borders.
static const uint8_t LIT_ALL
Show the liveries of all companies.
Definition livery.h:18
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
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.
GrfSpecFeature
Definition newgrf.h:70
@ GSF_INVALID
An invalid spec feature.
Definition newgrf.h:98
@ 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)
Evaluate a newgrf callback for vehicles with a different vehicle for parent scope.
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)
bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type)
Test for vehicle build probablity type.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
static uint8_t MapAircraftMovementAction(const Aircraft *v)
Map OTTD aircraft movement states to TTDPatch style movement actions (VarAction 2 Variable 0xE6) This...
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.
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
@ VSG_SCOPE_SELF
Resolved object itself.
@ VSG_SCOPE_PARENT
Related object of the resolved one.
@ VSG_SCOPE_RELATIVE
Relative position (vehicles only)
uint32_t GetRegister(uint i)
Gets the value of a so-called newgrf "register".
@ OUFB_NO_UNLOAD
Totally no unloading will be done.
Definition order_type.h:72
@ OLFB_NO_LOAD
Do not load anything.
Definition order_type.h:82
RailType GetTileRailType(Tile tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
Definition rail.cpp:155
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:315
bool HasPowerOnRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType got power on a tile with a given RailType.
Definition rail.h:328
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:300
@ Catenary
Bit number for drawing a catenary.
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:245
@ Catenary
Bit number for adding catenary.
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:230
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:277
uint8_t subtype
Type of aircraft.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:72
uint8_t pos
Next desired position of the aircraft.
Definition aircraft.h:74
uint8_t state
State of the airport.
Definition aircraft.h:77
uint8_t turn_counter
Ticks between each turn to prevent > 45 degree turns.
Definition aircraft.h:80
bool IsNormalAircraft() const
Check if the aircraft type is a normal flying device; eg not a rotor or a shadow.
Definition aircraft.h:121
StationID targetairport
Airport to go to next.
Definition aircraft.h:76
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.
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:137
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.
EngineID GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
Looks up an EngineID in the EngineOverrideManager.
Definition engine.cpp:530
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
EngineFlags flags
Flags of the engine.
Definition engine_base.h:56
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:61
VariableGRFFileProps grf_prop
Properties related the the grf file.
Definition engine_base.h:83
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
uint16_t 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:113
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoType -> local ID)
Definition newgrf.h:135
std::vector< BadgeID > badge_list
Badge translation table (local index -> global index)
Definition newgrf.h:137
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:78
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.
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:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:70
OrderLoadFlags GetLoadType() const
How must the consist be loaded?
Definition order_base.h:136
OrderUnloadFlags GetUnloadType() const
How must the consist be unloaded?
Definition order_base.h:138
TileIndex tile
The base tile of the area.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
Tindex index
Index of this pool item.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
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)
Interface for SpriteGroup-s to access the gamestate.
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
CallbackID callback
Callback being resolved.
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.
Buses, trucks and trams belong to this class.
Definition roadveh.h:98
uint8_t state
Definition roadveh.h:100
uint16_t crashed_ctr
Animation counter when the vehicle has crashed.
Definition roadveh.h:105
uint8_t overtaking_ctr
The length of the current overtake attempt.
Definition roadveh.h:104
uint8_t overtaking
Set to RVSB_DRIVE_SIDE when overtaking, otherwise 0.
Definition roadveh.h:103
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
T * Next() const
Get next vehicle in the chain.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
T * First() const
Get the first vehicle in the chain.
virtual const SpriteGroup * Resolve(ResolverObject &object) const
Base sprite group resolver.
Station data structure.
Airport airport
Tile area the airport covers.
'Train' is either a loco or a wagon.
Definition train.h:90
void SetSpriteGroup(size_t index, const struct SpriteGroup *spritegroup)
Set the SpriteGroup at the specified index.
const struct SpriteGroup * GetSpriteGroup(size_t index) const
Get 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.
const SpriteGroup * ResolveReal(const RealSpriteGroup *group) const override
Get the real sprites of the grf.
@ 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).
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.
Resolver for a vehicle scope.
uint32_t GetTriggers() const override
Get the triggers.
const struct Vehicle * v
The vehicle being resolved.
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:744
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.
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.
uint8_t waiting_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:764
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition vehicle.cpp:3144
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.
debug_inline bool IsGroundVehicle() const
Check if the vehicle is a ground vehicle.
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:95
Definition of the game-calendar-timer.
Base for the train class.
@ VRF_POWEREDWAGON
Wagon is powered.
Definition train.h:27
@ VRF_TOGGLE_REVERSE
Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle ...
Definition train.h:31
@ VRF_REVERSE_DIRECTION
Reverse the visible direction of the vehicle.
Definition train.h:28
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:2055
void VehicleEnteredDepotThisTick(Vehicle *v)
Adds a vehicle to the list of vehicles that visited a depot this tick.
Definition vehicle.cpp:917
@ 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.
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.
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.