Merge pull request #14397 from Gymnasiast/refactor/hardcoded-terrain-constants

Remove hardcoded terrain style constants from RCT1 and MapGen
This commit is contained in:
Michael Steenbeek 2021-03-31 20:18:12 +02:00 committed by GitHub
commit 9ee3c81768
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 194 additions and 121 deletions

View File

@ -1299,7 +1299,7 @@ static void editor_load_selected_objects()
{
const ObjectRepositoryItem* item = &items[i];
const rct_object_entry* entry = &item->ObjectEntry;
void* loadedObject = object_manager_get_loaded_object(entry);
const auto* loadedObject = object_manager_get_loaded_object(ObjectEntryDescriptor(*item));
if (loadedObject == nullptr)
{
loadedObject = object_manager_load_object(entry);

View File

@ -242,7 +242,7 @@ static void window_install_track_paint(rct_window* w, rct_drawpixelinfo* dpi)
{
auto ft = Formatter();
void* objectEntry = object_manager_load_object(&td6->vehicle_object);
const auto* objectEntry = object_manager_load_object(&td6->vehicle_object);
if (objectEntry != nullptr)
{
auto groupIndex = object_manager_get_loaded_object_entry_index(objectEntry);

View File

@ -421,8 +421,8 @@ static void window_mapgen_draw_tab_images(rct_drawpixelinfo* dpi, rct_window* w)
static int32_t _mapSize = 150;
static int32_t _baseHeight = 12;
static int32_t _waterLevel = 6;
static int32_t _floorTexture = TERRAIN_GRASS;
static int32_t _wallTexture = TERRAIN_EDGE_ROCK;
static int32_t _floorTexture = 0;
static int32_t _wallTexture = 0;
static bool _randomTerrain = true;
static int32_t _placeTrees = 1;

View File

@ -436,7 +436,7 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
}
const rct_object_entry* entry = &ori->ObjectEntry;
void* loadedObject = object_manager_load_object(entry);
const auto* loadedObject = object_manager_load_object(entry);
if (loadedObject == nullptr)
{
fprintf(stderr, "Unable to load object.\n");

View File

@ -1071,7 +1071,7 @@ static int32_t cc_load_object(InteractiveConsole& console, const arguments_t& ar
}
const rct_object_entry* entry = &ori->ObjectEntry;
void* loadedObject = object_manager_get_loaded_object(entry);
const auto* loadedObject = object_manager_get_loaded_object(ObjectEntryDescriptor(*ori));
if (loadedObject != nullptr)
{
console.WriteLineError("Object is already in scenario.");

View File

@ -20,6 +20,7 @@
#include "../localisation/StringIds.h"
#include "../world/Scenery.h"
#include "ObjectLimits.h"
#include "ObjectRepository.h"
#include <algorithm>
#include <cstring>
@ -301,6 +302,20 @@ std::unique_ptr<IStream> ObjectAsset::GetStream() const
return {};
}
ObjectEntryDescriptor::ObjectEntryDescriptor(const ObjectRepositoryItem& ori)
{
if (!ori.Identifier.empty())
{
Generation = ObjectGeneration::JSON;
Identifier = std::string(ori.Identifier);
}
else
{
Generation = ObjectGeneration::DAT;
Entry = ori.ObjectEntry;
}
}
#ifdef __WARN_SUGGEST_FINAL_METHODS__
# pragma GCC diagnostic pop
#endif

View File

@ -22,6 +22,7 @@
using ObjectEntryIndex = uint16_t;
constexpr const ObjectEntryIndex OBJECT_ENTRY_INDEX_NULL = std::numeric_limits<ObjectEntryIndex>::max();
struct ObjectRepositoryItem;
// First 0xF of rct_object_entry->flags
enum class ObjectType : uint8_t
@ -180,6 +181,8 @@ struct ObjectEntryDescriptor
Generation = ObjectGeneration::JSON;
Identifier = std::string(newIdentifier);
}
explicit ObjectEntryDescriptor(const ObjectRepositoryItem& ori);
};
struct IObjectRepository;

View File

@ -816,26 +816,30 @@ Object* object_manager_get_loaded_object_by_index(size_t index)
return loadedObject;
}
Object* object_manager_get_loaded_object(const rct_object_entry* entry)
Object* object_manager_get_loaded_object(const ObjectEntryDescriptor& entry)
{
auto& objectManager = OpenRCT2::GetContext()->GetObjectManager();
Object* loadedObject = objectManager.GetLoadedObject(ObjectEntryDescriptor(*entry));
Object* loadedObject = objectManager.GetLoadedObject(entry);
return loadedObject;
}
ObjectEntryIndex object_manager_get_loaded_object_entry_index(const void* loadedObject)
ObjectEntryIndex object_manager_get_loaded_object_entry_index(const Object* loadedObject)
{
auto& objectManager = OpenRCT2::GetContext()->GetObjectManager();
const Object* object = static_cast<const Object*>(loadedObject);
auto entryIndex = objectManager.GetLoadedObjectEntryIndex(object);
auto entryIndex = objectManager.GetLoadedObjectEntryIndex(loadedObject);
return entryIndex;
}
void* object_manager_load_object(const rct_object_entry* entry)
ObjectEntryIndex object_manager_get_loaded_object_entry_index(const ObjectEntryDescriptor& entry)
{
return object_manager_get_loaded_object_entry_index(object_manager_get_loaded_object(entry));
}
Object* object_manager_load_object(const rct_object_entry* entry)
{
auto& objectManager = OpenRCT2::GetContext()->GetObjectManager();
Object* loadedObject = objectManager.LoadObject(entry);
return static_cast<void*>(loadedObject);
return loadedObject;
}
void object_manager_unload_objects(const std::vector<rct_object_entry>& entries)

View File

@ -46,9 +46,10 @@ struct IObjectManager
std::unique_ptr<IObjectManager> CreateObjectManager(IObjectRepository& objectRepository);
Object* object_manager_get_loaded_object_by_index(size_t index);
Object* object_manager_get_loaded_object(const rct_object_entry* entry);
ObjectEntryIndex object_manager_get_loaded_object_entry_index(const void* loadedObject);
void* object_manager_load_object(const rct_object_entry* entry);
Object* object_manager_get_loaded_object(const ObjectEntryDescriptor& entry);
ObjectEntryIndex object_manager_get_loaded_object_entry_index(const Object* loadedObject);
ObjectEntryIndex object_manager_get_loaded_object_entry_index(const ObjectEntryDescriptor& entry);
Object* object_manager_load_object(const rct_object_entry* entry);
void object_manager_unload_objects(const std::vector<rct_object_entry>& entries);
void object_manager_unload_all_objects();
rct_string_id object_manager_get_source_game_string(const ObjectSourceGame sourceGame);

View File

@ -9,11 +9,13 @@
#include "TerrainEdgeObject.h"
#include "../Context.h"
#include "../core/IStream.hpp"
#include "../core/Json.hpp"
#include "../core/String.hpp"
#include "../drawing/Drawing.h"
#include "../localisation/Localisation.h"
#include "ObjectManager.h"
void TerrainEdgeObject::Load()
{
@ -58,3 +60,10 @@ void TerrainEdgeObject::ReadJson(IReadObjectContext* context, json_t& root)
PopulateTablesFromJson(context, root);
NumImagesLoaded = GetImageTable().GetCount();
}
TerrainEdgeObject* TerrainEdgeObject::GetById(ObjectEntryIndex entryIndex)
{
auto& objMgr = OpenRCT2::GetContext()->GetObjectManager();
auto obj = objMgr.GetLoadedObject(ObjectType::TerrainSurface, entryIndex);
return obj != nullptr ? static_cast<TerrainEdgeObject*>(obj) : nullptr;
}

View File

@ -31,4 +31,6 @@ public:
void Unload() override;
void DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t height) const override;
static TerrainEdgeObject* GetById(ObjectEntryIndex entryIndex);
};

