1
0
Fork 0

Codechange: Unify random trigger enums and turn them into enum classes. (#14066)

pull/14067/head
frosch 2025-04-21 20:03:34 +02:00 committed by GitHub
parent f399b8eb29
commit 61a0a520f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 185 additions and 148 deletions

View File

@ -74,7 +74,7 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
TimerGameCalendar::Date build_date{}; ///< Date of construction
uint16_t random_bits = 0; ///< Random bits assigned to this station
uint8_t waiting_random_triggers = 0; ///< Waiting triggers (NewGRF) for this station
StationRandomTriggers waiting_random_triggers; ///< Waiting triggers (NewGRF), shared by all station parts/tiles, road stops, ... essentially useless and broken by design.
uint8_t cached_anim_triggers = 0; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
uint8_t cached_roadstop_anim_triggers = 0; ///< NOSAVE: Combined animation trigger bitmask for road stops, used to determine if trigger processing should happen.
CargoTypes cached_cargo_triggers{}; ///< NOSAVE: Combined cargo trigger bitmask

View File

@ -1167,7 +1167,7 @@ static void TriggerIndustryProduction(Industry *i)
}
}
TriggerIndustryRandomisation(i, INDUSTRY_TRIGGER_RECEIVED_CARGO);
TriggerIndustryRandomisation(i, IndustryRandomTrigger::CargoReceived);
TriggerIndustryAnimation(i, IAT_INDUSTRY_RECEIVED_CARGO);
}
@ -1779,7 +1779,7 @@ static void LoadUnloadVehicle(Vehicle *front)
/* If there's goods waiting at the station, and the vehicle
* has capacity for it, load it on the vehicle. */
if ((v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0 || (ge->HasData() && ge->GetData().cargo.AvailableCount() > 0)) && MayLoadUnderExclusiveRights(st, v)) {
if (v->cargo.StoredCount() == 0) TriggerVehicleRandomisation(v, VEHICLE_TRIGGER_NEW_CARGO);
if (v->cargo.StoredCount() == 0) TriggerVehicleRandomisation(v, VehicleRandomTrigger::NewCargo);
if (_settings_game.order.gradual_loading) cap_left = std::min(cap_left, GetLoadAmount(v));
uint loaded = ge->GetOrCreateData().cargo.Load(cap_left, &v->cargo, next_station, v->GetCargoTile());
@ -1811,10 +1811,10 @@ static void LoadUnloadVehicle(Vehicle *front)
st->last_vehicle_type = v->type;
if (ge->GetData().cargo.TotalCount() == 0) {
TriggerStationRandomisation(st, st->xy, SRT_CARGO_TAKEN, v->cargo_type);
TriggerStationRandomisation(st, st->xy, StationRandomTrigger::CargoTaken, v->cargo_type);
TriggerStationAnimation(st, st->xy, SAT_CARGO_TAKEN, v->cargo_type);
TriggerAirportAnimation(st, AAT_STATION_CARGO_TAKEN, v->cargo_type);
TriggerRoadStopRandomisation(st, st->xy, RSRT_CARGO_TAKEN, v->cargo_type);
TriggerRoadStopRandomisation(st, st->xy, StationRandomTrigger::CargoTaken, v->cargo_type);
TriggerRoadStopAnimation(st, st->xy, SAT_CARGO_TAKEN, v->cargo_type);
}
@ -1834,10 +1834,10 @@ static void LoadUnloadVehicle(Vehicle *front)
if (anything_loaded || anything_unloaded) {
if (front->type == VEH_TRAIN) {
TriggerStationRandomisation(st, front->tile, SRT_TRAIN_LOADS);
TriggerStationRandomisation(st, front->tile, StationRandomTrigger::VehicleLoads);
TriggerStationAnimation(st, front->tile, SAT_TRAIN_LOADS);
} else if (front->type == VEH_ROAD) {
TriggerRoadStopRandomisation(st, front->tile, RSRT_VEH_LOADS);
TriggerRoadStopRandomisation(st, front->tile, StationRandomTrigger::VehicleLoads);
TriggerRoadStopAnimation(st, front->tile, SAT_TRAIN_LOADS);
}
}
@ -1910,7 +1910,7 @@ static void LoadUnloadVehicle(Vehicle *front)
/* Make sure the vehicle is marked dirty, since we need to update the NewGRF
* properties such as weight, power and TE whenever the trigger runs. */
dirty_vehicle = true;
TriggerVehicleRandomisation(front, VEHICLE_TRIGGER_EMPTY);
TriggerVehicleRandomisation(front, VehicleRandomTrigger::Empty);
}
if (dirty_vehicle) {

View File

@ -15,4 +15,16 @@ typedef uint16_t HouseClassID; ///< Classes of houses.
struct HouseSpec;
/** Randomisation triggers for houses */
enum class HouseRandomTrigger : uint8_t {
/* The tile of the house has been triggered during the tileloop. */
TileLoop,
/*
* The top tile of a (multitile) building has been triggered during and all
* the tileloop other tiles of the same building get the same random value.
*/
TileLoopNorth,
};
using HouseRandomTriggers = EnumBitSet<HouseRandomTrigger, uint8_t>;
#endif /* HOUSE_TYPE_H */

View File

@ -844,7 +844,7 @@ static void TileLoop_Industry(TileIndex tile)
* returning from TileLoop_Water. */
if (!IsTileType(tile, MP_INDUSTRY)) return;
TriggerIndustryTileRandomisation(tile, INDTILE_TRIGGER_TILE_LOOP);
TriggerIndustryTileRandomisation(tile, IndustryRandomTrigger::TileLoop);
if (!IsIndustryCompleted(tile)) {
MakeIndustryTileBigger(tile);
@ -1222,7 +1222,7 @@ static void ProduceIndustryGoods(Industry *i)
if (cut) ChopLumberMillTrees(i);
}
TriggerIndustryRandomisation(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
TriggerIndustryRandomisation(i, IndustryRandomTrigger::IndustryTick);
TriggerIndustryAnimation(i, IAT_INDUSTRY_TICK);
}
}

View File

