diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -1320,10 +1320,11 @@ bool IsSlopeRefused(Slope current, Slope * @param it Industry tiles table. * @param itspec_index The index of the itsepc to build/fund * @param type Type of the industry. + * @param initial_random_bits The random bits the industry is going to have after construction. * @param [out] custom_shape_check Perform custom check for the site. * @return Failed or succeeded command. */ -static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, uint itspec_index, int type, bool *custom_shape_check = NULL) +static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, uint itspec_index, int type, uint16 initial_random_bits, bool *custom_shape_check = NULL) { bool refused_slope = false; bool custom_shape = false; @@ -1355,7 +1356,7 @@ static CommandCost CheckIfIndustryTilesA if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) { custom_shape = true; - CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index); + CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits); if (ret.Failed()) return ret; } else { Slope tileh = GetTileSlope(cur_tile, NULL); @@ -1564,8 +1565,9 @@ enum ProductionLevels { * @param layout Number of the layout. * @param t Nearest town. * @param founder Founder of the industry; OWNER_NONE in case of random construction. + * @param initial_random_bits Random bits for the industry. */ -static void DoCreateNewIndustry(Industry *i, TileIndex tile, int type, const IndustryTileTable *it, byte layout, const Town *t, Owner founder) +static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, const Town *t, Owner founder, uint16 initial_random_bits) { const IndustrySpec *indspec = GetIndustrySpec(type); @@ -1593,10 +1595,10 @@ static void DoCreateNewIndustry(Industry i->town = t; i->owner = OWNER_NONE; - uint32 r = Random(); + uint16 r = Random(); i->random_colour = GB(r, 0, 4); i->counter = GB(r, 4, 12); - i->random = GB(r, 16, 16); + i->random = initial_random_bits; i->produced_cargo_waiting[0] = 0; i->produced_cargo_waiting[1] = 0; i->incoming_cargo_waiting[0] = 0; @@ -1691,13 +1693,14 @@ static void DoCreateNewIndustry(Industry * @param indspec pointer to industry specifications * @param itspec_index the index of the itsepc to build/fund * @param seed random seed (possibly) used by industries + * @param initial_random_bits The random bits the industry is going to have after construction. * @param founder Founder of the industry * @param ip Pointer to store newly created industry. * @return Succeeded or failed command. * * @post \c *ip contains the newly created industry if all checks are successful and the \a flags request actual creation, else it contains \c NULL afterwards. */ -static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlag flags, const IndustrySpec *indspec, uint itspec_index, uint32 seed, Owner founder, Industry **ip) +static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlag flags, const IndustrySpec *indspec, uint itspec_index, uint32 random_var8f, uint16 random_initial_bits, Owner founder, Industry **ip) { assert(itspec_index < indspec->num_table); const IndustryTileTable *it = indspec->table[itspec_index]; @@ -1705,11 +1708,11 @@ static CommandCost CreateNewIndustryHelp *ip = NULL; - CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, &custom_shape_check); + CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, &custom_shape_check); if (ret.Failed()) return ret; if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) { - ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, seed); + ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits); } else { ret = _check_new_industry_procs[indspec->check_proc](tile); } @@ -1736,7 +1739,7 @@ static CommandCost CreateNewIndustryHelp if (flags & DC_EXEC) { *ip = new Industry(tile); if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type); - DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder); + DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits); } return CommandCost(); @@ -1748,7 +1751,7 @@ static CommandCost CreateNewIndustryHelp * @param p1 various bitstuffed elements * - p1 = (bit 0 - 7) - industry type see build_industry.h and see industry.h * - p1 = (bit 8 - 15) - first layout to try - * @param p2 seed to use for variable 8F + * @param p2 seed to use for desyncfree randomisations * @param text unused * @return the cost of this operation or an error */ @@ -1772,6 +1775,11 @@ CommandCost CmdBuildIndustry(TileIndex t return CMD_ERROR; } + Randomizer randomizer; + randomizer.SetSeed(p2); + uint16 random_initial_bits = GB(p2, 0, 16); + uint32 random_var8f = randomizer.Next(); + Industry *ind = NULL; if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry()) { if (flags & DC_EXEC) { @@ -1787,7 +1795,7 @@ CommandCost CmdBuildIndustry(TileIndex t * because parameter evaluation order is not guaranteed in the c++ standard */ tile = RandomTile(); - CommandCost ret = CreateNewIndustryHelper(tile, it, flags, indspec, RandomRange(indspec->num_table), p2, founder, &ind); + CommandCost ret = CreateNewIndustryHelper(tile, it, flags, indspec, RandomRange(indspec->num_table), random_var8f, random_initial_bits, founder, &ind); if (ret.Succeeded()) break; } } @@ -1803,10 +1811,10 @@ CommandCost CmdBuildIndustry(TileIndex t do { if (--count < 0) return ret; if (--num < 0) num = indspec->num_table - 1; - ret = CheckIfIndustryTilesAreFree(tile, itt[num], num, it); + ret = CheckIfIndustryTilesAreFree(tile, itt[num], num, it, random_initial_bits); } while (ret.Failed()); - ret = CreateNewIndustryHelper(tile, it, flags, indspec, num, p2, _current_company, &ind); + ret = CreateNewIndustryHelper(tile, it, flags, indspec, num, random_var8f, random_initial_bits, _current_company, &ind); if (ret.Failed()) return ret; } @@ -1832,8 +1840,9 @@ static Industry *CreateNewIndustry(TileI const IndustrySpec *indspec = GetIndustrySpec(type); uint32 seed = Random(); + uint32 seed2 = Random(); Industry *i = NULL; - CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, OWNER_NONE, &i); + CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, GB(seed2, 0, 16), OWNER_NONE, &i); assert(i != NULL || ret.Failed()); return i; } diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -102,7 +102,7 @@ static uint32 HouseGetRandomBits(const R /* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */ TileIndex tile = object->u.house.tile; assert(IsValidTile(tile) && (object->u.house.not_yet_constructed || IsTileType(tile, MP_HOUSE))); - return object->u.house.not_yet_constructed ? 0 : GetHouseRandomBits(tile); + return object->u.house.not_yet_constructed ? object->u.house.initial_random_bits : GetHouseRandomBits(tile); } static uint32 HouseGetTriggers(const ResolverObject *object) @@ -389,7 +389,7 @@ static void NewHouseResolver(ResolverObj res->grffile = (hs != NULL ? hs->grffile : NULL); } -uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, bool not_yet_constructed) +uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, bool not_yet_constructed, uint8 initial_random_bits) { ResolverObject object; const SpriteGroup *group; @@ -401,6 +401,7 @@ uint16 GetHouseCallback(CallbackID callb object.callback_param1 = param1; object.callback_param2 = param2; object.u.house.not_yet_constructed = not_yet_constructed; + object.u.house.initial_random_bits = initial_random_bits; group = SpriteGroup::Resolve(HouseSpec::Get(house_id)->spritegroup, &object); if (group == NULL) return CALLBACK_FAILED; diff --git a/src/newgrf_house.h b/src/newgrf_house.h --- a/src/newgrf_house.h +++ b/src/newgrf_house.h @@ -44,7 +44,7 @@ void DrawNewHouseTile(TileInfo *ti, Hous void AnimateNewHouseTile(TileIndex tile); void ChangeHouseAnimationFrame(const struct GRFFile *file, TileIndex tile, uint16 callback_result); -uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, bool not_yet_constructed = false); +uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, bool not_yet_constructed = false, uint8 initial_random_bits = 0); bool CanDeleteHouse(TileIndex tile); diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -459,9 +459,10 @@ uint32 IndustryLocationGetVariable(const * @param type Type of industry to build. * @param layout Layout number. * @param seed Seed for the random generator. + * @param initial_random_bits The random bits the industry is going to have after construction. * @return Succeeded or failed command. */ -CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint layout, uint32 seed) +CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint layout, uint32 seed, uint16 initial_random_bits) { const IndustrySpec *indspec = GetIndustrySpec(type); @@ -475,6 +476,7 @@ CommandCost CheckIfCallBackAllowsCreatio ind.type = type; ind.selected_layout = layout; ind.town = ClosestTownFromTile(tile, UINT_MAX); + ind.random = initial_random_bits; NewIndustryResolver(&object, tile, &ind, type); object.GetVariable = IndustryLocationGetVariable; diff --git a/src/newgrf_industries.h b/src/newgrf_industries.h --- a/src/newgrf_industries.h +++ b/src/newgrf_industries.h @@ -37,7 +37,7 @@ uint32 IndustryGetVariable(const Resolve uint16 GetIndustryCallback(CallbackID callback, uint32 param1, uint32 param2, Industry *industry, IndustryType type, TileIndex tile); uint32 GetIndustryIDAtOffset(TileIndex new_tile, const Industry *i, uint32 cur_grfid); void IndustryProductionCallback(Industry *ind, int reason); -CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint layout, uint32 seed); +CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint layout, uint32 seed, uint16 initial_random_bits); bool CheckIfCallBackAllowsAvailability(IndustryType type, IndustryAvailabilityCallType creation_type); IndustryType MapNewGRFIndustryType(IndustryType grf_type, uint32 grf_id); diff --git a/src/newgrf_industrytiles.cpp b/src/newgrf_industrytiles.cpp --- a/src/newgrf_industrytiles.cpp +++ b/src/newgrf_industrytiles.cpp @@ -257,15 +257,17 @@ extern bool IsSlopeRefused(Slope current * @param type Industry type. * @param gfx Gfx of the tile. * @param itspec_index Layout. + * @param initial_random_bits Random bits of industry after construction * @return Suceeded or failed command. */ -CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, uint itspec_index) +CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, uint itspec_index, uint16 initial_random_bits) { Industry ind; ind.index = INVALID_INDUSTRY; ind.location.tile = ind_base_tile; ind.location.w = 0; ind.type = type; + ind.random = initial_random_bits; uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_SHAPE_CHECK, 0, itspec_index, gfx, &ind, ind_tile); if (callback_res == CALLBACK_FAILED) { diff --git a/src/newgrf_industrytiles.h b/src/newgrf_industrytiles.h --- a/src/newgrf_industrytiles.h +++ b/src/newgrf_industrytiles.h @@ -27,7 +27,7 @@ enum IndustryAnimationTrigger { bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds); uint16 GetIndustryTileCallback(CallbackID callback, uint32 param1, uint32 param2, IndustryGfx gfx_id, Industry *industry, TileIndex tile); -CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, uint itspec_index); +CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, uint itspec_index, uint16 initial_random_bits); void AnimateNewIndustryTile(TileIndex tile); bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random = Random()); diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -319,6 +319,7 @@ struct ResolverObject { TileIndex tile; Town *town; HouseID house_id; + uint16 initial_random_bits; ///< Random bits during construction checks bool not_yet_constructed; ///< True for construction check } house; struct { diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -2164,8 +2164,10 @@ static bool BuildTownHouse(Town *t, Tile /* 1x1 house checks are already done */ } + byte random_bits = Random(); + if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) { - uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile, true); + uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile, true, random_bits); if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue; } @@ -2191,7 +2193,7 @@ static bool BuildTownHouse(Town *t, Tile } } - MakeTownHouse(tile, t, construction_counter, construction_stage, house, Random()); + MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits); return true; }