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