4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file newgrf_engine.cpp NewGRF handling of engines. */
16 #include "company_func.h"
17 #include "newgrf_cargo.h"
18 #include "newgrf_spritegroup.h"
19 #include "date_func.h"
20 #include "vehicle_func.h"
21 #include "core/random_func.hpp"
23 #include "station_base.h"
24 #include "company_base.h"
25 #include "newgrf_railtype.h"
28 struct WagonOverride
{
32 const SpriteGroup
*group
;
35 void SetWagonOverrideSprites(EngineID engine
, CargoID cargo
, const SpriteGroup
*group
, EngineID
*train_id
, uint trains
)
37 Engine
*e
= Engine::Get(engine
);
40 assert(cargo
< NUM_CARGO
+ 2); // Include CT_DEFAULT and CT_PURCHASE pseudo cargoes.
43 e
->overrides
= ReallocT(e
->overrides
, e
->overrides_count
);
45 wo
= &e
->overrides
[e
->overrides_count
- 1];
49 wo
->train_id
= MallocT
<EngineID
>(trains
);
50 memcpy(wo
->train_id
, train_id
, trains
* sizeof *train_id
);
53 const SpriteGroup
*GetWagonOverrideSpriteSet(EngineID engine
, CargoID cargo
, EngineID overriding_engine
)
55 const Engine
*e
= Engine::Get(engine
);
57 /* XXX: This could turn out to be a timesink on profiles. We could
58 * always just dedicate 65535 bytes for an [engine][train] trampoline
59 * for O(1). Or O(logMlogN) and searching binary tree or smt. like
62 for (uint i
= 0; i
< e
->overrides_count
; i
++) {
63 const WagonOverride
*wo
= &e
->overrides
[i
];
65 if (wo
->cargo
!= cargo
&& wo
->cargo
!= CT_DEFAULT
) continue;
67 for (uint j
= 0; j
< wo
->trains
; j
++) {
68 if (wo
->train_id
[j
] == overriding_engine
) return wo
->group
;
75 * Unload all wagon override sprite groups.
77 void UnloadWagonOverrides(Engine
*e
)
79 for (uint i
= 0; i
< e
->overrides_count
; i
++) {
80 WagonOverride
*wo
= &e
->overrides
[i
];
84 e
->overrides_count
= 0;
89 void SetCustomEngineSprites(EngineID engine
, byte cargo
, const SpriteGroup
*group
)
91 Engine
*e
= Engine::Get(engine
);
92 assert(cargo
< lengthof(e
->grf_prop
.spritegroup
));
94 if (e
->grf_prop
.spritegroup
[cargo
] != NULL
) {
95 grfmsg(6, "SetCustomEngineSprites: engine %d cargo %d already has group -- replacing", engine
, cargo
);
97 e
->grf_prop
.spritegroup
[cargo
] = group
;
102 * Tie a GRFFile entry to an engine, to allow us to retrieve GRF parameters
104 * @param engine Engine ID to tie the GRFFile to.
105 * @param file Pointer of GRFFile to tie.
107 void SetEngineGRF(EngineID engine
, const GRFFile
*file
)
109 Engine
*e
= Engine::Get(engine
);
110 e
->grf_prop
.grffile
= file
;
114 static int MapOldSubType(const Vehicle
*v
)
118 if (Train::From(v
)->IsEngine()) return 0;
119 if (Train::From(v
)->IsFreeWagon()) return 4;
122 case VEH_SHIP
: return 0;
124 case VEH_DISASTER
: return v
->subtype
;
125 case VEH_EFFECT
: return v
->subtype
<< 1;
126 default: NOT_REACHED();
131 /* TTDP style aircraft movement states for GRF Action 2 Var 0xE2 */
132 enum TTDPAircraftMovementStates
{
138 AMS_TTDP_TO_ENTRY_2_AND_3
,
139 AMS_TTDP_TO_ENTRY_2_AND_3_AND_H
,
140 AMS_TTDP_TO_JUNCTION
,
141 AMS_TTDP_LEAVE_RUNWAY
,
149 AMS_TTDP_FLIGHT_APPROACH
,
150 AMS_TTDP_UNUSED_0x11
,
151 AMS_TTDP_FLIGHT_TO_TOWER
,
152 AMS_TTDP_UNUSED_0x13
,
153 AMS_TTDP_FLIGHT_FINAL
,
154 AMS_TTDP_FLIGHT_DESCENT
,
156 AMS_TTDP_HELI_TAKEOFF_AIRPORT
,
157 AMS_TTDP_HELI_TO_TAKEOFF_AIRPORT
,
158 AMS_TTDP_HELI_LAND_AIRPORT
,
159 AMS_TTDP_HELI_TAKEOFF_HELIPORT
,
160 AMS_TTDP_HELI_TO_TAKEOFF_HELIPORT
,
161 AMS_TTDP_HELI_LAND_HELIPORT
,
166 * Map OTTD aircraft movement states to TTDPatch style movement states
167 * (VarAction 2 Variable 0xE2)
169 static byte
MapAircraftMovementState(const Aircraft
*v
)
171 const Station
*st
= GetTargetAirportIfValid(v
);
172 if (st
== NULL
) return AMS_TTDP_FLIGHT_TO_TOWER
;
174 const AirportFTAClass
*afc
= st
->airport
.GetFTA();
175 uint16 amdflag
= afc
->MovingData(v
->pos
)->flag
;
179 /* The international airport is a special case as helicopters can land in
180 * front of the hangar. Helicopters also change their air.state to
181 * AMED_HELI_LOWER some time before actually descending. */
183 /* This condition only occurs for helicopters, during descent,
184 * to a landing by the hangar of an international airport. */
185 if (amdflag
& AMED_HELI_LOWER
) return AMS_TTDP_HELI_LAND_AIRPORT
;
187 /* This condition only occurs for helicopters, before starting descent,
188 * to a landing by the hangar of an international airport. */
189 if (amdflag
& AMED_SLOWTURN
) return AMS_TTDP_FLIGHT_TO_TOWER
;
191 /* The final two conditions apply to helicopters or aircraft.
192 * Has reached hangar? */
193 if (amdflag
& AMED_EXACTPOS
) return AMS_TTDP_HANGAR
;
195 /* Still moving towards hangar. */
196 return AMS_TTDP_TO_HANGAR
;
199 if (amdflag
& AMED_EXACTPOS
) return AMS_TTDP_TO_PAD1
;
200 return AMS_TTDP_TO_JUNCTION
;
203 if (amdflag
& AMED_EXACTPOS
) return AMS_TTDP_TO_PAD2
;
204 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H
;
212 /* TTDPatch only has 3 terminals, so treat these states the same */
213 if (amdflag
& AMED_EXACTPOS
) return AMS_TTDP_TO_PAD3
;
214 return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H
;
219 /* Will only occur for helicopters.*/
220 if (amdflag
& AMED_HELI_LOWER
) return AMS_TTDP_HELI_LAND_AIRPORT
; // Descending.
221 if (amdflag
& AMED_SLOWTURN
) return AMS_TTDP_FLIGHT_TO_TOWER
; // Still hasn't started descent.
222 return AMS_TTDP_TO_JUNCTION
; // On the ground.
224 case TAKEOFF
: // Moving to takeoff position.
225 return AMS_TTDP_TO_OUTWAY
;
227 case STARTTAKEOFF
: // Accelerating down runway.
228 return AMS_TTDP_TAKEOFF
;
230 case ENDTAKEOFF
: // Ascent
231 return AMS_TTDP_CLIMBING
;
233 case HELITAKEOFF
: // Helicopter is moving to take off position.
234 if (afc
->delta_z
== 0) {
235 return amdflag
& AMED_HELI_RAISE
?
236 AMS_TTDP_HELI_TAKEOFF_AIRPORT
: AMS_TTDP_TO_JUNCTION
;
238 return AMS_TTDP_HELI_TAKEOFF_HELIPORT
;
242 return amdflag
& AMED_HOLD
? AMS_TTDP_FLIGHT_APPROACH
: AMS_TTDP_FLIGHT_TO_TOWER
;
244 case LANDING
: // Descent
245 return AMS_TTDP_FLIGHT_DESCENT
;
247 case ENDLANDING
: // On the runway braking
248 if (amdflag
& AMED_BRAKE
) return AMS_TTDP_BRAKING
;
249 /* Landed - moving off runway */
250 return AMS_TTDP_TO_INWAY
;
253 case HELIENDLANDING
: // Helicoptor is decending.
254 if (amdflag
& AMED_HELI_LOWER
) {
255 return afc
->delta_z
== 0 ?
256 AMS_TTDP_HELI_LAND_AIRPORT
: AMS_TTDP_HELI_LAND_HELIPORT
;
258 return AMS_TTDP_FLIGHT_TO_TOWER
;
262 return AMS_TTDP_HANGAR
;
267 /* TTDP style aircraft movement action for GRF Action 2 Var 0xE6 */
268 enum TTDPAircraftMovementActions
{
273 AMA_TTDP_HANGAR_TO_PAD1
,
274 AMA_TTDP_HANGAR_TO_PAD2
,
275 AMA_TTDP_HANGAR_TO_PAD3
,
276 AMA_TTDP_LANDING_TO_PAD1
,
277 AMA_TTDP_LANDING_TO_PAD2
,
278 AMA_TTDP_LANDING_TO_PAD3
,
279 AMA_TTDP_PAD1_TO_HANGAR
,
280 AMA_TTDP_PAD2_TO_HANGAR
,
281 AMA_TTDP_PAD3_TO_HANGAR
,
282 AMA_TTDP_PAD1_TO_TAKEOFF
,
283 AMA_TTDP_PAD2_TO_TAKEOFF
,
284 AMA_TTDP_PAD3_TO_TAKEOFF
,
285 AMA_TTDP_HANGAR_TO_TAKOFF
,
286 AMA_TTDP_LANDING_TO_HANGAR
,
292 * Map OTTD aircraft movement states to TTDPatch style movement actions
293 * (VarAction 2 Variable 0xE6)
294 * This is not fully supported yet but it's enough for Planeset.
296 static byte
MapAircraftMovementAction(const Aircraft
*v
)
300 return (v
->cur_speed
> 0) ? AMA_TTDP_LANDING_TO_HANGAR
: AMA_TTDP_IN_HANGAR
;
304 return (v
->current_order
.IsType(OT_LOADING
)) ? AMA_TTDP_ON_PAD1
: AMA_TTDP_LANDING_TO_PAD1
;
308 return (v
->current_order
.IsType(OT_LOADING
)) ? AMA_TTDP_ON_PAD2
: AMA_TTDP_LANDING_TO_PAD2
;
317 return (v
->current_order
.IsType(OT_LOADING
)) ? AMA_TTDP_ON_PAD3
: AMA_TTDP_LANDING_TO_PAD3
;
319 case TAKEOFF
: // Moving to takeoff position
320 case STARTTAKEOFF
: // Accelerating down runway
321 case ENDTAKEOFF
: // Ascent
323 /* @todo Need to find which terminal (or hangar) we've come from. How? */
324 return AMA_TTDP_PAD1_TO_TAKEOFF
;
327 return AMA_TTDP_IN_FLIGHT
;
329 case LANDING
: // Descent
330 case ENDLANDING
: // On the runway braking
333 /* @todo Need to check terminal we're landing to. Is it known yet? */
334 return (v
->current_order
.IsType(OT_GOTO_DEPOT
)) ?
335 AMA_TTDP_LANDING_TO_HANGAR
: AMA_TTDP_LANDING_TO_PAD1
;
338 return AMA_TTDP_IN_HANGAR
;
343 /* virtual */ uint32
VehicleScopeResolver::GetRandomBits() const
345 return this->v
== NULL
? 0 : this->v
->random_bits
;
348 /* virtual */ uint32
VehicleScopeResolver::GetTriggers() const
350 return this->v
== NULL
? 0 : this->v
->waiting_triggers
;
353 /* virtual */ void VehicleScopeResolver::SetTriggers(int triggers
) const
355 /* Evil cast to get around const-ness. This used to be achieved by an
356 * innocent looking function pointer cast... Currently I cannot see a
357 * way of avoiding this without removing consts deep within gui code.
359 Vehicle
*v
= const_cast<Vehicle
*>(this->v
);
361 /* This function must only be called when processing triggers -- any
362 * other time is an error. */
363 assert(this->ro
.trigger
!= 0);
365 if (v
!= NULL
) v
->waiting_triggers
= triggers
;
369 /* virtual */ ScopeResolver
*VehicleResolverObject::GetScope(VarSpriteGroupScope scope
, byte relative
)
372 case VSG_SCOPE_SELF
: return &this->self_scope
;
373 case VSG_SCOPE_PARENT
: return &this->parent_scope
;
374 case VSG_SCOPE_RELATIVE
: {
375 int32 count
= GB(relative
, 0, 4);
376 if (this->self_scope
.v
!= NULL
&& (relative
!= this->cached_relative_count
|| count
== 0)) {
377 /* Note: This caching only works as long as the VSG_SCOPE_RELATIVE cannot be used in
378 * VarAct2 with procedure calls. */
379 if (count
== 0) count
= GetRegister(0x100);
381 const Vehicle
*v
= NULL
;
382 switch (GB(relative
, 6, 2)) {
383 default: NOT_REACHED();
384 case 0x00: // count back (away from the engine), starting at this vehicle
385 v
= this->self_scope
.v
;
387 case 0x01: // count forward (toward the engine), starting at this vehicle
388 v
= this->self_scope
.v
;
391 case 0x02: // count back, starting at the engine
392 v
= this->parent_scope
.v
;
394 case 0x03: { // count back, starting at the first vehicle in this chain of vehicles with the same ID, as for vehicle variable 41
395 const Vehicle
*self
= this->self_scope
.v
;
396 for (const Vehicle
*u
= self
->First(); u
!= self
; u
= u
->Next()) {
397 if (u
->engine_type
!= self
->engine_type
) {
400 if (v
== NULL
) v
= u
;
403 if (v
== NULL
) v
= self
;
407 this->relative_scope
.SetVehicle(v
->Move(count
));
409 return &this->relative_scope
;
411 default: return ResolverObject::GetScope(scope
, relative
);
416 * Determines the livery of an engine.
418 * This always uses dual company colours independent of GUI settings. So it is desync-safe.
420 * @param engine Engine type
421 * @param v Vehicle, NULL in purchase list.
422 * @return Livery to use
424 static const Livery
*LiveryHelper(EngineID engine
, const Vehicle
*v
)
429 if (!Company::IsValidID(_current_company
)) return NULL
;
430 l
= GetEngineLivery(engine
, _current_company
, INVALID_ENGINE
, NULL
, LIT_ALL
);
431 } else if (v
->IsGroundVehicle()) {
432 l
= GetEngineLivery(v
->engine_type
, v
->owner
, v
->GetGroundVehicleCache()->first_engine
, v
, LIT_ALL
);
434 l
= GetEngineLivery(v
->engine_type
, v
->owner
, INVALID_ENGINE
, v
, LIT_ALL
);
441 * Helper to get the position of a vehicle within a chain of vehicles.
442 * @param v the vehicle to get the position of.
443 * @param consecutive whether to look at the whole chain or the vehicles
444 * with the same 'engine type'.
445 * @return the position in the chain from front and tail and chain length.
447 static uint32
PositionHelper(const Vehicle
*v
, bool consecutive
)
450 byte chain_before
= 0;
451 byte chain_after
= 0;
453 for (u
= v
->First(); u
!= v
; u
= u
->Next()) {
455 if (consecutive
&& u
->engine_type
!= v
->engine_type
) chain_before
= 0;
458 while (u
->Next() != NULL
&& (!consecutive
|| u
->Next()->engine_type
== v
->engine_type
)) {
463 return chain_before
| chain_after
<< 8 | (chain_before
+ chain_after
+ consecutive
) << 16;
466 static uint32
VehicleGetVariable(Vehicle
*v
, const VehicleScopeResolver
*object
, byte variable
, uint32 parameter
, bool *available
)
468 /* Calculated vehicle parameters */
470 case 0x25: // Get engine GRF ID
471 return v
->GetGRFID();
473 case 0x40: // Get length of consist
474 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_CONSIST_LENGTH
)) {
475 v
->grf_cache
.position_consist_length
= PositionHelper(v
, false);
476 SetBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_CONSIST_LENGTH
);
478 return v
->grf_cache
.position_consist_length
;
480 case 0x41: // Get length of same consecutive wagons
481 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_SAME_ID_LENGTH
)) {
482 v
->grf_cache
.position_same_id_length
= PositionHelper(v
, true);
483 SetBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_SAME_ID_LENGTH
);
485 return v
->grf_cache
.position_same_id_length
;
487 case 0x42: { // Consist cargo information
488 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_CONSIST_CARGO_INFORMATION
)) {
490 byte cargo_classes
= 0;
491 uint8 common_cargoes
[NUM_CARGO
];
492 uint8 common_subtypes
[256];
493 byte user_def_data
= 0;
494 CargoID common_cargo_type
= CT_INVALID
;
495 uint8 common_subtype
= 0xFF; // Return 0xFF if nothing is carried
497 /* Reset our arrays */
498 memset(common_cargoes
, 0, sizeof(common_cargoes
));
499 memset(common_subtypes
, 0, sizeof(common_subtypes
));
501 for (u
= v
; u
!= NULL
; u
= u
->Next()) {
502 if (v
->type
== VEH_TRAIN
) user_def_data
|= Train::From(u
)->tcache
.user_def_data
;
504 /* Skip empty engines */
505 if (!u
->GetEngine()->CanCarryCargo()) continue;
507 cargo_classes
|= CargoSpec::Get(u
->cargo_type
)->classes
;
508 common_cargoes
[u
->cargo_type
]++;
511 /* Pick the most common cargo type */
512 uint common_cargo_best_amount
= 0;
513 for (CargoID cargo
= 0; cargo
< NUM_CARGO
; cargo
++) {
514 if (common_cargoes
[cargo
] > common_cargo_best_amount
) {
515 common_cargo_best_amount
= common_cargoes
[cargo
];
516 common_cargo_type
= cargo
;
520 /* Count subcargo types of common_cargo_type */
521 for (u
= v
; u
!= NULL
; u
= u
->Next()) {
522 /* Skip empty engines and engines not carrying common_cargo_type */
523 if (u
->cargo_type
!= common_cargo_type
|| !u
->GetEngine()->CanCarryCargo()) continue;
525 common_subtypes
[u
->cargo_subtype
]++;
528 /* Pick the most common subcargo type*/
529 uint common_subtype_best_amount
= 0;
530 for (uint i
= 0; i
< lengthof(common_subtypes
); i
++) {
531 if (common_subtypes
[i
] > common_subtype_best_amount
) {
532 common_subtype_best_amount
= common_subtypes
[i
];
537 /* Note: We have to store the untranslated cargotype in the cache as the cache can be read by different NewGRFs,
538 * which will need different translations */
539 v
->grf_cache
.consist_cargo_information
= cargo_classes
| (common_cargo_type
<< 8) | (common_subtype
<< 16) | (user_def_data
<< 24);
540 SetBit(v
->grf_cache
.cache_valid
, NCVV_CONSIST_CARGO_INFORMATION
);
543 /* The cargo translation is specific to the accessing GRF, and thus cannot be cached. */
544 CargoID common_cargo_type
= (v
->grf_cache
.consist_cargo_information
>> 8) & 0xFF;
546 /* Unlike everywhere else the cargo translation table is only used since grf version 8, not 7.
547 * Note: The grffile == NULL case only happens if this function is called for default vehicles.
548 * And this is only done by CheckCaches(). */
549 const GRFFile
*grffile
= object
->ro
.grffile
;
550 uint8 common_bitnum
= (common_cargo_type
== CT_INVALID
) ? 0xFF :
551 (grffile
== NULL
|| grffile
->grf_version
< 8) ? CargoSpec::Get(common_cargo_type
)->bitnum
: grffile
->cargo_map
[common_cargo_type
];
553 return (v
->grf_cache
.consist_cargo_information
& 0xFFFF00FF) | common_bitnum
<< 8;
556 case 0x43: // Company information
557 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_COMPANY_INFORMATION
)) {
558 v
->grf_cache
.company_information
= GetCompanyInfo(v
->owner
, LiveryHelper(v
->engine_type
, v
));
559 SetBit(v
->grf_cache
.cache_valid
, NCVV_COMPANY_INFORMATION
);
561 return v
->grf_cache
.company_information
;
563 case 0x44: // Aircraft information
564 if (v
->type
!= VEH_AIRCRAFT
|| !Aircraft::From(v
)->IsNormalAircraft()) return UINT_MAX
;
567 const Vehicle
*w
= v
->Next();
568 uint16 altitude
= v
->z_pos
- w
->z_pos
; // Aircraft height - shadow height
569 byte airporttype
= ATP_TTDP_LARGE
;
571 const Station
*st
= GetTargetAirportIfValid(Aircraft::From(v
));
573 if (st
!= NULL
&& st
->airport
.tile
!= INVALID_TILE
) {
574 airporttype
= st
->airport
.GetSpec()->ttd_airport_type
;
577 return (Clamp(altitude
, 0, 0xFF) << 8) | airporttype
;
580 case 0x45: { // Curvature info
582 * F - previous wagon to current wagon, 0 if vehicle is first
583 * B - current wagon to next wagon, 0 if wagon is last
584 * T - previous wagon to next wagon, 0 in an S-bend
586 if (!v
->IsGroundVehicle()) return 0;
588 const Vehicle
*u_p
= v
->Previous();
589 const Vehicle
*u_n
= v
->Next();
590 DirDiff f
= (u_p
== NULL
) ? DIRDIFF_SAME
: DirDifference(u_p
->direction
, v
->direction
);
591 DirDiff b
= (u_n
== NULL
) ? DIRDIFF_SAME
: DirDifference(v
->direction
, u_n
->direction
);
592 DirDiff t
= ChangeDirDiff(f
, b
);
594 return ((t
> DIRDIFF_REVERSE
? t
| 8 : t
) << 16) |
595 ((b
> DIRDIFF_REVERSE
? b
| 8 : b
) << 8) |
596 ( f
> DIRDIFF_REVERSE
? f
| 8 : f
);
599 case 0x46: // Motion counter
600 return v
->motion_counter
;
602 case 0x47: { // Vehicle cargo info
604 * tt - the cargo type transported by the vehicle,
605 * translated if a translation table has been installed.
606 * ww - cargo unit weight in 1/16 tons, same as cargo prop. 0F.
607 * cccc - the cargo class value of the cargo transported by the vehicle.
609 const CargoSpec
*cs
= CargoSpec::Get(v
->cargo_type
);
611 return (cs
->classes
<< 16) | (cs
->weight
<< 8) | v
->GetGRF()->cargo_map
[v
->cargo_type
];
614 case 0x48: return v
->GetEngine()->flags
; // Vehicle Type Info
615 case 0x49: return v
->build_year
;
618 if (v
->type
!= VEH_TRAIN
) return 0;
619 Train
*t
= Train::From(v
);
620 RailType rt
= t
->GetTrackRailType();
621 return (HasPowerOnRail(t
->railtype
, rt
) ? 0x100 : 0) | GetReverseRailTypeTranslation(rt
, object
->ro
.grffile
);
624 case 0x4B: // Long date of last service
625 return v
->date_of_last_service
;
627 case 0x4C: // Current maximum speed in NewGRF units
628 if (!v
->IsPrimaryVehicle()) return 0;
629 return v
->GetCurrentMaxSpeed();
631 case 0x4D: // Position within articulated vehicle
632 if (!HasBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_IN_VEHICLE
)) {
633 byte artic_before
= 0;
634 for (const Vehicle
*u
= v
; u
->IsArticulatedPart(); u
= u
->Previous()) artic_before
++;
635 byte artic_after
= 0;
636 for (const Vehicle
*u
= v
; u
->HasArticulatedPart(); u
= u
->Next()) artic_after
++;
637 v
->grf_cache
.position_in_vehicle
= artic_before
| artic_after
<< 8;
638 SetBit(v
->grf_cache
.cache_valid
, NCVV_POSITION_IN_VEHICLE
);
640 return v
->grf_cache
.position_in_vehicle
;
642 /* Variables which use the parameter */
643 case 0x60: // Count consist's engine ID occurrence
644 if (v
->type
!= VEH_TRAIN
) return v
->GetEngine()->grf_prop
.local_id
== parameter
? 1 : 0;
648 for (; v
!= NULL
; v
= v
->Next()) {
649 if (v
->GetEngine()->grf_prop
.local_id
== parameter
) count
++;
654 case 0x61: // Get variable of n-th vehicle in chain [signed number relative to vehicle]
655 if (!v
->IsGroundVehicle() || parameter
== 0x61) {
660 /* Only allow callbacks that don't change properties to avoid circular dependencies. */
661 if (object
->ro
.callback
== CBID_NO_CALLBACK
|| object
->ro
.callback
== CBID_RANDOM_TRIGGER
|| object
->ro
.callback
== CBID_TRAIN_ALLOW_WAGON_ATTACH
||
662 object
->ro
.callback
== CBID_VEHICLE_START_STOP_CHECK
|| object
->ro
.callback
== CBID_VEHICLE_32DAY_CALLBACK
|| object
->ro
.callback
== CBID_VEHICLE_COLOUR_MAPPING
) {
663 Vehicle
*u
= v
->Move((int32
)GetRegister(0x10F));
664 if (u
== NULL
) return 0; // available, but zero
666 if (parameter
== 0x5F) {
667 /* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */
668 return (u
->random_bits
<< 8) | u
->waiting_triggers
;
670 return VehicleGetVariable(u
, object
, parameter
, GetRegister(0x10E), available
);
676 case 0x62: { // Curvature/position difference for n-th vehicle in chain [signed number relative to vehicle]
678 * zz - Signed difference of z position between the selected and this vehicle.
679 * yy - Signed difference of y position between the selected and this vehicle.
680 * xx - Signed difference of x position between the selected and this vehicle.
681 * F - Flags, bit 7 corresponds to VS_HIDDEN.
682 * D - Dir difference, like in 0x45.
684 if (!v
->IsGroundVehicle()) return 0;
686 const Vehicle
*u
= v
->Move((int8
)parameter
);
687 if (u
== NULL
) return 0;
689 /* Get direction difference. */
690 bool prev
= (int8
)parameter
< 0;
691 uint32 ret
= prev
? DirDifference(u
->direction
, v
->direction
) : DirDifference(v
->direction
, u
->direction
);
692 if (ret
> DIRDIFF_REVERSE
) ret
|= 0x08;
694 if (u
->vehstatus
& VS_HIDDEN
) ret
|= 0x80;
696 /* Get position difference. */
697 ret
|= ((prev
? u
->x_pos
- v
->x_pos
: v
->x_pos
- u
->x_pos
) & 0xFF) << 8;
698 ret
|= ((prev
? u
->y_pos
- v
->y_pos
: v
->y_pos
- u
->y_pos
) & 0xFF) << 16;
699 ret
|= ((prev
? u
->z_pos
- v
->z_pos
: v
->z_pos
- u
->z_pos
) & 0xFF) << 24;
708 if (v
->type
== VEH_TRAIN
) {
709 const Train
*t
= Train::From(v
);
710 bool is_powered_wagon
= HasBit(t
->flags
, VRF_POWEREDWAGON
);
711 const Train
*u
= is_powered_wagon
? t
->First() : t
; // for powered wagons the engine defines the type of engine (i.e. railtype)
712 RailType railtype
= t
->GetTrackRailType();
713 bool powered
= t
->IsEngine() || is_powered_wagon
;
714 bool has_power
= HasPowerOnRail(u
->railtype
, railtype
);
716 if (powered
&& has_power
) SetBit(modflags
, 5);
717 if (powered
&& !has_power
) SetBit(modflags
, 6);
718 if (HasBit(t
->flags
, VRF_TOGGLE_REVERSE
)) SetBit(modflags
, 8);
720 if (HasBit(v
->vehicle_flags
, VF_BUILT_AS_PROTOTYPE
)) SetBit(modflags
, 10);
722 return variable
== 0xFE ? modflags
: GB(modflags
, 8, 8);
726 /* General vehicle properties */
727 switch (variable
- 0x80) {
728 case 0x00: return v
->type
+ 0x10;
729 case 0x01: return MapOldSubType(v
);
730 case 0x04: return v
->index
;
731 case 0x05: return GB(v
->index
, 8, 8);
732 case 0x0A: return v
->current_order
.MapOldOrder();
733 case 0x0B: return v
->current_order
.GetDestination();
734 case 0x0C: return v
->GetNumOrders();
735 case 0x0D: return v
->cur_real_order_index
;
739 if (v
->current_order
.IsType(OT_LOADING
)) {
740 ticks
= v
->load_unload_ticks
;
743 case VEH_TRAIN
: ticks
= Train::From(v
)->wait_counter
; break;
744 case VEH_AIRCRAFT
: ticks
= Aircraft::From(v
)->turn_counter
; break;
745 default: ticks
= 0; break;
748 return (variable
- 0x80) == 0x10 ? ticks
: GB(ticks
, 8, 8);
750 case 0x12: return Clamp(v
->date_of_last_service
- DAYS_TILL_ORIGINAL_BASE_YEAR
, 0, 0xFFFF);
751 case 0x13: return GB(Clamp(v
->date_of_last_service
- DAYS_TILL_ORIGINAL_BASE_YEAR
, 0, 0xFFFF), 8, 8);
752 case 0x14: return v
->GetServiceInterval();
753 case 0x15: return GB(v
->GetServiceInterval(), 8, 8);
754 case 0x16: return v
->last_station_visited
;
755 case 0x17: return v
->tick_counter
;
761 max_speed
= Aircraft::From(v
)->GetSpeedOldUnits(); // Convert to old units.
765 max_speed
= v
->vcache
.cached_max_speed
;
768 return (variable
- 0x80) == 0x18 ? max_speed
: GB(max_speed
, 8, 8);
770 case 0x1A: return v
->x_pos
;
771 case 0x1B: return GB(v
->x_pos
, 8, 8);
772 case 0x1C: return v
->y_pos
;
773 case 0x1D: return GB(v
->y_pos
, 8, 8);
774 case 0x1E: return v
->z_pos
;
775 case 0x1F: return object
->info_view
? DIR_W
: v
->direction
;
776 case 0x28: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
777 case 0x29: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs.
778 case 0x32: return v
->vehstatus
;
779 case 0x33: return 0; // non-existent high byte of vehstatus
780 case 0x34: return v
->type
== VEH_AIRCRAFT
? (v
->cur_speed
* 10) / 128 : v
->cur_speed
;
781 case 0x35: return GB(v
->type
== VEH_AIRCRAFT
? (v
->cur_speed
* 10) / 128 : v
->cur_speed
, 8, 8);
782 case 0x36: return v
->subspeed
;
783 case 0x37: return v
->acceleration
;
784 case 0x39: return v
->cargo_type
;
785 case 0x3A: return v
->cargo_cap
;
786 case 0x3B: return GB(v
->cargo_cap
, 8, 8);
787 case 0x3C: return ClampToU16(v
->cargo
.StoredCount());
788 case 0x3D: return GB(ClampToU16(v
->cargo
.StoredCount()), 8, 8);
789 case 0x3E: return v
->cargo
.Source();
790 case 0x3F: return ClampU(v
->cargo
.DaysInTransit(), 0, 0xFF);
791 case 0x40: return ClampToU16(v
->age
);
792 case 0x41: return GB(ClampToU16(v
->age
), 8, 8);
793 case 0x42: return ClampToU16(v
->max_age
);
794 case 0x43: return GB(ClampToU16(v
->max_age
), 8, 8);
795 case 0x44: return Clamp(v
->build_year
, ORIGINAL_BASE_YEAR
, ORIGINAL_MAX_YEAR
) - ORIGINAL_BASE_YEAR
;
796 case 0x45: return v
->unitnumber
;
797 case 0x46: return v
->GetEngine()->grf_prop
.local_id
;
798 case 0x47: return GB(v
->GetEngine()->grf_prop
.local_id
, 8, 8);
800 if (v
->type
!= VEH_TRAIN
|| v
->spritenum
!= 0xFD) return v
->spritenum
;
801 return HasBit(Train::From(v
)->flags
, VRF_REVERSE_DIRECTION
) ? 0xFE : 0xFD;
803 case 0x49: return v
->day_counter
;
804 case 0x4A: return v
->breakdowns_since_last_service
;
805 case 0x4B: return v
->breakdown_ctr
;
806 case 0x4C: return v
->breakdown_delay
;
807 case 0x4D: return v
->breakdown_chance
;
808 case 0x4E: return v
->reliability
;
809 case 0x4F: return GB(v
->reliability
, 8, 8);
810 case 0x50: return v
->reliability_spd_dec
;
811 case 0x51: return GB(v
->reliability_spd_dec
, 8, 8);
812 case 0x52: return ClampToI32(v
->GetDisplayProfitThisYear());
813 case 0x53: return GB(ClampToI32(v
->GetDisplayProfitThisYear()), 8, 24);
814 case 0x54: return GB(ClampToI32(v
->GetDisplayProfitThisYear()), 16, 16);
815 case 0x55: return GB(ClampToI32(v
->GetDisplayProfitThisYear()), 24, 8);
816 case 0x56: return ClampToI32(v
->GetDisplayProfitLastYear());
817 case 0x57: return GB(ClampToI32(v
->GetDisplayProfitLastYear()), 8, 24);
818 case 0x58: return GB(ClampToI32(v
->GetDisplayProfitLastYear()), 16, 16);
819 case 0x59: return GB(ClampToI32(v
->GetDisplayProfitLastYear()), 24, 8);
820 case 0x5A: return v
->Next() == NULL
? INVALID_VEHICLE
: v
->Next()->index
;
821 case 0x5C: return ClampToI32(v
->value
);
822 case 0x5D: return GB(ClampToI32(v
->value
), 8, 24);
823 case 0x5E: return GB(ClampToI32(v
->value
), 16, 16);
824 case 0x5F: return GB(ClampToI32(v
->value
), 24, 8);
825 case 0x72: return v
->cargo_subtype
;
826 case 0x7A: return v
->random_bits
;
827 case 0x7B: return v
->waiting_triggers
;
830 /* Vehicle specific properties */
833 Train
*t
= Train::From(v
);
834 switch (variable
- 0x80) {
835 case 0x62: return (t
->trackdir
< TRACKDIR_END
) ? TrackToTrackBits(TrackdirToTrack(t
->trackdir
)) : (TrackBits
)(uint
)t
->trackdir
;
836 case 0x66: return t
->railtype
;
837 case 0x73: return 0x80 + VEHICLE_LENGTH
- t
->gcache
.cached_veh_length
;
838 case 0x74: return t
->gcache
.cached_power
;
839 case 0x75: return GB(t
->gcache
.cached_power
, 8, 24);
840 case 0x76: return GB(t
->gcache
.cached_power
, 16, 16);
841 case 0x77: return GB(t
->gcache
.cached_power
, 24, 8);
842 case 0x7C: return t
->First()->index
;
843 case 0x7D: return GB(t
->First()->index
, 8, 8);
844 case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
850 RoadVehicle
*rv
= RoadVehicle::From(v
);
851 switch (variable
- 0x80) {
852 case 0x62: return rv
->state
;
853 case 0x64: return rv
->blocked_ctr
;
854 case 0x65: return GB(rv
->blocked_ctr
, 8, 8);
855 case 0x66: return rv
->overtaking
;
856 case 0x67: return rv
->overtaking_ctr
;
857 case 0x68: return rv
->crashed_ctr
;
858 case 0x69: return GB(rv
->crashed_ctr
, 8, 8);
864 Ship
*s
= Ship::From(v
);
865 switch (variable
- 0x80) {
866 case 0x62: return (s
->trackdir
< TRACKDIR_END
) ? TrackToTrackBits(TrackdirToTrack(s
->trackdir
)) : (TrackBits
)(uint
)s
->trackdir
;
872 Aircraft
*a
= Aircraft::From(v
);
873 switch (variable
- 0x80) {
874 case 0x62: return MapAircraftMovementState(a
); // Current movement state
875 case 0x63: return a
->targetairport
; // Airport to which the action refers
876 case 0x66: return MapAircraftMovementAction(a
); // Current movement action
884 DEBUG(grf
, 1, "Unhandled vehicle variable 0x%X, type 0x%X", variable
, (uint
)v
->type
);
890 /* virtual */ uint32
VehicleScopeResolver::GetVariable(byte variable
, uint32 parameter
, bool *available
) const
892 if (this->v
== NULL
) {
893 /* Vehicle does not exist, so we're in a purchase list */
895 case 0x43: return GetCompanyInfo(_current_company
, LiveryHelper(this->self_type
, NULL
)); // Owner information
896 case 0x46: return 0; // Motion counter
897 case 0x47: { // Vehicle cargo info
898 const Engine
*e
= Engine::Get(this->self_type
);
899 CargoID cargo_type
= e
->GetDefaultCargoType();
900 if (cargo_type
!= CT_INVALID
) {
901 const CargoSpec
*cs
= CargoSpec::Get(cargo_type
);
902 return (cs
->classes
<< 16) | (cs
->weight
<< 8) | e
->GetGRF()->cargo_map
[cargo_type
];
907 case 0x48: return Engine::Get(this->self_type
)->flags
; // Vehicle Type Info
908 case 0x49: return _cur_year
; // 'Long' format build year
909 case 0x4B: return _date
; // Long date of last service
910 case 0x92: return Clamp(_date
- DAYS_TILL_ORIGINAL_BASE_YEAR
, 0, 0xFFFF); // Date of last service
911 case 0x93: return GB(Clamp(_date
- DAYS_TILL_ORIGINAL_BASE_YEAR
, 0, 0xFFFF), 8, 8);
912 case 0xC4: return Clamp(_cur_year
, ORIGINAL_BASE_YEAR
, ORIGINAL_MAX_YEAR
) - ORIGINAL_BASE_YEAR
; // Build year
913 case 0xDA: return INVALID_VEHICLE
; // Next vehicle
914 case 0xF2: return 0; // Cargo subtype
921 return VehicleGetVariable(const_cast<Vehicle
*>(this->v
), this, variable
, parameter
, available
);
925 /* virtual */ const SpriteGroup
*VehicleResolverObject::ResolveReal(const RealSpriteGroup
*group
) const
927 const Vehicle
*v
= this->self_scope
.v
;
930 if (group
->num_loading
> 0) return group
->loading
[0];
931 if (group
->num_loaded
> 0) return group
->loaded
[0];
935 bool in_motion
= !v
->First()->current_order
.IsType(OT_LOADING
);
937 uint totalsets
= in_motion
? group
->num_loaded
: group
->num_loading
;
939 if (totalsets
== 0) return NULL
;
941 uint set
= (v
->cargo
.StoredCount() * totalsets
) / max((uint16
)1, v
->cargo_cap
);
942 set
= min(set
, totalsets
- 1);
944 return in_motion
? group
->loaded
[set
] : group
->loading
[set
];
948 * Scope resolver of a single vehicle.
949 * @param ro Surrounding resolver.
950 * @param engine_type Engine type
951 * @param v %Vehicle being resolved.
952 * @param info_view Indicates if the item is being drawn in an info window.
954 VehicleScopeResolver::VehicleScopeResolver(ResolverObject
&ro
, EngineID engine_type
, const Vehicle
*v
, bool info_view
)
958 this->self_type
= engine_type
;
959 this->info_view
= info_view
;
963 * Get the grf file associated with an engine type.
964 * @param engine_type Engine to query.
965 * @return grf file associated with the engine.
967 static const GRFFile
*GetEngineGrfFile(EngineID engine_type
)
969 const Engine
*e
= Engine::Get(engine_type
);
970 return (e
!= NULL
) ? e
->GetGRF() : NULL
;
974 * Resolver of a vehicle (chain).
975 * @param engine_type Engine type
976 * @param v %Vehicle being resolved.
977 * @param info_view Indicates if the item is being drawn in an info window.
978 * @param callback Callback ID.
979 * @param callback_param1 First parameter (var 10) of the callback.
980 * @param callback_param2 Second parameter (var 18) of the callback.
982 VehicleResolverObject::VehicleResolverObject(EngineID engine_type
, const Vehicle
*v
, bool info_view
,
983 CallbackID callback
, uint32 callback_param1
, uint32 callback_param2
)
984 : ResolverObject(GetEngineGrfFile(engine_type
), callback
, callback_param1
, callback_param2
),
985 self_scope(*this, engine_type
, v
, info_view
),
986 parent_scope(*this, engine_type
, ((v
!= NULL
) ? v
->First() : v
), info_view
),
987 relative_scope(*this, engine_type
, v
, info_view
),
988 cached_relative_count(0)
993 * Retrieve the SpriteGroup for the specified vehicle.
994 * If the vehicle is not specified, the purchase list group for the engine is
995 * chosen. For trains, an additional engine override lookup is performed.
996 * @param engine Engine type of the vehicle.
997 * @param v The vehicle itself.
998 * @param use_cache Use cached override
999 * @returns The selected SpriteGroup for the vehicle.
1001 static const SpriteGroup
*GetVehicleSpriteGroup(EngineID engine
, const Vehicle
*v
, bool use_cache
= true)
1003 const SpriteGroup
*group
;
1007 cargo
= CT_PURCHASE
;
1009 cargo
= v
->cargo_type
;
1011 if (v
->IsGroundVehicle()) {
1012 /* For trains we always use cached value, except for callbacks because the override spriteset
1013 * to use may be different than the one cached. It happens for callback 0x15 (refit engine),
1014 * as v->cargo_type is temporary changed to the new type */
1015 if (use_cache
&& v
->type
== VEH_TRAIN
) {
1016 group
= Train::From(v
)->tcache
.cached_override
;
1018 group
= GetWagonOverrideSpriteSet(v
->engine_type
, v
->cargo_type
, v
->GetGroundVehicleCache()->first_engine
);
1020 if (group
!= NULL
) return group
;
1024 const Engine
*e
= Engine::Get(engine
);
1026 assert(cargo
< lengthof(e
->grf_prop
.spritegroup
));
1027 group
= e
->grf_prop
.spritegroup
[cargo
];
1028 if (group
!= NULL
) return group
;
1030 /* Fall back to the default set if the selected cargo type is not defined */
1031 return e
->grf_prop
.spritegroup
[CT_DEFAULT
];
1035 SpriteID
GetCustomEngineSprite(EngineID engine
, const Vehicle
*v
, Direction direction
, EngineImageType image_type
)
1037 VehicleResolverObject
object(engine
, v
, false, CBID_NO_CALLBACK
, image_type
);
1038 const SpriteGroup
*group
= SpriteGroup::Resolve(GetVehicleSpriteGroup(engine
, v
), object
);
1039 if (group
== NULL
|| group
->GetNumResults() == 0) return 0;
1041 return group
->GetResult() + (direction
% group
->GetNumResults());
1045 SpriteID
GetRotorOverrideSprite(EngineID engine
, const Aircraft
*v
, bool info_view
, EngineImageType image_type
)
1047 const Engine
*e
= Engine::Get(engine
);
1049 /* Only valid for helicopters */
1050 assert(e
->type
== VEH_AIRCRAFT
);
1051 assert(!(e
->u
.air
.subtype
& AIR_CTOL
));
1053 VehicleResolverObject
object(engine
, v
, info_view
, CBID_NO_CALLBACK
, image_type
);
1054 const SpriteGroup
*group
= GetWagonOverrideSpriteSet(engine
, CT_DEFAULT
, engine
);
1055 group
= SpriteGroup::Resolve(group
, object
);
1057 if (group
== NULL
|| group
->GetNumResults() == 0) return 0;
1059 if (v
== NULL
) return group
->GetResult();
1061 return group
->GetResult() + (info_view
? 0 : (v
->Next()->Next()->state
% group
->GetNumResults()));
1066 * Check if a wagon is currently using a wagon override
1067 * @param v The wagon to check
1068 * @return true if it is using an override, false otherwise
1070 bool UsesWagonOverride(const Vehicle
*v
)
1072 assert(v
->type
== VEH_TRAIN
);
1073 return Train::From(v
)->tcache
.cached_override
!= NULL
;
1077 * Evaluate a newgrf callback for vehicles
1078 * @param callback The callback to evaluate
1079 * @param param1 First parameter of the callback
1080 * @param param2 Second parameter of the callback
1081 * @param engine Engine type of the vehicle to evaluate the callback for
1082 * @param v The vehicle to evaluate the callback for, or NULL if it doesnt exist yet
1083 * @return The value the callback returned, or CALLBACK_FAILED if it failed
1085 uint16
GetVehicleCallback(CallbackID callback
, uint32 param1
, uint32 param2
, EngineID engine
, const Vehicle
*v
)
1087 VehicleResolverObject
object(engine
, v
, false, callback
, param1
, param2
);
1088 const SpriteGroup
*group
= SpriteGroup::Resolve(GetVehicleSpriteGroup(engine
, v
, false), object
);
1089 if (group
== NULL
) return CALLBACK_FAILED
;
1091 return group
->GetCallbackResult();
1095 * Evaluate a newgrf callback for vehicles with a different vehicle for parent scope.
1096 * @param callback The callback to evaluate
1097 * @param param1 First parameter of the callback
1098 * @param param2 Second parameter of the callback
1099 * @param engine Engine type of the vehicle to evaluate the callback for
1100 * @param v The vehicle to evaluate the callback for, or NULL if it doesn't exist yet
1101 * @param parent The vehicle to use for parent scope
1102 * @return The value the callback returned, or CALLBACK_FAILED if it failed
1104 uint16
GetVehicleCallbackParent(CallbackID callback
, uint32 param1
, uint32 param2
, EngineID engine
, const Vehicle
*v
, const Vehicle
*parent
)
1106 VehicleResolverObject
object(engine
, v
, false, callback
, param1
, param2
);
1107 object
.parent_scope
.SetVehicle(parent
);
1109 const SpriteGroup
*group
= SpriteGroup::Resolve(GetVehicleSpriteGroup(engine
, v
, false), object
);
1110 if (group
== NULL
) return CALLBACK_FAILED
;
1112 return group
->GetCallbackResult();
1116 /* Callback 36 handlers */
1117 uint
GetVehicleProperty(const Vehicle
*v
, PropertyID property
, uint orig_value
)
1119 return GetEngineProperty(v
->engine_type
, property
, orig_value
, v
);
1123 uint
GetEngineProperty(EngineID engine
, PropertyID property
, uint orig_value
, const Vehicle
*v
)
1125 uint16 callback
= GetVehicleCallback(CBID_VEHICLE_MODIFY_PROPERTY
, property
, 0, engine
, v
);
1126 if (callback
!= CALLBACK_FAILED
) return callback
;
1132 static void DoTriggerVehicle(Vehicle
*v
, VehicleTrigger trigger
, byte base_random_bits
, bool first
)
1134 /* We can't trigger a non-existent vehicle... */
1137 VehicleResolverObject
object(v
->engine_type
, v
, false, CBID_RANDOM_TRIGGER
);
1138 object
.trigger
= trigger
;
1140 const SpriteGroup
*group
= SpriteGroup::Resolve(GetVehicleSpriteGroup(v
->engine_type
, v
), object
);
1141 if (group
== NULL
) return;
1143 byte new_random_bits
= Random();
1144 uint32 reseed
= object
.GetReseedSum(); // The scope only affects triggers, not the reseeding
1145 v
->random_bits
&= ~reseed
;
1146 v
->random_bits
|= (first
? new_random_bits
: base_random_bits
) & reseed
;
1149 case VEHICLE_TRIGGER_NEW_CARGO
:
1150 /* All vehicles in chain get ANY_NEW_CARGO trigger now.
1151 * So we call it for the first one and they will recurse.
1152 * Indexing part of vehicle random bits needs to be
1153 * same for all triggered vehicles in the chain (to get
1154 * all the random-cargo wagons carry the same cargo,
1155 * i.e.), so we give them all the NEW_CARGO triggered
1156 * vehicle's portion of random bits. */
1158 DoTriggerVehicle(v
->First(), VEHICLE_TRIGGER_ANY_NEW_CARGO
, new_random_bits
, false);
1161 case VEHICLE_TRIGGER_DEPOT
:
1162 /* We now trigger the next vehicle in chain recursively.
1163 * The random bits portions may be different for each
1164 * vehicle in chain. */
1165 if (v
->Next() != NULL
) DoTriggerVehicle(v
->Next(), trigger
, 0, true);
1168 case VEHICLE_TRIGGER_EMPTY
:
1169 /* We now trigger the next vehicle in chain
1170 * recursively. The random bits portions must be same
1171 * for each vehicle in chain, so we give them all
1172 * first chained vehicle's portion of random bits. */
1173 if (v
->Next() != NULL
) DoTriggerVehicle(v
->Next(), trigger
, first
? new_random_bits
: base_random_bits
, false);
1176 case VEHICLE_TRIGGER_ANY_NEW_CARGO
:
1177 /* Now pass the trigger recursively to the next vehicle
1180 if (v
->Next() != NULL
) DoTriggerVehicle(v
->Next(), VEHICLE_TRIGGER_ANY_NEW_CARGO
, base_random_bits
, false);
1183 case VEHICLE_TRIGGER_CALLBACK_32
:
1184 /* Do not do any recursion */
1189 void TriggerVehicle(Vehicle
*v
, VehicleTrigger trigger
)
1191 if (trigger
== VEHICLE_TRIGGER_DEPOT
) {
1192 /* store that the vehicle entered a depot this tick */
1193 VehicleEnteredDepotThisTick(v
);
1196 v
->InvalidateNewGRFCacheOfChain();
1197 DoTriggerVehicle(v
, trigger
, 0, true);
1198 v
->InvalidateNewGRFCacheOfChain();
1201 /* Functions for changing the order of vehicle purchase lists */
1203 struct ListOrderChange
{
1205 uint target
; ///< local ID
1208 static SmallVector
<ListOrderChange
, 16> _list_order_changes
;
1211 * Record a vehicle ListOrderChange.
1212 * @param engine Engine to move
1213 * @param target Local engine ID to move \a engine in front of
1214 * @note All sorting is done later in CommitVehicleListOrderChanges
1216 void AlterVehicleListOrder(EngineID engine
, uint target
)
1218 /* Add the list order change to a queue */
1219 ListOrderChange
*loc
= _list_order_changes
.Append();
1220 loc
->engine
= engine
;
1221 loc
->target
= target
;
1225 * Comparator function to sort engines via scope-GRFID and local ID.
1226 * @param a left side
1227 * @param b right side
1228 * @return comparison result
1230 static int CDECL
EnginePreSort(const EngineID
*a
, const EngineID
*b
)
1232 const EngineIDMapping
*id_a
= _engine_mngr
.Get(*a
);
1233 const EngineIDMapping
*id_b
= _engine_mngr
.Get(*b
);
1235 /* 1. Sort by engine type */
1236 if (id_a
->type
!= id_b
->type
) return (int)id_a
->type
- (int)id_b
->type
;
1238 /* 2. Sort by scope-GRFID */
1239 if (id_a
->grfid
!= id_b
->grfid
) return id_a
->grfid
< id_b
->grfid
? -1 : 1;
1241 /* 3. Sort by local ID */
1242 return (int)id_a
->internal_id
- (int)id_b
->internal_id
;
1246 * Deternine default engine sorting and execute recorded ListOrderChanges from AlterVehicleListOrder.
1248 void CommitVehicleListOrderChanges()
1250 /* Pre-sort engines by scope-grfid and local index */
1251 SmallVector
<EngineID
, 16> ordering
;
1253 FOR_ALL_ENGINES(e
) {
1254 *ordering
.Append() = e
->index
;
1256 QSortT(ordering
.Begin(), ordering
.Length(), EnginePreSort
);
1258 /* Apply Insertion-Sort operations */
1259 const ListOrderChange
*end
= _list_order_changes
.End();
1260 for (const ListOrderChange
*it
= _list_order_changes
.Begin(); it
!= end
; ++it
) {
1261 EngineID source
= it
->engine
;
1262 uint local_target
= it
->target
;
1264 const EngineIDMapping
*id_source
= _engine_mngr
.Get(source
);
1265 if (id_source
->internal_id
== local_target
) continue;
1267 EngineID target
= _engine_mngr
.GetID(id_source
->type
, local_target
, id_source
->grfid
);
1268 if (target
== INVALID_ENGINE
) continue;
1270 int source_index
= ordering
.FindIndex(source
);
1271 int target_index
= ordering
.FindIndex(target
);
1273 assert(source_index
>= 0 && target_index
>= 0);
1274 assert(source_index
!= target_index
);
1276 EngineID
*list
= ordering
.Begin();
1277 if (source_index
< target_index
) {
1279 for (int i
= source_index
; i
< target_index
; ++i
) list
[i
] = list
[i
+ 1];
1280 list
[target_index
] = source
;
1282 for (int i
= source_index
; i
> target_index
; --i
) list
[i
] = list
[i
- 1];
1283 list
[target_index
] = source
;
1287 /* Store final sort-order */
1288 const EngineID
*idend
= ordering
.End();
1290 for (const EngineID
*it
= ordering
.Begin(); it
!= idend
; ++it
, ++index
) {
1291 Engine::Get(*it
)->list_position
= index
;
1294 /* Clear out the queue */
1295 _list_order_changes
.Reset();
1299 * Fill the grf_cache of the given vehicle.
1300 * @param v The vehicle to fill the cache for.
1302 void FillNewGRFVehicleCache(const Vehicle
*v
)
1304 VehicleResolverObject
ro(v
->engine_type
, v
);
1306 /* These variables we have to check; these are the ones with a cache. */
1307 static const int cache_entries
[][2] = {
1308 { 0x40, NCVV_POSITION_CONSIST_LENGTH
},
1309 { 0x41, NCVV_POSITION_SAME_ID_LENGTH
},
1310 { 0x42, NCVV_CONSIST_CARGO_INFORMATION
},
1311 { 0x43, NCVV_COMPANY_INFORMATION
},
1312 { 0x4D, NCVV_POSITION_IN_VEHICLE
},
1314 assert_compile(NCVV_END
== lengthof(cache_entries
));
1316 /* Resolve all the variables, so their caches are set. */
1317 for (size_t i
= 0; i
< lengthof(cache_entries
); i
++) {
1318 /* Only resolve when the cache isn't valid. */
1319 if (HasBit(v
->grf_cache
.cache_valid
, cache_entries
[i
][1])) continue;
1321 ro
.GetScope(VSG_SCOPE_SELF
)->GetVariable(cache_entries
[i
][0], 0, &stub
);
1324 /* Make sure really all bits are set. */
1325 assert(v
->grf_cache
.cache_valid
== (1 << NCVV_END
) - 1);