@ -247,10 +247,10 @@ inline void SetIndustryRandomBits(Tile tile, uint8_t bits)
* @pre IsTileType(tile, MP_INDUSTRY)
* @return requested triggers
*/
inline uint8_t GetIndustryRandomTriggers(Tile tile)
inline IndustryRandomTriggers GetIndustryRandomTriggers(Tile tile)
{
assert(IsTileType(tile, MP_INDUSTRY));
return GB(tile.m6(), 3, 3);
return static_cast<IndustryRandomTriggers>(GB(tile.m6(), 3, 3));
}
@ -261,10 +261,10 @@ inline uint8_t GetIndustryRandomTriggers(Tile tile)
* @param triggers the triggers to set
* @pre IsTileType(tile, MP_INDUSTRY)
*/
inline void SetIndustryRandomTriggers(Tile tile, uint8_t triggers)
inline void SetIndustryRandomTriggers(Tile tile, IndustryRandomTriggers triggers)
{
assert(IsTileType(tile, MP_INDUSTRY));
SB(tile.m6(), 3, 3, triggers);
SB(tile.m6(), 3, 3, triggers.base());
}
/**
@ -283,7 +283,7 @@ inline void MakeIndustry(Tile t, IndustryID index, IndustryGfx gfx, uint8_t rand
SetIndustryRandomBits(t, random); // m3
t.m4() = 0;
SetIndustryGfx(t, gfx); // m5, part of m6
SetIndustryRandomTriggers(t, 0); // rest of m6
SetIndustryRandomTriggers(t, {}); // rest of m6
SetWaterClass(t, wc);
t.m7() = 0;
}

View File

@ -21,6 +21,14 @@ struct Industry;
struct IndustrySpec;
struct IndustryTileSpec;
/** Available industry random triggers. */
enum class IndustryRandomTrigger : uint8_t {
TileLoop, ///< The tile of the industry has been triggered during the tileloop.
IndustryTick, ///< The industry has been triggered via its tick.
CargoReceived, ///< Cargo has been delivered.
};
using IndustryRandomTriggers = EnumBitSet<IndustryRandomTrigger, uint8_t>;
static const IndustryType NUM_INDUSTRYTYPES_PER_GRF = 128; ///< maximum number of industry types per NewGRF; limited to 128 because bit 7 has a special meaning in some variables/callbacks (see MapNewGRFIndustryType).
static const IndustryType NEW_INDUSTRYOFFSET = 37; ///< original number of industry types

View File

