find/generator.c

#include <SDL.h>

#include "world.h"
#include "random.h"

#define FULLNESS 15.0
#define SPARSITY 40.0
#define CAVERNITY 20.0

#define SURFACE_COLLECTIBLE_RARITY 50

static void fill_circle(Uint8 tiles[], int x, int y, float radius, tile t) {
	int boundary = SDL_fabs(radius) + 0.5;
	int min_x = SDL_max(x - boundary, 0);
	int max_x = SDL_min(x + boundary, CHUNK_DIM - 1);
	int min_y = SDL_max(y - boundary, 0);
	int max_y = SDL_min(y + boundary, CHUNK_DIM - 1);
	for (int iy = min_y; iy <= max_y; iy++) {
		for (int ix = min_x; ix <= max_x; ix++) {
			int dx = ix - x;
			int dy = iy - y;
			if (dx * dx + dy * dy <= radius * radius) {
				if (dx != 0 || dy != 0 || radius > 0.5) {
					tiles[tile_index((SDL_Point) {ix, iy})] = t;
				}
			}
		}
	}
}

void generate_chunk(world *w, chunk *c) {
	SDL_memset(c->tiles, TILE_EMPTY, sizeof(c->tiles));
	if (c->pos.y < 0) return;

	for (int y = 0; y < CHUNK_DIM; y++) {
		for (int x = 0; x < CHUNK_DIM; x++) {
			float radius = SDL_pow(rand_float(), SPARSITY);
			if (rand_int() % 4 == 0) radius = -radius;
			radius *= (radius > 0) ? FULLNESS : CAVERNITY;
			if (c->pos.y == 0) {
				if (y < 96) radius = 0;
				else if (radius > 0) radius *= 1.8;
			}

			tile t = radius > 0 ? TILE_WALL : TILE_EMPTY;
			fill_circle(c->tiles, x, y, SDL_abs(radius), t);
		}
	}

	int rarity = c->pos.x != 0 && c->pos.x != -1 ?
		SURFACE_COLLECTIBLE_RARITY : 8;
	if (c->pos.y == 0) {
		for (int x = 0; x < CHUNK_DIM; x++) {
			if (rand_int() % rarity == 0) {
				int y = 0;
				while (!is_solid(c->tiles[tile_index((SDL_Point) {x, y + 1})]))
					y++;
				tile t = rand_int() % TILE_LIGHT;
				c->tiles[tile_index((SDL_Point) {x, y})] = t;
			}
		}
	}
}