View File

@ -11,12 +11,14 @@
#include "TerrainSurfaceObject.h"
#include "../Context.h"
#include "../core/IStream.hpp"
#include "../core/Json.hpp"
#include "../core/String.hpp"
#include "../drawing/Drawing.h"
#include "../localisation/Localisation.h"
#include "../world/Location.hpp"
#include "ObjectManager.h"
void TerrainSurfaceObject::Load()
{
@ -145,3 +147,10 @@ uint32_t TerrainSurfaceObject::GetImageId(
}
return EntryBaseImageId + (result * NUM_IMAGES_IN_ENTRY) + offset;
}
TerrainSurfaceObject* TerrainSurfaceObject::GetById(ObjectEntryIndex entryIndex)
{
auto& objMgr = OpenRCT2::GetContext()->GetObjectManager();
auto obj = objMgr.GetLoadedObject(ObjectType::TerrainSurface, entryIndex);
return obj != nullptr ? static_cast<TerrainSurfaceObject*>(obj) : nullptr;
}

View File

@ -69,4 +69,6 @@ public:
uint32_t GetImageId(
const CoordsXY& position, int32_t length, int32_t rotation, int32_t offset, bool grid, bool underground) const;
static TerrainSurfaceObject* GetById(ObjectEntryIndex entryIndex);
};

