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