1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +01:00

finalise placing of trees

This commit is contained in:
IntelOrca
2015-02-10 19:52:24 +00:00
parent 9cc108abbb
commit 5b3c1b6764
6 changed files with 373 additions and 55 deletions

View File

@@ -2697,8 +2697,8 @@ STR_2691 :{WINDOW_COLOUR_2}Base height:
STR_2692 :{WINDOW_COLOUR_2}Water level:
STR_2693 :{WINDOW_COLOUR_2}Terrain:
STR_2694 :Generate
STR_2695 :???
STR_2696 :???
STR_2695 :Random terrain
STR_2696 :Place trees
STR_2697 :???
STR_2698 :???
STR_2699 :???

View File

@@ -2692,13 +2692,13 @@ STR_2686 :???
STR_2687 :???
STR_2688 :???
STR_2689 :???
STR_2690 :???
STR_2691 :???
STR_2692 :???
STR_2693 :???
STR_2694 :???
STR_2695 :???
STR_2696 :???
STR_2690 :Map Generation
STR_2691 :{WINDOW_COLOUR_2}Base height:
STR_2692 :{WINDOW_COLOUR_2}Water level:
STR_2693 :{WINDOW_COLOUR_2}Terrain:
STR_2694 :Generate
STR_2695 :Random terrain
STR_2696 :Place trees
STR_2697 :???
STR_2698 :???
STR_2699 :???

View File

@@ -45,7 +45,7 @@ enum {
WIDX_GENERATE,
WIDX_MAP_SIZE,
WIDX_MAP_SIZE = 7,
WIDX_MAP_SIZE_UP,
WIDX_MAP_SIZE_DOWN,
WIDX_BASE_HEIGHT,
@@ -55,7 +55,10 @@ enum {
WIDX_WATER_LEVEL_UP,
WIDX_WATER_LEVEL_DOWN,
WIDX_FLOOR_TEXTURE,
WIDX_WALL_TEXTURE
WIDX_WALL_TEXTURE,
WIDX_RANDOM_TERRAIN = 7,
WIDX_PLACE_TREES,
};
#pragma region Widgets
@@ -93,6 +96,9 @@ static rct_widget window_mapgen_random_widgets[] = {
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_NONE },
{ WWT_DROPDOWN_BUTTON, 1, 104, 198, 52, 63, 2694, STR_NONE },
{ WWT_CHECKBOX, 1, 4, 198, 52, 63, 2695, STR_NONE },
{ WWT_CHECKBOX, 1, 4, 198, 70, 81, 2696, STR_NONE },
{ WIDGETS_END },
};
@@ -207,7 +213,9 @@ static uint32 window_mapgen_page_enabled_widgets[] = {
(1 << WIDX_CLOSE) |
(1 << WIDX_TAB_1) |
(1 << WIDX_TAB_2) |
(1 << WIDX_GENERATE)
(1 << WIDX_GENERATE) |
(1 << WIDX_RANDOM_TERRAIN) |
(1 << WIDX_PLACE_TREES)
};
#pragma endregion
@@ -236,6 +244,8 @@ static int _baseHeight = 12;
static int _waterLevel = 6;
static int _floorTexture = TERRAIN_GRASS;
static int _wallTexture = TERRAIN_EDGE_ROCK;
static int _randomTerrrain = 1;
static int _placeTrees = 1;
rct_window *window_mapgen_open()
{
@@ -267,7 +277,7 @@ rct_window *window_mapgen_open()
window_invalidate(w);
w->widgets = window_mapgen_page_widgets[0];
w->enabled_widgets = window_mapgen_page_enabled_widgets[0];
w->var_020 = RCT2_GLOBAL(0x00988E3C, uint32);
w->var_020 = 0xFFFFFFFF;
w->event_handlers = window_mapgen_page_events[0];
w->pressed_widgets = 0;
w->disabled_widgets = 0;
@@ -282,6 +292,7 @@ static void window_mapgen_base_mouseup()
{
short widgetIndex;
rct_window *w;
mapgen_settings mapgenSettings;
window_widget_get_registers(w, widgetIndex);
@@ -294,7 +305,13 @@ static void window_mapgen_base_mouseup()
window_mapgen_set_page(w, widgetIndex - WIDX_TAB_1);
break;
case WIDX_GENERATE:
mapgen_generate_blank(_mapSize, _baseHeight + 2, _waterLevel + 2, _floorTexture, _wallTexture);
mapgenSettings.mapSize = _mapSize;
mapgenSettings.height = _baseHeight + 2;
mapgenSettings.waterLevel = _waterLevel + 2;
mapgenSettings.floor = _floorTexture;
mapgenSettings.wall = _wallTexture;
mapgen_generate_blank(&mapgenSettings);
gfx_invalidate_screen();
break;
}
@@ -470,6 +487,7 @@ static void window_mapgen_random_mouseup()
{
rct_window * w;
short widgetIndex;
mapgen_settings mapgenSettings;
window_widget_get_registers(w, widgetIndex);
@@ -482,9 +500,22 @@ static void window_mapgen_random_mouseup()
window_mapgen_set_page(w, widgetIndex - WIDX_TAB_1);
break;
case WIDX_GENERATE:
mapgen_generate(_mapSize);
mapgenSettings.mapSize = _mapSize;
mapgenSettings.height = _baseHeight + 2;
mapgenSettings.waterLevel = _waterLevel + 2;
mapgenSettings.floor = _randomTerrrain ? -1 : _floorTexture;
mapgenSettings.wall = _randomTerrrain ? -1 : _wallTexture;
mapgenSettings.trees = _placeTrees;
mapgen_generate(&mapgenSettings);
gfx_invalidate_screen();
break;
case WIDX_RANDOM_TERRAIN:
_randomTerrrain ^= 1;
break;
case WIDX_PLACE_TREES:
_placeTrees ^= 1;
break;
}
}
@@ -512,6 +543,12 @@ static void window_mapgen_random_invalidate()
window_init_scroll_widgets(w);
}
w->pressed_widgets = 0;
if (_randomTerrrain)
w->pressed_widgets |= 1 << WIDX_RANDOM_TERRAIN;
if (_placeTrees)
w->pressed_widgets |= 1 << WIDX_PLACE_TREES;
window_mapgen_set_pressed_tab(w);
window_mapgen_anchor_border_widgets(w);
}

