Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature : New Trees Placement Algorithm "Forest". #6848

Closed
wants to merge 9 commits into from
60 changes: 59 additions & 1 deletion src/tree_cmd.cpp
Expand Up @@ -55,6 +55,7 @@ byte _trees_tick_ctr;
static const uint16 DEFAULT_TREE_STEPS = 1000; ///< Default number of attempts for placing trees.
static const uint16 DEFAULT_RAINFOREST_TREE_STEPS = 15000; ///< Default number of attempts for placing extra trees at rainforest in tropic.
static const uint16 EDITOR_TREE_DIV = 5; ///< Game editor tree generation divisor factor.
static const uint16 IMPROVED_TREES_DIV = 16; ///< Improved generation divisor factor for alone trees.

/**
* Tests if a tile can be converted to MP_TREES
Expand All @@ -78,6 +79,34 @@ 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;

// 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);
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.
Expand Down Expand Up @@ -185,6 +214,8 @@ static void PlaceTree(TileIndex tile, uint32 r)
*/
static void PlaceTreeGroups(uint num_groups)
{
const uint MAX_DISTANCE_FROM_CENTER = 13;

do {
TileIndex center_tile = RandomTile();

Expand All @@ -193,11 +224,20 @@ static void PlaceTreeGroups(uint num_groups)
int x = GB(r, 0, 5) - 16;
int y = GB(r, 8, 5) - 16;
uint dist = abs(x) + abs(y);

uint max_dist = MAX_DISTANCE_FROM_CENTER;

if (_settings_newgame.game_creation.tree_placer == TP_IMPROVED) {
max_dist = GB(r, 16, 3) + 8;
}

if (dist > max_dist) continue;

TileIndex cur_tile = TileAddWrap(center_tile, x, y);

IncreaseGeneratingWorldProgress(GWP_TREE);

if (cur_tile != INVALID_TILE && dist <= 13 && CanPlantTreesOnTile(cur_tile, true)) {
if (cur_tile != INVALID_TILE && CanPlantTreesOnTile(cur_tile, true)) {
PlaceTree(cur_tile, r);
}
}
Expand Down Expand Up @@ -249,6 +289,7 @@ void PlaceTreesRandomly()

i = ScaleByMapSize(DEFAULT_TREE_STEPS);
if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV;
if (_settings_game.game_creation.tree_placer == TP_IMPROVED) i /= IMPROVED_TREES_DIV;
do {
uint32 r = Random();
TileIndex tile = RandomTileSeed(r);
Expand Down Expand Up @@ -701,6 +742,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_IMPROVED && !IsNearbyForest(tile)) return;

PlantTreesOnTile(tile, treetype, 0, 0);

break;
Expand All @@ -718,6 +762,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;
Expand All @@ -739,6 +789,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;

Expand Down Expand Up @@ -774,6 +829,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_IMPROVED && !IsNearbyForest(tile)) return;

PlantTreesOnTile(tile, tree, 0, 0);
}
}
Expand Down