diff --git a/worldgen-c/src/worldgen.c b/worldgen-c/src/worldgen.c index 010b3a3..3f7e043 100644 --- a/worldgen-c/src/worldgen.c +++ b/worldgen-c/src/worldgen.c @@ -125,6 +125,11 @@ static inline int clamp_int(int v, int min_v, int max_v) { return v; } +static inline double smoothstep01(double v) { + v = clamp01(v); + return v * v * (3.0 - 2.0 * v); +} + static int ground_slope(worldgen_ctx *ctx, int x, int z); static uint16_t select_surface_block(worldgen_ctx *ctx, const column_data *data, int world_x, int world_z); static void generate_chunk_trails(worldgen_ctx *ctx, int chunk_x, int chunk_z, column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *out); @@ -519,6 +524,15 @@ static double redwood_tree_presence(worldgen_ctx *ctx, int x, int z) { return clamp01(presence); } +static double buildable_flatland_mask(worldgen_ctx *ctx, int x, int z, double mountain_factor) { + double cell = worley_distance(x + 71000, z - 71000, 0.00082, 0xB17D4B11u); + double broad_patch = smoothstep01((0.66 - cell) / 0.28); + double gate = simplex_noise2(&ctx->noise, (x - 91000) * 0.00022, (z + 91000) * 0.00022) * 0.5 + 0.5; + double campus_patch = broad_patch * smoothstep01((gate - 0.32) / 0.36); + double mountain_guard = 1.0 - smoothstep01((mountain_factor - 0.42) / 0.34) * 0.82; + return clamp01(campus_patch * mountain_guard); +} + static double region_blend(worldgen_ctx *ctx, int x, int z) { (void)ctx; @@ -634,6 +648,7 @@ static int column_height(worldgen_ctx *ctx, int x, int z) { double mix_base = region * 0.35 + base_mountain * 0.55; double mix = clamp01(mix_base * 0.65 + 0.15); double height = lowland * (1.0 - mix) + highland * mix; + double build_flats = buildable_flatland_mask(ctx, x, z, mountain_factor); double flat_noise = simplex_noise2(&ctx->noise, warp2_x * 0.0015, warp2_z * 0.0015) * 0.5 + 0.5; double flat_bias = (mix < 0.45 ? (0.45 - mix) * 1.6 : 0.0) * flat_noise; @@ -648,15 +663,24 @@ static int column_height(worldgen_ctx *ctx, int x, int z) { double region_bias = 0.7 + 0.3 * clamp01(region); double plains_detail_quiet = clamp01(1.0 - mix * 1.2); double adjusted_weight = detail_weight * region_bias * (1.0 - plains_detail_quiet * 0.8); + adjusted_weight *= 1.0 - build_flats * 0.92; height += simplex_noise2(&ctx->noise, warp2_x * 0.02, warp2_z * 0.02) * 5.0 * adjusted_weight; height += simplex_noise2(&ctx->noise, warp2_x * 0.05, warp2_z * 0.05) * 2.0 * adjusted_weight; height += simplex_noise2(&ctx->noise, warp2_x * 0.1, warp2_z * 0.1) * 1.0 * adjusted_weight; - height += simplex_noise3(&ctx->noise, warp2_x * 0.015, warp2_z * 0.015, region * 7.0) * 1.5; + height += simplex_noise3(&ctx->noise, warp2_x * 0.015, warp2_z * 0.015, region * 7.0) * 1.5 * (1.0 - build_flats * 0.85); + if (build_flats > 0.0) { + double campus_target = ctx->sea_level + 4; + campus_target += simplex_noise2(&ctx->noise, (x + 51000) * 0.00055, (z - 51000) * 0.00055) * 2.0; + campus_target += simplex_noise2(&ctx->noise, (x - 62000) * 0.0014, (z + 62000) * 0.0014) * 0.8; + double campus_blend = build_flats * 0.88; + height = height * (1.0 - campus_blend) + campus_target * campus_blend; + } double flats = clamp01((old_growth - 0.25) / 0.75); if (flats > 0.0) { double plains_target = ctx->sea_level - 2 + simplex_noise2(&ctx->noise, (x - 22000) * 0.002, (z + 22000) * 0.002) * 5.0; plains_target += simplex_noise2(&ctx->noise, (x + 33000) * 0.01, (z - 33000) * 0.01) * 1.5; - height = height * (1.0 - flats) + plains_target * flats; + double plains_blend = flats * (1.0 - build_flats * 0.55); + height = height * (1.0 - plains_blend) + plains_target * plains_blend; } return (int)height;