mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-15 19:13:07 +01:00
Move TreePlacement into its own unit as well
This commit is contained in:
@@ -628,6 +628,7 @@
|
||||
<ClInclude Include="world\map_generator\MapHelpers.h" />
|
||||
<ClInclude Include="world\map_generator\PngTerrainGenerator.h" />
|
||||
<ClInclude Include="world\map_generator\SimplexNoise.h" />
|
||||
<ClInclude Include="world\map_generator\TreePlacement.h" />
|
||||
<ClInclude Include="world\tile_element\BannerElement.h" />
|
||||
<ClInclude Include="world\tile_element\EntranceElement.h" />
|
||||
<ClInclude Include="world\tile_element\LargeSceneryElement.h" />
|
||||
@@ -1126,6 +1127,7 @@
|
||||
<ClCompile Include="world\map_generator\MapHelpers.cpp" />
|
||||
<ClCompile Include="world\map_generator\PngTerrainGenerator.cpp" />
|
||||
<ClCompile Include="world\map_generator\SimplexNoise.cpp" />
|
||||
<ClCompile Include="world\map_generator\TreePlacement.cpp" />
|
||||
<ClCompile Include="world\tile_element\BannerElement.cpp" />
|
||||
<ClCompile Include="world\tile_element\EntranceElement.cpp" />
|
||||
<ClCompile Include="world\tile_element\LargeSceneryElement.cpp" />
|
||||
|
||||
@@ -26,55 +26,17 @@
|
||||
#include "../Map.h"
|
||||
#include "../Scenery.h"
|
||||
#include "../tile_element/Slope.h"
|
||||
#include "../tile_element/SmallSceneryElement.h"
|
||||
#include "../tile_element/SurfaceElement.h"
|
||||
#include "../tile_element/TileElement.h"
|
||||
#include "MapHelpers.h"
|
||||
#include "PngTerrainGenerator.h"
|
||||
#include "SimplexNoise.h"
|
||||
#include "TreePlacement.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
#pragma region Random objects
|
||||
|
||||
static constexpr const char* GrassTrees[] = {
|
||||
// Dark
|
||||
"rct2.scenery_small.tcf", // Caucasian Fir Tree
|
||||
"rct2.scenery_small.trf", // Red Fir Tree
|
||||
"rct2.scenery_small.trf2", // Red Fir Tree
|
||||
"rct2.scenery_small.tsp", // Scots Pine Tree
|
||||
"rct2.scenery_small.tmzp", // Montezuma Pine Tree
|
||||
"rct2.scenery_small.tap", // Aleppo Pine Tree
|
||||
"rct2.scenery_small.tcrp", // Corsican Pine Tree
|
||||
"rct2.scenery_small.tbp", // Black Poplar Tree
|
||||
|
||||
// Light
|
||||
"rct2.scenery_small.tcl", // Cedar of Lebanon Tree
|
||||
"rct2.scenery_small.tel", // European Larch Tree
|
||||
};
|
||||
|
||||
static constexpr const char* DesertTrees[] = {
|
||||
"rct2.scenery_small.tmp", // Monkey-Puzzle Tree
|
||||
"rct2.scenery_small.thl", // Honey Locust Tree
|
||||
"rct2.scenery_small.th1", // Canary Palm Tree
|
||||
"rct2.scenery_small.th2", // Palm Tree
|
||||
"rct2.scenery_small.tpm", // Palm Tree
|
||||
"rct2.scenery_small.tropt1", // Tree
|
||||
"rct2.scenery_small.tbc", // Cactus
|
||||
"rct2.scenery_small.tsc", // Cactus
|
||||
};
|
||||
|
||||
static constexpr const char* SnowTrees[] = {
|
||||
"rct2.scenery_small.tcfs", // Snow-covered Caucasian Fir Tree
|
||||
"rct2.scenery_small.tnss", // Snow-covered Norway Spruce Tree
|
||||
"rct2.scenery_small.trf3", // Snow-covered Red Fir Tree
|
||||
"rct2.scenery_small.trfs", // Snow-covered Red Fir Tree
|
||||
};
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// Randomly chosen base terrains. We rarely want a whole map made out of chequerboard or rock.
|
||||
static constexpr std::string_view BaseTerrain[] = {
|
||||
"rct2.terrain_surface.grass", "rct2.terrain_surface.sand", "rct2.terrain_surface.sand_brown",
|
||||
@@ -84,7 +46,6 @@ static constexpr std::string_view BaseTerrain[] = {
|
||||
static void MapGenGenerateBlank(MapGenSettings* settings);
|
||||
static void MapGenGenerateSimplex(MapGenSettings* settings);
|
||||
|
||||
static void MapGenPlaceTrees(MapGenSettings* settings);
|
||||
static void MapGenAddBeaches(MapGenSettings* settings);
|
||||
|
||||
void MapGenGenerate(MapGenSettings* settings)
|
||||
@@ -281,168 +242,6 @@ static void MapGenAddBeaches(MapGenSettings* settings)
|
||||
}
|
||||
}
|
||||
|
||||
static void MapGenPlaceTree(ObjectEntryIndex type, const CoordsXY& loc)
|
||||
{
|
||||
auto* sceneryEntry = OpenRCT2::ObjectManager::GetObjectEntry<SmallSceneryEntry>(type);
|
||||
if (sceneryEntry == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t surfaceZ = TileElementHeight(loc.ToTileCentre());
|
||||
|
||||
auto* sceneryElement = TileElementInsert<SmallSceneryElement>({ loc, surfaceZ }, 0b1111);
|
||||
Guard::Assert(sceneryElement != nullptr);
|
||||
|
||||
sceneryElement->SetClearanceZ(surfaceZ + sceneryEntry->height);
|
||||
sceneryElement->SetDirection(UtilRand() & 3);
|
||||
sceneryElement->SetEntryIndex(type);
|
||||
sceneryElement->SetAge(0);
|
||||
sceneryElement->SetPrimaryColour(COLOUR_YELLOW);
|
||||
}
|
||||
|
||||
static bool MapGenSurfaceTakesGrassTrees(const TerrainSurfaceObject& surface)
|
||||
{
|
||||
const auto& id = surface.GetIdentifier();
|
||||
return id == "rct2.terrain_surface.grass" || id == "rct2.terrain_surface.grass_clumps" || id == "rct2.terrain_surface.dirt";
|
||||
}
|
||||
|
||||
static bool MapGenSurfaceTakesSandTrees(const TerrainSurfaceObject& surface)
|
||||
{
|
||||
const auto& id = surface.GetIdentifier();
|
||||
return id == "rct2.terrain_surface.sand" || id == "rct2.terrain_surface.sand_brown"
|
||||
|| id == "rct2.terrain_surface.sand_red";
|
||||
}
|
||||
|
||||
static bool MapGenSurfaceTakesSnowTrees(const TerrainSurfaceObject& surface)
|
||||
{
|
||||
const auto& id = surface.GetIdentifier();
|
||||
return id == "rct2.terrain_surface.ice";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool TryFindTreeInList(std::string_view id, const T& treeList)
|
||||
{
|
||||
for (size_t j = 0; j < std::size(treeList); j++)
|
||||
{
|
||||
if (treeList[j] == id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly places a selection of preset trees on the map. Picks the right tree for the terrain it is placing it on.
|
||||
*/
|
||||
static void MapGenPlaceTrees(MapGenSettings* settings)
|
||||
{
|
||||
std::vector<int32_t> grassTreeIds;
|
||||
std::vector<int32_t> desertTreeIds;
|
||||
std::vector<int32_t> snowTreeIds;
|
||||
|
||||
for (auto i = 0u; i < getObjectEntryGroupCount(ObjectType::SmallScenery); i++)
|
||||
{
|
||||
auto* sceneryEntry = OpenRCT2::ObjectManager::GetObjectEntry<SmallSceneryEntry>(i);
|
||||
auto entry = ObjectEntryGetObject(ObjectType::SmallScenery, i);
|
||||
|
||||
if (sceneryEntry == nullptr)
|
||||
continue;
|
||||
|
||||
if (TryFindTreeInList(entry->GetIdentifier(), GrassTrees))
|
||||
{
|
||||
grassTreeIds.push_back(i);
|
||||
}
|
||||
else if (TryFindTreeInList(entry->GetIdentifier(), DesertTrees))
|
||||
{
|
||||
desertTreeIds.push_back(i);
|
||||
}
|
||||
else if (TryFindTreeInList(entry->GetIdentifier(), SnowTrees))
|
||||
{
|
||||
snowTreeIds.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Place trees
|
||||
float treeToLandRatio = static_cast<float>(settings->treeToLandRatio) / 100.0f;
|
||||
|
||||
auto& gameState = GetGameState();
|
||||
for (int32_t y = 1; y < gameState.MapSize.y - 1; y++)
|
||||
{
|
||||
for (int32_t x = 1; x < gameState.MapSize.x - 1; x++)
|
||||
{
|
||||
auto pos = CoordsXY{ x, y } * kCoordsXYStep;
|
||||
auto* surfaceElement = MapGetSurfaceElementAt(pos);
|
||||
if (surfaceElement == nullptr)
|
||||
continue;
|
||||
|
||||
// Don't place on water
|
||||
if (surfaceElement->GetWaterHeight() > 0)
|
||||
continue;
|
||||
|
||||
if (settings->minTreeAltitude > surfaceElement->BaseHeight
|
||||
|| settings->maxTreeAltitude < surfaceElement->BaseHeight)
|
||||
continue;
|
||||
|
||||
// On sand surfaces, give the tile a score based on nearby water, to be used to determine whether to spawn
|
||||
// vegetation
|
||||
float oasisScore = 0.0f;
|
||||
ObjectEntryIndex treeObjectEntryIndex = OBJECT_ENTRY_INDEX_NULL;
|
||||
const auto& surfaceStyleObject = *TerrainSurfaceObject::GetById(surfaceElement->GetSurfaceObjectIndex());
|
||||
if (MapGenSurfaceTakesSandTrees(surfaceStyleObject))
|
||||
{
|
||||
oasisScore = -0.5f;
|
||||
constexpr auto maxOasisDistance = 4;
|
||||
for (int32_t offsetY = -maxOasisDistance; offsetY <= maxOasisDistance; offsetY++)
|
||||
{
|
||||
for (int32_t offsetX = -maxOasisDistance; offsetX <= maxOasisDistance; offsetX++)
|
||||
{
|
||||
// Get map coord, clamped to the edges
|
||||
const auto offset = CoordsXY{ offsetX * kCoordsXYStep, offsetY * kCoordsXYStep };
|
||||
auto neighbourPos = pos + offset;
|
||||
neighbourPos.x = std::clamp(neighbourPos.x, kCoordsXYStep, kCoordsXYStep * (gameState.MapSize.x - 1));
|
||||
neighbourPos.y = std::clamp(neighbourPos.y, kCoordsXYStep, kCoordsXYStep * (gameState.MapSize.y - 1));
|
||||
|
||||
const auto neighboutSurface = MapGetSurfaceElementAt(neighbourPos);
|
||||
if (neighboutSurface != nullptr && neighboutSurface->GetWaterHeight() > 0)
|
||||
{
|
||||
float distance = std::sqrt(offsetX * offsetX + offsetY * offsetY);
|
||||
oasisScore += 0.5f / (maxOasisDistance * distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use tree:land ratio except when near an oasis
|
||||
constexpr static auto randModulo = 0xFFFF;
|
||||
if (static_cast<float>(UtilRand() & randModulo) / randModulo > std::max(treeToLandRatio, oasisScore))
|
||||
continue;
|
||||
|
||||
// Use fractal noise to group tiles that are likely to spawn trees together
|
||||
float noiseValue = FractalNoise(x, y, 0.025f, 2, 2.0f, 0.65f);
|
||||
// Reduces the range to rarely stray further than 0.5 from the mean.
|
||||
float noiseOffset = UtilRandNormalDistributed() * 0.25f;
|
||||
if (noiseValue + oasisScore < noiseOffset)
|
||||
continue;
|
||||
|
||||
if (!grassTreeIds.empty() && MapGenSurfaceTakesGrassTrees(surfaceStyleObject))
|
||||
{
|
||||
treeObjectEntryIndex = grassTreeIds[UtilRand() % grassTreeIds.size()];
|
||||
}
|
||||
else if (!desertTreeIds.empty() && MapGenSurfaceTakesSandTrees(surfaceStyleObject))
|
||||
{
|
||||
treeObjectEntryIndex = desertTreeIds[UtilRand() % desertTreeIds.size()];
|
||||
}
|
||||
else if (!snowTreeIds.empty() && MapGenSurfaceTakesSnowTrees(surfaceStyleObject))
|
||||
{
|
||||
treeObjectEntryIndex = snowTreeIds[UtilRand() % snowTreeIds.size()];
|
||||
}
|
||||
|
||||
if (treeObjectEntryIndex != OBJECT_ENTRY_INDEX_NULL)
|
||||
MapGenPlaceTree(treeObjectEntryIndex, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets each tile's water level to the specified water level if underneath that water level.
|
||||
*/
|
||||
|
||||
225
src/openrct2/world/map_generator/TreePlacement.cpp
Normal file
225
src/openrct2/world/map_generator/TreePlacement.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2025 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "TreePlacement.h"
|
||||
|
||||
#include "../../GameState.h"
|
||||
#include "../../core/Guard.hpp"
|
||||
#include "../../object/ObjectEntryManager.h"
|
||||
#include "../../object/ObjectList.h"
|
||||
#include "../../object/ObjectManager.h"
|
||||
#include "../../object/SmallSceneryEntry.h"
|
||||
#include "../../object/TerrainSurfaceObject.h"
|
||||
#include "../../util/Util.h"
|
||||
#include "../Map.h"
|
||||
#include "../tile_element/SmallSceneryElement.h"
|
||||
#include "../tile_element/SurfaceElement.h"
|
||||
#include "../tile_element/TileElement.h"
|
||||
#include "MapGen.h"
|
||||
#include "SimplexNoise.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
static constexpr const char* kGrassTrees[] = {
|
||||
// Dark
|
||||
"rct2.scenery_small.tcf", // Caucasian Fir Tree
|
||||
"rct2.scenery_small.trf", // Red Fir Tree
|
||||
"rct2.scenery_small.trf2", // Red Fir Tree
|
||||
"rct2.scenery_small.tsp", // Scots Pine Tree
|
||||
"rct2.scenery_small.tmzp", // Montezuma Pine Tree
|
||||
"rct2.scenery_small.tap", // Aleppo Pine Tree
|
||||
"rct2.scenery_small.tcrp", // Corsican Pine Tree
|
||||
"rct2.scenery_small.tbp", // Black Poplar Tree
|
||||
|
||||
// Light
|
||||
"rct2.scenery_small.tcl", // Cedar of Lebanon Tree
|
||||
"rct2.scenery_small.tel", // European Larch Tree
|
||||
};
|
||||
|
||||
static constexpr const char* kDesertTrees[] = {
|
||||
"rct2.scenery_small.tmp", // Monkey-Puzzle Tree
|
||||
"rct2.scenery_small.thl", // Honey Locust Tree
|
||||
"rct2.scenery_small.th1", // Canary Palm Tree
|
||||
"rct2.scenery_small.th2", // Palm Tree
|
||||
"rct2.scenery_small.tpm", // Palm Tree
|
||||
"rct2.scenery_small.tropt1", // Tree
|
||||
"rct2.scenery_small.tbc", // Cactus
|
||||
"rct2.scenery_small.tsc", // Cactus
|
||||
};
|
||||
|
||||
static constexpr const char* kSnowTrees[] = {
|
||||
"rct2.scenery_small.tcfs", // Snow-covered Caucasian Fir Tree
|
||||
"rct2.scenery_small.tnss", // Snow-covered Norway Spruce Tree
|
||||
"rct2.scenery_small.trf3", // Snow-covered Red Fir Tree
|
||||
"rct2.scenery_small.trfs", // Snow-covered Red Fir Tree
|
||||
};
|
||||
|
||||
static void MapGenPlaceTree(ObjectEntryIndex type, const CoordsXY& loc)
|
||||
{
|
||||
auto* sceneryEntry = ObjectManager::GetObjectEntry<SmallSceneryEntry>(type);
|
||||
if (sceneryEntry == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t surfaceZ = TileElementHeight(loc.ToTileCentre());
|
||||
|
||||
auto* sceneryElement = TileElementInsert<SmallSceneryElement>({ loc, surfaceZ }, 0b1111);
|
||||
Guard::Assert(sceneryElement != nullptr);
|
||||
|
||||
sceneryElement->SetClearanceZ(surfaceZ + sceneryEntry->height);
|
||||
sceneryElement->SetDirection(UtilRand() & 3);
|
||||
sceneryElement->SetEntryIndex(type);
|
||||
sceneryElement->SetAge(0);
|
||||
sceneryElement->SetPrimaryColour(COLOUR_YELLOW);
|
||||
}
|
||||
|
||||
static bool MapGenSurfaceTakesGrassTrees(const TerrainSurfaceObject& surface)
|
||||
{
|
||||
const auto& id = surface.GetIdentifier();
|
||||
return id == "rct2.terrain_surface.grass" || id == "rct2.terrain_surface.grass_clumps" || id == "rct2.terrain_surface.dirt";
|
||||
}
|
||||
|
||||
static bool MapGenSurfaceTakesSandTrees(const TerrainSurfaceObject& surface)
|
||||
{
|
||||
const auto& id = surface.GetIdentifier();
|
||||
return id == "rct2.terrain_surface.sand" || id == "rct2.terrain_surface.sand_brown"
|
||||
|| id == "rct2.terrain_surface.sand_red";
|
||||
}
|
||||
|
||||
static bool MapGenSurfaceTakesSnowTrees(const TerrainSurfaceObject& surface)
|
||||
{
|
||||
const auto& id = surface.GetIdentifier();
|
||||
return id == "rct2.terrain_surface.ice";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool TryFindTreeInList(std::string_view id, const T& treeList)
|
||||
{
|
||||
for (size_t j = 0; j < std::size(treeList); j++)
|
||||
{
|
||||
if (treeList[j] == id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly places a selection of preset trees on the map. Picks the right tree for the terrain it is placing it on.
|
||||
*/
|
||||
void MapGenPlaceTrees(MapGenSettings* settings)
|
||||
{
|
||||
std::vector<int32_t> grassTreeIds;
|
||||
std::vector<int32_t> desertTreeIds;
|
||||
std::vector<int32_t> snowTreeIds;
|
||||
|
||||
for (auto i = 0u; i < getObjectEntryGroupCount(ObjectType::SmallScenery); i++)
|
||||
{
|
||||
auto* sceneryEntry = OpenRCT2::ObjectManager::GetObjectEntry<SmallSceneryEntry>(i);
|
||||
auto entry = ObjectEntryGetObject(ObjectType::SmallScenery, i);
|
||||
|
||||
if (sceneryEntry == nullptr)
|
||||
continue;
|
||||
|
||||
if (TryFindTreeInList(entry->GetIdentifier(), kGrassTrees))
|
||||
{
|
||||
grassTreeIds.push_back(i);
|
||||
}
|
||||
else if (TryFindTreeInList(entry->GetIdentifier(), kDesertTrees))
|
||||
{
|
||||
desertTreeIds.push_back(i);
|
||||
}
|
||||
else if (TryFindTreeInList(entry->GetIdentifier(), kSnowTrees))
|
||||
{
|
||||
snowTreeIds.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Place trees
|
||||
float treeToLandRatio = static_cast<float>(settings->treeToLandRatio) / 100.0f;
|
||||
|
||||
auto& gameState = GetGameState();
|
||||
for (int32_t y = 1; y < gameState.MapSize.y - 1; y++)
|
||||
{
|
||||
for (int32_t x = 1; x < gameState.MapSize.x - 1; x++)
|
||||
{
|
||||
auto pos = CoordsXY{ x, y } * kCoordsXYStep;
|
||||
auto* surfaceElement = MapGetSurfaceElementAt(pos);
|
||||
if (surfaceElement == nullptr)
|
||||
continue;
|
||||
|
||||
// Don't place on water
|
||||
if (surfaceElement->GetWaterHeight() > 0)
|
||||
continue;
|
||||
|
||||
if (settings->minTreeAltitude > surfaceElement->BaseHeight
|
||||
|| settings->maxTreeAltitude < surfaceElement->BaseHeight)
|
||||
continue;
|
||||
|
||||
// On sand surfaces, give the tile a score based on nearby water, to be used to determine whether to spawn
|
||||
// vegetation
|
||||
float oasisScore = 0.0f;
|
||||
ObjectEntryIndex treeObjectEntryIndex = OBJECT_ENTRY_INDEX_NULL;
|
||||
const auto& surfaceStyleObject = *TerrainSurfaceObject::GetById(surfaceElement->GetSurfaceObjectIndex());
|
||||
if (MapGenSurfaceTakesSandTrees(surfaceStyleObject))
|
||||
{
|
||||
oasisScore = -0.5f;
|
||||
constexpr auto maxOasisDistance = 4;
|
||||
for (int32_t offsetY = -maxOasisDistance; offsetY <= maxOasisDistance; offsetY++)
|
||||
{
|
||||
for (int32_t offsetX = -maxOasisDistance; offsetX <= maxOasisDistance; offsetX++)
|
||||
{
|
||||
// Get map coord, clamped to the edges
|
||||
const auto offset = CoordsXY{ offsetX * kCoordsXYStep, offsetY * kCoordsXYStep };
|
||||
auto neighbourPos = pos + offset;
|
||||
neighbourPos.x = std::clamp(neighbourPos.x, kCoordsXYStep, kCoordsXYStep * (gameState.MapSize.x - 1));
|
||||
neighbourPos.y = std::clamp(neighbourPos.y, kCoordsXYStep, kCoordsXYStep * (gameState.MapSize.y - 1));
|
||||
|
||||
const auto neighboutSurface = MapGetSurfaceElementAt(neighbourPos);
|
||||
if (neighboutSurface != nullptr && neighboutSurface->GetWaterHeight() > 0)
|
||||
{
|
||||
float distance = std::sqrt(offsetX * offsetX + offsetY * offsetY);
|
||||
oasisScore += 0.5f / (maxOasisDistance * distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use tree:land ratio except when near an oasis
|
||||
constexpr static auto randModulo = 0xFFFF;
|
||||
if (static_cast<float>(UtilRand() & randModulo) / randModulo > std::max(treeToLandRatio, oasisScore))
|
||||
continue;
|
||||
|
||||
// Use fractal noise to group tiles that are likely to spawn trees together
|
||||
float noiseValue = FractalNoise(x, y, 0.025f, 2, 2.0f, 0.65f);
|
||||
// Reduces the range to rarely stray further than 0.5 from the mean.
|
||||
float noiseOffset = UtilRandNormalDistributed() * 0.25f;
|
||||
if (noiseValue + oasisScore < noiseOffset)
|
||||
continue;
|
||||
|
||||
if (!grassTreeIds.empty() && MapGenSurfaceTakesGrassTrees(surfaceStyleObject))
|
||||
{
|
||||
treeObjectEntryIndex = grassTreeIds[UtilRand() % grassTreeIds.size()];
|
||||
}
|
||||
else if (!desertTreeIds.empty() && MapGenSurfaceTakesSandTrees(surfaceStyleObject))
|
||||
{
|
||||
treeObjectEntryIndex = desertTreeIds[UtilRand() % desertTreeIds.size()];
|
||||
}
|
||||
else if (!snowTreeIds.empty() && MapGenSurfaceTakesSnowTrees(surfaceStyleObject))
|
||||
{
|
||||
treeObjectEntryIndex = snowTreeIds[UtilRand() % snowTreeIds.size()];
|
||||
}
|
||||
|
||||
if (treeObjectEntryIndex != OBJECT_ENTRY_INDEX_NULL)
|
||||
MapGenPlaceTree(treeObjectEntryIndex, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/openrct2/world/map_generator/TreePlacement.h
Normal file
12
src/openrct2/world/map_generator/TreePlacement.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2025 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
struct MapGenSettings;
|
||||
|
||||
void MapGenPlaceTrees(MapGenSettings* settings);
|
||||
Reference in New Issue
Block a user