View File

@ -304,7 +304,7 @@ static const TerrainSurfaceObject* get_surface_object(size_t index)
}
static uint32_t get_surface_image(
const paint_session* session, uint8_t index, int32_t offset, uint8_t rotation, int32_t grassLength, bool grid,
const paint_session* session, ObjectEntryIndex index, int32_t offset, uint8_t rotation, int32_t grassLength, bool grid,
bool underground)
{
// Provide fallback for RCT1 surfaces if the user does have RCT1 linked.
@ -971,7 +971,7 @@ void surface_paint(paint_session* session, uint8_t direction, uint16_t height, c
const auto zoomLevel = dpi->zoom_level;
const uint8_t rotation = session->CurrentRotation;
const uint32_t terrain_type = tileElement->AsSurface()->GetSurfaceStyle();
const auto terrain_type = tileElement->AsSurface()->GetSurfaceStyle();
const uint8_t surfaceShape = viewport_surface_paint_setup_get_relative_slope(tileElement, rotation);
const CoordsXY& base = session->SpritePosition;
const corner_height& cornerHeights = corner_heights[surfaceShape];
@ -1279,8 +1279,8 @@ void surface_paint(paint_session* session, uint8_t direction, uint16_t height, c
if (!(session->ViewFlags & VIEWPORT_FLAG_HIDE_VERTICAL))
{
const uint32_t edgeStyle = tileElement->AsSurface()->GetEdgeStyle();
if (edgeStyle >= TERRAIN_EDGE_COUNT)
const auto edgeStyle = tileElement->AsSurface()->GetEdgeStyle();
if (static_cast<int32_t>(edgeStyle) >= object_entry_group_counts[EnumValue(ObjectType::TerrainEdge)])
{
log_verbose("edgeStyle: %d", edgeStyle);
}

View File

@ -30,6 +30,8 @@ constexpr const uint8_t RCT1_MAX_BANNERS = 100;
constexpr int32_t RCT1_COORDS_Z_STEP = 4;
constexpr const uint32_t RCT1_NUM_LL_CSG_ENTRIES = 69917;
constexpr const uint32_t RCT1_LL_CSG1_DAT_FILE_SIZE = 41402869;
constexpr const uint32_t RCT1_NUM_TERRAIN_SURFACES = 16;
constexpr const uint32_t RCT1_NUM_TERRAIN_EDGES = 15;
struct ParkLoadResult;

View File

@ -12,6 +12,7 @@
#include "../common.h"
#include "../core/Guard.hpp"
#include "../interface/Colour.h"
#include "../object/ObjectManager.h"
#include "../ride/Ride.h"
#include "../ride/RideData.h"
#include "../world/Surface.h"
@ -115,54 +116,63 @@ namespace RCT1
return map[rct1SpriteType];
}
uint8_t GetTerrain(uint8_t terrain)
ObjectEntryIndex GetTerrain(uint8_t terrainSurface)
{
static constexpr const uint8_t map[] =
static constexpr std::string_view map[RCT1_NUM_TERRAIN_SURFACES] =
{
TERRAIN_GRASS,
TERRAIN_SAND,
TERRAIN_DIRT,
TERRAIN_ROCK,
TERRAIN_MARTIAN,
TERRAIN_CHECKERBOARD,
TERRAIN_GRASS_CLUMPS,
TERRAIN_ROOF_BROWN,
TERRAIN_ICE,
TERRAIN_ROOF_LOG,
TERRAIN_ROOF_IRON,
TERRAIN_ROOF_GREY,
TERRAIN_GRID_RED,
TERRAIN_GRID_YELLOW,
TERRAIN_GRID_BLUE,
TERRAIN_GRID_GREEN
"rct2.surface.grass",
"rct2.surface.sand",
"rct2.surface.dirt",
"rct2.surface.rock",
"rct2.surface.martian",
"rct2.surface.chequerboard",
"rct2.surface.grassclumps",
"rct1.aa.surface.roofred",
"rct2.surface.ice",
"rct1.ll.surface.wood",
"rct1.ll.surface.rust",
"rct1.ll.surface.roofgrey",
"rct2.surface.gridred",
"rct2.surface.gridyellow",
"rct2.surface.gridpurple",
"rct2.surface.gridgreen",
};
Guard::ArgumentInRange<size_t>(terrain, 0, std::size(map), "Unsupported RCT1 terrain type.");
return map[terrain];
std::string selectedSurface = "rct2.surface.grass";
if (terrainSurface < std::size(map))
{
selectedSurface = map[terrainSurface];
}
return object_manager_get_loaded_object_entry_index(ObjectEntryDescriptor(selectedSurface));
}
uint8_t GetTerrainEdge(uint8_t terrainEdge)
ObjectEntryIndex GetTerrainEdge(uint8_t terrainEdge)
{
static constexpr const uint8_t map[] =
static constexpr std::string_view map[RCT1_NUM_TERRAIN_EDGES] =
{
TERRAIN_EDGE_ROCK, // rct2.edge.rock
TERRAIN_EDGE_BRICK, // rct1.edge.brick
TERRAIN_EDGE_IRON, // rct1.edge.iron
TERRAIN_EDGE_WOOD_RED, // rct2.edge.woodred
TERRAIN_EDGE_GREY, // rct1.aa.edge.grey
TERRAIN_EDGE_YELLOW, // rct1.aa.edge.yellow
TERRAIN_EDGE_WOOD_BLACK, // rct2.edge.woodblack
TERRAIN_EDGE_RED, // rct1.aa.edge.red
TERRAIN_EDGE_ICE, // rct2.edge.ice
TERRAIN_EDGE_PURPLE, // rct1.ll.edge.purple
TERRAIN_EDGE_GREEN, // rct1.ll.edge.green
TERRAIN_EDGE_STONE_BROWN, // rct1.ll.edge.stonebrown
TERRAIN_EDGE_STONE_GREY, // rct1.ll.edge.stonegrey
TERRAIN_EDGE_SKYSCRAPER_A, // rct1.ll.edge.skyscrapera
TERRAIN_EDGE_SKYSCRAPER_B, // rct1.ll.edge.skyscraperb
TERRAIN_EDGE_ROCK // rct2.edge.rock (Unused)
"rct2.edge.rock",
"rct1.edge.brick",
"rct1.edge.iron",
"rct2.edge.woodred",
"rct1.aa.edge.grey",
"rct1.aa.edge.yellow",
"rct2.edge.woodblack",
"rct1.aa.edge.red",
"rct2.edge.ice",
"rct1.ll.edge.purple",
"rct1.ll.edge.green",
"rct1.ll.edge.stonebrown",
"rct1.ll.edge.stonegrey",
"rct1.ll.edge.skyscrapera",
"rct1.ll.edge.skyscraperb",
};
Guard::ArgumentInRange<size_t>(terrainEdge, 0, std::size(map), "Unsupported RCT1 terrain edge.");
return map[terrainEdge];
std::string selectedEdge = "rct2.edge.rock";
if (terrainEdge < std::size(map))
{
selectedEdge = map[terrainEdge];
}
return object_manager_get_loaded_object_entry_index(ObjectEntryDescriptor(selectedEdge));
}
uint8_t GetRideType(uint8_t rideType, uint8_t vehicleType)

View File

@ -23,8 +23,8 @@ namespace RCT1
colour_t GetColour(colour_t colour);
PeepSpriteType GetPeepSpriteType(uint8_t rct1SpriteType);
uint8_t GetTerrain(uint8_t terrain);
uint8_t GetTerrainEdge(uint8_t terrainEdge);
ObjectEntryIndex GetTerrain(uint8_t terrain);
ObjectEntryIndex GetTerrainEdge(uint8_t terrainEdge);
uint8_t GetRideType(uint8_t rideType, uint8_t vehicleType);
RCT1VehicleColourSchemeCopyDescriptor GetColourSchemeCopyDescriptor(uint8_t vehicleType);

View File

@ -2144,8 +2144,8 @@ static void track_design_preview_clear_map()
tile_element->SetLastForTile(true);
tile_element->AsSurface()->SetSlope(TILE_ELEMENT_SLOPE_FLAT);
tile_element->AsSurface()->SetWaterHeight(0);
tile_element->AsSurface()->SetSurfaceStyle(TERRAIN_GRASS);
tile_element->AsSurface()->SetEdgeStyle(TERRAIN_EDGE_ROCK);
tile_element->AsSurface()->SetSurfaceStyle(0);
tile_element->AsSurface()->SetEdgeStyle(0);
tile_element->AsSurface()->SetGrassLength(GRASS_LENGTH_CLEAR_0);
tile_element->AsSurface()->SetOwnership(OWNERSHIP_OWNED);
tile_element->AsSurface()->SetParkFences(0);

View File

@ -268,8 +268,8 @@ void map_init(int32_t size)
tile_element->AsSurface()->SetGrassLength(GRASS_LENGTH_CLEAR_0);
tile_element->AsSurface()->SetOwnership(OWNERSHIP_UNOWNED);
tile_element->AsSurface()->SetParkFences(0);
tile_element->AsSurface()->SetSurfaceStyle(TERRAIN_GRASS);
tile_element->AsSurface()->SetEdgeStyle(TERRAIN_EDGE_ROCK);
tile_element->AsSurface()->SetSurfaceStyle(0);
tile_element->AsSurface()->SetEdgeStyle(0);
}
gGrassSceneryTileLoopPosition = 0;
@ -1682,8 +1682,8 @@ static void clear_element_at(const CoordsXY& loc, TileElement** elementPtr)
element->clearance_height = MINIMUM_LAND_HEIGHT;
element->owner = 0;
element->AsSurface()->SetSlope(TILE_ELEMENT_SLOPE_FLAT);
element->AsSurface()->SetSurfaceStyle(TERRAIN_GRASS);
element->AsSurface()->SetEdgeStyle(TERRAIN_EDGE_ROCK);
element->AsSurface()->SetSurfaceStyle(0);
element->AsSurface()->SetEdgeStyle(0);
element->AsSurface()->SetGrassLength(GRASS_LENGTH_CLEAR_0);
element->AsSurface()->SetOwnership(OWNERSHIP_UNOWNED);
element->AsSurface()->SetParkFences(0);

View File

@ -18,6 +18,9 @@
#include "../localisation/Localisation.h"
#include "../localisation/StringIds.h"
#include "../object/Object.h"
#include "../object/ObjectManager.h"
#include "../object/TerrainEdgeObject.h"
#include "../object/TerrainSurfaceObject.h"
#include "../platform/platform.h"
#include "../util/Util.h"
#include "Map.h"
@ -82,7 +85,8 @@ static constexpr const char* SnowTrees[] = {
#pragma endregion
// Randomly chosen base terrains. We rarely want a whole map made out of chequerboard or rock.
static constexpr const uint8_t BaseTerrain[] = { TERRAIN_GRASS, TERRAIN_SAND, TERRAIN_SAND_LIGHT, TERRAIN_DIRT, TERRAIN_ICE };
static constexpr const std::string_view BaseTerrain[] = { "rct2.surface.grass", "rct2.surface.sand", "rct2.surface.sandbrown",
"rct2.surface.dirt", "rct2.surface.ice" };
static void mapgen_place_trees();
static void mapgen_set_water_level(int32_t waterLevel);
@ -134,46 +138,43 @@ void mapgen_generate_blank(mapgen_settings* settings)
void mapgen_generate(mapgen_settings* settings)
{
int32_t x, y, mapSize, floorTexture, wallTexture, waterLevel;
auto mapSize = settings->mapSize;
auto waterLevel = settings->water_level;
const auto selectedFloor = TerrainSurfaceObject::GetById(settings->floor);
std::string floorTexture = selectedFloor != nullptr ? std::string(selectedFloor->GetIdentifier()) : "";
const auto selectedEdge = TerrainEdgeObject::GetById(settings->wall);
std::string edgeTexture = selectedFloor != nullptr ? std::string(selectedEdge->GetIdentifier()) : "";
mapSize = settings->mapSize;
floorTexture = settings->floor;
wallTexture = settings->wall;
waterLevel = settings->water_level;
if (floorTexture == -1)
if (floorTexture.empty())
floorTexture = BaseTerrain[util_rand() % std::size(BaseTerrain)];
if (wallTexture == -1)
if (edgeTexture.empty())
{
// Base edge type on surface type
switch (floorTexture)
{
case TERRAIN_DIRT:
wallTexture = TERRAIN_EDGE_WOOD_RED;
break;
case TERRAIN_ICE:
wallTexture = TERRAIN_EDGE_ICE;
break;
default:
wallTexture = TERRAIN_EDGE_ROCK;
break;
}
if (floorTexture == "rct2.surface.dirt")
edgeTexture = "rct2.edge.woodred";
else if (floorTexture == "rct2.surface.ice")
edgeTexture = "rct2.edge.ice";
else
edgeTexture = "rct2.edge.rock";
}
auto floorTextureId = object_manager_get_loaded_object_entry_index(ObjectEntryDescriptor(floorTexture));
auto edgeTextureId = object_manager_get_loaded_object_entry_index(ObjectEntryDescriptor(edgeTexture));
map_clear_all_elements();
// Initialise the base map
map_init(mapSize);
for (y = 1; y < mapSize - 1; y++)
for (auto y = 1; y < mapSize - 1; y++)
{
for (x = 1; x < mapSize - 1; x++)
for (auto x = 1; x < mapSize - 1; x++)
{
auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY());
if (surfaceElement != nullptr)
{
surfaceElement->SetSurfaceStyle(floorTexture);
surfaceElement->SetEdgeStyle(wallTexture);
surfaceElement->SetSurfaceStyle(floorTextureId);
surfaceElement->SetEdgeStyle(edgeTextureId);
surfaceElement->base_height = settings->height;
surfaceElement->clearance_height = settings->height;
}
@ -201,27 +202,29 @@ void mapgen_generate(mapgen_settings* settings)
mapgen_set_water_level(waterLevel);
// Add sandy beaches
int32_t beachTexture = floorTexture;
if (settings->floor == -1 && floorTexture == TERRAIN_GRASS)
std::string beachTexture = std::string(floorTexture);
if (settings->floor == -1 && floorTexture == "rct2.surface.grass")
{
switch (util_rand() % 4)
{
case 0:
beachTexture = TERRAIN_SAND;
beachTexture = "rct2.surface.sand";
break;
case 1:
beachTexture = TERRAIN_SAND_LIGHT;
beachTexture = "rct2.surface.sandbrown";
break;
}
}
for (y = 1; y < mapSize - 1; y++)
auto beachTextureId = object_manager_get_loaded_object_entry_index(ObjectEntryDescriptor(beachTexture));
for (auto y = 1; y < mapSize - 1; y++)
{
for (x = 1; x < mapSize - 1; x++)
for (auto x = 1; x < mapSize - 1; x++)
{
auto surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY());
if (surfaceElement != nullptr && surfaceElement->base_height < waterLevel + 6)
surfaceElement->SetSurfaceStyle(beachTexture);
surfaceElement->SetSurfaceStyle(beachTextureId);
}
}
@ -252,6 +255,24 @@ static void mapgen_place_tree(int32_t type, const CoordsXY& loc)
sceneryElement->SetPrimaryColour(COLOUR_YELLOW);
}
static bool MapGenSurfaceTakesGrassTrees(const TerrainSurfaceObject& surface)
{
const auto& id = surface.GetIdentifier();
return id == "rct2.surface.grass" || id == "rct2.surface.grassclumps" || id == "rct2.surface.dirt";
}
static bool MapGenSurfaceTakesSandTrees(const TerrainSurfaceObject& surface)
{
const auto& id = surface.GetIdentifier();
return id == "rct2.surface.sand" || id == "rct2.surface.sandbrown" || id == "rct2.surface.sandred";
}
static bool MapGenSurfaceTakesSnowTrees(const TerrainSurfaceObject& surface)
{
const auto& id = surface.GetIdentifier();
return id == "rct2.surface.ice";
}
/**
* Randomly places a selection of preset trees on the map. Picks the right tree for the terrain it is placing it on.
*/
@ -353,33 +374,28 @@ static void mapgen_place_trees()
auto* surfaceElement = map_get_surface_element_at(pos.ToCoordsXY());
if (surfaceElement == nullptr)
continue;
switch (surfaceElement->GetSurfaceStyle())
const auto* object = TerrainSurfaceObject::GetById(surfaceElement->GetSurfaceStyle());
if (MapGenSurfaceTakesGrassTrees(*object))
{
case TERRAIN_GRASS:
case TERRAIN_DIRT:
case TERRAIN_GRASS_CLUMPS:
if (grassTreeIds.empty())
break;
type = grassTreeIds[util_rand() % grassTreeIds.size()];
if (grassTreeIds.empty())
break;
case TERRAIN_SAND:
case TERRAIN_SAND_DARK:
case TERRAIN_SAND_LIGHT:
if (desertTreeIds.empty())
break;
if (util_rand() % 4 == 0)
type = desertTreeIds[util_rand() % desertTreeIds.size()];
type = grassTreeIds[util_rand() % grassTreeIds.size()];
}
else if (MapGenSurfaceTakesSandTrees(*object))
{
if (desertTreeIds.empty())
break;
case TERRAIN_ICE:
if (snowTreeIds.empty())
break;
type = snowTreeIds[util_rand() % snowTreeIds.size()];
if (util_rand() % 4 == 0)
type = desertTreeIds[util_rand() % desertTreeIds.size()];
}
else if (MapGenSurfaceTakesSnowTrees(*object))
{
if (snowTreeIds.empty())
break;
type = snowTreeIds[util_rand() % snowTreeIds.size()];
}
if (type != -1)