From 53d21538443e183ff8b3959fe84550d4964f312a Mon Sep 17 00:00:00 2001 From: Sylvain Devidal Date: Wed, 4 Jul 2018 13:37:37 +0200 Subject: [PATCH 01/10] Feature: New Trees Placement Algorithm "Forest" --- src/lang/english.txt | 3 ++- src/tree_cmd.cpp | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 881db7cfc7..2414bd5d91 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1586,11 +1586,12 @@ STR_CONFIG_SETTING_RIVER_AMOUNT :River amount: { STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Choose how many rivers to generate STR_CONFIG_SETTING_TREE_PLACER :Tree placer algorithm: {STRING2} -STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Choose the distribution of trees on the map: 'Original' plants trees uniformly scattered, 'Improved' plants them in groups +STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Choose the distribution of trees on the map: 'Original' plants trees uniformly scattered, 'Improved' plants them in groups, 'Forest' plants them in forests ###length 3 STR_CONFIG_SETTING_TREE_PLACER_NONE :None STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Original STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Improved +STR_CONFIG_SETTING_TREE_PLACER_FOREST :Forest STR_CONFIG_SETTING_ROAD_SIDE :Road vehicles: {STRING2} STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Choose the driving side diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 1a58c6c2e1..4dd618f720 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -41,6 +41,7 @@ enum TreePlacer { TP_NONE, ///< No tree placer algorithm TP_ORIGINAL, ///< The original algorithm TP_IMPROVED, ///< A 'improved' algorithm + TP_FOREST, ///< An algorithm trying to make only forests }; /** Where to place trees while in-game? */ @@ -80,6 +81,30 @@ static bool CanPlantTreesOnTile(TileIndex tile, bool allow_desert) } } +/** +* Tests if a tile is near an already existing forest. +* Trees won't spread if not placed near some other trees. +* +* @param tile the tile of interest +* @return true if the tile is near a forest +*/ +static bool IsNearbyForest(TileIndex tile) +{ + uint planted_tile_count = 0; + + for (int x = -2; x <= 2; x++) { + for (int y = -2; y <= 2; y++) { + TileIndex vincity = TileAddWrap(tile, x, y); + if (vincity != INVALID_TILE && + IsTileType(vincity, MP_TREES)) { + planted_tile_count++; + } + } + } + + return (planted_tile_count >= 6); +} + /** * Creates a tree tile * Ground type and density is preserved. @@ -257,7 +282,10 @@ void PlaceTreesRandomly() if (CanPlantTreesOnTile(tile, true)) { PlaceTree(tile, r); - if (_settings_game.game_creation.tree_placer != TP_IMPROVED) continue; + if (_settings_game.game_creation.tree_placer != TP_IMPROVED && + _settings_game.game_creation.tree_placer != TP_FOREST) { + continue; + } /* Place a number of trees based on the tile height. * This gives a cool effect of multiple trees close together. @@ -358,6 +386,7 @@ void GenerateTrees() switch (_settings_game.game_creation.tree_placer) { case TP_ORIGINAL: i = _settings_game.game_creation.landscape == LT_ARCTIC ? 15 : 6; break; + case TP_FOREST: /* FALL THROUGH */ case TP_IMPROVED: i = _settings_game.game_creation.landscape == LT_ARCTIC ? 4 : 2; break; default: NOT_REACHED(); } @@ -371,6 +400,8 @@ void GenerateTrees() if (num_groups != 0) PlaceTreeGroups(num_groups); + if (_settings_game.game_creation.tree_placer == TP_FOREST) return; + for (; i != 0; i--) { PlaceTreesRandomly(); } @@ -758,6 +789,9 @@ static void TileLoop_Trees(TileIndex tile) /* Don't plant trees, if ground was freshly cleared */ if (IsTileType(tile, MP_CLEAR) && GetClearGround(tile) == CLEAR_GRASS && GetClearDensity(tile) != 3) return; + /* Plants trees only near existing forests */ + if (_settings_game.game_creation.tree_placer == TP_FOREST && !IsNearbyForest(tile)) return; + PlantTreesOnTile(tile, treetype, 0, 0); break; @@ -859,6 +893,9 @@ void OnTick_Trees() r = Random(); tile = RandomTileSeed(r); if (CanPlantTreesOnTile(tile, false) && (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { + /* Plants trees only near existing forests */ + if (_settings_game.game_creation.tree_placer == TP_FOREST && !IsNearbyForest(tile)) return; + PlantTreesOnTile(tile, tree, 0, 0); } } From a2dd8ed419ca72a71288a522d7b71ce018575985 Mon Sep 17 00:00:00 2001 From: Sylvain Devidal Date: Sun, 8 Jul 2018 22:31:15 +0200 Subject: [PATCH 02/10] Codechange: Use of proper FALLTHROUGH macro --- src/tree_cmd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 4dd618f720..64792089cf 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -386,7 +386,8 @@ void GenerateTrees() switch (_settings_game.game_creation.tree_placer) { case TP_ORIGINAL: i = _settings_game.game_creation.landscape == LT_ARCTIC ? 15 : 6; break; - case TP_FOREST: /* FALL THROUGH */ + case TP_FOREST: + FALLTHROUGH; case TP_IMPROVED: i = _settings_game.game_creation.landscape == LT_ARCTIC ? 4 : 2; break; default: NOT_REACHED(); } From 3a3b1c5f040c50b4bc87309165b11dc0c449545b Mon Sep 17 00:00:00 2001 From: Sylvain Devidal Date: Fri, 20 Jul 2018 09:49:47 +0200 Subject: [PATCH 03/10] Codechange: Merged "Improved" and "Forest" options. --- src/lang/english.txt | 3 +-- src/tree_cmd.cpp | 14 ++++---------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 2414bd5d91..881db7cfc7 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1586,12 +1586,11 @@ STR_CONFIG_SETTING_RIVER_AMOUNT :River amount: { STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Choose how many rivers to generate STR_CONFIG_SETTING_TREE_PLACER :Tree placer algorithm: {STRING2} -STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Choose the distribution of trees on the map: 'Original' plants trees uniformly scattered, 'Improved' plants them in groups, 'Forest' plants them in forests +STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Choose the distribution of trees on the map: 'Original' plants trees uniformly scattered, 'Improved' plants them in groups ###length 3 STR_CONFIG_SETTING_TREE_PLACER_NONE :None STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Original STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Improved -STR_CONFIG_SETTING_TREE_PLACER_FOREST :Forest STR_CONFIG_SETTING_ROAD_SIDE :Road vehicles: {STRING2} STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Choose the driving side diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 64792089cf..c28fbf6f9c 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -41,7 +41,6 @@ enum TreePlacer { TP_NONE, ///< No tree placer algorithm TP_ORIGINAL, ///< The original algorithm TP_IMPROVED, ///< A 'improved' algorithm - TP_FOREST, ///< An algorithm trying to make only forests }; /** Where to place trees while in-game? */ @@ -96,7 +95,7 @@ static bool IsNearbyForest(TileIndex tile) for (int y = -2; y <= 2; y++) { TileIndex vincity = TileAddWrap(tile, x, y); if (vincity != INVALID_TILE && - IsTileType(vincity, MP_TREES)) { + IsTileType(vincity, MP_TREES)) { planted_tile_count++; } } @@ -282,8 +281,7 @@ void PlaceTreesRandomly() if (CanPlantTreesOnTile(tile, true)) { PlaceTree(tile, r); - if (_settings_game.game_creation.tree_placer != TP_IMPROVED && - _settings_game.game_creation.tree_placer != TP_FOREST) { + if (_settings_game.game_creation.tree_placer != TP_IMPROVED) { continue; } @@ -386,8 +384,6 @@ void GenerateTrees() switch (_settings_game.game_creation.tree_placer) { case TP_ORIGINAL: i = _settings_game.game_creation.landscape == LT_ARCTIC ? 15 : 6; break; - case TP_FOREST: - FALLTHROUGH; case TP_IMPROVED: i = _settings_game.game_creation.landscape == LT_ARCTIC ? 4 : 2; break; default: NOT_REACHED(); } @@ -401,8 +397,6 @@ void GenerateTrees() if (num_groups != 0) PlaceTreeGroups(num_groups); - if (_settings_game.game_creation.tree_placer == TP_FOREST) return; - for (; i != 0; i--) { PlaceTreesRandomly(); } @@ -791,7 +785,7 @@ static void TileLoop_Trees(TileIndex tile) if (IsTileType(tile, MP_CLEAR) && GetClearGround(tile) == CLEAR_GRASS && GetClearDensity(tile) != 3) return; /* Plants trees only near existing forests */ - if (_settings_game.game_creation.tree_placer == TP_FOREST && !IsNearbyForest(tile)) return; + if (_settings_game.game_creation.tree_placer == TP_IMPROVED && !IsNearbyForest(tile)) return; PlantTreesOnTile(tile, treetype, 0, 0); @@ -895,7 +889,7 @@ void OnTick_Trees() tile = RandomTileSeed(r); if (CanPlantTreesOnTile(tile, false) && (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { /* Plants trees only near existing forests */ - if (_settings_game.game_creation.tree_placer == TP_FOREST && !IsNearbyForest(tile)) return; + if (_settings_game.game_creation.tree_placer == TP_IMPROVED && !IsNearbyForest(tile)) return; PlantTreesOnTile(tile, tree, 0, 0); } From ac06b4a7a63cf07fb0153dcd906a2794f10364f8 Mon Sep 17 00:00:00 2001 From: Sylvain Devidal Date: Mon, 23 Jul 2018 18:27:02 +0200 Subject: [PATCH 04/10] Fix: "Alone" trees are now replaced after death. They also can spread on their own tile. --- src/tree_cmd.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index c28fbf6f9c..8b41065d0a 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -91,6 +91,10 @@ static bool IsNearbyForest(TileIndex tile) { uint planted_tile_count = 0; + // An already planted tilte can always be planted again + if (IsTileType(tile, MP_TREES)) return true; + + // Count the trees arround the clear tile to determine if it's near a forest for (int x = -2; x <= 2; x++) { for (int y = -2; y <= 2; y++) { TileIndex vincity = TileAddWrap(tile, x, y); @@ -281,9 +285,7 @@ void PlaceTreesRandomly() if (CanPlantTreesOnTile(tile, true)) { PlaceTree(tile, r); - if (_settings_game.game_creation.tree_placer != TP_IMPROVED) { - continue; - } + if (_settings_game.game_creation.tree_placer != TP_IMPROVED) continue; /* Place a number of trees based on the tile height. * This gives a cool effect of multiple trees close together. @@ -807,6 +809,12 @@ static void TileLoop_Trees(TileIndex tile) AddTreeCount(tile, -1); SetTreeGrowth(tile, 3); } else { + // Backups the type of tree if using improved trees + TreeType treetype; + if (_settings_game.game_creation.tree_placer == TP_IMPROVED && IsTileType(tile, MP_TREES)) { + treetype = GetTreeType(tile); + } + /* just one tree, change type into MP_CLEAR */ switch (GetTreeGround(tile)) { case TREE_GROUND_SHORE: MakeShore(tile); break; @@ -828,6 +836,11 @@ static void TileLoop_Trees(TileIndex tile) } break; } + + // When using improved trees, when a "alone" tree is dead, a new one is planted immediately + if (_settings_game.game_creation.tree_placer == TP_IMPROVED && !IsNearbyForest(tile)) { + PlantTreesOnTile(tile, treetype, 0, 0); + } } break; From 23f8519624186b5d049313f1c50db51507cf1938 Mon Sep 17 00:00:00 2001 From: Su Date: Sat, 25 May 2024 22:33:36 +0100 Subject: [PATCH 05/10] Codefix: Remove typos and use correct formatting Co-authored-by: Tyler Trahan --- src/tree_cmd.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 8b41065d0a..265e61deb8 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -91,10 +91,10 @@ static bool IsNearbyForest(TileIndex tile) { uint planted_tile_count = 0; - // An already planted tilte can always be planted again + /* An already planted tile can always be planted again. */ if (IsTileType(tile, MP_TREES)) return true; - // Count the trees arround the clear tile to determine if it's near a forest + /* Count the trees around the clear tile to determine if it's near a forest */ for (int x = -2; x <= 2; x++) { for (int y = -2; y <= 2; y++) { TileIndex vincity = TileAddWrap(tile, x, y); @@ -809,7 +809,7 @@ static void TileLoop_Trees(TileIndex tile) AddTreeCount(tile, -1); SetTreeGrowth(tile, 3); } else { - // Backups the type of tree if using improved trees + /* Backups the type of tree if using improved trees */ TreeType treetype; if (_settings_game.game_creation.tree_placer == TP_IMPROVED && IsTileType(tile, MP_TREES)) { treetype = GetTreeType(tile); @@ -837,7 +837,7 @@ static void TileLoop_Trees(TileIndex tile) break; } - // When using improved trees, when a "alone" tree is dead, a new one is planted immediately + /* When using improved trees, when a "alone" tree is dead, a new one is planted immediately. */ if (_settings_game.game_creation.tree_placer == TP_IMPROVED && !IsNearbyForest(tile)) { PlantTreesOnTile(tile, treetype, 0, 0); } From 573b55cf9fcc857a9e1531f50b9d7c9c6c015810 Mon Sep 17 00:00:00 2001 From: Susan Date: Sat, 25 May 2024 23:07:43 +0100 Subject: [PATCH 06/10] Codechange: remove magic number --- src/tree_cmd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 265e61deb8..2fe5817432 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -57,6 +57,7 @@ uint8_t _trees_tick_ctr; static const uint16_t DEFAULT_TREE_STEPS = 1000; ///< Default number of attempts for placing trees. static const uint16_t DEFAULT_RAINFOREST_TREE_STEPS = 15000; ///< Default number of attempts for placing extra trees at rainforest in tropic. static const uint16_t EDITOR_TREE_DIV = 5; ///< Game editor tree generation divisor factor. +static const uint16_t FOREST_THRESHOLD = 6; ///< Minimum amount of trees required to be considered a forest. /** * Tests if a tile can be converted to MP_TREES @@ -105,7 +106,7 @@ static bool IsNearbyForest(TileIndex tile) } } - return (planted_tile_count >= 6); + return (planted_tile_count >= FOREST_THRESHOLD); } /** From 6335312b3c51c80b7d22f7204c549573b4c0da33 Mon Sep 17 00:00:00 2001 From: Susan Date: Tue, 4 Jun 2024 10:59:57 +0100 Subject: [PATCH 07/10] Codechange: don't remove trees only to immediately replant them --- src/tree_cmd.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 2fe5817432..2705b310d1 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -802,7 +802,7 @@ static void TileLoop_Trees(TileIndex tile) break; case 6: // final stage of tree destruction - if (!CanPlantExtraTrees(tile)) { + if (!CanPlantExtraTrees(tile) || (_settings_game.game_creation.tree_placer == TP_IMPROVED && !IsNearbyForest(tile))) { /* if trees can't spread just plant a new one to prevent deforestation */ SetTreeGrowth(tile, 0); } else if (GetTreeCount(tile) > 1) { @@ -810,12 +810,6 @@ static void TileLoop_Trees(TileIndex tile) AddTreeCount(tile, -1); SetTreeGrowth(tile, 3); } else { - /* Backups the type of tree if using improved trees */ - TreeType treetype; - if (_settings_game.game_creation.tree_placer == TP_IMPROVED && IsTileType(tile, MP_TREES)) { - treetype = GetTreeType(tile); - } - /* just one tree, change type into MP_CLEAR */ switch (GetTreeGround(tile)) { case TREE_GROUND_SHORE: MakeShore(tile); break; @@ -837,11 +831,6 @@ static void TileLoop_Trees(TileIndex tile) } break; } - - /* When using improved trees, when a "alone" tree is dead, a new one is planted immediately. */ - if (_settings_game.game_creation.tree_placer == TP_IMPROVED && !IsNearbyForest(tile)) { - PlantTreesOnTile(tile, treetype, 0, 0); - } } break; From 6d40780434d86096eb7381a886ed8013fb60aa86 Mon Sep 17 00:00:00 2001 From: Susan Date: Tue, 4 Jun 2024 11:30:14 +0100 Subject: [PATCH 08/10] Codechange: use TileArea to search for trees --- src/tree_cmd.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 2705b310d1..aaf211cef8 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -58,6 +58,7 @@ static const uint16_t DEFAULT_TREE_STEPS = 1000; ///< Default number static const uint16_t DEFAULT_RAINFOREST_TREE_STEPS = 15000; ///< Default number of attempts for placing extra trees at rainforest in tropic. static const uint16_t EDITOR_TREE_DIV = 5; ///< Game editor tree generation divisor factor. static const uint16_t FOREST_THRESHOLD = 6; ///< Minimum amount of trees required to be considered a forest. +static const uint16_t FOREST_SEARCH_RADIUS = 2; ///< Radius of area to examine when determining forest status. /** * Tests if a tile can be converted to MP_TREES @@ -96,13 +97,9 @@ static bool IsNearbyForest(TileIndex tile) if (IsTileType(tile, MP_TREES)) return true; /* Count the trees around the clear tile to determine if it's near a forest */ - for (int x = -2; x <= 2; x++) { - for (int y = -2; y <= 2; y++) { - TileIndex vincity = TileAddWrap(tile, x, y); - if (vincity != INVALID_TILE && - IsTileType(vincity, MP_TREES)) { - planted_tile_count++; - } + for (TileIndex t : TileArea(tile).Expand(FOREST_SEARCH_RADIUS)) { + if (IsTileType(t, MP_TREES)) { + planted_tile_count++; } } From a75532dd477a727af2ca4fabd2638711f2884400 Mon Sep 17 00:00:00 2001 From: Susan Date: Tue, 4 Jun 2024 13:11:30 +0100 Subject: [PATCH 09/10] Codechange: exit early if past forest threshold --- src/tree_cmd.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index aaf211cef8..eeea0c50b3 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -99,11 +99,14 @@ static bool IsNearbyForest(TileIndex tile) /* Count the trees around the clear tile to determine if it's near a forest */ for (TileIndex t : TileArea(tile).Expand(FOREST_SEARCH_RADIUS)) { if (IsTileType(t, MP_TREES)) { - planted_tile_count++; + if (++planted_tile_count >= FOREST_THRESHOLD) + { + return true; + } } } - return (planted_tile_count >= FOREST_THRESHOLD); + return false; } /** From 89182e4b155820e3c09469a3cfd38c5f5600bd60 Mon Sep 17 00:00:00 2001 From: Su Date: Tue, 4 Jun 2024 14:08:00 +0100 Subject: [PATCH 10/10] Codefix: early continue, avoid sideeffects Co-authored-by: Peter Nelson --- src/tree_cmd.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index eeea0c50b3..b3a94011a6 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -98,12 +98,9 @@ static bool IsNearbyForest(TileIndex tile) /* Count the trees around the clear tile to determine if it's near a forest */ for (TileIndex t : TileArea(tile).Expand(FOREST_SEARCH_RADIUS)) { - if (IsTileType(t, MP_TREES)) { - if (++planted_tile_count >= FOREST_THRESHOLD) - { - return true; - } - } + if (!IsTileType(t, MP_TREES)) continue; + ++planted_tile_count; + if (planted_tile_count >= FOREST_THRESHOLD) return true; } return false;