diff --git a/src/newgrf_airport.cpp b/src/newgrf_airport.cpp index f5918c8ee4..69a081a212 100644 --- a/src/newgrf_airport.cpp +++ b/src/newgrf_airport.cpp @@ -171,8 +171,7 @@ static const SpriteGroup *AirportResolveReal(const ResolverObject *object, const static uint32 AirportGetRandomBits(const ResolverObject *object) { const Station *st = object->u.airport.st; - const TileIndex tile = object->u.airport.tile; - return (st == NULL ? 0 : st->random_bits) | (tile == INVALID_TILE ? 0 : GetStationTileRandomBits(tile) << 16); + return st == NULL ? 0 : st->random_bits; } static uint32 AirportGetTriggers(const ResolverObject *object) @@ -201,10 +200,7 @@ static void NewAirportResolver(ResolverObject *res, TileIndex tile, Station *st, res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); const AirportSpec *as = AirportSpec::Get(airport_id); res->grffile = as->grf_prop.grffile; diff --git a/src/newgrf_airporttiles.cpp b/src/newgrf_airporttiles.cpp index 5a1ba24c1e..28fdb0c20d 100644 --- a/src/newgrf_airporttiles.cpp +++ b/src/newgrf_airporttiles.cpp @@ -238,10 +238,7 @@ static void AirportTileResolver(ResolverObject *res, const AirportTileSpec *ats, res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); res->grffile = ats->grf_prop.grffile; } diff --git a/src/newgrf_canal.cpp b/src/newgrf_canal.cpp index 12ffc736a1..9f4de9e4a0 100644 --- a/src/newgrf_canal.cpp +++ b/src/newgrf_canal.cpp @@ -89,10 +89,8 @@ static void NewCanalResolver(ResolverObject *res, TileIndex tile, const GRFFile res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); + res->grffile = grffile; } diff --git a/src/newgrf_cargo.cpp b/src/newgrf_cargo.cpp index 257e96ee6f..7eb397016c 100644 --- a/src/newgrf_cargo.cpp +++ b/src/newgrf_cargo.cpp @@ -66,10 +66,8 @@ static void NewCargoResolver(ResolverObject *res, const CargoSpec *cs) res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); + res->grffile = cs->grffile; } diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index dc1dffcf45..f2f28883a1 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -878,10 +878,7 @@ static inline void NewVehicleResolver(ResolverObject *res, EngineID engine_type, res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); const Engine *e = Engine::Get(engine_type); res->grffile = (e != NULL ? e->grf_prop.grffile : NULL); @@ -1073,8 +1070,9 @@ static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, byte base_rando if (group == NULL) return; new_random_bits = Random(); - v->random_bits &= ~object.reseed; - v->random_bits |= (first ? new_random_bits : base_random_bits) & object.reseed; + uint32 reseed = object.GetReseedSum(); // The scope only affects triggers, not the reseeding + v->random_bits &= ~reseed; + v->random_bits |= (first ? new_random_bits : base_random_bits) & reseed; switch (trigger) { case VEHICLE_TRIGGER_NEW_CARGO: diff --git a/src/newgrf_generic.cpp b/src/newgrf_generic.cpp index 7d83d73b1b..862b1c5ee8 100644 --- a/src/newgrf_generic.cpp +++ b/src/newgrf_generic.cpp @@ -126,10 +126,8 @@ static inline void NewGenericResolver(ResolverObject *res, const GRFFile *grffil res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); + res->grffile = grffile; } diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 8484bb5e84..ec67c05eec 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -944,7 +944,7 @@ struct NewGRFWindow : public QueryStringBaseWindow { break; case SNGRFS_SET_PARAMETERS: { // Edit parameters - if (this->active_sel == NULL || !this->editable || !this->show_params) break; + if (this->active_sel == NULL || !this->editable || !this->show_params || this->active_sel->num_valid_params == 0) break; OpenGRFParameterWindow(this->active_sel); break; @@ -1099,7 +1099,7 @@ struct NewGRFWindow : public QueryStringBaseWindow { SNGRFS_MOVE_DOWN, WIDGET_LIST_END ); - this->SetWidgetDisabledState(SNGRFS_SET_PARAMETERS, !this->show_params || disable_all); + this->SetWidgetDisabledState(SNGRFS_SET_PARAMETERS, !this->show_params || disable_all || this->active_sel->num_valid_params == 0); this->SetWidgetDisabledState(SNGRFS_TOGGLE_PALETTE, disable_all); if (!disable_all) { diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 44e0347ac2..6991303525 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -381,10 +381,7 @@ static void NewHouseResolver(ResolverObject *res, HouseID house_id, TileIndex ti res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); const HouseSpec *hs = HouseSpec::Get(house_id); res->grffile = (hs != NULL ? hs->grf_prop.grffile : NULL); @@ -592,8 +589,9 @@ static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_rando byte new_random_bits = Random(); byte random_bits = GetHouseRandomBits(tile); - random_bits &= ~object.reseed; - random_bits |= (first ? new_random_bits : base_random) & object.reseed; + uint32 reseed = object.GetReseedSum(); // The scope only affects triggers, not the reseeding + random_bits &= ~reseed; + random_bits |= (first ? new_random_bits : base_random) & reseed; SetHouseRandomBits(tile, random_bits); switch (trigger) { diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index 70cd0a2c15..36dd28ad9d 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -387,10 +387,7 @@ static void NewIndustryResolver(ResolverObject *res, TileIndex tile, Industry *i res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); const IndustrySpec *indspec = GetIndustrySpec(type); res->grffile = (indspec != NULL ? indspec->grf_prop.grffile : NULL); diff --git a/src/newgrf_industrytiles.cpp b/src/newgrf_industrytiles.cpp index 994d068f6c..0f078fe98a 100644 --- a/src/newgrf_industrytiles.cpp +++ b/src/newgrf_industrytiles.cpp @@ -165,10 +165,7 @@ static void NewIndustryTileResolver(ResolverObject *res, IndustryGfx gfx, TileIn res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); const IndustryTileSpec *its = GetIndustryTileSpec(gfx); res->grffile = (its != NULL ? its->grf_prop.grffile : NULL); @@ -345,7 +342,14 @@ bool StartStopIndustryTileAnimation(const Industry *ind, IndustryAnimationTrigge return ret; } -static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, Industry *ind) +/** + * Trigger random triggers for an industry tile and reseed its random bits. + * @param tile Industry tile to trigger. + * @param trigger Trigger to trigger. + * @param ind Industry of the tile. + * @param [in,out] reseed_industry Collects bits to reseed for the industry. + */ +static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, Industry *ind, uint32 &reseed_industry) { ResolverObject object; @@ -366,24 +370,55 @@ static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, I byte new_random_bits = Random(); byte random_bits = GetIndustryRandomBits(tile); - random_bits &= ~object.reseed; - random_bits |= new_random_bits & object.reseed; + random_bits &= ~object.reseed[VSG_SCOPE_SELF]; + random_bits |= new_random_bits & object.reseed[VSG_SCOPE_SELF]; SetIndustryRandomBits(tile, random_bits); MarkTileDirtyByTile(tile); + + reseed_industry |= object.reseed[VSG_SCOPE_PARENT]; } +/** + * Reseeds the random bits of an industry. + * @param ind Industry. + * @param reseed Bits to reseed. + */ +static void DoReseedIndustry(Industry *ind, uint32 reseed) +{ + if (reseed == 0 || ind == NULL) return; + + uint16 random_bits = Random(); + ind->random &= reseed; + ind->random |= random_bits & reseed; +} + +/** + * Trigger a random trigger for a single industry tile. + * @param tile Industry tile to trigger. + * @param trigger Trigger to trigger. + */ void TriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger) { - DoTriggerIndustryTile(tile, trigger, Industry::GetByTile(tile)); + uint32 reseed_industry = 0; + Industry *ind = Industry::GetByTile(tile); + DoTriggerIndustryTile(tile, trigger, ind, reseed_industry); + DoReseedIndustry(ind, reseed_industry); } +/** + * Trigger a random trigger for all industry tiles. + * @param ind Industry to trigger. + * @param trigger Trigger to trigger. + */ void TriggerIndustry(Industry *ind, IndustryTileTrigger trigger) { + uint32 reseed_industry = 0; TILE_AREA_LOOP(tile, ind->location) { if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == ind->index) { - DoTriggerIndustryTile(tile, trigger, ind); + DoTriggerIndustryTile(tile, trigger, ind, reseed_industry); } } + DoReseedIndustry(ind, reseed_industry); } /** diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp index d33bc38aab..0b274b4179 100644 --- a/src/newgrf_object.cpp +++ b/src/newgrf_object.cpp @@ -376,10 +376,7 @@ static void NewObjectResolver(ResolverObject *res, const ObjectSpec *spec, const res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); res->grffile = spec->grf_prop.grffile; } diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp index 11c52c95ce..04d71ee33b 100644 --- a/src/newgrf_railtype.cpp +++ b/src/newgrf_railtype.cpp @@ -81,10 +81,7 @@ static inline void NewRailTypeResolver(ResolverObject *res, TileIndex tile, Tile res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); res->grffile = grffile; } diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index 5edf44b28b..36550e103d 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -213,7 +213,7 @@ const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject *object) const if (res) { waiting_triggers &= ~match; - object->reseed |= (this->num_groups - 1) << this->lowest_randbit; + object->reseed[this->var_scope] |= (this->num_groups - 1) << this->lowest_randbit; } else { waiting_triggers |= object->trigger; } diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index af30c5ddfd..a7fdfbbeb6 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -122,12 +122,15 @@ protected: /* Shared by deterministic and random groups. */ enum VarSpriteGroupScope { - VSG_SCOPE_SELF, - /* Engine of consists for vehicles, city for stations. */ - VSG_SCOPE_PARENT, - /* Any vehicle in the consist (vehicles only) */ - VSG_SCOPE_RELATIVE, + VSG_BEGIN, + + VSG_SCOPE_SELF = VSG_BEGIN, ///< Resolved object itself + VSG_SCOPE_PARENT, ///< Related object of the resolved one + VSG_SCOPE_RELATIVE, ///< Relative position (vehicles only) + + VSG_END }; +DECLARE_POSTFIX_INCREMENT(VarSpriteGroupScope) enum DeterministicSpriteGroupSize { DSG_SIZE_BYTE, @@ -304,7 +307,7 @@ struct ResolverObject { byte trigger; uint32 last_value; ///< Result of most recent DeterministicSpriteGroup (including procedure calls) - uint32 reseed; ///< Collects bits to rerandomise while triggering triggers. + uint32 reseed[VSG_END]; ///< Collects bits to rerandomise while triggering triggers. VarSpriteGroupScope scope; ///< Scope of currently resolved DeterministicSpriteGroup resp. RandomizedSpriteGroup byte count; ///< Additional scope for RandomizedSpriteGroup @@ -377,6 +380,31 @@ struct ResolverObject { void (*SetTriggers)(const struct ResolverObject*, int); uint32 (*GetVariable)(const struct ResolverObject*, byte, byte, bool*); const SpriteGroup *(*ResolveReal)(const struct ResolverObject*, const RealSpriteGroup*); + + /** + * Returns the OR-sum of all bits that need reseeding + * independent of the scope they were accessed with. + * @return OR-sum of the bits. + */ + uint32 GetReseedSum() const + { + uint32 sum = 0; + for (VarSpriteGroupScope vsg = VSG_BEGIN; vsg < VSG_END; vsg++) { + sum |= this->reseed[vsg]; + } + return sum; + } + + /** + * Resets the dynamic state of the resolver object. + * To be called before resolving an Action-1-2-3 chain. + */ + void ResetState() + { + this->last_value = 0; + this->trigger = 0; + memset(this->reseed, 0, sizeof(this->reseed)); + } }; #endif /* NEWGRF_SPRITEGROUP_H */ diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index b84fbf0a31..cf58828146 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -531,10 +531,8 @@ static void NewStationResolver(ResolverObject *res, const StationSpec *statspec, res->callback = CBID_NO_CALLBACK; res->callback_param1 = 0; res->callback_param2 = 0; - res->last_value = 0; - res->trigger = 0; - res->reseed = 0; - res->count = 0; + res->ResetState(); + res->grffile = (statspec != NULL ? statspec->grf_prop.grffile : NULL); } diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 80e55f3fa3..cd6ef54941 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -279,8 +279,8 @@ static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags) if (flags & DC_EXEC) { DoClearSquare(tile); - MakeWaterKeepingClass(tile + delta, GetTileOwner(tile)); - MakeWaterKeepingClass(tile - delta, GetTileOwner(tile)); + MakeWaterKeepingClass(tile + delta, GetTileOwner(tile + delta)); + MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta)); MarkCanalsAndRiversAroundDirty(tile - delta); MarkCanalsAndRiversAroundDirty(tile + delta); } diff --git a/src/water_map.h b/src/water_map.h index f768a7d782..2efe4422c4 100644 --- a/src/water_map.h +++ b/src/water_map.h @@ -420,8 +420,10 @@ static inline void MakeLock(TileIndex t, Owner o, DiagDirection d, WaterClass wc TileIndexDiff delta = TileOffsByDiagDir(d); MakeLockTile(t, o, LOCK_MIDDLE + d, WATER_CLASS_CANAL); - MakeLockTile(t - delta, o, LOCK_LOWER + d, wc_lower); - MakeLockTile(t + delta, o, LOCK_UPPER + d, wc_upper); + /* Keep the current owner for the upper and lower part if it is a + * water tile so we can restore the owner after deleting the lock. */ + MakeLockTile(t - delta, IsWaterTile(t - delta) ? GetTileOwner(t - delta) : o, LOCK_LOWER + d, wc_lower); + MakeLockTile(t + delta, IsWaterTile(t + delta) ? GetTileOwner(t + delta) : o, LOCK_UPPER + d, wc_upper); } #endif /* WATER_MAP_H */