mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-09 23:50:25 +00:00
(svn r27928) -Fix: [NewGRF] While executing random triggers, var 5F should include the new triggers.
-Fix: [NewGRF] Reset used random triggers only after all A123 chains have been resolved, so that all RA2 in all chains can test the shard triggers. This also includes multiple RA2 in the same A123 chain. -Fix: [NewGRF] Industry random triggers are stored per tile, even when randomising the shared random bits of the parent industry.
This commit is contained in:
parent
146e4eddb6
commit
82ae414e8d
@ -347,21 +347,6 @@ static byte MapAircraftMovementAction(const Aircraft *v)
|
|||||||
return this->v == NULL ? 0 : this->v->waiting_triggers;
|
return this->v == NULL ? 0 : this->v->waiting_triggers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual */ void VehicleScopeResolver::SetTriggers(int triggers) const
|
|
||||||
{
|
|
||||||
/* Evil cast to get around const-ness. This used to be achieved by an
|
|
||||||
* innocent looking function pointer cast... Currently I cannot see a
|
|
||||||
* way of avoiding this without removing consts deep within gui code.
|
|
||||||
*/
|
|
||||||
Vehicle *v = const_cast<Vehicle *>(this->v);
|
|
||||||
|
|
||||||
/* This function must only be called when processing triggers -- any
|
|
||||||
* other time is an error. */
|
|
||||||
assert(this->ro.trigger != 0);
|
|
||||||
|
|
||||||
if (v != NULL) v->waiting_triggers = triggers;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* virtual */ ScopeResolver *VehicleResolverObject::GetScope(VarSpriteGroupScope scope, byte relative)
|
/* virtual */ ScopeResolver *VehicleResolverObject::GetScope(VarSpriteGroupScope scope, byte relative)
|
||||||
{
|
{
|
||||||
@ -1140,13 +1125,18 @@ static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, byte base_rando
|
|||||||
assert(v != NULL);
|
assert(v != NULL);
|
||||||
|
|
||||||
VehicleResolverObject object(v->engine_type, v, VehicleResolverObject::WO_CACHED, false, CBID_RANDOM_TRIGGER);
|
VehicleResolverObject object(v->engine_type, v, VehicleResolverObject::WO_CACHED, false, CBID_RANDOM_TRIGGER);
|
||||||
object.trigger = trigger;
|
object.waiting_triggers = v->waiting_triggers | trigger;
|
||||||
|
v->waiting_triggers = object.waiting_triggers; // store now for var 5F
|
||||||
|
|
||||||
const SpriteGroup *group = object.Resolve();
|
const SpriteGroup *group = object.Resolve();
|
||||||
if (group == NULL) return;
|
if (group == NULL) return;
|
||||||
|
|
||||||
|
/* Store remaining triggers. */
|
||||||
|
v->waiting_triggers = object.GetRemainingTriggers();
|
||||||
|
|
||||||
|
/* Rerandomise bits. Scopes other than SELF are invalid for rerandomisation. For bug-to-bug-compatibility with TTDP we ignore the scope. */
|
||||||
byte new_random_bits = Random();
|
byte new_random_bits = Random();
|
||||||
uint32 reseed = object.GetReseedSum(); // The scope only affects triggers, not the reseeding
|
uint32 reseed = object.GetReseedSum();
|
||||||
v->random_bits &= ~reseed;
|
v->random_bits &= ~reseed;
|
||||||
v->random_bits |= (first ? new_random_bits : base_random_bits) & reseed;
|
v->random_bits |= (first ? new_random_bits : base_random_bits) & reseed;
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ struct VehicleScopeResolver : public ScopeResolver {
|
|||||||
/* virtual */ uint32 GetRandomBits() const;
|
/* virtual */ uint32 GetRandomBits() const;
|
||||||
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
||||||
/* virtual */ uint32 GetTriggers() const;
|
/* virtual */ uint32 GetTriggers() const;
|
||||||
/* virtual */ void SetTriggers(int triggers) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Resolver for a vehicle (chain) */
|
/** Resolver for a vehicle (chain) */
|
||||||
|
@ -169,12 +169,6 @@ void DecreaseBuildingCount(Town *t, HouseID house_id)
|
|||||||
return this->not_yet_constructed ? 0 : GetHouseTriggers(this->tile);
|
return this->not_yet_constructed ? 0 : GetHouseTriggers(this->tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual */ void HouseScopeResolver::SetTriggers(int triggers) const
|
|
||||||
{
|
|
||||||
assert(!this->not_yet_constructed && IsValidTile(this->tile) && IsTileType(this->tile, MP_HOUSE));
|
|
||||||
SetHouseTriggers(this->tile, triggers);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32 GetNumHouses(HouseID house_id, const Town *town)
|
static uint32 GetNumHouses(HouseID house_id, const Town *town)
|
||||||
{
|
{
|
||||||
uint8 map_id_count, town_id_count, map_class_count, town_class_count;
|
uint8 map_id_count, town_id_count, map_class_count, town_class_count;
|
||||||
@ -613,14 +607,19 @@ static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_rando
|
|||||||
if (hs->grf_prop.spritegroup[0] == NULL) return;
|
if (hs->grf_prop.spritegroup[0] == NULL) return;
|
||||||
|
|
||||||
HouseResolverObject object(hid, tile, Town::GetByTile(tile), CBID_RANDOM_TRIGGER);
|
HouseResolverObject object(hid, tile, Town::GetByTile(tile), CBID_RANDOM_TRIGGER);
|
||||||
object.trigger = trigger;
|
object.waiting_triggers = GetHouseTriggers(tile) | trigger;
|
||||||
|
SetHouseTriggers(tile, object.waiting_triggers); // store now for var 5F
|
||||||
|
|
||||||
const SpriteGroup *group = object.Resolve();
|
const SpriteGroup *group = object.Resolve();
|
||||||
if (group == NULL) return;
|
if (group == NULL) return;
|
||||||
|
|
||||||
|
/* Store remaining triggers. */
|
||||||
|
SetHouseTriggers(tile, object.GetRemainingTriggers());
|
||||||
|
|
||||||
|
/* Rerandomise bits. Scopes other than SELF are invalid for houses. For bug-to-bug-compatibility with TTDP we ignore the scope. */
|
||||||
byte new_random_bits = Random();
|
byte new_random_bits = Random();
|
||||||
byte random_bits = GetHouseRandomBits(tile);
|
byte random_bits = GetHouseRandomBits(tile);
|
||||||
uint32 reseed = object.GetReseedSum(); // The scope only affects triggers, not the reseeding
|
uint32 reseed = object.GetReseedSum();
|
||||||
random_bits &= ~reseed;
|
random_bits &= ~reseed;
|
||||||
random_bits |= (first ? new_random_bits : base_random) & reseed;
|
random_bits |= (first ? new_random_bits : base_random) & reseed;
|
||||||
SetHouseRandomBits(tile, random_bits);
|
SetHouseRandomBits(tile, random_bits);
|
||||||
|
@ -33,7 +33,6 @@ struct HouseScopeResolver : public ScopeResolver {
|
|||||||
/* virtual */ uint32 GetRandomBits() const;
|
/* virtual */ uint32 GetRandomBits() const;
|
||||||
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
||||||
/* virtual */ uint32 GetTriggers() const;
|
/* virtual */ uint32 GetTriggers() const;
|
||||||
/* virtual */ void SetTriggers(int triggers) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Resolver object to be used for houses (feature 07 spritegroups). */
|
/** Resolver object to be used for houses (feature 07 spritegroups). */
|
||||||
|
@ -383,12 +383,6 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
|
|||||||
return this->industry != NULL ? this->industry->random_triggers : 0;
|
return this->industry != NULL ? this->industry->random_triggers : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual */ void IndustriesScopeResolver::SetTriggers(int triggers) const
|
|
||||||
{
|
|
||||||
assert(this->industry != NULL && this->industry->index != INVALID_INDUSTRY);
|
|
||||||
this->industry->random_triggers = triggers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* virtual */ void IndustriesScopeResolver::StorePSA(uint pos, int32 value)
|
/* virtual */ void IndustriesScopeResolver::StorePSA(uint pos, int32 value)
|
||||||
{
|
{
|
||||||
if (this->industry->index == INVALID_INDUSTRY) return;
|
if (this->industry->index == INVALID_INDUSTRY) return;
|
||||||
|
@ -26,7 +26,6 @@ struct IndustriesScopeResolver : public ScopeResolver {
|
|||||||
/* virtual */ uint32 GetRandomBits() const;
|
/* virtual */ uint32 GetRandomBits() const;
|
||||||
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
||||||
/* virtual */ uint32 GetTriggers() const;
|
/* virtual */ uint32 GetTriggers() const;
|
||||||
/* virtual */ void SetTriggers(int triggers) const;
|
|
||||||
/* virtual */ void StorePSA(uint pos, int32 value);
|
/* virtual */ void StorePSA(uint pos, int32 value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,12 +117,6 @@ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile)
|
|||||||
return GetIndustryTriggers(this->tile);
|
return GetIndustryTriggers(this->tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual */ void IndustryTileScopeResolver::SetTriggers(int triggers) const
|
|
||||||
{
|
|
||||||
assert(this->industry != NULL && this->industry->index != INVALID_INDUSTRY && IsValidTile(this->tile) && IsTileType(this->tile, MP_INDUSTRY));
|
|
||||||
SetIndustryTriggers(this->tile, triggers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the associated NewGRF file from the industry graphics.
|
* Get the associated NewGRF file from the industry graphics.
|
||||||
* @param gfx Graphics to query.
|
* @param gfx Graphics to query.
|
||||||
@ -326,11 +320,16 @@ static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, I
|
|||||||
if (itspec->grf_prop.spritegroup[0] == NULL) return;
|
if (itspec->grf_prop.spritegroup[0] == NULL) return;
|
||||||
|
|
||||||
IndustryTileResolverObject object(gfx, tile, ind, CBID_RANDOM_TRIGGER);
|
IndustryTileResolverObject object(gfx, tile, ind, CBID_RANDOM_TRIGGER);
|
||||||
object.trigger = trigger;
|
object.waiting_triggers = GetIndustryTriggers(tile) | trigger;
|
||||||
|
SetIndustryTriggers(tile, object.waiting_triggers); // store now for var 5F
|
||||||
|
|
||||||
const SpriteGroup *group = object.Resolve();
|
const SpriteGroup *group = object.Resolve();
|
||||||
if (group == NULL) return;
|
if (group == NULL) return;
|
||||||
|
|
||||||
|
/* Store remaining triggers. */
|
||||||
|
SetIndustryTriggers(tile, object.GetRemainingTriggers());
|
||||||
|
|
||||||
|
/* Rerandomise tile bits */
|
||||||
byte new_random_bits = Random();
|
byte new_random_bits = Random();
|
||||||
byte random_bits = GetIndustryRandomBits(tile);
|
byte random_bits = GetIndustryRandomBits(tile);
|
||||||
random_bits &= ~object.reseed[VSG_SCOPE_SELF];
|
random_bits &= ~object.reseed[VSG_SCOPE_SELF];
|
||||||
|
@ -26,7 +26,6 @@ struct IndustryTileScopeResolver : public ScopeResolver {
|
|||||||
/* virtual */ uint32 GetRandomBits() const;
|
/* virtual */ uint32 GetRandomBits() const;
|
||||||
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
||||||
/* virtual */ uint32 GetTriggers() const;
|
/* virtual */ uint32 GetTriggers() const;
|
||||||
/* virtual */ void SetTriggers(int triggers) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Resolver for industry tiles. */
|
/** Resolver for industry tiles. */
|
||||||
|
@ -109,12 +109,6 @@ ScopeResolver::~ScopeResolver() {}
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the triggers. Base class implementation does nothing.
|
|
||||||
* @param triggers Triggers to set.
|
|
||||||
*/
|
|
||||||
/* virtual */ void ScopeResolver::SetTriggers(int triggers) const {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a variable value. Default implementation has no available variables.
|
* Get a variable value. Default implementation has no available variables.
|
||||||
* @param variable Variable to read
|
* @param variable Variable to read
|
||||||
@ -304,21 +298,15 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
|
|||||||
const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject &object) const
|
const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject &object) const
|
||||||
{
|
{
|
||||||
ScopeResolver *scope = object.GetScope(this->var_scope, this->count);
|
ScopeResolver *scope = object.GetScope(this->var_scope, this->count);
|
||||||
if (object.trigger != 0) {
|
if (object.callback == CBID_RANDOM_TRIGGER) {
|
||||||
/* Handle triggers */
|
/* Handle triggers */
|
||||||
/* Magic code that may or may not do the right things... */
|
byte match = this->triggers & object.waiting_triggers;
|
||||||
byte waiting_triggers = scope->GetTriggers();
|
|
||||||
byte match = this->triggers & (waiting_triggers | object.trigger);
|
|
||||||
bool res = (this->cmp_mode == RSG_CMP_ANY) ? (match != 0) : (match == this->triggers);
|
bool res = (this->cmp_mode == RSG_CMP_ANY) ? (match != 0) : (match == this->triggers);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
waiting_triggers &= ~match;
|
object.used_triggers |= match;
|
||||||
object.reseed[this->var_scope] |= (this->num_groups - 1) << this->lowest_randbit;
|
object.reseed[this->var_scope] |= (this->num_groups - 1) << this->lowest_randbit;
|
||||||
} else {
|
|
||||||
waiting_triggers |= object.trigger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scope->SetTriggers(waiting_triggers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 mask = (this->num_groups - 1) << this->lowest_randbit;
|
uint32 mask = (this->num_groups - 1) << this->lowest_randbit;
|
||||||
|
@ -293,7 +293,6 @@ struct ScopeResolver {
|
|||||||
|
|
||||||
virtual uint32 GetRandomBits() const;
|
virtual uint32 GetRandomBits() const;
|
||||||
virtual uint32 GetTriggers() const;
|
virtual uint32 GetTriggers() const;
|
||||||
virtual void SetTriggers(int triggers) const;
|
|
||||||
|
|
||||||
virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
||||||
virtual void StorePSA(uint reg, int32 value);
|
virtual void StorePSA(uint reg, int32 value);
|
||||||
@ -315,9 +314,10 @@ struct ResolverObject {
|
|||||||
uint32 callback_param1; ///< First parameter (var 10) of the callback.
|
uint32 callback_param1; ///< First parameter (var 10) of the callback.
|
||||||
uint32 callback_param2; ///< Second parameter (var 18) of the callback.
|
uint32 callback_param2; ///< Second parameter (var 18) of the callback.
|
||||||
|
|
||||||
byte trigger;
|
|
||||||
|
|
||||||
uint32 last_value; ///< Result of most recent DeterministicSpriteGroup (including procedure calls)
|
uint32 last_value; ///< Result of most recent DeterministicSpriteGroup (including procedure calls)
|
||||||
|
|
||||||
|
uint32 waiting_triggers; ///< Waiting triggers to be used by any rerandomisation. (scope independent)
|
||||||
|
uint32 used_triggers; ///< Subset of cur_triggers, which actually triggered some rerandomisation. (scope independent)
|
||||||
uint32 reseed[VSG_END]; ///< Collects bits to rerandomise while triggering triggers.
|
uint32 reseed[VSG_END]; ///< Collects bits to rerandomise while triggering triggers.
|
||||||
|
|
||||||
const GRFFile *grffile; ///< GRFFile the resolved SpriteGroup belongs to
|
const GRFFile *grffile; ///< GRFFile the resolved SpriteGroup belongs to
|
||||||
@ -346,6 +346,14 @@ struct ResolverObject {
|
|||||||
|
|
||||||
virtual ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0);
|
virtual ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the waiting triggers that did not trigger any rerandomisation.
|
||||||
|
*/
|
||||||
|
uint32 GetRemainingTriggers() const
|
||||||
|
{
|
||||||
|
return this->waiting_triggers & ~this->used_triggers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the OR-sum of all bits that need reseeding
|
* Returns the OR-sum of all bits that need reseeding
|
||||||
* independent of the scope they were accessed with.
|
* independent of the scope they were accessed with.
|
||||||
@ -367,7 +375,8 @@ struct ResolverObject {
|
|||||||
void ResetState()
|
void ResetState()
|
||||||
{
|
{
|
||||||
this->last_value = 0;
|
this->last_value = 0;
|
||||||
this->trigger = 0;
|
this->waiting_triggers = 0;
|
||||||
|
this->used_triggers = 0;
|
||||||
memset(this->reseed, 0, sizeof(this->reseed));
|
memset(this->reseed, 0, sizeof(this->reseed));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -235,13 +235,6 @@ static uint32 GetRailContinuationInfo(TileIndex tile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* virtual */ void StationScopeResolver::SetTriggers(int triggers) const
|
|
||||||
{
|
|
||||||
BaseStation *st = const_cast<BaseStation *>(this->st);
|
|
||||||
assert(st != NULL);
|
|
||||||
st->waiting_triggers = triggers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Station variable cache
|
* Station variable cache
|
||||||
* This caches 'expensive' station variable lookups which iterate over
|
* This caches 'expensive' station variable lookups which iterate over
|
||||||
@ -997,8 +990,9 @@ void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert trigger to bit */
|
/* Store triggers now for var 5F */
|
||||||
uint8 trigger_bit = 1 << trigger;
|
SetBit(st->waiting_triggers, trigger);
|
||||||
|
uint32 used_triggers = 0;
|
||||||
|
|
||||||
/* Check all tiles over the station to check if the specindex is still in use */
|
/* Check all tiles over the station to check if the specindex is still in use */
|
||||||
TILE_AREA_LOOP(tile, area) {
|
TILE_AREA_LOOP(tile, area) {
|
||||||
@ -1014,11 +1008,13 @@ void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigg
|
|||||||
|
|
||||||
if (cargo_type == CT_INVALID || HasBit(ss->cargo_triggers, cargo_type)) {
|
if (cargo_type == CT_INVALID || HasBit(ss->cargo_triggers, cargo_type)) {
|
||||||
StationResolverObject object(ss, st, tile, CBID_RANDOM_TRIGGER, 0);
|
StationResolverObject object(ss, st, tile, CBID_RANDOM_TRIGGER, 0);
|
||||||
object.trigger = trigger_bit;
|
object.waiting_triggers = st->waiting_triggers;
|
||||||
|
|
||||||
const SpriteGroup *group = object.Resolve();
|
const SpriteGroup *group = object.Resolve();
|
||||||
if (group == NULL) continue;
|
if (group == NULL) continue;
|
||||||
|
|
||||||
|
used_triggers |= object.used_triggers;
|
||||||
|
|
||||||
uint32 reseed = object.GetReseedSum();
|
uint32 reseed = object.GetReseedSum();
|
||||||
if (reseed != 0) {
|
if (reseed != 0) {
|
||||||
whole_reseed |= reseed;
|
whole_reseed |= reseed;
|
||||||
@ -1037,6 +1033,7 @@ void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigg
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update whole station random bits */
|
/* Update whole station random bits */
|
||||||
|
st->waiting_triggers &= ~used_triggers;
|
||||||
if ((whole_reseed & 0xFFFF) != 0) {
|
if ((whole_reseed & 0xFFFF) != 0) {
|
||||||
st->random_bits &= ~whole_reseed;
|
st->random_bits &= ~whole_reseed;
|
||||||
st->random_bits |= Random() & whole_reseed;
|
st->random_bits |= Random() & whole_reseed;
|
||||||
|
@ -34,7 +34,6 @@ struct StationScopeResolver : public ScopeResolver {
|
|||||||
|
|
||||||
/* virtual */ uint32 GetRandomBits() const;
|
/* virtual */ uint32 GetRandomBits() const;
|
||||||
/* virtual */ uint32 GetTriggers() const;
|
/* virtual */ uint32 GetTriggers() const;
|
||||||
/* virtual */ void SetTriggers(int triggers) const;
|
|
||||||
|
|
||||||
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user