View File

@@ -21,6 +21,9 @@
#include "map.h"
#include "map_helpers.h"
/**
* Not perfect, this still leaves some particular tiles unsmoothed.
*/
int map_smooth(int l, int t, int r, int b)
{
int i, x, y, highest, count, cornerHeights[4], doubleCorner, raisedLand = 0;
@@ -140,3 +143,148 @@ int map_smooth(int l, int t, int r, int b)
return raisedLand;
}
int map_get_corner_height(int x, int y, int corner)
{
rct_map_element *mapElement = map_get_surface_element_at(x, y);
int baseHeight = mapElement->base_height;
int slope = mapElement->properties.surface.slope;
int doubleCorner = slope & 16;
if (doubleCorner) {
if (!(slope & 1)) doubleCorner = 4;
else if (!(slope & 2)) doubleCorner = 8;
else if (!(slope & 4)) doubleCorner = 1;
else if (!(slope & 8)) doubleCorner = 2;
}
switch (corner) {
case 0:
return baseHeight + (slope & 1 ? (doubleCorner == 1 ? 4 : 2) : 0);
case 1:
return baseHeight + (slope & 8 ? (doubleCorner == 8 ? 4 : 2) : 0);
case 2:
return baseHeight + (slope & 2 ? (doubleCorner == 2 ? 4 : 2) : 0);
case 3:
return baseHeight + (slope & 4 ? (doubleCorner == 4 ? 4 : 2) : 0);
default:
return baseHeight;
}
}
/**
* There are non-smoothed tiles with this version, but diagonal land blocks end up being wavy.
*/
int map_smooth_wavy(int l, int t, int r, int b)
{
int i, x, y, highest, count, cornerHeights[4], doubleCorner, raisedLand = 0;
rct_map_element *mapElement;
for (y = t; y < b; y++) {
for (x = l; x < r; x++) {
mapElement = map_get_surface_element_at(x, y);
mapElement->properties.surface.slope &= ~0x1F;
// Raise to edge height - 2
highest = mapElement->base_height;
highest = max(highest, map_get_surface_element_at(x - 1, y + 0)->base_height);
highest = max(highest, map_get_surface_element_at(x + 1, y + 0)->base_height);
highest = max(highest, map_get_surface_element_at(x + 0, y - 1)->base_height);
highest = max(highest, map_get_surface_element_at(x + 0, y + 1)->base_height);
if (mapElement->base_height < highest - 2) {
raisedLand = 1;
mapElement->base_height = mapElement->clearance_height = highest - 2;
}
// Check corners
doubleCorner = -1;
cornerHeights[0] = max(map_get_corner_height(x - 1, y - 1, 0), max(map_get_corner_height(x + 1, y + 0, 1), map_get_corner_height(x + 0, y + 1, 2)));
cornerHeights[1] = max(map_get_corner_height(x + 1, y - 1, 1), max(map_get_corner_height(x - 1, y + 0, 0), map_get_corner_height(x + 0, y + 1, 3)));
cornerHeights[2] = max(map_get_corner_height(x + 1, y + 1, 3), max(map_get_corner_height(x + 1, y + 0, 3), map_get_corner_height(x + 0, y - 1, 0)));
cornerHeights[3] = max(map_get_corner_height(x - 1, y + 1, 2), max(map_get_corner_height(x - 1, y + 0, 2), map_get_corner_height(x + 0, y - 1, 1)));
highest = mapElement->base_height;
for (i = 0; i < 4; i++)
highest = max(highest, cornerHeights[i]);
if (highest >= mapElement->base_height + 4) {
count = 0;
for (i = 0; i < 4; i++)
if (cornerHeights[i] == highest)
count++;
if (count == 1) {
if (mapElement->base_height < highest - 4) {
mapElement->base_height = mapElement->clearance_height = highest - 4;
raisedLand = 1;
}
if (cornerHeights[0] == highest && cornerHeights[2] <= cornerHeights[0] - 4)
doubleCorner = 0;
else if (cornerHeights[1] == highest && cornerHeights[3] <= cornerHeights[1] - 4)
doubleCorner = 1;
else if (cornerHeights[2] == highest && cornerHeights[0] <= cornerHeights[2] - 4)
doubleCorner = 2;
else if (cornerHeights[3] == highest && cornerHeights[1] <= cornerHeights[3] - 4)
doubleCorner = 3;
} else {
if (mapElement->base_height < highest - 2) {
mapElement->base_height = mapElement->clearance_height = highest - 2;
raisedLand = 1;
}
}
}
if (doubleCorner != -1) {
mapElement->properties.surface.slope |= 16;
switch (doubleCorner) {
case 0:
mapElement->properties.surface.slope |= 2 | 4 | 8;
break;
case 1:
mapElement->properties.surface.slope |= 1 | 2 | 4;
break;
case 2:
mapElement->properties.surface.slope |= 1 | 2 | 8;
break;
case 3:
mapElement->properties.surface.slope |= 1 | 4 | 8;
break;
}
} else {
// Corners
if (
map_get_corner_height(x + 1, y + 1, 3) > mapElement->base_height ||
map_get_corner_height(x + 1, y + 0, 1) > mapElement->base_height ||
map_get_corner_height(x + 0, y + 1, 2) > mapElement->base_height
)
mapElement->properties.surface.slope |= 1;
if (
map_get_corner_height(x - 1, y + 1, 2) > mapElement->base_height ||
map_get_corner_height(x - 1, y + 0, 0) > mapElement->base_height ||
map_get_corner_height(x + 0, y + 1, 3) > mapElement->base_height
)
mapElement->properties.surface.slope |= 8;
if (
map_get_corner_height(x + 1, y - 1, 1) > mapElement->base_height ||
map_get_corner_height(x + 1, y + 0, 3) > mapElement->base_height ||
map_get_corner_height(x + 0, y - 1, 0) > mapElement->base_height
)
mapElement->properties.surface.slope |= 2;
if (
map_get_corner_height(x - 1, y - 1, 0) > mapElement->base_height ||
map_get_corner_height(x - 1, y + 0, 2) > mapElement->base_height ||
map_get_corner_height(x + 0, y - 1, 1) > mapElement->base_height
)
mapElement->properties.surface.slope |= 4;
// Raise
if (mapElement->properties.surface.slope == (1 | 2 | 4 | 8)) {
mapElement->properties.surface.slope &= ~0x1F;
mapElement->base_height = mapElement->clearance_height += 2;
}
}
}
}
return raisedLand;
}

