diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -22,6 +22,7 @@ #include "company_base.h" #include "core/random_func.hpp" #include "newgrf_generic.h" +#include "date_func.h" #include "table/strings.h" #include "table/tree_land.h" @@ -803,6 +804,23 @@ static void TileLoop_Trees(TileIndex til MarkTileDirtyByTile(tile); } +/** + * Decrement the tree tick counter. + * The interval is scaled by map size to allow for the same density regardless of size. + * Adjustment for map sizes below the standard 256 * 256 are handled earlier. + * @return true if the counter was decremented past zero + */ +bool DecrementTreeCounter() +{ + /* Ensure _trees_tick_ctr can be decremented past zero only once for the largest map size. */ + static_assert(2 * (MAX_MAP_SIZE_BITS - MIN_MAP_SIZE_BITS) - 4 <= std::numeric_limits::digits); + + /* byte underflow */ + byte old_trees_tick_ctr = _trees_tick_ctr; + _trees_tick_ctr -= ScaleByMapSize(1); + return old_trees_tick_ctr <= _trees_tick_ctr; +} + void OnTick_Trees() { /* Don't spread trees if that's not allowed */ @@ -812,16 +830,24 @@ void OnTick_Trees() TileIndex tile; TreeType tree; + /* Skip some tree ticks for map sizes below 256 * 256. 64 * 64 is 16 times smaller, so + * this is the maximum number of ticks that are skipped. Number of ticks to skip is + * inversely proportional to map size, so that is handled to create a mask. */ + int skip = ScaleByMapSize(16); + if (skip < 16 && (_tick_counter & (16 / skip - 1)) != 0) return; + /* place a tree at a random rainforest spot */ - if (_settings_game.game_creation.landscape == LT_TROPIC && - (r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) && - CanPlantTreesOnTile(tile, false) && - (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { - PlantTreesOnTile(tile, tree, 0, 0); + if (_settings_game.game_creation.landscape == LT_TROPIC) { + for (uint c = ScaleByMapSize(1); c > 0; c--) { + if ((r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) && + CanPlantTreesOnTile(tile, false) && + (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { + PlantTreesOnTile(tile, tree, 0, 0); + } + } } - /* byte underflow */ - if (--_trees_tick_ctr != 0 || _settings_game.construction.extra_tree_placement == ETP_SPREAD_RAINFOREST) return; + if (!DecrementTreeCounter() || _settings_game.construction.extra_tree_placement == ETP_SPREAD_RAINFOREST) return; /* place a tree at a random spot */ r = Random();