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/>.
8 /** @file newgrf_engine.cpp NewGRF handling of engines. */
14 #include "company_func.h"
15 #include "newgrf_cargo.h"
16 #include "newgrf_spritegroup.h"
17 #include "timer/timer_game_calendar.h"
18 #include "vehicle_func.h"
19 #include "core/random_func.hpp"
20 #include "core/container_func.hpp"
22 #include "station_base.h"
23 #include "company_base.h"
24 #include "newgrf_railtype.h"
25 #include "newgrf_roadtype.h"
28 #include "safeguards.h"
30 void SetWagonOverrideSprites(EngineID engine
, CargoID cargo
, const SpriteGroup
*group
, EngineID
*train_id
, uint trains
)
32 Engine
*e
= Engine::Get(engine
);
34 assert(cargo
< NUM_CARGO
+ 2); // Include SpriteGroupCargo::SG_DEFAULT and SpriteGroupCargo::SG_PURCHASE pseudo cargoes.
36 WagonOverride
*wo
= &e
->overrides
.emplace_back();
39 wo
->engines
.assign(train_id
, train_id
+ trains
);
42 const SpriteGroup
*GetWagonOverrideSpriteSet(EngineID engine
, CargoID cargo
, EngineID overriding_engine
)
44 const Engine
*e
= Engine::Get(engine
);
46 for (const WagonOverride
&wo
: e
->overrides
) {
47 if (wo
.cargo
!= cargo
&& wo
.cargo
!= SpriteGroupCargo::SG_DEFAULT
) continue;
48 if (std::find(wo
.engines
.begin(), wo
.engines
.end(), overriding_engine
) != wo
.engines
.end()) return wo
.group
;
53 void SetCustomEngineSprites(EngineID engine
, byte cargo
, const SpriteGroup
*group
)
55 Engine
*e
= Engine::Get(engine
);
56 assert(cargo
< lengthof(e
->grf_prop
.spritegroup
));
58 if (e
->grf_prop
.spritegroup
[cargo
] != nullptr) {
59 GrfMsg(6, "SetCustomEngineSprites: engine {} cargo {} already has group -- replacing", engine
, cargo
);
61 e
->grf_prop
.spritegroup
[cargo
] = group
;
66 * Tie a GRFFile entry to an engine, to allow us to retrieve GRF parameters
68 * @param engine Engine ID to tie the GRFFile to.
69 * @param file Pointer of GRFFile to tie.
71 void SetEngineGRF(EngineID engine
, const GRFFile
*file
)
73 Engine
*e
= Engine::Get(engine
);
74 e
->grf_prop
.grffile
= file
;
78 static int MapOldSubType(const Vehicle
*v
)
82 if (Train::From(v
)->IsEngine()) return 0;
83 if (Train::From(v
)->IsFreeWagon()) return 4;
86 case VEH_SHIP
: return 0;
88 case VEH_DISASTER
: return v
->subtype
;
89 case VEH_EFFECT
: return v
->subtype
<< 1;
90 default: NOT_REACHED();
95 /* TTDP style aircraft movement states for GRF Action 2 Var 0xE2 */
96 enum TTDPAircraftMovementStates
{
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
,
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
,
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
,
130 * Map OTTD aircraft movement states to TTDPatch style movement states
131 * (VarAction 2 Variable 0xE2)
133 static byte
MapAircraftMovementState(const Aircraft
*v
)
135 const Station
*st
= GetTargetAirportIfValid(v
);
136 if (st
== nullptr) return AMS_TTDP_FLIGHT_TO_TOWER
;
138 const AirportFTAClass
*afc
= st
->airport
.GetFTA();
139 uint16_t amdflag
= afc
->MovingData(v
->pos
)->flag
;
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 * AMED_HELI_LOWER some time before actually descending. */
147 /* This condition only occurs for helicopters, during descent,
148 * to a landing by the hangar of an international airport. */
149 if (amdflag
& AMED_HELI_LOWER
) return AMS_TTDP_HELI_LAND_AIRPORT
;
151 /* This condition only occurs for helicopters, before starting descent,
152 * to a landing by the hangar of an international airport. */
153 if (amdflag
& AMED_SLOWTURN
) return AMS_TTDP_FLIGHT_TO_TOWER
;
155 /* The final two conditions apply to helicopters or aircraft.
156 * Has reached hangar? */
157 if (amdflag
& AMED_EXACTPOS
) return AMS_TTDP_HANGAR
;
159 /* Still moving towards hangar. */
160 return AMS_TTDP_TO_HANGAR
;
163 if (amdflag
& AMED_EXACTPOS
) return AMS_TTDP_TO_PAD1
;
164 return AMS_TTDP_TO_JUNCTION
;
167 if (amdflag
& AMED_EXACTPOS
) return AMS_TTDP_TO_PAD2
;
168 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H
;
176 /* TTDPatch only has 3 terminals, so treat these states the same */
177 if (amdflag
& AMED_EXACTPOS
) return AMS_TTDP_TO_PAD3
;
178 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H
;
183 /* Will only occur for helicopters.*/
184 if (amdflag
& AMED_HELI_LOWER
) return AMS_TTDP_HELI_LAND_AIRPORT
; // Descending.
185 if (amdflag
& AMED_SLOWTURN
) return AMS_TTDP_FLIGHT_TO_TOWER
; // Still hasn't started descent.
186 return AMS_TTDP_TO_JUNCTION
; // On the ground.
188 case TAKEOFF
: // Moving to takeoff position.
189 return AMS_TTDP_TO_OUTWAY
;
191 case STARTTAKEOFF
: // Accelerating down runway.
192 return AMS_TTDP_TAKEOFF
;
194 case ENDTAKEOFF
: // Ascent
195 return AMS_TTDP_CLIMBING
;
197 case HELITAKEOFF
: // Helicopter is moving to take off position.
198 if (afc
->delta_z
== 0) {
199 return amdflag
& AMED_HELI_RAISE
?
200 AMS_TTDP_HELI_TAKEOFF_AIRPORT
: AMS_TTDP_TO_JUNCTION
;
202 return AMS_TTDP_HELI_TAKEOFF_HELIPORT
;
206 return amdflag
& AMED_HOLD
? AMS_TTDP_FLIGHT_APPROACH
: AMS_TTDP_FLIGHT_TO_TOWER
;
208 case LANDING
: // Descent
209 return AMS_TTDP_FLIGHT_DESCENT
;
211 case ENDLANDING
: // On the runway braking
212 if (amdflag
& AMED_BRAKE
) return AMS_TTDP_BRAKING
;
213 /* Landed - moving off runway */
214 return AMS_TTDP_TO_INWAY
;
217 case HELIENDLANDING
: // Helicoptor is descending.
218 if (amdflag
& AMED_HELI_LOWER
) {
219 return afc
->delta_z
== 0 ?
220 AMS_TTDP_HELI_LAND_AIRPORT
: AMS_TTDP_HELI_LAND_HELIPORT
;
222 return AMS_TTDP_FLIGHT_TO_TOWER
;
226 return AMS_TTDP_HANGAR
;
231 /* TTDP style aircraft movement action for GRF Action 2 Var 0xE6 */
232 enum TTDPAircraftMovementActions
{
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
,
256 * Map OTTD aircraft movement states to TTDPatch style movement actions
257 * (VarAction 2 Variable 0xE6)
258 * This is not fully supported yet but it's enough for Planeset.
260 static byte
MapAircraftMovementAction(const Aircraft
*v
)
264 return (v
->cur_speed
> 0) ? AMA_TTDP_LANDING_TO_HANGAR
: AMA_TTDP_IN_HANGAR
;
268 return (v
->current_order
.IsType(OT_LOADING
)) ? AMA_TTDP_ON_PAD1
: AMA_TTDP_LANDING_TO_PAD1
;
272 return (v
->current_order
.IsType(OT_LOADING
)) ? AMA_TTDP_ON_PAD2
: AMA_TTDP_LANDING_TO_PAD2
;
281 return (v
->current_order
.IsType(OT_LOADING
)) ? AMA_TTDP_ON_PAD3
: AMA_TTDP_LANDING_TO_PAD3
;
283 case TAKEOFF
: // Moving to takeoff position
284 case STARTTAKEOFF
: // Accelerating down runway
285 case ENDTAKEOFF
: // Ascent
287 /* @todo Need to find which terminal (or hangar) we've come from. How? */
288 return AMA_TTDP_PAD1_TO_TAKEOFF
;
291 return AMA_TTDP_IN_FLIGHT
;
293 case LANDING
: // Descent
294 case ENDLANDING
: // On the runway braking
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
;
302 return AMA_TTDP_IN_HANGAR
;
307 /* virtual */ uint32_t VehicleScopeResolver::GetRandomBits() const
309 return this->v
== nullptr ? 0 : this->v
->random_bits
;
312 /* virtual */ uint32_t VehicleScopeResolver::GetTriggers() const
314 return this->v
== nullptr ? 0 : this->v
->waiting_triggers
;
318 /* virtual */ ScopeResolver
*VehicleResolverObject::GetScope(VarSpriteGroupScope scope
, byte relative
)
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);
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
;
336 case 0x01: // count forward (toward the engine), starting at this vehicle
337 v
= this->self_scope
.v
;
340 case 0x02: // count back, starting at the engine
341 v
= this->parent_scope
.v
;
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
) {
349 if (v
== nullptr) v
= u
;
352 if (v
== nullptr) v
= self
;
356 this->relative_scope
.SetVehicle(v
->Move(count
));
358 return &this->relative_scope
;
360 default: return ResolverObject::GetScope(scope
, relative
);
365 * Determines the livery of an engine.
367 * This always uses dual company colours independent of GUI settings. So it is desync-safe.
369 * @param engine Engine type
370 * @param v Vehicle, nullptr in purchase list.
371 * @return Livery to use
373 static const Livery
*LiveryHelper(EngineID engine
, const Vehicle
*v
)
378 if (!Company::IsValidID(_current_company
)) return nullptr;
379 l
= GetEngineLivery(engine
, _current_company
, INVALID_ENGINE
, nullptr, LIT_ALL
);
380 } else if (v
->IsGroundVehicle()) {
381 l
= GetEngineLivery(v
->engine_type
, v
->owner
, v
->GetGroundVehicleCache()->first_engine
, v
, LIT_ALL
);
383 l
= GetEngineLivery(v
->engine_type
, v
->owner
, INVALID_ENGINE
, v
, LIT_ALL
);
390 * Helper to get the position of a vehicle within a chain of vehicles.
391 * @param v the vehicle to get the position of.
392 * @param consecutive whether to look at the whole chain or the vehicles
393 * with the same 'engine type'.
394 * @return the position in the chain from front and tail and chain length.
396 static uint32_t PositionHelper(const Vehicle
*v
, bool consecutive
)
399 byte chain_before
= 0;
400 byte chain_after
= 0;
402 for (u
= v
->First(); u
!= v
; u
= u
->Next()) {
404 if (consecutive
&& u
->engine_type
!= v
->engine_type
) chain_before
= 0;
407 while (u
->Next() != nullptr && (!consecutive
|| u
->Next()->engine_type
== v
->engine_type
)) {
412 return chain_before
| chain_after
<< 8 | (chain_before
+ chain_after
+ consecutive
) << 16;
415 static uint32_t VehicleGetVariable(Vehicle
*v
, const VehicleScopeResolver
*object
, byte variable
, uint32_t parameter
, bool *available
)
417 /* Calculated vehicle parameters */
419 case 0x25: // Get engine GRF ID
420 return v
->GetGRFID();
422 case 0x40: // Get length of consist
423 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_CONSIST_LENGTH
)) {
424 v
->grf_cache
.position_consist_length
= PositionHelper(v
, false);
425 SetBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_CONSIST_LENGTH
);
427 return v
->grf_cache
.position_consist_length
;
429 case 0x41: // Get length of same consecutive wagons
430 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_SAME_ID_LENGTH
)) {
431 v
->grf_cache
.position_same_id_length
= PositionHelper(v
, true);
432 SetBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_SAME_ID_LENGTH
);
434 return v
->grf_cache
.position_same_id_length
;
436 case 0x42: { // Consist cargo information
437 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_CONSIST_CARGO_INFORMATION
)) {
438 std::array
<uint8_t, NUM_CARGO
> common_cargoes
{};
439 byte cargo_classes
= 0;
440 byte user_def_data
= 0;
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
;
445 /* Skip empty engines */
446 if (!u
->GetEngine()->CanCarryCargo()) continue;
448 cargo_classes
|= CargoSpec::Get(u
->cargo_type
)->classes
;
449 common_cargoes
[u
->cargo_type
]++;
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 CargoID common_cargo_type
= (*cargo_it
== 0) ? INVALID_CARGO
: static_cast<CargoID
>(std::distance(std::begin(common_cargoes
), cargo_it
));
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;
463 common_subtypes
[u
->cargo_subtype
]++;
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
));
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);
474 SetBit(v
->grf_cache
.cache_valid
, NCVV_CONSIST_CARGO_INFORMATION
);
477 /* The cargo translation is specific to the accessing GRF, and thus cannot be cached. */
478 CargoID common_cargo_type
= (v
->grf_cache
.consist_cargo_information
>> 8) & 0xFF;
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().
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
];
492 return (v
->grf_cache
.consist_cargo_information
& 0xFFFF00FF) | common_bitnum
<< 8;
495 case 0x43: // Company information
496 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_COMPANY_INFORMATION
)) {
497 v
->grf_cache
.company_information
= GetCompanyInfo(v
->owner
, LiveryHelper(v
->engine_type
, v
));
498 SetBit(v
->grf_cache
.cache_valid
, NCVV_COMPANY_INFORMATION
);
500 return v
->grf_cache
.company_information
;
502 case 0x44: // Aircraft information
503 if (v
->type
!= VEH_AIRCRAFT
|| !Aircraft::From(v
)->IsNormalAircraft()) return UINT_MAX
;
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 byte airporttype
= ATP_TTDP_LARGE
;
511 const Station
*st
= GetTargetAirportIfValid(Aircraft::From(v
));
513 if (st
!= nullptr && st
->airport
.tile
!= INVALID_TILE
) {
514 airporttype
= st
->airport
.GetSpec()->ttd_airport_type
;
517 return (ClampTo
<uint8_t>(altitude
) << 8) | airporttype
;
520 case 0x45: { // Curvature info
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
526 if (!v
->IsGroundVehicle()) return 0;
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
);
534 return ((t
> DIRDIFF_REVERSE
? t
| 8 : t
) << 16) |
535 ((b
> DIRDIFF_REVERSE
? b
| 8 : b
) << 8) |
536 ( f
> DIRDIFF_REVERSE
? f
| 8 : f
);
539 case 0x46: // Motion counter
540 return v
->motion_counter
;
542 case 0x47: { // Vehicle cargo info
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.
549 const CargoSpec
*cs
= CargoSpec::Get(v
->cargo_type
);
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().
556 return (cs
->classes
<< 16) | (cs
->weight
<< 8) | object
->ro
.grffile
->cargo_map
[v
->cargo_type
];
559 case 0x48: return v
->GetEngine()->flags
; // Vehicle Type Info
560 case 0x49: return v
->build_year
.base();
565 RailType rt
= GetTileRailType(v
->tile
);
566 const RailTypeInfo
*rti
= GetRailTypeInfo(rt
);
567 return ((rti
->flags
& RTFB_CATENARY
) ? 0x200 : 0) |
568 (HasPowerOnRail(Train::From(v
)->railtype
, rt
) ? 0x100 : 0) |
569 GetReverseRailTypeTranslation(rt
, object
->ro
.grffile
);
573 RoadType rt
= GetRoadType(v
->tile
, GetRoadTramType(RoadVehicle::From(v
)->roadtype
));
574 const RoadTypeInfo
*rti
= GetRoadTypeInfo(rt
);
575 return ((rti
->flags
& ROTFB_CATENARY
) ? 0x200 : 0) |
577 GetReverseRoadTypeTranslation(rt
, object
->ro
.grffile
);
584 case 0x4B: // Long date of last service
585 return v
->date_of_last_service_newgrf
.base();
587 case 0x4C: // Current maximum speed in NewGRF units
588 if (!v
->IsPrimaryVehicle()) return 0;
589 return v
->GetCurrentMaxSpeed();
591 case 0x4D: // Position within articulated vehicle
592 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_IN_VEHICLE
)) {
593 byte artic_before
= 0;
594 for (const Vehicle
*u
= v
; u
->IsArticulatedPart(); u
= u
->Previous()) artic_before
++;
595 byte 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;
598 SetBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_IN_VEHICLE
);
600 return v
->grf_cache
.position_in_vehicle
;
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;
608 for (; v
!= nullptr; v
= v
->Next()) {
609 if (v
->GetEngine()->grf_prop
.local_id
== parameter
) count
++;
614 case 0x61: // Get variable of n-th vehicle in chain [signed number relative to vehicle]
615 if (!v
->IsGroundVehicle() || parameter
== 0x61) {
620 /* Only allow callbacks that don't change properties to avoid circular dependencies. */
621 if (object
->ro
.callback
== CBID_NO_CALLBACK
|| object
->ro
.callback
== CBID_RANDOM_TRIGGER
|| object
->ro
.callback
== CBID_TRAIN_ALLOW_WAGON_ATTACH
||
622 object
->ro
.callback
== CBID_VEHICLE_START_STOP_CHECK
|| object
->ro
.callback
== CBID_VEHICLE_32DAY_CALLBACK
|| object
->ro
.callback
== CBID_VEHICLE_COLOUR_MAPPING
||
623 object
->ro
.callback
== CBID_VEHICLE_SPAWN_VISUAL_EFFECT
) {
624 Vehicle
*u
= v
->Move((int32_t)GetRegister(0x10F));
625 if (u
== nullptr) return 0; // available, but zero
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
;
631 return VehicleGetVariable(u
, object
, parameter
, GetRegister(0x10E), available
);
637 case 0x62: { // Curvature/position difference for n-th vehicle in chain [signed number relative to vehicle]
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 VS_HIDDEN.
643 * D - Dir difference, like in 0x45.
645 if (!v
->IsGroundVehicle()) return 0;
647 const Vehicle
*u
= v
->Move((int8_t)parameter
);
648 if (u
== nullptr) return 0;
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;
655 if (u
->vehstatus
& VS_HIDDEN
) ret
|= 0x80;
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;
666 /* Tile compatibility wrt. arbitrary track-type
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).
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) |
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) |
692 default: return 0x00;
697 uint16_t modflags
= 0;
699 if (v
->type
== VEH_TRAIN
) {
700 const Train
*t
= Train::From(v
);
701 bool is_powered_wagon
= HasBit(t
->flags
, VRF_POWEREDWAGON
);
702 const Train
*u
= is_powered_wagon
? t
->First() : t
; // for powered wagons the engine defines the type of engine (i.e. railtype)
703 RailType railtype
= GetRailType(v
->tile
);
704 bool powered
= t
->IsEngine() || is_powered_wagon
;
705 bool has_power
= HasPowerOnRail(u
->railtype
, railtype
);
707 if (powered
&& has_power
) SetBit(modflags
, 5);
708 if (powered
&& !has_power
) SetBit(modflags
, 6);
709 if (HasBit(t
->flags
, VRF_TOGGLE_REVERSE
)) SetBit(modflags
, 8);
711 if (HasBit(v
->vehicle_flags
, VF_CARGO_UNLOADING
)) SetBit(modflags
, 1);
712 if (HasBit(v
->vehicle_flags
, VF_BUILT_AS_PROTOTYPE
)) SetBit(modflags
, 10);
714 return variable
== 0xFE ? modflags
: GB(modflags
, 8, 8);
719 * General vehicle properties
721 * Some parts of the TTD Vehicle structure are omitted for various reasons
722 * (see http://marcin.ttdpatch.net/sv1codec/TTD-locations.html#_VehicleArray)
724 switch (variable
- 0x80) {
725 case 0x00: return v
->type
+ 0x10;
726 case 0x01: return MapOldSubType(v
);
727 case 0x02: break; // not implemented
728 case 0x03: break; // not implemented
729 case 0x04: return v
->index
;
730 case 0x05: return GB(v
->index
, 8, 8);
731 case 0x06: break; // not implemented
732 case 0x07: break; // not implemented
733 case 0x08: break; // not implemented
734 case 0x09: break; // not implemented
735 case 0x0A: return v
->current_order
.MapOldOrder();
736 case 0x0B: return v
->current_order
.GetDestination();
737 case 0x0C: return v
->GetNumOrders();
738 case 0x0D: return v
->cur_real_order_index
;
739 case 0x0E: break; // not implemented
740 case 0x0F: break; // not implemented
744 if (v
->current_order
.IsType(OT_LOADING
)) {
745 ticks
= v
->load_unload_ticks
;
748 case VEH_TRAIN
: ticks
= Train::From(v
)->wait_counter
; break;
749 case VEH_AIRCRAFT
: ticks
= Aircraft::From(v
)->turn_counter
; break;
750 default: ticks
= 0; break;
753 return (variable
- 0x80) == 0x10 ? ticks
: GB(ticks
, 8, 8);
755 case 0x12: return ClampTo
<uint16_t>(v
->date_of_last_service_newgrf
- CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR
);
756 case 0x13: return GB(ClampTo
<uint16_t>(v
->date_of_last_service_newgrf
- CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR
), 8, 8);
757 case 0x14: return v
->GetServiceInterval();
758 case 0x15: return GB(v
->GetServiceInterval(), 8, 8);
759 case 0x16: return v
->last_station_visited
;
760 case 0x17: return v
->tick_counter
;
766 max_speed
= Aircraft::From(v
)->GetSpeedOldUnits(); // Convert to old units.
770 max_speed
= v
->vcache
.cached_max_speed
;
773 return (variable
- 0x80) == 0x18 ? max_speed
: GB(max_speed
, 8, 8);
775 case 0x1A: return v
->x_pos
;
776 case 0x1B: return GB(v
->x_pos
, 8, 8);
777 case 0x1C: return v
->y_pos
;
778 case 0x1D: return GB(v
->y_pos
, 8, 8);
779 case 0x1E: return v
->z_pos
;
780 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.
781 case 0x20: break; // not implemented
782 case 0x21: break; // not implemented
783 case 0x22: break; // not implemented
784 case 0x23: break; // not implemented
785 case 0x24: break; // not implemented
786 case 0x25: break; // not implemented
787 case 0x26: break; // not implemented
788 case 0x27: break; // not implemented
789 case 0x28: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
790 case 0x29: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
791 case 0x2A: break; // not implemented
792 case 0x2B: break; // not implemented
793 case 0x2C: break; // not implemented
794 case 0x2D: break; // not implemented
795 case 0x2E: break; // not implemented
796 case 0x2F: break; // not implemented
797 case 0x30: break; // not implemented
798 case 0x31: break; // not implemented
799 case 0x32: return v
->vehstatus
;
800 case 0x33: return 0; // non-existent high byte of vehstatus
801 case 0x34: return v
->type
== VEH_AIRCRAFT
? (v
->cur_speed
* 10) / 128 : v
->cur_speed
;
802 case 0x35: return GB(v
->type
== VEH_AIRCRAFT
? (v
->cur_speed
* 10) / 128 : v
->cur_speed
, 8, 8);
803 case 0x36: return v
->subspeed
;
804 case 0x37: return v
->acceleration
;
805 case 0x38: break; // not implemented
806 case 0x39: return v
->cargo_type
;
807 case 0x3A: return v
->cargo_cap
;
808 case 0x3B: return GB(v
->cargo_cap
, 8, 8);
809 case 0x3C: return ClampTo
<uint16_t>(v
->cargo
.StoredCount());
810 case 0x3D: return GB(ClampTo
<uint16_t>(v
->cargo
.StoredCount()), 8, 8);
811 case 0x3E: return v
->cargo
.GetFirstStation();
812 case 0x3F: return ClampTo
<uint8_t>(v
->cargo
.PeriodsInTransit());
813 case 0x40: return ClampTo
<uint16_t>(v
->age
);
814 case 0x41: return GB(ClampTo
<uint16_t>(v
->age
), 8, 8);
815 case 0x42: return ClampTo
<uint16_t>(v
->max_age
);
816 case 0x43: return GB(ClampTo
<uint16_t>(v
->max_age
), 8, 8);
817 case 0x44: return (Clamp(v
->build_year
, CalendarTime::ORIGINAL_BASE_YEAR
, CalendarTime::ORIGINAL_MAX_YEAR
) - CalendarTime::ORIGINAL_BASE_YEAR
).base();
818 case 0x45: return v
->unitnumber
;
819 case 0x46: return v
->GetEngine()->grf_prop
.local_id
;
820 case 0x47: return GB(v
->GetEngine()->grf_prop
.local_id
, 8, 8);
822 if (v
->type
!= VEH_TRAIN
|| v
->spritenum
!= 0xFD) return v
->spritenum
;
823 return HasBit(Train::From(v
)->flags
, VRF_REVERSE_DIRECTION
) ? 0xFE : 0xFD;
825 case 0x49: return v
->day_counter
;
826 case 0x4A: return v
->breakdowns_since_last_service
;
827 case 0x4B: return v
->breakdown_ctr
;
828 case 0x4C: return v
->breakdown_delay
;
829 case 0x4D: return v
->breakdown_chance
;
830 case 0x4E: return v
->reliability
;
831 case 0x4F: return GB(v
->reliability
, 8, 8);
832 case 0x50: return v
->reliability_spd_dec
;
833 case 0x51: return GB(v
->reliability_spd_dec
, 8, 8);
834 case 0x52: return ClampTo
<int32_t>(v
->GetDisplayProfitThisYear());
835 case 0x53: return GB(ClampTo
<int32_t>(v
->GetDisplayProfitThisYear()), 8, 24);
836 case 0x54: return GB(ClampTo
<int32_t>(v
->GetDisplayProfitThisYear()), 16, 16);
837 case 0x55: return GB(ClampTo
<int32_t>(v
->GetDisplayProfitThisYear()), 24, 8);
838 case 0x56: return ClampTo
<int32_t>(v
->GetDisplayProfitLastYear());
839 case 0x57: return GB(ClampTo
<int32_t>(v
->GetDisplayProfitLastYear()), 8, 24);
840 case 0x58: return GB(ClampTo
<int32_t>(v
->GetDisplayProfitLastYear()), 16, 16);
841 case 0x59: return GB(ClampTo
<int32_t>(v
->GetDisplayProfitLastYear()), 24, 8);
842 case 0x5A: return v
->Next() == nullptr ? INVALID_VEHICLE
: v
->Next()->index
;
843 case 0x5B: break; // not implemented
844 case 0x5C: return ClampTo
<int32_t>(v
->value
);
845 case 0x5D: return GB(ClampTo
<int32_t>(v
->value
), 8, 24);
846 case 0x5E: return GB(ClampTo
<int32_t>(v
->value
), 16, 16);
847 case 0x5F: return GB(ClampTo
<int32_t>(v
->value
), 24, 8);
848 case 0x60: break; // not implemented
849 case 0x61: break; // not implemented
850 case 0x62: break; // vehicle specific, see below
851 case 0x63: break; // not implemented
852 case 0x64: break; // vehicle specific, see below
853 case 0x65: break; // vehicle specific, see below
854 case 0x66: break; // vehicle specific, see below
855 case 0x67: break; // vehicle specific, see below
856 case 0x68: break; // vehicle specific, see below
857 case 0x69: break; // vehicle specific, see below
858 case 0x6A: break; // not implemented
859 case 0x6B: break; // not implemented
860 case 0x6C: break; // not implemented
861 case 0x6D: break; // not implemented
862 case 0x6E: break; // not implemented
863 case 0x6F: break; // not implemented
864 case 0x70: break; // not implemented
865 case 0x71: break; // not implemented
866 case 0x72: return v
->cargo_subtype
;
867 case 0x73: break; // vehicle specific, see below
868 case 0x74: break; // vehicle specific, see below
869 case 0x75: break; // vehicle specific, see below
870 case 0x76: break; // vehicle specific, see below
871 case 0x77: break; // vehicle specific, see below
872 case 0x78: break; // not implemented
873 case 0x79: break; // not implemented
874 case 0x7A: return v
->random_bits
;
875 case 0x7B: return v
->waiting_triggers
;
876 case 0x7C: break; // vehicle specific, see below
877 case 0x7D: break; // vehicle specific, see below
878 case 0x7E: break; // not implemented
879 case 0x7F: break; // vehicle specific, see below
882 /* Vehicle specific properties */
885 Train
*t
= Train::From(v
);
886 switch (variable
- 0x80) {
887 case 0x62: return t
->track
;
888 case 0x66: return t
->railtype
;
889 case 0x73: return 0x80 + VEHICLE_LENGTH
- t
->gcache
.cached_veh_length
;
890 case 0x74: return t
->gcache
.cached_power
;
891 case 0x75: return GB(t
->gcache
.cached_power
, 8, 24);
892 case 0x76: return GB(t
->gcache
.cached_power
, 16, 16);
893 case 0x77: return GB(t
->gcache
.cached_power
, 24, 8);
894 case 0x7C: return t
->First()->index
;
895 case 0x7D: return GB(t
->First()->index
, 8, 8);
896 case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
902 RoadVehicle
*rv
= RoadVehicle::From(v
);
903 switch (variable
- 0x80) {
904 case 0x62: return rv
->state
;
905 case 0x64: return rv
->blocked_ctr
;
906 case 0x65: return GB(rv
->blocked_ctr
, 8, 8);
907 case 0x66: return rv
->overtaking
;
908 case 0x67: return rv
->overtaking_ctr
;
909 case 0x68: return rv
->crashed_ctr
;
910 case 0x69: return GB(rv
->crashed_ctr
, 8, 8);
916 Ship
*s
= Ship::From(v
);
917 switch (variable
- 0x80) {
918 case 0x62: return s
->state
;
924 Aircraft
*a
= Aircraft::From(v
);
925 switch (variable
- 0x80) {
926 case 0x62: return MapAircraftMovementState(a
); // Current movement state
927 case 0x63: return a
->targetairport
; // Airport to which the action refers
928 case 0x66: return MapAircraftMovementAction(a
); // Current movement action
936 Debug(grf
, 1, "Unhandled vehicle variable 0x{:X}, type 0x{:X}", variable
, (uint
)v
->type
);
942 /* virtual */ uint32_t VehicleScopeResolver::GetVariable(byte variable
, [[maybe_unused
]] uint32_t parameter
, bool *available
) const
944 if (this->v
== nullptr) {
945 /* Vehicle does not exist, so we're in a purchase list */
947 case 0x43: return GetCompanyInfo(_current_company
, LiveryHelper(this->self_type
, nullptr)); // Owner information
948 case 0x46: return 0; // Motion counter
949 case 0x47: { // Vehicle cargo info
950 const Engine
*e
= Engine::Get(this->self_type
);
951 CargoID cargo_type
= e
->GetDefaultCargoType();
952 if (IsValidCargoID(cargo_type
)) {
953 const CargoSpec
*cs
= CargoSpec::Get(cargo_type
);
954 return (cs
->classes
<< 16) | (cs
->weight
<< 8) | this->ro
.grffile
->cargo_map
[cargo_type
];
959 case 0x48: return Engine::Get(this->self_type
)->flags
; // Vehicle Type Info
960 case 0x49: return TimerGameCalendar::year
.base(); // 'Long' format build year
961 case 0x4B: return TimerGameCalendar::date
.base(); // Long date of last service
962 case 0x92: return ClampTo
<uint16_t>(TimerGameCalendar::date
- CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR
); // Date of last service
963 case 0x93: return GB(ClampTo
<uint16_t>(TimerGameCalendar::date
- CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR
), 8, 8);
964 case 0xC4: return (Clamp(TimerGameCalendar::year
, CalendarTime::ORIGINAL_BASE_YEAR
, CalendarTime::ORIGINAL_MAX_YEAR
) - CalendarTime::ORIGINAL_BASE_YEAR
).base(); // Build year
965 case 0xC6: return Engine::Get(this->self_type
)->grf_prop
.local_id
;
966 case 0xC7: return GB(Engine::Get(this->self_type
)->grf_prop
.local_id
, 8, 8);
967 case 0xDA: return INVALID_VEHICLE
; // Next vehicle
968 case 0xF2: return 0; // Cargo subtype
975 return VehicleGetVariable(const_cast<Vehicle
*>(this->v
), this, variable
, parameter
, available
);
979 /* virtual */ const SpriteGroup
*VehicleResolverObject::ResolveReal(const RealSpriteGroup
*group
) const
981 const Vehicle
*v
= this->self_scope
.v
;
984 if (!group
->loading
.empty()) return group
->loading
[0];
985 if (!group
->loaded
.empty()) return group
->loaded
[0];
989 bool in_motion
= !v
->First()->current_order
.IsType(OT_LOADING
);
991 uint totalsets
= in_motion
? (uint
)group
->loaded
.size() : (uint
)group
->loading
.size();
993 if (totalsets
== 0) return nullptr;
995 uint set
= (v
->cargo
.StoredCount() * totalsets
) / std::max
<uint16_t>(1u, v
->cargo_cap
);
996 set
= std::min(set
, totalsets
- 1);
998 return in_motion
? group
->loaded
[set
] : group
->loading
[set
];
1001 GrfSpecFeature
VehicleResolverObject::GetFeature() const
1003 switch (Engine::Get(this->self_scope
.self_type
)->type
) {
1004 case VEH_TRAIN
: return GSF_TRAINS
;
1005 case VEH_ROAD
: return GSF_ROADVEHICLES
;
1006 case VEH_SHIP
: return GSF_SHIPS
;
1007 case VEH_AIRCRAFT
: return GSF_AIRCRAFT
;
1008 default: return GSF_INVALID
;
1012 uint32_t VehicleResolverObject::GetDebugID() const
1014 return Engine::Get(this->self_scope
.self_type
)->grf_prop
.local_id
;
1018 * Get the grf file associated with an engine type.
1019 * @param engine_type Engine to query.
1020 * @return grf file associated with the engine.
1022 static const GRFFile
*GetEngineGrfFile(EngineID engine_type
)
1024 const Engine
*e
= Engine::Get(engine_type
);
1025 return (e
!= nullptr) ? e
->GetGRF() : nullptr;
1029 * Resolver of a vehicle (chain).
1030 * @param engine_type Engine type
1031 * @param v %Vehicle being resolved.
1032 * @param wagon_override Application of wagon overrides.
1033 * @param rotor_in_gui Helicopter rotor is drawn in GUI.
1034 * @param callback Callback ID.
1035 * @param callback_param1 First parameter (var 10) of the callback.
1036 * @param callback_param2 Second parameter (var 18) of the callback.
1038 VehicleResolverObject::VehicleResolverObject(EngineID engine_type
, const Vehicle
*v
, WagonOverride wagon_override
, bool rotor_in_gui
,
1039 CallbackID callback
, uint32_t callback_param1
, uint32_t callback_param2
)
1040 : ResolverObject(GetEngineGrfFile(engine_type
), callback
, callback_param1
, callback_param2
),
1041 self_scope(*this, engine_type
, v
, rotor_in_gui
),
1042 parent_scope(*this, engine_type
, ((v
!= nullptr) ? v
->First() : v
), rotor_in_gui
),
1043 relative_scope(*this, engine_type
, v
, rotor_in_gui
),
1044 cached_relative_count(0)
1046 if (wagon_override
== WO_SELF
) {
1047 this->root_spritegroup
= GetWagonOverrideSpriteSet(engine_type
, SpriteGroupCargo::SG_DEFAULT
, engine_type
);
1049 if (wagon_override
!= WO_NONE
&& v
!= nullptr && v
->IsGroundVehicle()) {
1050 assert(v
->engine_type
== engine_type
); // overrides make little sense with fake scopes
1052 /* For trains we always use cached value, except for callbacks because the override spriteset
1053 * to use may be different than the one cached. It happens for callback 0x15 (refit engine),
1054 * as v->cargo_type is temporary changed to the new type */
1055 if (wagon_override
== WO_CACHED
&& v
->type
== VEH_TRAIN
) {
1056 this->root_spritegroup
= Train::From(v
)->tcache
.cached_override
;
1058 this->root_spritegroup
= GetWagonOverrideSpriteSet(v
->engine_type
, v
->cargo_type
, v
->GetGroundVehicleCache()->first_engine
);
1062 if (this->root_spritegroup
== nullptr) {
1063 const Engine
*e
= Engine::Get(engine_type
);
1064 CargoID cargo
= v
!= nullptr ? v
->cargo_type
: SpriteGroupCargo::SG_PURCHASE
;
1065 assert(cargo
< lengthof(e
->grf_prop
.spritegroup
));
1066 this->root_spritegroup
= e
->grf_prop
.spritegroup
[cargo
] != nullptr ? e
->grf_prop
.spritegroup
[cargo
] : e
->grf_prop
.spritegroup
[SpriteGroupCargo::SG_DEFAULT
];
1073 void GetCustomEngineSprite(EngineID engine
, const Vehicle
*v
, Direction direction
, EngineImageType image_type
, VehicleSpriteSeq
*result
)
1075 VehicleResolverObject
object(engine
, v
, VehicleResolverObject::WO_CACHED
, false, CBID_NO_CALLBACK
);
1078 bool sprite_stack
= HasBit(EngInfo(engine
)->misc_flags
, EF_SPRITE_STACK
);
1079 uint max_stack
= sprite_stack
? lengthof(result
->seq
) : 1;
1080 for (uint stack
= 0; stack
< max_stack
; ++stack
) {
1081 object
.ResetState();
1082 object
.callback_param1
= image_type
| (stack
<< 8);
1083 const SpriteGroup
*group
= object
.Resolve();
1084 uint32_t reg100
= sprite_stack
? GetRegister(0x100) : 0;
1085 if (group
!= nullptr && group
->GetNumResults() != 0) {
1086 result
->seq
[result
->count
].sprite
= group
->GetResult() + (direction
% group
->GetNumResults());
1087 result
->seq
[result
->count
].pal
= GB(reg100
, 0, 16); // zero means default recolouring
1090 if (!HasBit(reg100
, 31)) break;
1095 void GetRotorOverrideSprite(EngineID engine
, const struct Aircraft
*v
, EngineImageType image_type
, VehicleSpriteSeq
*result
)
1097 const Engine
*e
= Engine::Get(engine
);
1099 /* Only valid for helicopters */
1100 assert(e
->type
== VEH_AIRCRAFT
);
1101 assert(!(e
->u
.air
.subtype
& AIR_CTOL
));
1103 /* We differ from TTDPatch by resolving the sprite using the primary vehicle 'v', and not using the rotor vehicle 'v->Next()->Next()'.
1104 * TTDPatch copies some variables between the vehicles each time, to somehow synchronize the rotor vehicle with the primary vehicle.
1105 * We use 'rotor_in_gui' to replicate when the variables differ.
1106 * But some other variables like 'rotor state' and 'rotor speed' are not available in OpenTTD, while they are in TTDPatch. */
1107 bool rotor_in_gui
= image_type
!= EIT_ON_MAP
;
1108 VehicleResolverObject
object(engine
, v
, VehicleResolverObject::WO_SELF
, rotor_in_gui
, CBID_NO_CALLBACK
);
1110 uint rotor_pos
= v
== nullptr || rotor_in_gui
? 0 : v
->Next()->Next()->state
;
1112 bool sprite_stack
= HasBit(e
->info
.misc_flags
, EF_SPRITE_STACK
);
1113 uint max_stack
= sprite_stack
? lengthof(result
->seq
) : 1;
1114 for (uint stack
= 0; stack
< max_stack
; ++stack
) {
1115 object
.ResetState();
1116 object
.callback_param1
= image_type
| (stack
<< 8);
1117 const SpriteGroup
*group
= object
.Resolve();
1118 uint32_t reg100
= sprite_stack
? GetRegister(0x100) : 0;
1119 if (group
!= nullptr && group
->GetNumResults() != 0) {
1120 result
->seq
[result
->count
].sprite
= group
->GetResult() + (rotor_pos
% group
->GetNumResults());
1121 result
->seq
[result
->count
].pal
= GB(reg100
, 0, 16); // zero means default recolouring
1124 if (!HasBit(reg100
, 31)) break;
1130 * Check if a wagon is currently using a wagon override
1131 * @param v The wagon to check
1132 * @return true if it is using an override, false otherwise
1134 bool UsesWagonOverride(const Vehicle
*v
)
1136 assert(v
->type
== VEH_TRAIN
);
1137 return Train::From(v
)->tcache
.cached_override
!= nullptr;
1141 * Evaluate a newgrf callback for vehicles
1142 * @param callback The callback to evaluate
1143 * @param param1 First parameter of the callback
1144 * @param param2 Second parameter of the callback
1145 * @param engine Engine type of the vehicle to evaluate the callback for
1146 * @param v The vehicle to evaluate the callback for, or nullptr if it doesn't exist yet
1147 * @return The value the callback returned, or CALLBACK_FAILED if it failed
1149 uint16_t GetVehicleCallback(CallbackID callback
, uint32_t param1
, uint32_t param2
, EngineID engine
, const Vehicle
*v
)
1151 VehicleResolverObject
object(engine
, v
, VehicleResolverObject::WO_UNCACHED
, false, callback
, param1
, param2
);
1152 return object
.ResolveCallback();
1156 * Evaluate a newgrf callback for vehicles with a different vehicle for parent scope.
1157 * @param callback The callback to evaluate
1158 * @param param1 First parameter of the callback
1159 * @param param2 Second parameter of the callback
1160 * @param engine Engine type of the vehicle to evaluate the callback for
1161 * @param v The vehicle to evaluate the callback for, or nullptr if it doesn't exist yet
1162 * @param parent The vehicle to use for parent scope
1163 * @return The value the callback returned, or CALLBACK_FAILED if it failed
1165 uint16_t GetVehicleCallbackParent(CallbackID callback
, uint32_t param1
, uint32_t param2
, EngineID engine
, const Vehicle
*v
, const Vehicle
*parent
)
1167 VehicleResolverObject
object(engine
, v
, VehicleResolverObject::WO_NONE
, false, callback
, param1
, param2
);
1168 object
.parent_scope
.SetVehicle(parent
);
1169 return object
.ResolveCallback();
1173 /* Callback 36 handlers */
1174 int GetVehicleProperty(const Vehicle
*v
, PropertyID property
, int orig_value
, bool is_signed
)
1176 return GetEngineProperty(v
->engine_type
, property
, orig_value
, v
, is_signed
);
1180 int GetEngineProperty(EngineID engine
, PropertyID property
, int orig_value
, const Vehicle
*v
, bool is_signed
)
1182 uint16_t callback
= GetVehicleCallback(CBID_VEHICLE_MODIFY_PROPERTY
, property
, 0, engine
, v
);
1183 if (callback
!= CALLBACK_FAILED
) {
1185 /* Sign extend 15 bit integer */
1186 return static_cast<int16_t>(callback
<< 1) / 2;
1196 * Test for vehicle build probablity type.
1197 * @param v Vehicle whose build probability to test.
1198 * @param type Build probability type to test for.
1199 * @returns True iff the probability result says so.
1201 bool TestVehicleBuildProbability(Vehicle
*v
, EngineID engine
, BuildProbabilityType type
)
1203 uint16_t p
= GetVehicleCallback(CBID_VEHICLE_BUILD_PROBABILITY
, std::underlying_type
<BuildProbabilityType
>::type(type
), 0, engine
, v
);
1204 if (p
== CALLBACK_FAILED
) return false;
1206 const uint16_t PROBABILITY_RANGE
= 100;
1207 return p
+ RandomRange(PROBABILITY_RANGE
) >= PROBABILITY_RANGE
;
1210 static void DoTriggerVehicle(Vehicle
*v
, VehicleTrigger trigger
, uint16_t base_random_bits
, bool first
)
1212 /* We can't trigger a non-existent vehicle... */
1213 assert(v
!= nullptr);
1215 VehicleResolverObject
object(v
->engine_type
, v
, VehicleResolverObject::WO_CACHED
, false, CBID_RANDOM_TRIGGER
);
1216 object
.waiting_triggers
= v
->waiting_triggers
| trigger
;
1217 v
->waiting_triggers
= object
.waiting_triggers
; // store now for var 5F
1219 const SpriteGroup
*group
= object
.Resolve();
1220 if (group
== nullptr) return;
1222 /* Store remaining triggers. */
1223 v
->waiting_triggers
= object
.GetRemainingTriggers();
1225 /* Rerandomise bits. Scopes other than SELF are invalid for rerandomisation. For bug-to-bug-compatibility with TTDP we ignore the scope. */
1226 uint16_t new_random_bits
= Random();
1227 uint32_t reseed
= object
.GetReseedSum();
1228 v
->random_bits
&= ~reseed
;
1229 v
->random_bits
|= (first
? new_random_bits
: base_random_bits
) & reseed
;
1232 case VEHICLE_TRIGGER_NEW_CARGO
:
1233 /* All vehicles in chain get ANY_NEW_CARGO trigger now.
1234 * So we call it for the first one and they will recurse.
1235 * Indexing part of vehicle random bits needs to be
1236 * same for all triggered vehicles in the chain (to get
1237 * all the random-cargo wagons carry the same cargo,
1238 * i.e.), so we give them all the NEW_CARGO triggered
1239 * vehicle's portion of random bits. */
1241 DoTriggerVehicle(v
->First(), VEHICLE_TRIGGER_ANY_NEW_CARGO
, new_random_bits
, false);
1244 case VEHICLE_TRIGGER_DEPOT
:
1245 /* We now trigger the next vehicle in chain recursively.
1246 * The random bits portions may be different for each
1247 * vehicle in chain. */
1248 if (v
->Next() != nullptr) DoTriggerVehicle(v
->Next(), trigger
, 0, true);
1251 case VEHICLE_TRIGGER_EMPTY
:
1252 /* We now trigger the next vehicle in chain
1253 * recursively. The random bits portions must be same
1254 * for each vehicle in chain, so we give them all
1255 * first chained vehicle's portion of random bits. */
1256 if (v
->Next() != nullptr) DoTriggerVehicle(v
->Next(), trigger
, first
? new_random_bits
: base_random_bits
, false);
1259 case VEHICLE_TRIGGER_ANY_NEW_CARGO
:
1260 /* Now pass the trigger recursively to the next vehicle
1263 if (v
->Next() != nullptr) DoTriggerVehicle(v
->Next(), VEHICLE_TRIGGER_ANY_NEW_CARGO
, base_random_bits
, false);
1266 case VEHICLE_TRIGGER_CALLBACK_32
:
1267 /* Do not do any recursion */
1272 void TriggerVehicle(Vehicle
*v
, VehicleTrigger trigger
)
1274 if (trigger
== VEHICLE_TRIGGER_DEPOT
) {
1275 /* store that the vehicle entered a depot this tick */
1276 VehicleEnteredDepotThisTick(v
);
1279 v
->InvalidateNewGRFCacheOfChain();
1280 DoTriggerVehicle(v
, trigger
, 0, true);
1281 v
->InvalidateNewGRFCacheOfChain();
1284 /* Functions for changing the order of vehicle purchase lists */
1286 struct ListOrderChange
{
1288 uint target
; ///< local ID
1291 static std::vector
<ListOrderChange
> _list_order_changes
;
1294 * Record a vehicle ListOrderChange.
1295 * @param engine Engine to move
1296 * @param target Local engine ID to move \a engine in front of
1297 * @note All sorting is done later in CommitVehicleListOrderChanges
1299 void AlterVehicleListOrder(EngineID engine
, uint target
)
1301 /* Add the list order change to a queue */
1302 _list_order_changes
.push_back({engine
, target
});
1306 * Comparator function to sort engines via scope-GRFID and local ID.
1307 * @param a left side
1308 * @param b right side
1309 * @return comparison result
1311 static bool EnginePreSort(const EngineID
&a
, const EngineID
&b
)
1313 const EngineIDMapping
&id_a
= _engine_mngr
.at(a
);
1314 const EngineIDMapping
&id_b
= _engine_mngr
.at(b
);
1316 /* 1. Sort by engine type */
1317 if (id_a
.type
!= id_b
.type
) return (int)id_a
.type
< (int)id_b
.type
;
1319 /* 2. Sort by scope-GRFID */
1320 if (id_a
.grfid
!= id_b
.grfid
) return id_a
.grfid
< id_b
.grfid
;
1322 /* 3. Sort by local ID */
1323 return (int)id_a
.internal_id
< (int)id_b
.internal_id
;
1327 * Deternine default engine sorting and execute recorded ListOrderChanges from AlterVehicleListOrder.
1329 void CommitVehicleListOrderChanges()
1331 /* Pre-sort engines by scope-grfid and local index */
1332 std::vector
<EngineID
> ordering
;
1333 for (const Engine
*e
: Engine::Iterate()) {
1334 ordering
.push_back(e
->index
);
1336 std::sort(ordering
.begin(), ordering
.end(), EnginePreSort
);
1338 /* Apply Insertion-Sort operations */
1339 for (const ListOrderChange
&it
: _list_order_changes
) {
1340 EngineID source
= it
.engine
;
1341 uint local_target
= it
.target
;
1343 const EngineIDMapping
*id_source
= _engine_mngr
.data() + source
;
1344 if (id_source
->internal_id
== local_target
) continue;
1346 EngineID target
= _engine_mngr
.GetID(id_source
->type
, local_target
, id_source
->grfid
);
1347 if (target
== INVALID_ENGINE
) continue;
1349 int source_index
= find_index(ordering
, source
);
1350 int target_index
= find_index(ordering
, target
);
1352 assert(source_index
>= 0 && target_index
>= 0);
1353 assert(source_index
!= target_index
);
1355 EngineID
*list
= ordering
.data();
1356 if (source_index
< target_index
) {
1358 for (int i
= source_index
; i
< target_index
; ++i
) list
[i
] = list
[i
+ 1];
1359 list
[target_index
] = source
;
1361 for (int i
= source_index
; i
> target_index
; --i
) list
[i
] = list
[i
- 1];
1362 list
[target_index
] = source
;
1366 /* Store final sort-order */
1368 for (const EngineID
&eid
: ordering
) {
1369 Engine::Get(eid
)->list_position
= index
;
1373 /* Clear out the queue */
1374 _list_order_changes
.clear();
1375 _list_order_changes
.shrink_to_fit();
1379 * Fill the grf_cache of the given vehicle.
1380 * @param v The vehicle to fill the cache for.
1382 void FillNewGRFVehicleCache(const Vehicle
*v
)
1384 VehicleResolverObject
ro(v
->engine_type
, v
, VehicleResolverObject::WO_NONE
);
1386 /* These variables we have to check; these are the ones with a cache. */
1387 static const int cache_entries
[][2] = {
1388 { 0x40, NCVV_POSITION_CONSIST_LENGTH
},
1389 { 0x41, NCVV_POSITION_SAME_ID_LENGTH
},
1390 { 0x42, NCVV_CONSIST_CARGO_INFORMATION
},
1391 { 0x43, NCVV_COMPANY_INFORMATION
},
1392 { 0x4D, NCVV_POSITION_IN_VEHICLE
},
1394 static_assert(NCVV_END
== lengthof(cache_entries
));
1396 /* Resolve all the variables, so their caches are set. */
1397 for (size_t i
= 0; i
< lengthof(cache_entries
); i
++) {
1398 /* Only resolve when the cache isn't valid. */
1399 if (HasBit(v
->grf_cache
.cache_valid
, cache_entries
[i
][1])) continue;
1401 ro
.GetScope(VSG_SCOPE_SELF
)->GetVariable(cache_entries
[i
][0], 0, &stub
);
1404 /* Make sure really all bits are set. */
1405 assert(v
->grf_cache
.cache_valid
== (1 << NCVV_END
) - 1);