View File

@@ -23,9 +23,54 @@
#endif
#include <math.h>
#include "../addresses.h"
#include "../object.h"
#include "map.h"
#include "map_helpers.h"
#include "mapgen.h"
#include "scenery.h"
#pragma region Random objects
const char *GrassTrees[] = {
// Dark
"TCF ", // Caucasian Fir Tree
"TRF ", // Red Fir Tree
"TRF2 ", // Red Fir Tree
"TSP ", // Scots Pine Tree
"TMZP ", // Montezuma Pine Tree
"TAP ", // Aleppo Pine Tree
"TCRP ", // Corsican Pine Tree
"TBP ", // Black Poplar Tree
// Light
"TCL ", // Cedar of Lebanon Tree
"TEL ", // European Larch Tree
};
// Trees to be placed in proximity to water
const char *GrassWaterTrees[] = {
"TWW " // Weeping Willow Tree
};
const char *DesertTrees[] = {
"TMP ", // Monkey-Puzzle Tree
"THL ", // Honey Locust Tree
"TH1 ", // Canary Palm Tree
"TH2 ", // Palm Tree
"TPM ", // Palm Tree
"TROPT1 ", // Tree
"TBC ", // Cactus
"TSC ", // Cactus
};
const char *SnowTrees[] = {
"TCFS ", // Snow-covered Caucasian Fir Tree
"TNSS ", // Snow-covered Norway Spruce Tree
"TRF3 ", // Snow-covered Red Fir Tree
"TRFS ", // Snow-covered Red Fir Tree
};
#pragma endregion
static void mapgen_place_trees();
static void mapgen_set_water_level(int height);
@@ -40,40 +85,52 @@ static uint8 *_height;
const uint8 BaseTerrain[] = { TERRAIN_GRASS, TERRAIN_SAND, TERRAIN_SAND_LIGHT, TERRAIN_ICE };
void mapgen_generate_blank(int mapSize, int height, int waterLevel, int floor, int wall)
void mapgen_generate_blank(mapgen_settings *settings)
{
int x, y;
rct_map_element *mapElement;
map_init(settings->mapSize);
for (y = 1; y < settings->mapSize - 1; y++) {
for (x = 1; x < settings->mapSize - 1; x++) {
mapElement = map_get_surface_element_at(x, y);
map_element_set_terrain(mapElement, settings->floor);
map_element_set_terrain_edge(mapElement, settings->wall);
mapElement->base_height = settings->height;
mapElement->clearance_height = settings->height;
}
}
mapgen_set_water_level(settings->waterLevel);
}
void mapgen_generate(mapgen_settings *settings)
{
int i, x, y, mapSize, floorTexture, wallTexture;
rct_map_element *mapElement;
srand((unsigned int)time(NULL));
mapSize = settings->mapSize;
floorTexture = settings->floor;
wallTexture = settings->wall;
if (floorTexture == -1)
floorTexture = BaseTerrain[rand() % countof(BaseTerrain)];
if (wallTexture == -1) {
wallTexture = TERRAIN_EDGE_ROCK;
if (floorTexture == TERRAIN_ICE)
wallTexture = TERRAIN_EDGE_ICE;
}
map_init(mapSize);
for (y = 1; y < mapSize - 1; y++) {
for (x = 1; x < mapSize - 1; x++) {
mapElement = map_get_surface_element_at(x, y);
map_element_set_terrain(mapElement, floor);
map_element_set_terrain_edge(mapElement, wall);
mapElement->base_height = height;
mapElement->clearance_height = height;
}
}
mapgen_set_water_level(waterLevel);
}
void mapgen_generate(int mapSize)
{
int i, x, y, baseTerrain;
rct_map_element *mapElement;
map_init(mapSize);
srand((unsigned int)time(NULL));
baseTerrain = BaseTerrain[rand() % countof(BaseTerrain)];
for (y = 0; y < mapSize; y++) {
for (x = 0; x < mapSize; x++) {
mapElement = map_get_surface_element_at(x, y);
map_element_set_terrain(mapElement, baseTerrain);
if (baseTerrain == TERRAIN_ICE)
map_element_set_terrain_edge(mapElement, TERRAIN_EDGE_ICE);
map_element_set_terrain(mapElement, floorTexture);
map_element_set_terrain_edge(mapElement, wallTexture);
mapElement->base_height = settings->height;
mapElement->clearance_height = settings->height;
}
}
@@ -98,7 +155,7 @@ void mapgen_generate(int mapSize)
int border = 2 + (rand() % 24);
for (i = 0; i < 128; i++) {
int radius = 4 + (rand() % 64);
int radius = 4 + (rand() % 32);
mapgen_blob(
border + (rand() % (_heightSize - (border * 2))),
border + (rand() % (_heightSize - (border * 2))),
@@ -112,11 +169,10 @@ void mapgen_generate(int mapSize)
while (map_smooth(1, 1, mapSize - 1, mapSize - 1)) { }
mapgen_set_water_level(6 + (rand() % 4) * 2);
// mapgen_place_trees();
}
const uint8 GrassTrees[] = { 21, 22, 27, 31, 42, 69, 71, 82, 84, 94, 95, 109 };
const uint8 DesertTrees[] = { 15, 16, 17, 19, 72, 81, 90, 91 };
if (settings->trees != 0)
mapgen_place_trees();
}
static void mapgen_place_tree(int type, int x, int y)
{
@@ -157,9 +213,46 @@ static void mapgen_place_tree(int type, int x, int y)
static void mapgen_place_trees()
{
int x, y, mapSize, i, rindex, type;
int x, y, mapSize, i, j, rindex, type;
rct_map_element *mapElement;
int numGrassTreeIds = 0, numDesertTreeIds = 0, numSnowTreeIds = 0;
int *grassTreeIds = (int*)malloc(countof(GrassTrees) * sizeof(int));
int *desertTreeIds = (int*)malloc(countof(DesertTrees) * sizeof(int));
int *snowTreeIds = (int*)malloc(countof(SnowTrees) * sizeof(int));
for (i = 0; i < object_entry_group_counts[OBJECT_TYPE_SMALL_SCENERY]; i++) {
rct_scenery_entry *sceneryEntry = g_smallSceneryEntries[i];
rct_object_entry_extended *entry = &object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].entries[i];
if (sceneryEntry == (rct_scenery_entry*)0xFFFFFFFF || sceneryEntry == NULL)
continue;
for (j = 0; j < countof(GrassTrees); j++)
if (strncmp(GrassTrees[j], entry->name, 8) == 0)
break;
if (j != countof(GrassTrees)) {
grassTreeIds[numGrassTreeIds++] = i;
continue;
}
for (j = 0; j < countof(DesertTrees); j++)
if (strncmp(DesertTrees[j], entry->name, 8) == 0)
break;
if (j != countof(DesertTrees)) {
desertTreeIds[numDesertTreeIds++] = i;
continue;
}
for (j = 0; j < countof(SnowTrees); j++)
if (strncmp(SnowTrees[j], entry->name, 8) == 0)
break;
if (j != countof(SnowTrees)) {
snowTreeIds[numSnowTreeIds++] = i;
continue;
}
}
mapSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, sint16);
int availablePositionsCount = 0;
@@ -197,16 +290,44 @@ static void mapgen_place_trees()
for (i = 0; i < min(availablePositionsCount, 2048 + (rand() % 10000)); i++) {
pos = &availablePositions[i];
mapElement = map_get_surface_element_at(x, y);
if (map_element_get_terrain(mapElement) == TERRAIN_SAND)
type = DesertTrees[rand() % countof(DesertTrees)];
else
type = GrassTrees[rand() % countof(GrassTrees)];
type = -1;
mapElement = map_get_surface_element_at(pos->x, pos->y);
switch (map_element_get_terrain(mapElement)) {
case TERRAIN_GRASS:
case TERRAIN_DIRT:
case TERRAIN_GRASS_CLUMPS:
if (numGrassTreeIds == 0)
break;
type = grassTreeIds[rand() % numGrassTreeIds];
break;
case TERRAIN_SAND:
case TERRAIN_SAND_DARK:
case TERRAIN_SAND_LIGHT:
if (numDesertTreeIds == 0)
break;
if (rand() % 4 == 0)
type = desertTreeIds[rand() % numDesertTreeIds];
break;
case TERRAIN_ICE:
if (numSnowTreeIds == 0)
break;
type = snowTreeIds[rand() % numSnowTreeIds];
break;
}
if (type != -1)
mapgen_place_tree(type, pos->x, pos->y);
}
free(availablePositions);
free(grassTreeIds);
free(desertTreeIds);
free(snowTreeIds);
}
static void mapgen_set_water_level(int waterLevel)

View File

@@ -21,7 +21,19 @@
#ifndef _MAPGEN_H_
#define _MAPGEN_H_
void mapgen_generate_blank(int mapSize, int height, int waterLevel, int floor, int wall);
void mapgen_generate(int mapSize);
typedef struct {
// Base
int mapSize;
int height;
int waterLevel;
int floor;
int wall;
// Features (e.g. tree, rivers, lakes etc.)
int trees;
} mapgen_settings;
void mapgen_generate_blank(mapgen_settings *settings);
void mapgen_generate(mapgen_settings *settings);
#endif