diff --git a/src/landscape.cpp b/src/landscape.cpp index 165185b11e..46c10cca33 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -827,14 +827,10 @@ CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 TileIndex _cur_tileloop_tile; +TileIndex _aux_tileloop_tile; -/** - * Gradually iterate over all tiles on the map, calling their TileLoopProcs once every 256 ticks. - */ -void RunTileLoop() +static uint32 GetTileLoopFeedback() { - PerformanceAccumulator framerate(PFE_GL_LANDSCAPE); - /* The pseudorandom sequence of tiles is generated using a Galois linear feedback * shift register (LFSR). This allows a deterministic pseudorandom ordering, but * still with minimal state and fast iteration. */ @@ -846,7 +842,17 @@ void RunTileLoop() 0x4004B2, 0x800B87, 0x10004F3, 0x200072D, 0x40006AE, 0x80009E3, }; static_assert(lengthof(feedbacks) == MAX_MAP_TILES_BITS - 2 * MIN_MAP_SIZE_BITS + 1); - const uint32 feedback = feedbacks[MapLogX() + MapLogY() - 2 * MIN_MAP_SIZE_BITS]; + return feedbacks[MapLogX() + MapLogY() - 2 * MIN_MAP_SIZE_BITS]; +} + +/** + * Gradually iterate over all tiles on the map, calling their TileLoopProcs once every 256 ticks. + */ +void RunTileLoop() +{ + PerformanceAccumulator framerate(PFE_GL_LANDSCAPE); + + const uint32 feedback = GetTileLoopFeedback(); /* We update every tile every 256 ticks, so divide the map size by 2^8 = 256 */ uint count = 1 << (MapLogX() + MapLogY() - 8); @@ -873,6 +879,30 @@ void RunTileLoop() _cur_tileloop_tile = tile; } +void RunAuxiliaryTileLoop() +{ + /* At day lengths <= 4, flooding is handled by main tile loop */ + if (_settings_game.economy.day_length_factor <= 4 || (_scaled_tick_counter % 4) != 0) return; + + PerformanceAccumulator framerate(PFE_GL_LANDSCAPE); + + const uint32 feedback = GetTileLoopFeedback(); + uint count = 1 << (MapLogX() + MapLogY() - 8); + TileIndex tile = _aux_tileloop_tile; + + while (count--) { + if (!IsNonFloodingWaterTile(tile)) { + FloodingBehaviour fb = GetFloodingBehaviour(tile); + if (fb != FLOOD_NONE) TileLoopWaterFlooding(fb, tile); + } + + /* Get the next tile in sequence using a Galois LFSR. */ + tile = (tile >> 1) ^ (-(int32)(tile & 1) & feedback); + } + + _aux_tileloop_tile = tile; +} + void InitializeLandscape() { for (uint y = _settings_game.construction.freeform_edges ? 1 : 0; y < MapMaxY(); y++) { diff --git a/src/landscape.h b/src/landscape.h index 08dad6c782..ce90bc2b71 100644 --- a/src/landscape.h +++ b/src/landscape.h @@ -166,6 +166,7 @@ bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here); void DoClearSquare(TileIndex tile); void RunTileLoop(); +void RunAuxiliaryTileLoop(); void InitializeLandscape(); void GenerateLandscape(byte mode); diff --git a/src/misc.cpp b/src/misc.cpp index 0d19994627..76336f77b5 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -44,6 +44,7 @@ extern TileIndex _cur_tileloop_tile; +extern TileIndex _aux_tileloop_tile; extern void ClearAllSignalSpeedRestrictions(); extern void MakeNewgameSettingsLive(); @@ -91,6 +92,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin _scaled_tick_counter = 0; _scaled_date_ticks_offset = 0; _cur_tileloop_tile = 1; + _aux_tileloop_tile = 1; _thd.redsq = INVALID_TILE; _road_layout_change_counter = 0; _loaded_local_company = COMPANY_SPECTATOR; diff --git a/src/openttd.cpp b/src/openttd.cpp index 47f73884c2..34bf6836ee 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1962,6 +1962,7 @@ void StateGameLoop() SetWindowDirty(WC_STATUS_BAR, 0); } + RunAuxiliaryTileLoop(); if (_tick_skip_counter < _settings_game.economy.day_length_factor) { AnimateAnimatedTiles(); CallVehicleTicks(); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index d77ba8a246..83ffef376d 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -646,6 +646,9 @@ bool AfterLoadGame() /* The LFSR used in RunTileLoop iteration cannot have a zeroed state, make it non-zeroed. */ if (_cur_tileloop_tile == 0) _cur_tileloop_tile = 1; + extern TileIndex _aux_tileloop_tile; + if (_aux_tileloop_tile == 0) _aux_tileloop_tile = 1; + if (IsSavegameVersionBefore(SLV_98)) GamelogOldver(); GamelogTestRevision(); diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 40644ce211..0a9f5a2fe1 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -177,6 +177,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_NO_TREE_COUNTER, XSCF_IGNORABLE_ALL, 1, 1, "no_tree_counter", nullptr, nullptr, nullptr }, { XSLFI_TOWN_SETTING_OVERRIDE, XSCF_NULL, 1, 1, "town_setting_override", nullptr, nullptr, nullptr }, { XSLFI_LINKGRAPH_SPARSE_EDGES, XSCF_NULL, 1, 1, "linkgraph_sparse_edges", nullptr, nullptr, nullptr }, + { XSLFI_AUX_TILE_LOOP, XSCF_NULL, 1, 1, "aux_tile_loop", nullptr, nullptr, nullptr }, { XSLFI_SCRIPT_INT64, XSCF_NULL, 1, 1, "script_int64", nullptr, nullptr, nullptr }, { XSLFI_U64_TICK_COUNTER, XSCF_NULL, 1, 1, "u64_tick_counter", nullptr, nullptr, nullptr }, { XSLFI_LINKGRAPH_TRAVEL_TIME, XSCF_NULL, 1, 1, "linkgraph_travel_time", nullptr, nullptr, nullptr }, diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 8ee5178f15..3ff95bf7ff 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -130,6 +130,7 @@ enum SlXvFeatureIndex { XSLFI_NO_TREE_COUNTER, ///< No tree counter XSLFI_TOWN_SETTING_OVERRIDE, ///< Town setting overrides XSLFI_LINKGRAPH_SPARSE_EDGES, ///< Link graph edge matrix is stored in sparse format, and saved in order + XSLFI_AUX_TILE_LOOP, ///< Auxiliary tile loop XSLFI_SCRIPT_INT64, ///< See: SLV_SCRIPT_INT64 XSLFI_U64_TICK_COUNTER, ///< See: SLV_U64_TICK_COUNTER diff --git a/src/saveload/misc_sl.cpp b/src/saveload/misc_sl.cpp index 81e44bc236..cf1123d471 100644 --- a/src/saveload/misc_sl.cpp +++ b/src/saveload/misc_sl.cpp @@ -25,6 +25,7 @@ #include "../safeguards.h" extern TileIndex _cur_tileloop_tile; +extern TileIndex _aux_tileloop_tile; extern uint16 _disaster_delay; extern byte _trees_tick_ctr; extern uint64 _aspect_cfg_hash; @@ -102,6 +103,7 @@ static const SaveLoad _date_desc[] = { SLEG_CONDVAR_X(_road_layout_change_counter, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_LAYOUT_CHANGE_CTR)), SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REALISTIC_TRAIN_BRAKING, 4, 6)), // _extra_aspects SLEG_CONDVAR_X(_aspect_cfg_hash, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REALISTIC_TRAIN_BRAKING, 7)), + SLEG_CONDVAR_X(_aux_tileloop_tile, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_AUX_TILE_LOOP)), SLE_CONDNULL(4, SLV_11, SLV_120), }; diff --git a/src/saveload/upstream/misc_sl.cpp b/src/saveload/upstream/misc_sl.cpp index b43ebdcb68..fdda96b540 100644 --- a/src/saveload/upstream/misc_sl.cpp +++ b/src/saveload/upstream/misc_sl.cpp @@ -24,6 +24,7 @@ #include "../../safeguards.h" extern TileIndex _cur_tileloop_tile; +extern TileIndex _aux_tileloop_tile; extern uint16 _disaster_delay; extern byte _trees_tick_ctr; diff --git a/src/water.h b/src/water.h index be17882187..a02f877116 100644 --- a/src/water.h +++ b/src/water.h @@ -27,6 +27,7 @@ FloodingBehaviour GetFloodingBehaviour(TileIndex tile); void ClearNeighbourNonFloodingStates(TileIndex tile); void TileLoop_Water(TileIndex tile); +void TileLoopWaterFlooding(FloodingBehaviour flooding_behaviour, TileIndex tile); bool FloodHalftile(TileIndex t); void DoFloodTile(TileIndex target); diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 22f3a4f80f..fc781306c4 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -1324,9 +1324,17 @@ void TileLoop_Water(TileIndex tile) { if (IsTileType(tile, MP_WATER)) AmbientSoundEffect(tile); + /* At day lengths > 4, handle flooding in auxiliary tile loop */ + if (_settings_game.economy.day_length_factor > 4) return; + if (IsNonFloodingWaterTile(tile)) return; - switch (GetFloodingBehaviour(tile)) { + TileLoopWaterFlooding(GetFloodingBehaviour(tile), tile); +} + +void TileLoopWaterFlooding(FloodingBehaviour flooding_behaviour, TileIndex tile) +{ + switch (flooding_behaviour) { case FLOOD_ACTIVE: { int non_water_neighbours = 0; for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {