eco2d/code/apps/server/source/world_gen.c

133 lines
4.2 KiB
C
Raw Normal View History

2021-01-11 16:20:12 +00:00
#include "world.h"
#include "blocks.h"
2021-01-11 17:30:47 +00:00
#include "perlin.h"
2021-01-11 16:20:12 +00:00
#include "zpl.h"
2021-01-11 16:49:00 +00:00
#include <math.h>
2021-01-14 16:37:20 +00:00
#include <stdlib.h>
2021-01-11 16:49:00 +00:00
2021-01-11 17:15:11 +00:00
#define WORLD_BLOCK_OBSERVER(name) uint32_t name(uint32_t id, uint32_t block_idx)
typedef WORLD_BLOCK_OBSERVER(world_block_observer_proc);
2021-01-11 17:30:47 +00:00
#define WORLD_PERLIN_FREQ 1.0
#define WORLD_PERLIN_OCTAVES 1
2021-01-11 17:15:11 +00:00
static void world_fill_rect(uint32_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) {
2021-01-11 16:20:12 +00:00
for (uint32_t cy=y; cy<y+h; cy++) {
for (uint32_t cx=x; cx<x+w; cx++) {
2021-01-14 16:37:20 +00:00
if (cx < 0 || cx >= world.width) continue;
if (cy < 0 || cy >= world.height) continue;
uint32_t i = (cy*world.width) + cx;
2021-01-11 17:15:11 +00:00
if (proc) {
uint32_t new_id = (*proc)(id, i);
2021-01-11 17:30:47 +00:00
if (new_id != BLOCK_INVALID) {
id = new_id;
}
else continue;
2021-01-11 17:15:11 +00:00
}
2021-01-14 16:37:20 +00:00
world.data[i] = id;
2021-01-11 16:20:12 +00:00
}
}
}
2021-01-14 16:03:10 +00:00
static void world_fill_circle(uint32_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) {
for (uint32_t cy=y; cy<y+h; cy++) {
for (uint32_t cx=x; cx<x+w; cx++) {
2021-01-14 16:37:20 +00:00
if (cx < 0 || cx >= world.width) continue;
if (cy < 0 || cy >= world.height) continue;
uint32_t i = (cy*world.width) + cx;
2021-01-14 16:03:10 +00:00
if (proc) {
uint32_t new_id = (*proc)(id, i);
if (new_id != BLOCK_INVALID) {
id = new_id;
}
else continue;
}
2021-01-14 16:37:20 +00:00
world.data[i] = id;
2021-01-14 16:03:10 +00:00
}
}
}
2021-01-11 17:15:11 +00:00
static void world_fill_rect_anchor(uint32_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, float ax, float ay, world_block_observer_proc *proc) {
uint32_t w2 = (uint32_t)floorf(w*ax);
uint32_t h2 = (uint32_t)floorf(h*ay);
world_fill_rect(id, x-w2, y-h2, w, h, proc);
}
static WORLD_BLOCK_OBSERVER(shaper) {
uint32_t biome = blocks_get_biome(id);
uint32_t kind = blocks_get_kind(id);
2021-01-14 16:37:20 +00:00
uint32_t old_biome = blocks_get_biome(world.data[block_idx]);
uint32_t old_kind = blocks_get_kind(world.data[block_idx]);
2021-01-11 17:15:11 +00:00
if (biome == old_biome) {
if (kind == BLOCK_KIND_WALL && kind == old_kind) {
return blocks_find(biome, BLOCK_KIND_HILL);
}
2021-01-11 21:50:14 +00:00
if (kind == BLOCK_KIND_HILL && kind == old_kind) {
return blocks_find(biome, BLOCK_KIND_HILL_SNOW);
}
2021-01-11 17:15:11 +00:00
}
return id;
2021-01-11 16:49:00 +00:00
}
2021-01-11 17:39:34 +00:00
static uint8_t world_perlin_cond(uint32_t block_idx, double chance) {
2021-01-14 16:37:20 +00:00
uint32_t x = block_idx % world.width;
uint32_t y = block_idx / world.width;
2021-01-11 17:30:47 +00:00
2021-01-14 16:37:20 +00:00
return perlin_fbm(world.seed, x, y, WORLD_PERLIN_FREQ, WORLD_PERLIN_OCTAVES) < chance;
2021-01-11 17:33:27 +00:00
}
2021-01-11 17:39:34 +00:00
static WORLD_BLOCK_OBSERVER(shaper_noise80) {
return world_perlin_cond(block_idx, 0.80) ? shaper(id, block_idx) : BLOCK_INVALID;
}
2021-01-11 17:33:27 +00:00
2021-01-11 17:39:34 +00:00
static WORLD_BLOCK_OBSERVER(shaper_noise50) {
return world_perlin_cond(block_idx, 0.50) ? shaper(id, block_idx) : BLOCK_INVALID;
2021-01-11 17:33:27 +00:00
}
static WORLD_BLOCK_OBSERVER(shaper_noise33) {
2021-01-11 17:39:34 +00:00
return world_perlin_cond(block_idx, 0.33) ? shaper(id, block_idx) : BLOCK_INVALID;
2021-01-11 17:30:47 +00:00
}
2021-01-14 16:03:10 +00:00
static void world_fill_mountain(uint32_t x, uint32_t y) {
}
2021-01-11 18:10:56 +00:00
#define RAND_RANGE(x,y) (x + (uint32_t)rand()%(y-(x)))
2021-01-11 17:30:47 +00:00
int32_t world_gen() {
2021-01-11 16:20:12 +00:00
// TODO: perform world gen
// atm, we will fill the world with ground and surround it by walls
uint32_t wall_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_WALL);
uint32_t grnd_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_GROUND);
uint32_t watr_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_WATER);
2021-01-14 16:37:20 +00:00
srand(world.seed);
2021-01-11 18:10:56 +00:00
2021-01-11 16:20:12 +00:00
// walls
2021-01-14 16:37:20 +00:00
world_fill_rect(wall_id, 0, 0, world.width, world.height, NULL);
2021-01-11 16:20:12 +00:00
// ground
2021-01-14 16:37:20 +00:00
world_fill_rect(grnd_id, 1, 1, world.width-2, world.height-2, NULL);
2021-01-11 16:20:12 +00:00
// water
2021-01-11 21:50:14 +00:00
for (int i=0; i<RAND_RANGE(0, 12); i++) {
2021-01-14 16:37:20 +00:00
world_fill_rect_anchor(watr_id, RAND_RANGE(0, world.width), RAND_RANGE(0, world.height), 4+RAND_RANGE(0,3), 4+RAND_RANGE(0,3), 0.5f, 0.5f, shaper_noise33);
2021-01-11 18:10:56 +00:00
}
2021-01-11 17:15:11 +00:00
2021-01-11 21:50:14 +00:00
const uint32_t HILLS_SIZE = 21;
2021-01-11 17:15:11 +00:00
2021-01-11 21:50:14 +00:00
// hills
for (int i=0; i<RAND_RANGE(8, 224); i++) {
2021-01-14 16:37:20 +00:00
world_fill_rect_anchor(wall_id, RAND_RANGE(0, world.width), RAND_RANGE(0, world.height), RAND_RANGE(0,HILLS_SIZE), RAND_RANGE(0,HILLS_SIZE), 0.5f, 0.5f, shaper_noise33);
2021-01-11 18:10:56 +00:00
}
2021-01-11 16:20:12 +00:00
return WORLD_ERROR_NONE;
}