@ -311,7 +311,7 @@ static uint8_t MapAircraftMovementAction(const Aircraft *v)
/* virtual */ uint32_t VehicleScopeResolver::GetRandomTriggers() const
{
return this->v == nullptr ? 0 : this->v->waiting_random_triggers;
return this->v == nullptr ? 0 : this->v->waiting_random_triggers.base();
}
@ -626,7 +626,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
if (parameter == 0x5F) {
/* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */
return (u->random_bits << 8) | u->waiting_random_triggers;
return (u->random_bits << 8) | u->waiting_random_triggers.base();
} else {
return VehicleGetVariable(u, object, parameter, GetRegister(0x10E), available);
}
@ -891,7 +891,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
case 0x78: break; // not implemented
case 0x79: break; // not implemented
case 0x7A: return v->random_bits;
case 0x7B: return v->waiting_random_triggers;
case 0x7B: return v->waiting_random_triggers.base();
case 0x7C: break; // vehicle specific, see below
case 0x7D: break; // vehicle specific, see below
case 0x7E: break; // not implemented
@ -1061,7 +1061,7 @@ static const GRFFile *GetEngineGrfFile(EngineID engine_type)
*/
VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle *v, WagonOverride wagon_override, bool rotor_in_gui,
CallbackID callback, uint32_t callback_param1, uint32_t callback_param2)
: ResolverObject(GetEngineGrfFile(engine_type), callback, callback_param1, callback_param2),
: SpecializedResolverObject<VehicleRandomTriggers>(GetEngineGrfFile(engine_type), callback, callback_param1, callback_param2),
self_scope(*this, engine_type, v, rotor_in_gui),
parent_scope(*this, engine_type, ((v != nullptr) ? v->First() : v), rotor_in_gui),
relative_scope(*this, engine_type, v, rotor_in_gui),
@ -1247,20 +1247,20 @@ bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityTy
return p + RandomRange(PROBABILITY_RANGE) >= PROBABILITY_RANGE;
}
static void DoTriggerVehicleRandomisation(Vehicle *v, VehicleTrigger trigger, uint16_t base_random_bits, bool first)
static void DoTriggerVehicleRandomisation(Vehicle *v, VehicleRandomTrigger trigger, uint16_t base_random_bits, bool first)
{
/* We can't trigger a non-existent vehicle... */
assert(v != nullptr);
VehicleResolverObject object(v->engine_type, v, VehicleResolverObject::WO_CACHED, false, CBID_RANDOM_TRIGGER);
object.waiting_random_triggers = v->waiting_random_triggers | trigger;
v->waiting_random_triggers = object.waiting_random_triggers; // store now for var 5F
v->waiting_random_triggers.Set(trigger); // store now for var 5F
object.SetWaitingRandomTriggers(v->waiting_random_triggers);
const SpriteGroup *group = object.Resolve();
if (group == nullptr) return;
/* Store remaining triggers. */
v->waiting_random_triggers = object.GetRemainingRandomTriggers();
v->waiting_random_triggers.Reset(object.GetUsedRandomTriggers());
/* Rerandomise bits. Scopes other than SELF are invalid for rerandomisation. For bug-to-bug-compatibility with TTDP we ignore the scope. */
uint16_t new_random_bits = Random();
@ -1269,7 +1269,7 @@ static void DoTriggerVehicleRandomisation(Vehicle *v, VehicleTrigger trigger, ui
v->random_bits |= (first ? new_random_bits : base_random_bits) & reseed;
switch (trigger) {
case VEHICLE_TRIGGER_NEW_CARGO:
case VehicleRandomTrigger::NewCargo:
/* All vehicles in chain get ANY_NEW_CARGO trigger now.
* So we call it for the first one and they will recurse.
* Indexing part of vehicle random bits needs to be
@ -1278,17 +1278,17 @@ static void DoTriggerVehicleRandomisation(Vehicle *v, VehicleTrigger trigger, ui
* i.e.), so we give them all the NEW_CARGO triggered
* vehicle's portion of random bits. */
assert(first);
DoTriggerVehicleRandomisation(v->First(), VEHICLE_TRIGGER_ANY_NEW_CARGO, new_random_bits, false);
DoTriggerVehicleRandomisation(v->First(), VehicleRandomTrigger::AnyNewCargo, new_random_bits, false);
break;
case VEHICLE_TRIGGER_DEPOT:
case VehicleRandomTrigger::Depot:
/* We now trigger the next vehicle in chain recursively.
* The random bits portions may be different for each
* vehicle in chain. */
if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), trigger, 0, true);
break;
case VEHICLE_TRIGGER_EMPTY:
case VehicleRandomTrigger::Empty:
/* We now trigger the next vehicle in chain
* recursively. The random bits portions must be same
* for each vehicle in chain, so we give them all
@ -1296,20 +1296,20 @@ static void DoTriggerVehicleRandomisation(Vehicle *v, VehicleTrigger trigger, ui
if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), trigger, first ? new_random_bits : base_random_bits, false);
break;
case VEHICLE_TRIGGER_ANY_NEW_CARGO:
case VehicleRandomTrigger::AnyNewCargo:
/* Now pass the trigger recursively to the next vehicle
* in chain. */
assert(!first);
if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false);
if (v->Next() != nullptr) DoTriggerVehicleRandomisation(v->Next(), trigger, base_random_bits, false);
break;
case VEHICLE_TRIGGER_CALLBACK_32:
case VehicleRandomTrigger::Callback32:
/* Do not do any recursion */
break;
}
}
void TriggerVehicleRandomisation(Vehicle *v, VehicleTrigger trigger)
void TriggerVehicleRandomisation(Vehicle *v, VehicleRandomTrigger trigger)
{
v->InvalidateNewGRFCacheOfChain();
DoTriggerVehicleRandomisation(v, trigger, 0, true);

View File

@ -44,7 +44,7 @@ struct VehicleScopeResolver : public ScopeResolver {
};
/** Resolver for a vehicle (chain) */
struct VehicleResolverObject : public ResolverObject {
struct VehicleResolverObject : public SpecializedResolverObject<VehicleRandomTriggers> {
/** Application of 'wagon overrides'. */
enum WagonOverride : uint8_t {
WO_NONE, //!< Resolve no wagon overrides.
@ -107,18 +107,7 @@ enum class BuildProbabilityType : uint8_t {
bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type);
enum VehicleTrigger : uint8_t {
VEHICLE_TRIGGER_NEW_CARGO = 0x01,
/* Externally triggered only for the first vehicle in chain */
VEHICLE_TRIGGER_DEPOT = 0x02,
/* Externally triggered only for the first vehicle in chain, only if whole chain is empty */
VEHICLE_TRIGGER_EMPTY = 0x04,
/* Not triggered externally (called for the whole chain if we got NEW_CARGO) */
VEHICLE_TRIGGER_ANY_NEW_CARGO = 0x08,
/* Externally triggered for each vehicle in chain */
VEHICLE_TRIGGER_CALLBACK_32 = 0x10,
};
void TriggerVehicleRandomisation(Vehicle *veh, VehicleTrigger trigger);
void TriggerVehicleRandomisation(Vehicle *veh, VehicleRandomTrigger trigger);
void AlterVehicleListOrder(EngineID engine, uint16_t target);
void CommitVehicleListOrderChanges();

View File

@ -107,7 +107,7 @@ void ResetHouses()
HouseResolverObject::HouseResolverObject(HouseID house_id, TileIndex tile, Town *town,
CallbackID callback, uint32_t param1, uint32_t param2,
bool not_yet_constructed, uint8_t initial_random_bits, CargoTypes watched_cargo_triggers, int view)
: ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2),
: SpecializedResolverObject<HouseRandomTriggers>(GetHouseSpecGrf(house_id), callback, param1, param2),
house_scope(*this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers, view),
town_scope(*this, town, not_yet_constructed) // Don't access StorePSA if house is not yet constructed.
{
@ -229,7 +229,7 @@ void DecreaseBuildingCount(Town *t, HouseID house_id)
/* virtual */ uint32_t HouseScopeResolver::GetRandomTriggers() const
{
/* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */
return this->not_yet_constructed ? 0 : GetHouseRandomTriggers(this->tile);
return this->not_yet_constructed ? 0 : GetHouseRandomTriggers(this->tile).base();
}
static uint32_t GetNumHouses(HouseID house_id, const Town *town)
@ -591,8 +591,8 @@ bool NewHouseTileLoop(TileIndex tile)
return true;
}
TriggerHouseRandomisation(tile, HOUSE_TRIGGER_TILE_LOOP);
if (hs->building_flags.Any(BUILDING_HAS_1_TILE)) TriggerHouseRandomisation(tile, HOUSE_TRIGGER_TILE_LOOP_TOP);
TriggerHouseRandomisation(tile, HouseRandomTrigger::TileLoop);
if (hs->building_flags.Any(BUILDING_HAS_1_TILE)) TriggerHouseRandomisation(tile, HouseRandomTrigger::TileLoopNorth);
/* Call the unsynchronized tile loop trigger */
TriggerHouseAnimation_TileLoop(tile, false, 0);
@ -620,7 +620,7 @@ bool NewHouseTileLoop(TileIndex tile)
return true;
}
static void DoTriggerHouseRandomisation(TileIndex tile, HouseTrigger trigger, uint8_t base_random, bool first)
static void DoTriggerHouseRandomisation(TileIndex tile, HouseRandomTrigger trigger, uint8_t base_random, bool first)
{
/* We can't trigger a non-existent building... */
assert(IsTileType(tile, MP_HOUSE));
@ -631,14 +631,17 @@ static void DoTriggerHouseRandomisation(TileIndex tile, HouseTrigger trigger, ui
if (hs->grf_prop.GetSpriteGroup() == nullptr) return;
HouseResolverObject object(hid, tile, Town::GetByTile(tile), CBID_RANDOM_TRIGGER);
object.waiting_random_triggers = GetHouseRandomTriggers(tile) | trigger;
SetHouseRandomTriggers(tile, object.waiting_random_triggers); // store now for var 5F
auto waiting_random_triggers = GetHouseRandomTriggers(tile);
waiting_random_triggers.Set(trigger);
SetHouseRandomTriggers(tile, waiting_random_triggers); // store now for var 5F
object.SetWaitingRandomTriggers(waiting_random_triggers);
const SpriteGroup *group = object.Resolve();
if (group == nullptr) return;
/* Store remaining triggers. */
SetHouseRandomTriggers(tile, object.GetRemainingRandomTriggers());
waiting_random_triggers.Reset(object.GetUsedRandomTriggers());
SetHouseRandomTriggers(tile, waiting_random_triggers);
/* Rerandomise bits. Scopes other than SELF are invalid for houses. For bug-to-bug-compatibility with TTDP we ignore the scope. */
uint8_t new_random_bits = Random();
@ -649,11 +652,11 @@ static void DoTriggerHouseRandomisation(TileIndex tile, HouseTrigger trigger, ui
SetHouseRandomBits(tile, random_bits);
switch (trigger) {
case HOUSE_TRIGGER_TILE_LOOP:
case HouseRandomTrigger::TileLoop:
/* Random value already set. */
break;
case HOUSE_TRIGGER_TILE_LOOP_TOP:
case HouseRandomTrigger::TileLoopNorth:
if (!first) {
/* The top tile is marked dirty by the usual TileLoop */
MarkTileDirtyByTile(tile);
@ -667,7 +670,7 @@ static void DoTriggerHouseRandomisation(TileIndex tile, HouseTrigger trigger, ui
}
}
void TriggerHouseRandomisation(TileIndex t, HouseTrigger trigger)
void TriggerHouseRandomisation(TileIndex t, HouseRandomTrigger trigger)
{
DoTriggerHouseRandomisation(t, trigger, 0, true);
}

View File

@ -49,7 +49,7 @@ struct HouseScopeResolver : public ScopeResolver {
};
/** Resolver object to be used for houses (feature 07 spritegroups). */
struct HouseResolverObject : public ResolverObject {
struct HouseResolverObject : public SpecializedResolverObject<HouseRandomTriggers> {
HouseScopeResolver house_scope;
TownScopeResolver town_scope;
@ -110,15 +110,6 @@ bool CanDeleteHouse(TileIndex tile);
bool NewHouseTileLoop(TileIndex tile);
enum HouseTrigger : uint8_t {
/* The tile of the house has been triggered during the tileloop. */
HOUSE_TRIGGER_TILE_LOOP = 0x01,
/*
* The top tile of a (multitile) building has been triggered during and all
* the tileloop other tiles of the same building get the same random value.
*/
HOUSE_TRIGGER_TILE_LOOP_TOP = 0x02,
};
void TriggerHouseRandomisation(TileIndex t, HouseTrigger trigger);
void TriggerHouseRandomisation(TileIndex t, HouseRandomTrigger trigger);
#endif /* NEWGRF_HOUSE_H */

View File

@ -115,7 +115,7 @@ uint32_t GetRelativePosition(TileIndex tile, TileIndex ind_tile)
assert(this->industry != nullptr && IsValidTile(this->tile));
assert(this->industry->index == IndustryID::Invalid() || IsTileType(this->tile, MP_INDUSTRY));
if (this->industry->index == IndustryID::Invalid()) return 0;
return GetIndustryRandomTriggers(this->tile);
return GetIndustryRandomTriggers(this->tile).base();
}
/**
@ -140,7 +140,7 @@ static const GRFFile *GetIndTileGrffile(IndustryGfx gfx)
*/
IndustryTileResolverObject::IndustryTileResolverObject(IndustryGfx gfx, TileIndex tile, Industry *indus,
CallbackID callback, uint32_t callback_param1, uint32_t callback_param2)
: ResolverObject(GetIndTileGrffile(gfx), callback, callback_param1, callback_param2),
: SpecializedResolverObject<IndustryRandomTriggers>(GetIndTileGrffile(gfx), callback, callback_param1, callback_param2),
indtile_scope(*this, indus, tile),
ind_scope(*this, tile, indus, indus->type),
gfx(gfx)
@ -310,7 +310,7 @@ bool TriggerIndustryAnimation(const Industry *ind, IndustryAnimationTrigger iat)
* @param ind Industry of the tile.
* @param[in,out] reseed_industry Collects bits to reseed for the industry.
*/
static void DoTriggerIndustryTileRandomisation(TileIndex tile, IndustryTileTrigger trigger, Industry *ind, uint32_t &reseed_industry)
static void DoTriggerIndustryTileRandomisation(TileIndex tile, IndustryRandomTrigger trigger, Industry *ind, uint32_t &reseed_industry)
{
assert(IsValidTile(tile) && IsTileType(tile, MP_INDUSTRY));
@ -320,14 +320,17 @@ static void DoTriggerIndustryTileRandomisation(TileIndex tile, IndustryTileTrigg
if (itspec->grf_prop.GetSpriteGroup() == nullptr) return;
IndustryTileResolverObject object(gfx, tile, ind, CBID_RANDOM_TRIGGER);
object.waiting_random_triggers = GetIndustryRandomTriggers(tile) | trigger;
SetIndustryRandomTriggers(tile, object.waiting_random_triggers); // store now for var 5F
auto waiting_random_triggers = GetIndustryRandomTriggers(tile);
waiting_random_triggers.Set(trigger);
SetIndustryRandomTriggers(tile, waiting_random_triggers); // store now for var 5F
object.SetWaitingRandomTriggers(waiting_random_triggers);
const SpriteGroup *group = object.Resolve();
if (group == nullptr) return;
/* Store remaining triggers. */
SetIndustryRandomTriggers(tile, object.GetRemainingRandomTriggers());
waiting_random_triggers.Reset(object.GetUsedRandomTriggers());
SetIndustryRandomTriggers(tile, waiting_random_triggers);
/* Rerandomise tile bits */
uint8_t new_random_bits = Random();
@ -359,7 +362,7 @@ static void DoReseedIndustry(Industry *ind, uint32_t reseed)
* @param tile Industry tile to trigger.
* @param trigger Trigger to trigger.
*/
void TriggerIndustryTileRandomisation(TileIndex tile, IndustryTileTrigger trigger)
void TriggerIndustryTileRandomisation(TileIndex tile, IndustryRandomTrigger trigger)
{
uint32_t reseed_industry = 0;
Industry *ind = Industry::GetByTile(tile);
@ -372,7 +375,7 @@ void TriggerIndustryTileRandomisation(TileIndex tile, IndustryTileTrigger trigge
* @param ind Industry to trigger.
* @param trigger Trigger to trigger.
*/
void TriggerIndustryRandomisation(Industry *ind, IndustryTileTrigger trigger)
void TriggerIndustryRandomisation(Industry *ind, IndustryRandomTrigger trigger)
{
uint32_t reseed_industry = 0;
for (TileIndex tile : ind->location) {

View File

@ -36,7 +36,7 @@ struct IndustryTileScopeResolver : public ScopeResolver {
};
/** Resolver for industry tiles. */
struct IndustryTileResolverObject : public ResolverObject {
struct IndustryTileResolverObject : public SpecializedResolverObject<IndustryRandomTriggers> {
IndustryTileScopeResolver indtile_scope; ///< Scope resolver for the industry tile.
IndustriesScopeResolver ind_scope; ///< Scope resolver for the industry owning the tile.
IndustryGfx gfx;
@ -65,14 +65,7 @@ void AnimateNewIndustryTile(TileIndex tile);
bool TriggerIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32_t random = Random());
bool TriggerIndustryAnimation(const Industry *ind, IndustryAnimationTrigger iat);
/** Available industry tile triggers. */
enum IndustryTileTrigger : uint8_t {
INDTILE_TRIGGER_TILE_LOOP = 0x01, ///< The tile of the industry has been triggered during the tileloop.
INDUSTRY_TRIGGER_INDUSTRY_TICK = 0x02, ///< The industry has been triggered via its tick.
INDUSTRY_TRIGGER_RECEIVED_CARGO = 0x04, ///< Cargo has been delivered.
};
void TriggerIndustryTileRandomisation(TileIndex t, IndustryTileTrigger trigger);
void TriggerIndustryRandomisation(Industry *ind, IndustryTileTrigger trigger);
void TriggerIndustryTileRandomisation(TileIndex t, IndustryRandomTrigger trigger);
void TriggerIndustryRandomisation(Industry *ind, IndustryRandomTrigger trigger);
#endif /* NEWGRF_INDUSTRYTILES_H */

View File

@ -65,7 +65,7 @@ uint32_t RoadStopScopeResolver::GetRandomBits() const
uint32_t RoadStopScopeResolver::GetRandomTriggers() const
{
return this->st == nullptr ? 0 : this->st->waiting_random_triggers;
return this->st == nullptr ? 0 : this->st->waiting_random_triggers.base();
}
uint32_t RoadStopScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
@ -226,7 +226,7 @@ const SpriteGroup *RoadStopResolverObject::ResolveReal(const RealSpriteGroup *gr
RoadStopResolverObject::RoadStopResolverObject(const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, RoadType roadtype, StationType type, uint8_t view,
CallbackID callback, uint32_t param1, uint32_t param2)
: ResolverObject(roadstopspec->grf_prop.grffile, callback, param1, param2), roadstop_scope(*this, st, roadstopspec, tile, roadtype, type, view)
: SpecializedResolverObject<StationRandomTriggers>(roadstopspec->grf_prop.grffile, callback, param1, param2), roadstop_scope(*this, st, roadstopspec, tile, roadtype, type, view)
{
CargoType ctype = SpriteGroupCargo::SG_DEFAULT_NA;
@ -417,7 +417,7 @@ void TriggerRoadStopAnimation(BaseStation *st, TileIndex trigger_tile, StationAn
* @param trigger trigger type
* @param cargo_type cargo type causing the trigger
*/
void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTrigger trigger, CargoType cargo_type)
void TriggerRoadStopRandomisation(Station *st, TileIndex tile, StationRandomTrigger trigger, CargoType cargo_type)
{
if (st == nullptr) st = Station::GetByTile(tile);
@ -426,32 +426,32 @@ void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTri
if (st->cached_roadstop_cargo_triggers == 0) return;
if (IsValidCargoType(cargo_type) && !HasBit(st->cached_roadstop_cargo_triggers, cargo_type)) return;
SetBit(st->waiting_random_triggers, trigger);
st->waiting_random_triggers.Set(trigger);
uint32_t whole_reseed = 0;
/* Bitmask of completely empty cargo types to be matched. */
CargoTypes empty_mask = (trigger == RSRT_CARGO_TAKEN) ? GetEmptyMask(st) : 0;
CargoTypes empty_mask = (trigger == StationRandomTrigger::CargoTaken) ? GetEmptyMask(st) : 0;
uint32_t used_random_triggers = 0;
StationRandomTriggers used_random_triggers;
auto process_tile = [&](TileIndex cur_tile) {
const RoadStopSpec *ss = GetRoadStopSpec(cur_tile);
if (ss == nullptr) return;
/* Cargo taken "will only be triggered if all of those
* cargo types have no more cargo waiting." */
if (trigger == RSRT_CARGO_TAKEN) {
if (trigger == StationRandomTrigger::CargoTaken) {
if ((ss->cargo_triggers & ~empty_mask) != 0) return;
}
if (!IsValidCargoType(cargo_type) || HasBit(ss->cargo_triggers, cargo_type)) {
RoadStopResolverObject object(ss, st, cur_tile, INVALID_ROADTYPE, GetStationType(cur_tile), GetStationGfx(cur_tile));
object.waiting_random_triggers = st->waiting_random_triggers;
object.SetWaitingRandomTriggers(st->waiting_random_triggers);
const SpriteGroup *group = object.Resolve();
if (group == nullptr) return;
used_random_triggers |= object.used_random_triggers;
used_random_triggers.Set(object.GetUsedRandomTriggers());
uint32_t reseed = object.GetReseedSum();
if (reseed != 0) {
@ -468,7 +468,7 @@ void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTri
}
}
};
if (trigger == RSRT_NEW_CARGO || trigger == RSRT_CARGO_TAKEN) {
if (trigger == StationRandomTrigger::NewCargo || trigger == StationRandomTrigger::CargoTaken) {
for (const RoadStopTileData &tile_data : st->custom_roadstop_tile_data) {
process_tile(tile_data.tile);
}
@ -477,7 +477,7 @@ void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTri
}
/* Update whole station random bits */
st->waiting_random_triggers &= ~used_random_triggers;
st->waiting_random_triggers.Reset(used_random_triggers);
if ((whole_reseed & 0xFFFF) != 0) {
st->random_bits &= ~whole_reseed;
st->random_bits |= Random() & whole_reseed;

View File

@ -35,15 +35,6 @@ enum RoadStopClassID : uint16_t {
};
DECLARE_INCREMENT_DECREMENT_OPERATORS(RoadStopClassID)
/* Some Triggers etc. */
enum RoadStopRandomTrigger : uint8_t {
RSRT_NEW_CARGO, ///< Trigger roadstop on arrival of new cargo.
RSRT_CARGO_TAKEN, ///< Trigger roadstop when cargo is completely taken.
RSRT_VEH_ARRIVES, ///< Trigger roadstop when road vehicle arrives.
RSRT_VEH_DEPARTS, ///< Trigger roadstop when road vehicle leaves.
RSRT_VEH_LOADS, ///< Trigger roadstop when road vehicle loads.
};
/**
* Various different options for availability, restricting
* the roadstop to be only for busses or for trucks.
@ -109,7 +100,7 @@ struct RoadStopScopeResolver : public ScopeResolver {
};
/** Road stop resolver. */
struct RoadStopResolverObject : public ResolverObject {
struct RoadStopResolverObject : public SpecializedResolverObject<StationRandomTriggers> {
RoadStopScopeResolver roadstop_scope; ///< The stop scope resolver.
std::optional<TownScopeResolver> town_scope = std::nullopt; ///< The town scope resolver (created on the first call).
@ -185,7 +176,7 @@ uint16_t GetRoadStopCallback(CallbackID callback, uint32_t param1, uint32_t para
void AnimateRoadStopTile(TileIndex tile);
uint8_t GetRoadStopTileAnimationSpeed(TileIndex tile);
void TriggerRoadStopAnimation(BaseStation *st, TileIndex tile, StationAnimationTrigger trigger, CargoType cargo_type = INVALID_CARGO);
void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTrigger trigger, CargoType cargo_type = INVALID_CARGO);
void TriggerRoadStopRandomisation(Station *st, TileIndex tile, StationRandomTrigger trigger, CargoType cargo_type = INVALID_CARGO);
bool GetIfNewStopsByType(RoadStopType rs, RoadType roadtype);
bool GetIfClassHasNewStopsByType(const RoadStopClass *roadstopclass, RoadStopType rs, RoadType roadtype);

View File

@ -258,11 +258,11 @@ const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject &object) const
ScopeResolver *scope = object.GetScope(this->var_scope, this->count);
if (object.callback == CBID_RANDOM_TRIGGER) {
/* Handle triggers */
uint8_t match = this->triggers & object.waiting_random_triggers;
uint8_t match = this->triggers & object.GetWaitingRandomTriggers();
bool res = (this->cmp_mode == RSG_CMP_ANY) ? (match != 0) : (match == this->triggers);
if (res) {
object.used_random_triggers |= match;
object.AddUsedRandomTriggers(match);
object.reseed[this->var_scope] |= (this->groups.size() - 1) << this->lowest_randbit;
}
}

View File

@ -318,8 +318,10 @@ struct ResolverObject {
uint32_t last_value = 0; ///< Result of most recent DeterministicSpriteGroup (including procedure calls)
protected:
uint32_t waiting_random_triggers = 0; ///< Waiting triggers to be used by any rerandomisation. (scope independent)
uint32_t used_random_triggers = 0; ///< Subset of cur_triggers, which actually triggered some rerandomisation. (scope independent)
public:
std::array<uint32_t, VSG_END> reseed; ///< Collects bits to rerandomise while triggering triggers.
const GRFFile *grffile = nullptr; ///< GRFFile the resolved SpriteGroup belongs to
@ -349,11 +351,19 @@ struct ResolverObject {
virtual ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, uint8_t relative = 0);
/**
* Returns the waiting triggers that did not trigger any rerandomisation.
* Used by RandomizedSpriteGroup: Triggers for rerandomisation
*/
uint32_t GetRemainingRandomTriggers() const
uint32_t GetWaitingRandomTriggers() const
{
return this->waiting_random_triggers & ~this->used_random_triggers;
return this->waiting_random_triggers;
}
/**
* Used by RandomizedSpriteGroup: Consume triggers.
*/
void AddUsedRandomTriggers(uint32_t triggers)
{
this->used_random_triggers |= triggers;
}
/**
@ -395,4 +405,30 @@ struct ResolverObject {
virtual uint32_t GetDebugID() const { return 0; }
};
/**
* Specialization of ResolverObject with type-safe access to RandomTriggers.
*/
template <class RandomTriggers>
struct SpecializedResolverObject : public ResolverObject {
using ResolverObject::ResolverObject;
/**
* Set waiting triggers for rerandomisation.
* This is scope independent, even though this is broken-by-design in most cases.
*/
void SetWaitingRandomTriggers(RandomTriggers triggers)
{
this->waiting_random_triggers = triggers.base();
}
/**
* Get the triggers, which were "consumed" by some rerandomisation.
* This is scope independent, even though this is broken-by-design in most cases.
*/
RandomTriggers GetUsedRandomTriggers() const
{
return static_cast<RandomTriggers>(this->used_random_triggers);
}
};
#endif /* NEWGRF_SPRITEGROUP_H */

View File

@ -246,7 +246,7 @@ static uint32_t GetRailContinuationInfo(TileIndex tile)
/* virtual */ uint32_t StationScopeResolver::GetRandomTriggers() const
{
return this->st == nullptr ? 0 : this->st->waiting_random_triggers;
return this->st == nullptr ? 0 : this->st->waiting_random_triggers.base();
}
@ -588,7 +588,7 @@ uint32_t StationResolverObject::GetDebugID() const
*/
StationResolverObject::StationResolverObject(const StationSpec *statspec, BaseStation *base_station, TileIndex tile,
CallbackID callback, uint32_t callback_param1, uint32_t callback_param2)
: ResolverObject(statspec->grf_prop.grffile, callback, callback_param1, callback_param2),
: SpecializedResolverObject<StationRandomTriggers>(statspec->grf_prop.grffile, callback, callback_param1, callback_param2),
station_scope(*this, statspec, base_station, tile)
{
/* Invalidate all cached vars */
@ -959,14 +959,14 @@ void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRan
if (IsValidCargoType(cargo_type) && !HasBit(st->cached_cargo_triggers, cargo_type)) return;
uint32_t whole_reseed = 0;
ETileArea area = ETileArea(st, trigger_tile, tas[trigger]);
ETileArea area = ETileArea(st, trigger_tile, tas[static_cast<size_t>(trigger)]);
/* Bitmask of completely empty cargo types to be matched. */
CargoTypes empty_mask = (trigger == SRT_CARGO_TAKEN) ? GetEmptyMask(st) : 0;
CargoTypes empty_mask = (trigger == StationRandomTrigger::CargoTaken) ? GetEmptyMask(st) : 0;
/* Store triggers now for var 5F */
SetBit(st->waiting_random_triggers, trigger);
uint32_t used_random_triggers = 0;
st->waiting_random_triggers.Set(trigger);
StationRandomTriggers used_random_triggers;
/* Check all tiles over the station to check if the specindex is still in use */
for (TileIndex tile : area) {
@ -976,18 +976,18 @@ void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRan
/* Cargo taken "will only be triggered if all of those
* cargo types have no more cargo waiting." */
if (trigger == SRT_CARGO_TAKEN) {
if (trigger == StationRandomTrigger::CargoTaken) {
if ((ss->cargo_triggers & ~empty_mask) != 0) continue;
}
if (!IsValidCargoType(cargo_type) || HasBit(ss->cargo_triggers, cargo_type)) {
StationResolverObject object(ss, st, tile, CBID_RANDOM_TRIGGER, 0);
object.waiting_random_triggers = st->waiting_random_triggers;
object.SetWaitingRandomTriggers(st->waiting_random_triggers);
const SpriteGroup *group = object.Resolve();
if (group == nullptr) continue;
used_random_triggers |= object.used_random_triggers;
used_random_triggers.Set(object.GetUsedRandomTriggers());
uint32_t reseed = object.GetReseedSum();
if (reseed != 0) {
@ -1007,7 +1007,7 @@ void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRan
}
/* Update whole station random bits */
st->waiting_random_triggers &= ~used_random_triggers;
st->waiting_random_triggers.Reset(used_random_triggers);
if ((whole_reseed & 0xFFFF) != 0) {
st->random_bits &= ~whole_reseed;
st->random_bits |= Random() & whole_reseed;

View File

@ -49,7 +49,7 @@ struct StationScopeResolver : public ScopeResolver {
};
/** Station resolver. */
struct StationResolverObject : public ResolverObject {
struct StationResolverObject : public SpecializedResolverObject<StationRandomTriggers> {
StationScopeResolver station_scope; ///< The station scope resolver.
std::optional<TownScopeResolver> town_scope = std::nullopt; ///< The town scope resolver (created on the first call).
@ -103,16 +103,6 @@ enum class StationSpecFlag : uint8_t {
};
using StationSpecFlags = EnumBitSet<StationSpecFlag, uint8_t>;
/** Randomisation triggers for stations */
enum StationRandomTrigger : uint8_t {
SRT_NEW_CARGO, ///< Trigger station on new cargo arrival.
SRT_CARGO_TAKEN, ///< Trigger station when cargo is completely taken.
SRT_TRAIN_ARRIVES, ///< Trigger platform when train arrives.
SRT_TRAIN_DEPARTS, ///< Trigger platform when train leaves.
SRT_TRAIN_LOADS, ///< Trigger platform when train loads/unloads.
SRT_PATH_RESERVATION, ///< Trigger platform when train reserves path.
};
/** Station specification. */
struct StationSpec : NewGRFSpecBase<StationClassID> {
StationSpec() : name(0),

View File

@ -80,7 +80,7 @@ private:
tile = TileAdd(tile, diff);
} while (IsCompatibleTrainStationTile(tile, start) && tile != this->origin_tile);
TriggerStationRandomisation(nullptr, start, SRT_PATH_RESERVATION);
TriggerStationRandomisation(nullptr, start, StationRandomTrigger::PathReservation);
return true;
}

View File

@ -113,7 +113,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
case MP_STATION:
if (HasStationRail(tile) && !HasStationReservation(tile)) {
SetRailStationReservation(tile, true);
if (trigger_stations && IsRailStation(tile)) TriggerStationRandomisation(nullptr, tile, SRT_PATH_RESERVATION);
if (trigger_stations && IsRailStation(tile)) TriggerStationRandomisation(nullptr, tile, StationRandomTrigger::PathReservation);
MarkTileDirtyByTile(tile); // some GRFs need redraw after reserving track
return true;
}

View File

@ -1455,7 +1455,7 @@ again:
v->last_station_visited = st->index;
RoadVehArrivesAt(v, st);
v->BeginLoading();
TriggerRoadStopRandomisation(st, v->tile, RSRT_VEH_ARRIVES);
TriggerRoadStopRandomisation(st, v->tile, StationRandomTrigger::VehicleArrives);
TriggerRoadStopAnimation(st, v->tile, SAT_TRAIN_ARRIVES);
}
return false;
@ -1519,7 +1519,7 @@ again:
if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
RoadVehArrivesAt(v, st);
v->BeginLoading();
TriggerRoadStopRandomisation(st, v->tile, RSRT_VEH_ARRIVES);
TriggerRoadStopRandomisation(st, v->tile, StationRandomTrigger::VehicleArrives);
TriggerRoadStopAnimation(st, v->tile, SAT_TRAIN_ARRIVES);
return false;
}

View File

@ -4278,10 +4278,10 @@ static uint UpdateStationWaiting(Station *st, CargoType cargo, uint amount, Sour
ge.status.Set(GoodsEntry::State::Rating);
}
TriggerStationRandomisation(st, st->xy, SRT_NEW_CARGO, cargo);
TriggerStationRandomisation(st, st->xy, StationRandomTrigger::NewCargo, cargo);
TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, cargo);
TriggerAirportAnimation(st, AAT_STATION_NEW_CARGO, cargo);
TriggerRoadStopRandomisation(st, st->xy, RSRT_NEW_CARGO, cargo);
TriggerRoadStopRandomisation(st, st->xy, StationRandomTrigger::NewCargo, cargo);
TriggerRoadStopAnimation(st, st->xy, SAT_NEW_CARGO, cargo);

View File

@ -76,6 +76,17 @@ enum StationHadVehicleOfType : uint8_t {
};
DECLARE_ENUM_AS_BIT_SET(StationHadVehicleOfType)
/** Randomisation triggers for stations and roadstops */
enum class StationRandomTrigger : uint8_t {
NewCargo, ///< Trigger station on new cargo arrival.
CargoTaken, ///< Trigger station when cargo is completely taken.
VehicleArrives, ///< Trigger platform when train arrives.
VehicleDeparts, ///< Trigger platform when train leaves.
VehicleLoads, ///< Trigger platform when train loads/unloads.
PathReservation, ///< Trigger platform when train reserves path.
};
using StationRandomTriggers = EnumBitSet<StationRandomTrigger, uint8_t>;
/* The different catchment area sizes. */
static constexpr uint CA_NONE = 0; ///< Catchment when the station has no facilities
static constexpr uint CA_BUS = 3; ///< Catchment for bus stops with "modified catchment" enabled

View File

@ -307,10 +307,10 @@ inline uint8_t GetHouseRandomBits(Tile t)
* @param triggers the activated triggers
* @pre IsTileType(t, MP_HOUSE)
*/
inline void SetHouseRandomTriggers(Tile t, uint8_t triggers)
inline void SetHouseRandomTriggers(Tile t, HouseRandomTriggers triggers)
{
assert(IsTileType(t, MP_HOUSE));
SB(t.m3(), 0, 5, triggers);
SB(t.m3(), 0, 5, triggers.base());
}
/**
@ -320,10 +320,10 @@ inline void SetHouseRandomTriggers(Tile t, uint8_t triggers)
* @pre IsTileType(t, MP_HOUSE)
* @return triggers
*/
inline uint8_t GetHouseRandomTriggers(Tile t)
inline HouseRandomTriggers GetHouseRandomTriggers(Tile t)
{
assert(IsTileType(t, MP_HOUSE));
return GB(t.m3(), 0, 5);
return static_cast<HouseRandomTriggers>(GB(t.m3(), 0, 5));
}
/**

View File

@ -3024,7 +3024,7 @@ static void TrainEnterStation(Train *v, StationID station)
v->BeginLoading();
TriggerStationRandomisation(st, v->tile, SRT_TRAIN_ARRIVES);
TriggerStationRandomisation(st, v->tile, StationRandomTrigger::VehicleArrives);
TriggerStationAnimation(st, v->tile, SAT_TRAIN_ARRIVES);
}

View File

@ -972,7 +972,7 @@ static void RunEconomyVehicleDayProc()
uint16_t callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
if (callback != CALLBACK_FAILED) {
if (HasBit(callback, 0)) {
TriggerVehicleRandomisation(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
TriggerVehicleRandomisation(v, VehicleRandomTrigger::Callback32); // Trigger vehicle trigger 10
}
/* After a vehicle trigger, the graphics and properties of the vehicle could change.
@ -1614,7 +1614,7 @@ void VehicleEnterDepot(Vehicle *v)
VehicleEnteredDepotThisTick(v);
/* After a vehicle trigger, the graphics and properties of the vehicle could change. */
TriggerVehicleRandomisation(v, VEHICLE_TRIGGER_DEPOT);
TriggerVehicleRandomisation(v, VehicleRandomTrigger::Depot);
v->MarkDirty();
InvalidateWindowData(WC_VEHICLE_VIEW, v->index);
@ -2394,7 +2394,7 @@ void Vehicle::LeaveStation()
if (this->type == VEH_TRAIN && !this->vehstatus.Test(VehState::Crashed)) {
/* Trigger station animation (trains only) */
if (IsTileType(this->tile, MP_STATION)) {
TriggerStationRandomisation(st, this->tile, SRT_TRAIN_DEPARTS);
TriggerStationRandomisation(st, this->tile, StationRandomTrigger::VehicleDeparts);
TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
}
@ -2403,7 +2403,7 @@ void Vehicle::LeaveStation()
if (this->type == VEH_ROAD && !this->vehstatus.Test(VehState::Crashed)) {
/* Trigger road stop animation */
if (IsStationRoadStopTile(this->tile)) {
TriggerRoadStopRandomisation(st, this->tile, RSRT_VEH_DEPARTS);
TriggerRoadStopRandomisation(st, this->tile, StationRandomTrigger::VehicleDeparts);
TriggerRoadStopAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
}
}

View File

@ -311,7 +311,7 @@ public:
uint32_t motion_counter = 0; ///< counter to occasionally play a vehicle sound.
uint8_t progress = 0; ///< The percentage (if divided by 256) this vehicle already crossed the tile unit.
uint8_t waiting_random_triggers = 0; ///< Triggers to be yet matched before rerandomizing the random bits.
VehicleRandomTriggers waiting_random_triggers; ///< Triggers to be yet matched before rerandomizing the random bits.
uint16_t random_bits = 0; ///< Bits used for randomized variational spritegroups.
StationID last_station_visited = StationID::Invalid(); ///< The last station we stopped at.

View File

@ -80,4 +80,14 @@ enum EngineImageType : uint8_t {
EIT_PREVIEW = 0x21, ///< Vehicle drawn in preview window, news, ...
};
/** Randomisation triggers for vehicles */
enum class VehicleRandomTrigger : uint8_t {
NewCargo, ///< Affected vehicle only: Vehicle is loaded with cargo, after it was empty.
Depot, ///< Front vehicle only: Consist arrived in depot.
Empty, ///< Front vehicle only: Entire consist is empty.
AnyNewCargo, ///< All vehicles in consist: Any vehicle in the consist received new cargo.
Callback32, ///< All vehicles in consist: 32 day callback requested rerandomisation
};
using VehicleRandomTriggers = EnumBitSet<VehicleRandomTrigger, uint8_t>;
#endif /* VEHICLE_TYPE_H */