diff --git a/src/input.c b/src/input.c
index a2e1f2bd1c..3755f61151 100644
--- a/src/input.c
+++ b/src/input.c
@@ -26,6 +26,7 @@
#include "game.h"
#include "input.h"
#include "map.h"
+#include "mapgen.h"
#include "osinterface.h"
#include "sprite.h"
#include "tutorial.h"
@@ -1547,6 +1548,11 @@ void handle_shortcut(int key)
break;
}
}
+
+ if (key == SDL_SCANCODE_R) {
+ mapgen_generate();
+ gfx_invalidate_screen();
+ }
}
/**
diff --git a/src/map_helpers.c b/src/map_helpers.c
index cb959cb2b2..dad39bc54d 100644
--- a/src/map_helpers.c
+++ b/src/map_helpers.c
@@ -28,7 +28,7 @@ int map_smooth(int l, int t, int r, int b)
for (y = t; y < b; y++) {
for (x = l; x < r; x++) {
mapElement = map_get_surface_element_at(x, y);
- mapElement->properties.surface.slope = 0;
+ mapElement->properties.surface.slope &= ~0x1F;
// Raise to edge height - 2
highest = mapElement->base_height;
@@ -131,7 +131,7 @@ int map_smooth(int l, int t, int r, int b)
// Raise
if (mapElement->properties.surface.slope == (1 | 2 | 4 | 8)) {
- mapElement->properties.surface.slope = 0;
+ mapElement->properties.surface.slope &= ~0x1F;
mapElement->base_height = mapElement->clearance_height += 2;
}
}
diff --git a/src/mapgen.c b/src/mapgen.c
index 19c59a21e9..798cf0522c 100644
--- a/src/mapgen.c
+++ b/src/mapgen.c
@@ -18,16 +18,32 @@
* along with this program. If not, see .
*****************************************************************************/
+#ifndef _USE_MATH_DEFINES
+ #define _USE_MATH_DEFINES
+#endif
+#include
+#include
+#include
#include "addresses.h"
#include "map.h"
#include "map_helpers.h"
#include "mapgen.h"
static void mapgen_set_water_level(int height);
+static void mapgen_blob(int cx, int cy, int size, int height);
+static void mapgen_smooth_height(int iterations);
+static void mapgen_set_height();
+
+static int _heightSize;
+static uint8 *_height;
+
+#define HEIGHT(x, y) (_height[(y) * _heightSize + (x)])
+
+const uint8 BaseTerrain[] = { TERRAIN_GRASS, TERRAIN_SAND, TERRAIN_SAND_LIGHT, TERRAIN_ICE };
void mapgen_generate()
{
- int x, y, mapSize;
+ int i, x, y, mapSize, baseTerrain;
rct_map_element *mapElement;
map_init();
@@ -35,29 +51,52 @@ void mapgen_generate()
// Not sure how to change map size at the moment, default is 150
mapSize = 150;
- for (y = 1; y < mapSize - 1; y++) {
- for (x = 1; x < mapSize - 1; x++) {
+ 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, TERRAIN_SAND);
+ map_element_set_terrain(mapElement, baseTerrain);
+ if (baseTerrain == TERRAIN_ICE)
+ map_element_set_terrain_edge(mapElement, TERRAIN_EDGE_ICE);
+ }
+ }
- double a = abs(x - (mapSize / 2)) / (double)(mapSize / 2);
- double b = abs(y - (mapSize / 2)) / (double)(mapSize / 2);
+ _heightSize = mapSize * 2;
+ _height = (uint8*)malloc((mapSize * 2) * (mapSize * 2) * sizeof(uint8));
+ for (y = 0; y < mapSize * 2; y++) {
+ for (x = 0; x < mapSize * 2; x++) {
+ double a = abs(x - (mapSize)) / (double)(mapSize);
+ double b = abs(y - (mapSize)) / (double)(mapSize);
a *= 2;
b *= 2;
double c = 1 - ((a*a + b*b) / 2);
c = clamp(0, c, 1);
- int height = 2 + rand() % ((int)(c * 22) + 1);
+ int h = 1 + rand() % ((int)(c * 22) + 1);
+ h = 1;
- mapElement->base_height = height * 2;
- mapElement->clearance_height = mapElement->base_height;
+ HEIGHT(x, y) = h;
}
}
- while (map_smooth(1, 1, mapSize - 1, mapSize - 1)) { }
+ int border = 2 + (rand() % 24);
+ for (i = 0; i < 128; i++) {
+ int radius = 4 + (rand() % 64);
+ mapgen_blob(
+ border + (rand() % (_heightSize - (border * 2))),
+ border + (rand() % (_heightSize - (border * 2))),
+ (int)(M_PI * radius * radius),
+ 1 + (rand() % 12)
+ );
+ }
+ mapgen_smooth_height(2);
+ mapgen_set_height();
+ free(_height);
- mapgen_set_water_level(8);
+ while (map_smooth(1, 1, mapSize - 1, mapSize - 1)) { }
+ mapgen_set_water_level(6 + (rand() % 4) * 2);
}
static void mapgen_set_water_level(int waterLevel)
@@ -74,4 +113,222 @@ static void mapgen_set_water_level(int waterLevel)
mapElement->properties.surface.terrain |= (waterLevel - 5);
}
}
+}
+
+static void mapgen_blob_fill(int height)
+{
+ // For each square find out whether it is landlocked by 255 and then fill it if it is
+ int left = 0,
+ top = 0,
+ right = _heightSize - 1,
+ bottom = _heightSize - 1;
+
+ uint8 *landX = (uint8*)malloc(_heightSize * _heightSize * sizeof(uint8));
+ int firstLand, lastLand;
+
+ // Check each row and see if each tile is between first land x and last land x
+ for (int y = top; y <= bottom; y++) {
+ // Calculate first land
+ firstLand = -1;
+ for (int xx = left; xx <= right; xx++) {
+ if (HEIGHT(xx, y) == 255) {
+ firstLand = xx;
+ break;
+ }
+ }
+
+ lastLand = -1;
+ if (firstLand >= 0) {
+ // Calculate last land
+ for (int xx = right; xx >= left; xx--) {
+ if (HEIGHT(xx, y) == 255) {
+ lastLand = xx;
+ break;
+ }
+ }
+ } else {
+ // No land on this row
+ continue;
+ }
+
+ for (int x = left; x <= right; x++)
+ if (x >= firstLand && x <= lastLand)
+ landX[x, y] = 1;
+ }
+
+ // Do the same for Y
+ for (int x = left; x <= right; x++) {
+ // Calculate first land
+ firstLand = -1;
+ for (int yy = top; yy <= bottom; yy++) {
+ if (HEIGHT(x, yy) == 255) {
+ firstLand = yy;
+ break;
+ }
+ }
+
+ lastLand = -1;
+ if (firstLand >= 0) {
+ // Calculate last land
+ for (int yy = bottom; yy >= top; yy--) {
+ if (HEIGHT(x, yy) == 255) {
+ lastLand = yy;
+ break;
+ }
+ }
+ } else {
+ // No land on this row
+ continue;
+ }
+
+ for (int y = top; y <= bottom; y++) {
+ if (y >= firstLand && y <= lastLand && landX[x, y]) {
+ // Not only do we know its landlocked to both x and y
+ // we can change the land too
+ HEIGHT(x, y) = 255;
+ }
+ }
+ }
+
+ // Replace all the 255 with the actual land height
+ for (int x = left; x <= right; x++)
+ for (int y = top; y <= bottom; y++)
+ if (HEIGHT(x, y) == 255)
+ HEIGHT(x, y) = height;
+
+ free(landX);
+}
+
+static void mapgen_blob(int cx, int cy, int size, int height)
+{
+ int x, y, currentSize, direction;
+
+ x = cx;
+ y = cy;
+ currentSize = 1;
+ direction = 0;
+ HEIGHT(y, x) = 255;
+
+ while (currentSize < size) {
+ if (rand() % 2 == 0) {
+ HEIGHT(x, y) = 255;
+ currentSize++;
+ }
+
+ switch (direction) {
+ case 0:
+ if (y == 0) {
+ currentSize = size;
+ break;
+ }
+
+ y--;
+ if (HEIGHT(x + 1, y) != 255)
+ direction = 1;
+ else if (HEIGHT(x, y - 1) != 255)
+ direction = 0;
+ else if (HEIGHT(x - 1, y) != 255)
+ direction = 3;
+ break;
+ case 1:
+ if (x == _heightSize - 1) {
+ currentSize = size;
+ break;
+ }
+
+ x++;
+ if (HEIGHT(x, y + 1) != 255)
+ direction = 2;
+ else if (HEIGHT(x + 1, y) != 255)
+ direction = 1;
+ else if (HEIGHT(x, y - 1) != 255)
+ direction = 0;
+ break;
+ case 2:
+ if (y == _heightSize - 1) {
+ currentSize = size;
+ break;
+ }
+
+ y++;
+ if (HEIGHT(x - 1, y) != 255)
+ direction = 3;
+ else if (HEIGHT(x, y + 1) != 255)
+ direction = 2;
+ else if (HEIGHT(x + 1, y) != 255)
+ direction = 1;
+ break;
+ case 3:
+ if (x == 0) {
+ currentSize = size;
+ break;
+ }
+
+ x--;
+ if (HEIGHT(x, y - 1) != 255)
+ direction = 0;
+ else if (HEIGHT(x - 1, y) != 255)
+ direction = 3;
+ else if (HEIGHT(x, y + 1) != 255)
+ direction = 2;
+ break;
+ }
+ }
+
+ mapgen_blob_fill(height);
+}
+
+static void mapgen_smooth_height(int iterations)
+{
+ int i, x, y, xx, yy, avg;
+ int arraySize = _heightSize * _heightSize * sizeof(uint8);
+ uint8 *copyHeight = malloc(arraySize);
+ memcpy(copyHeight, _height, arraySize);
+
+ for (i = 0; i < iterations; i++) {
+ for (y = 1; y < _heightSize - 1; y++) {
+ for (x = 1; x < _heightSize - 1; x++) {
+ avg = 0;
+ for (yy = -1; yy <= 1; yy++)
+ for (xx = -1; xx <= 1; xx++)
+ avg += copyHeight[(y + yy) * _heightSize + (x + xx)];
+ avg /= 9;
+ HEIGHT(x, y) = avg;
+ }
+ }
+ }
+}
+
+static void mapgen_set_height()
+{
+ int x, y, heightX, heightY, mapSize;
+ rct_map_element *mapElement;
+
+ mapSize = _heightSize / 2;
+ for (y = 1; y < mapSize - 1; y++) {
+ for (x = 1; x < mapSize - 1; x++) {
+ heightX = x * 2;
+ heightY = y * 2;
+
+ uint8 q00 = HEIGHT(heightX + 0, heightY + 0);
+ uint8 q01 = HEIGHT(heightX + 0, heightY + 1);
+ uint8 q10 = HEIGHT(heightX + 1, heightY + 0);
+ uint8 q11 = HEIGHT(heightX + 1, heightY + 1);
+
+ uint8 baseHeight = (q00 + q01 + q10 + q11) / 4;
+
+ mapElement = map_get_surface_element_at(x, y);
+ mapElement->base_height = baseHeight * 2;
+ mapElement->clearance_height = mapElement->base_height;
+
+ if (q00 > baseHeight)
+ mapElement->properties.surface.slope |= 4;
+ if (q01 > baseHeight)
+ mapElement->properties.surface.slope |= 8;
+ if (q10 > baseHeight)
+ mapElement->properties.surface.slope |= 2;
+ if (q11 > baseHeight)
+ mapElement->properties.surface.slope |= 1;
+ }
+ }
}
\ No newline at end of file