diff --git a/modules/world-worldgen/src/biome_edge_detector.zig b/modules/world-worldgen/src/biome_edge_detector.zig index 2610905d..0d4df9ce 100644 --- a/modules/world-worldgen/src/biome_edge_detector.zig +++ b/modules/world-worldgen/src/biome_edge_detector.zig @@ -113,6 +113,13 @@ pub const TRANSITION_RULES = [_]TransitionRule{ .{ .biome_a = .snowy_beach, .biome_b = .beach, .transition = .stony_shore }, .{ .biome_a = .snow_tundra, .biome_b = .beach, .transition = .snowy_beach }, .{ .biome_a = .taiga, .biome_b = .beach, .transition = .stony_shore }, + .{ .biome_a = .beach, .biome_b = .plains, .transition = .coastal_plains }, + .{ .biome_a = .beach, .biome_b = .forest, .transition = .coastal_plains }, + .{ .biome_a = .beach, .biome_b = .birch_forest, .transition = .coastal_plains }, + .{ .biome_a = .beach, .biome_b = .flower_forest, .transition = .coastal_plains }, + .{ .biome_a = .beach, .biome_b = .swamp, .transition = .coastal_plains }, + .{ .biome_a = .beach, .biome_b = .mangrove_swamp, .transition = .coastal_plains }, + .{ .biome_a = .beach, .biome_b = .tropical, .transition = .coastal_plains }, // Wetland <-> Forest .{ .biome_a = .swamp, .biome_b = .forest, .transition = .marsh }, diff --git a/modules/world-worldgen/src/biome_registry.zig b/modules/world-worldgen/src/biome_registry.zig index 47597e6c..5de8a8ae 100644 --- a/modules/world-worldgen/src/biome_registry.zig +++ b/modules/world-worldgen/src/biome_registry.zig @@ -184,9 +184,9 @@ pub const BiomePoint = struct { y_max: i32 = 256, // Maximum Y level /// Maximum allowed slope in blocks (0 = flat, 255 = vertical cliff) max_slope: i32 = 255, - /// Minimum continentalness (0-1). Set > 0.35 for land-only biomes + /// Minimum continentalness (0-1). Set > 0.37 for land-only biomes min_continental: f32 = 0.0, - /// Maximum continentalness. Set < 0.35 for ocean-only biomes + /// Maximum continentalness. Set < 0.37 for ocean-only biomes max_continental: f32 = 1.0, pub fn elevationCenter(self: BiomePoint) f32 { @@ -218,18 +218,18 @@ pub const StructuralParams = struct { /// Heat: 0=frozen, 50=temperate, 100=scorching /// Humidity: 0=arid, 50=normal, 100=saturated pub const BIOME_POINTS = [_]BiomePoint{ - // === Ocean Biomes (continental < 0.35) === + // === Ocean Biomes (continental < 0.37) === .{ .id = .deep_ocean, .heat = 50, .humidity = 50, .weight = 1.5, .max_continental = 0.20 }, - .{ .id = .frozen_ocean, .heat = 5, .humidity = 55, .weight = 1.1, .max_continental = 0.35 }, - .{ .id = .cold_ocean, .heat = 22, .humidity = 55, .weight = 1.1, .min_continental = 0.10, .max_continental = 0.35 }, - .{ .id = .ocean, .heat = 50, .humidity = 50, .weight = 1.5, .min_continental = 0.20, .max_continental = 0.35 }, - .{ .id = .warm_ocean, .heat = 85, .humidity = 75, .weight = 0.9, .min_continental = 0.20, .max_continental = 0.35 }, + .{ .id = .frozen_ocean, .heat = 5, .humidity = 55, .weight = 1.1, .max_continental = 0.37 }, + .{ .id = .cold_ocean, .heat = 22, .humidity = 55, .weight = 1.1, .min_continental = 0.10, .max_continental = 0.37 }, + .{ .id = .ocean, .heat = 50, .humidity = 50, .weight = 1.5, .min_continental = 0.20, .max_continental = 0.37 }, + .{ .id = .warm_ocean, .heat = 85, .humidity = 75, .weight = 0.9, .min_continental = 0.20, .max_continental = 0.37 }, .{ .id = .tropical, .heat = 95, .humidity = 90, .weight = 0.7, .min_continental = 0.30, .max_continental = 0.48, .max_slope = 3, .y_max = 72 }, // === Coastal Biomes === - .{ .id = .snowy_beach, .heat = 8, .humidity = 45, .weight = 0.7, .max_slope = 2, .min_continental = 0.35, .max_continental = 0.42, .y_max = 70 }, - .{ .id = .stony_shore, .heat = 30, .humidity = 45, .weight = 0.7, .min_continental = 0.35, .max_continental = 0.45, .y_max = 82 }, - .{ .id = .beach, .heat = 60, .humidity = 50, .weight = 0.6, .max_slope = 2, .min_continental = 0.35, .max_continental = 0.42, .y_max = 70 }, + .{ .id = .snowy_beach, .heat = 8, .humidity = 45, .weight = 0.7, .max_slope = 2, .min_continental = 0.37, .max_continental = 0.44, .y_max = 70 }, + .{ .id = .stony_shore, .heat = 30, .humidity = 45, .weight = 0.7, .min_continental = 0.37, .max_continental = 0.46, .y_max = 82 }, + .{ .id = .beach, .heat = 60, .humidity = 50, .weight = 0.6, .max_slope = 2, .min_continental = 0.37, .max_continental = 0.44, .y_max = 70 }, // === Cold Biomes === .{ .id = .snow_tundra, .heat = 5, .humidity = 30, .weight = 1.0, .min_continental = 0.42 }, @@ -253,7 +253,7 @@ pub const BIOME_POINTS = [_]BiomePoint{ // === Warm/Wet Biomes === .{ .id = .swamp, .heat = 65, .humidity = 85, .weight = 0.8, .max_slope = 3, .min_continental = 0.42, .y_max = 72 }, - .{ .id = .mangrove_swamp, .heat = 75, .humidity = 90, .weight = 0.6, .max_slope = 3, .min_continental = 0.35, .max_continental = 0.50, .y_max = 68 }, + .{ .id = .mangrove_swamp, .heat = 75, .humidity = 90, .weight = 0.6, .max_slope = 3, .min_continental = 0.37, .max_continental = 0.50, .y_max = 68 }, .{ .id = .jungle, .heat = 85, .humidity = 85, .weight = 0.9, .min_continental = 0.50 }, .{ .id = .bamboo_jungle, .heat = 88, .humidity = 92, .weight = 0.5, .min_continental = 0.55 }, .{ .id = .sparse_jungle, .heat = 78, .humidity = 62, .weight = 0.7, .min_continental = 0.50 }, @@ -269,7 +269,7 @@ pub const BIOME_POINTS = [_]BiomePoint{ .{ .id = .stony_peaks, .heat = 65, .humidity = 25, .weight = 0.55, .min_continental = 0.78, .y_min = 132 }, // === Special Biomes === - .{ .id = .mushroom_fields, .heat = 50, .humidity = 80, .weight = 0.3, .min_continental = 0.35, .max_continental = 0.45 }, + .{ .id = .mushroom_fields, .heat = 50, .humidity = 80, .weight = 0.3, .min_continental = 0.37, .max_continental = 0.45 }, .{ .id = .river, .heat = 50, .humidity = 70, .weight = 0.4, .min_continental = 0.42 }, // Selected by river mask, not Voronoi .{ .id = .frozen_river, .heat = 8, .humidity = 70, .weight = 0.4, .min_continental = 0.42 }, // Selected by river mask, not Voronoi @@ -278,7 +278,7 @@ pub const BIOME_POINTS = [_]BiomePoint{ .{ .id = .foothills, .heat = 45, .humidity = 45, .weight = 0.5, .min_continental = 0.55, .y_min = 75, .y_max = 100 }, .{ .id = .marsh, .heat = 55, .humidity = 78, .weight = 0.5, .min_continental = 0.42, .y_max = 68 }, .{ .id = .dry_plains, .heat = 70, .humidity = 25, .weight = 0.6, .min_continental = 0.42 }, - .{ .id = .coastal_plains, .heat = 55, .humidity = 50, .weight = 0.5, .min_continental = 0.35, .max_continental = 0.48 }, + .{ .id = .coastal_plains, .heat = 55, .humidity = 50, .weight = 0.5, .min_continental = 0.37, .max_continental = 0.48 }, }; // ============================================================================ @@ -305,7 +305,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = Range.any(), .humidity = Range.any(), .elevation = .{ .min = 0.0, .max = 0.30 }, - .continentalness = .{ .min = 0.0, .max = 0.35 }, + .continentalness = .{ .min = 0.0, .max = 0.37 }, .priority = 1, .surface = .{ .top = .sand, .filler = .sand, .depth_range = 3 }, .vegetation = .{ .tree_types = &.{} }, @@ -316,7 +316,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.0, .max = 0.15 }, .humidity = Range.any(), .elevation = .{ .min = 0.0, .max = 0.32 }, - .continentalness = .{ .min = 0.0, .max = 0.35 }, + .continentalness = .{ .min = 0.0, .max = 0.37 }, .priority = 4, .surface = .{ .top = .packed_ice, .filler = .gravel, .depth_range = 4 }, .vegetation = .{ .tree_types = &.{} }, @@ -328,7 +328,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.15, .max = 0.30 }, .humidity = Range.any(), .elevation = .{ .min = 0.0, .max = 0.32 }, - .continentalness = .{ .min = 0.0, .max = 0.35 }, + .continentalness = .{ .min = 0.0, .max = 0.37 }, .priority = 3, .surface = .{ .top = .gravel, .filler = .gravel, .depth_range = 4 }, .vegetation = .{ @@ -346,7 +346,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.70, .max = 1.0 }, .humidity = .{ .min = 0.50, .max = 1.0 }, .elevation = .{ .min = 0.0, .max = 0.32 }, - .continentalness = .{ .min = 0.20, .max = 0.35 }, + .continentalness = .{ .min = 0.20, .max = 0.37 }, .priority = 3, .surface = .{ .top = .sand, .filler = .sand, .depth_range = 3 }, .vegetation = .{ @@ -389,7 +389,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.2, .max = 1.0 }, .humidity = Range.any(), .elevation = .{ .min = 0.28, .max = 0.38 }, - .continentalness = .{ .min = 0.35, .max = 0.42 }, // NARROW beach band + .continentalness = .{ .min = 0.37, .max = 0.44 }, // NARROW beach band .max_height = 70, .max_slope = 2, .priority = 10, @@ -402,7 +402,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.20, .max = 0.45 }, .humidity = Range.any(), .elevation = .{ .min = 0.28, .max = 0.45 }, - .continentalness = .{ .min = 0.35, .max = 0.45 }, + .continentalness = .{ .min = 0.37, .max = 0.46 }, .max_height = 82, .max_slope = 8, .priority = 11, @@ -417,7 +417,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.0, .max = 0.18 }, .humidity = Range.any(), .elevation = .{ .min = 0.28, .max = 0.38 }, - .continentalness = .{ .min = 0.35, .max = 0.42 }, + .continentalness = .{ .min = 0.37, .max = 0.44 }, .max_height = 70, .max_slope = 2, .priority = 12, @@ -552,7 +552,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.80, .max = 1.0 }, // Very hot .humidity = .{ .min = 0.0, .max = 0.20 }, // Very dry .elevation = .{ .min = 0.35, .max = 0.60 }, - .continentalness = .{ .min = 0.60, .max = 1.0 }, // Inland + .continentalness = .{ .min = 0.52, .max = 1.0 }, // Inland .ruggedness = .{ .min = 0.0, .max = 0.35 }, .max_height = 90, .max_slope = 4, @@ -571,7 +571,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.50, .max = 0.80 }, .humidity = .{ .min = 0.70, .max = 1.0 }, .elevation = .{ .min = 0.28, .max = 0.40 }, - .continentalness = .{ .min = 0.55, .max = 0.75 }, // Coastal to mid-inland + .continentalness = .{ .min = 0.48, .max = 0.75 }, // Coastal to mid-inland .ruggedness = .{ .min = 0.0, .max = 0.30 }, .max_slope = 3, .priority = 5, @@ -590,7 +590,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.0, .max = 0.25 }, .humidity = Range.any(), .elevation = .{ .min = 0.30, .max = 0.70 }, - .continentalness = .{ .min = 0.60, .max = 1.0 }, // Inland + .continentalness = .{ .min = 0.52, .max = 1.0 }, // Inland .min_height = 70, .max_slope = 255, .priority = 4, @@ -605,12 +605,12 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .name = "Mountains", .temperature = .{ .min = 0.25, .max = 1.0 }, .humidity = Range.any(), - .elevation = .{ .min = 0.62, .max = 1.0 }, - .continentalness = .{ .min = 0.72, .max = 1.0 }, // Must be inland high or core - .ruggedness = .{ .min = 0.60, .max = 1.0 }, - .min_height = 102, - .min_ridge_mask = 0.1, - .priority = 2, + .elevation = .{ .min = 0.42, .max = 1.0 }, + .continentalness = .{ .min = 0.54, .max = 1.0 }, // Must be inland high or core + .ruggedness = .{ .min = 0.30, .max = 1.0 }, + .min_height = 82, + .min_ridge_mask = 0.0, + .priority = 10, .surface = .{ .top = .stone, .filler = .stone, .depth_range = 1 }, .vegetation = .{ .tree_types = &.{.sparse_oak} }, .terrain = .{ .height_amplitude = 1.35, .smoothing = 0.04, .height_offset = 4.0 }, @@ -620,12 +620,12 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .name = "Snowy Mountains", .temperature = .{ .min = 0.0, .max = 0.35 }, .humidity = Range.any(), - .elevation = .{ .min = 0.62, .max = 1.0 }, - .continentalness = .{ .min = 0.72, .max = 1.0 }, - .ruggedness = .{ .min = 0.55, .max = 1.0 }, - .min_height = 112, + .elevation = .{ .min = 0.42, .max = 1.0 }, + .continentalness = .{ .min = 0.54, .max = 1.0 }, + .ruggedness = .{ .min = 0.30, .max = 1.0 }, + .min_height = 84, .max_slope = 255, - .priority = 2, + .priority = 10, .surface = .{ .top = .snow_block, .filler = .stone, .depth_range = 1 }, .vegetation = .{ .tree_types = &.{} }, .terrain = .{ .height_amplitude = 1.35, .smoothing = 0.05, .height_offset = 6.0 }, @@ -636,10 +636,10 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .name = "Meadow", .temperature = .{ .min = 0.25, .max = 0.65 }, .humidity = .{ .min = 0.35, .max = 0.85 }, - .elevation = .{ .min = 0.50, .max = 0.74 }, - .continentalness = .{ .min = 0.64, .max = 0.95 }, + .elevation = .{ .min = 0.45, .max = 0.74 }, + .continentalness = .{ .min = 0.60, .max = 0.95 }, .ruggedness = .{ .min = 0.20, .max = 0.68 }, - .min_height = 82, + .min_height = 78, .max_height = 122, .max_slope = 10, .priority = 7, @@ -657,13 +657,13 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .name = "Grove", .temperature = .{ .min = 0.05, .max = 0.35 }, .humidity = .{ .min = 0.45, .max = 0.95 }, - .elevation = .{ .min = 0.52, .max = 0.80 }, - .continentalness = .{ .min = 0.66, .max = 0.98 }, + .elevation = .{ .min = 0.46, .max = 0.80 }, + .continentalness = .{ .min = 0.60, .max = 0.98 }, .ruggedness = .{ .min = 0.25, .max = 0.78 }, - .min_height = 88, + .min_height = 82, .max_height = 132, .max_slope = 12, - .priority = 8, + .priority = 10, .surface = .{ .top = .podzol, .filler = .dirt, .depth_range = 3 }, .vegetation = .{ .tree_types = &.{.spruce}, .decoration_rules = &.{ .{ .block = .tall_grass, .place_on = &.{ .podzol, .grass }, .chance = 0.12 }, @@ -678,10 +678,10 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .name = "Snowy Slopes", .temperature = .{ .min = 0.0, .max = 0.22 }, .humidity = .{ .min = 0.20, .max = 0.85 }, - .elevation = .{ .min = 0.64, .max = 0.92 }, - .continentalness = .{ .min = 0.72, .max = 1.0 }, + .elevation = .{ .min = 0.56, .max = 0.92 }, + .continentalness = .{ .min = 0.66, .max = 1.0 }, .ruggedness = .{ .min = 0.42, .max = 0.90 }, - .min_height = 112, + .min_height = 98, .max_height = 165, .priority = 8, .surface = .{ .top = .snow_block, .filler = .stone, .depth_range = 1 }, @@ -697,11 +697,11 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .name = "Jagged Peaks", .temperature = .{ .min = 0.10, .max = 0.50 }, .humidity = .{ .min = 0.20, .max = 0.75 }, - .elevation = .{ .min = 0.78, .max = 1.0 }, - .continentalness = .{ .min = 0.78, .max = 1.0 }, - .ruggedness = .{ .min = 0.70, .max = 1.0 }, - .min_height = 136, - .min_ridge_mask = 0.45, + .elevation = .{ .min = 0.70, .max = 1.0 }, + .continentalness = .{ .min = 0.72, .max = 1.0 }, + .ruggedness = .{ .min = 0.62, .max = 1.0 }, + .min_height = 118, + .min_ridge_mask = 0.35, .priority = 9, .surface = .{ .top = .stone, .filler = .stone, .depth_range = 1 }, .vegetation = .{ .tree_types = &.{}, .decoration_rules = &.{ @@ -716,10 +716,10 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .name = "Frozen Peaks", .temperature = .{ .min = 0.0, .max = 0.18 }, .humidity = .{ .min = 0.15, .max = 0.70 }, - .elevation = .{ .min = 0.78, .max = 1.0 }, - .continentalness = .{ .min = 0.78, .max = 1.0 }, - .ruggedness = .{ .min = 0.58, .max = 1.0 }, - .min_height = 138, + .elevation = .{ .min = 0.70, .max = 1.0 }, + .continentalness = .{ .min = 0.72, .max = 1.0 }, + .ruggedness = .{ .min = 0.52, .max = 1.0 }, + .min_height = 120, .priority = 9, .surface = .{ .top = .packed_ice, .filler = .stone, .depth_range = 1 }, .vegetation = .{ .tree_types = &.{}, .decoration_rules = &.{ @@ -734,10 +734,10 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .name = "Stony Peaks", .temperature = .{ .min = 0.45, .max = 0.85 }, .humidity = .{ .min = 0.0, .max = 0.45 }, - .elevation = .{ .min = 0.74, .max = 1.0 }, - .continentalness = .{ .min = 0.78, .max = 1.0 }, - .ruggedness = .{ .min = 0.52, .max = 1.0 }, - .min_height = 132, + .elevation = .{ .min = 0.66, .max = 1.0 }, + .continentalness = .{ .min = 0.70, .max = 1.0 }, + .ruggedness = .{ .min = 0.46, .max = 1.0 }, + .min_height = 112, .priority = 8, .surface = .{ .top = .stone, .filler = .stone, .depth_range = 1 }, .vegetation = .{ .tree_types = &.{}, .decoration_rules = &.{ @@ -755,7 +755,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.7, .max = 0.9 }, .humidity = .{ .min = 0.8, .max = 1.0 }, .elevation = .{ .min = 0.2, .max = 0.4 }, - .continentalness = .{ .min = 0.45, .max = 0.60 }, // Coastal swamp + .continentalness = .{ .min = 0.42, .max = 0.60 }, // Coastal swamp .priority = 6, .surface = .{ .top = .mud, .filler = .mud, .depth_range = 4 }, .vegetation = .{ .tree_types = &.{.mangrove} }, @@ -768,7 +768,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.75, .max = 1.0 }, .humidity = .{ .min = 0.7, .max = 1.0 }, .elevation = .{ .min = 0.30, .max = 0.75 }, - .continentalness = .{ .min = 0.60, .max = 1.0 }, + .continentalness = .{ .min = 0.52, .max = 1.0 }, .priority = 5, .surface = .{ .top = .grass, .filler = .dirt, .depth_range = 3 }, .vegetation = .{ .tree_types = &.{.jungle}, .decoration_rules = &.{ @@ -867,7 +867,7 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .temperature = .{ .min = 0.7, .max = 1.0 }, .humidity = .{ .min = 0.0, .max = 0.3 }, .elevation = .{ .min = 0.4, .max = 0.8 }, - .continentalness = .{ .min = 0.70, .max = 1.0 }, + .continentalness = .{ .min = 0.62, .max = 1.0 }, .ruggedness = .{ .min = 0.4, .max = 1.0 }, .priority = 6, .surface = .{ .top = .red_sand, .filler = .terracotta, .depth_range = 5 }, @@ -1014,8 +1014,8 @@ pub const BIOME_REGISTRY: []const BiomeDefinition = &.{ .continentalness = .{ .min = -1.0, .max = -0.5 }, // IMPOSSIBLE: edge-injection only .ruggedness = .{ .min = 0.0, .max = 0.35 }, .priority = 0, // Lowest priority - .surface = .{ .top = .grass, .filler = .dirt, .depth_range = 3 }, - .vegetation = .{ .tree_types = &.{}, .decoration_rules = &.{.{ .block = .tall_grass, .place_on = &.{.grass}, .chance = 0.4 }} }, // No trees + .surface = .{ .top = .sand, .filler = .sand, .depth_range = 3 }, + .vegetation = .{ .tree_types = &.{} }, .terrain = .{ .height_amplitude = 0.5, .smoothing = 0.3 }, .colors = .{ .grass = .{ 0.24, 0.66, 0.24 }, .foliage = .{ 0.18, 0.52, 0.16 } }, }, diff --git a/modules/world-worldgen/src/biome_registry_tests.zig b/modules/world-worldgen/src/biome_registry_tests.zig index aeb2e2fe..4ba8beaf 100644 --- a/modules/world-worldgen/src/biome_registry_tests.zig +++ b/modules/world-worldgen/src/biome_registry_tests.zig @@ -349,11 +349,11 @@ test "getBiomeDefinition ocean biomes have correct continentalness ranges" { try testing.expect(deep.continentalness.max <= 0.20); const ocean = getBiomeDefinition(.ocean); - try testing.expect(ocean.continentalness.max <= 0.35); - try testing.expect(ocean.continentalness.min < 0.35); + try testing.expect(ocean.continentalness.max <= 0.37); + try testing.expect(ocean.continentalness.min < 0.37); const warm = getBiomeDefinition(.warm_ocean); - try testing.expect(warm.continentalness.max <= 0.35); + try testing.expect(warm.continentalness.max <= 0.37); try testing.expect(warm.vegetation.seagrass_density > 0.0); try testing.expect(warm.vegetation.coral_density > 0.0); } @@ -363,7 +363,7 @@ test "getBiomeDefinition cold ocean variants have expected identity" { try testing.expectEqualStrings("Frozen Ocean", frozen.name); try testing.expectEqual(.packed_ice, frozen.surface.top); try testing.expect(frozen.temperature.max <= 0.15); - try testing.expect(frozen.continentalness.max <= 0.35); + try testing.expect(frozen.continentalness.max <= 0.37); const cold = getBiomeDefinition(.cold_ocean); try testing.expectEqualStrings("Cold Ocean", cold.name); @@ -384,8 +384,8 @@ test "getBiomeDefinition cold coastal variants have expected surfaces" { try testing.expectEqualStrings("Stony Shore", stony.name); try testing.expectEqual(.stone, stony.surface.top); try testing.expectEqual(.gravel, stony.surface.filler); - try testing.expect(stony.continentalness.min >= 0.35); - try testing.expect(stony.continentalness.max <= 0.45); + try testing.expect(stony.continentalness.min >= 0.37); + try testing.expect(stony.continentalness.max <= 0.46); const snowy = getBiomeDefinition(.snowy_beach); try testing.expectEqualStrings("Snowy Beach", snowy.name); @@ -394,6 +394,14 @@ test "getBiomeDefinition cold coastal variants have expected surfaces" { try testing.expect(snowy.temperature.max <= 0.20); } +test "getBiomeDefinition coastal plains is sandy transition" { + const coastal = getBiomeDefinition(.coastal_plains); + try testing.expectEqualStrings("Coastal Plains", coastal.name); + try testing.expectEqual(.sand, coastal.surface.top); + try testing.expectEqual(.sand, coastal.surface.filler); + try testing.expectEqual(@as(usize, 0), coastal.vegetation.decoration_rules.len); +} + test "getBiomeDefinition frozen river is river override only" { const frozen_river = getBiomeDefinition(.frozen_river); try testing.expectEqualStrings("Frozen River", frozen_river.name); diff --git a/modules/world-worldgen/src/biome_selector.zig b/modules/world-worldgen/src/biome_selector.zig index 06df0693..49f91dc9 100644 --- a/modules/world-worldgen/src/biome_selector.zig +++ b/modules/world-worldgen/src/biome_selector.zig @@ -12,7 +12,7 @@ const BIOME_POINTS = registry.BIOME_POINTS; const BLEND_EPSILON = registry.BLEND_EPSILON; const NORMALIZED_SEA_LEVEL = registry.NORMALIZED_SEA_LEVEL; -const OCEAN_CONTINENTALNESS_MAX: f32 = 0.35; +const OCEAN_CONTINENTALNESS_MAX: f32 = 0.37; // ============================================================================ // Voronoi Biome Selection (Issue #106) diff --git a/modules/world-worldgen/src/biome_selector_tests.zig b/modules/world-worldgen/src/biome_selector_tests.zig index b99699d1..e1a4570a 100644 --- a/modules/world-worldgen/src/biome_selector_tests.zig +++ b/modules/world-worldgen/src/biome_selector_tests.zig @@ -9,6 +9,7 @@ const std = @import("std"); const testing = std.testing; const selector = @import("biome_selector.zig"); +const edge_detector = @import("biome_edge_detector.zig"); const registry = @import("biome_registry.zig"); const BiomeId = registry.BiomeId; @@ -298,6 +299,12 @@ test "selectBiomeWithConstraints locks baseline climate and structural selection } } +test "beach transitions to coastal plains before common inland biomes" { + try testing.expectEqual(BiomeId.coastal_plains, edge_detector.getTransitionBiome(.beach, .plains).?); + try testing.expectEqual(BiomeId.coastal_plains, edge_detector.getTransitionBiome(.forest, .beach).?); + try testing.expectEqual(BiomeId.coastal_plains, edge_detector.getTransitionBiome(.beach, .swamp).?); +} + test "selectBiomeWithConstraintsAndRiver locks river and frozen river priority" { const temperate = ClimateParams{ .temperature = 0.5, diff --git a/modules/world-worldgen/src/biome_source.zig b/modules/world-worldgen/src/biome_source.zig index a0d43994..5bb65ea9 100644 --- a/modules/world-worldgen/src/biome_source.zig +++ b/modules/world-worldgen/src/biome_source.zig @@ -23,7 +23,7 @@ pub const BiomeResult = struct { pub const BiomeSourceParams = struct { sea_level: i32 = 64, edge_detection_enabled: bool = true, - ocean_threshold: f32 = 0.35, + ocean_threshold: f32 = 0.37, }; /// Unified biome selection interface. diff --git a/modules/world-worldgen/src/height_sampler.zig b/modules/world-worldgen/src/height_sampler.zig index 4d65c5f9..3d73ae04 100644 --- a/modules/world-worldgen/src/height_sampler.zig +++ b/modules/world-worldgen/src/height_sampler.zig @@ -36,27 +36,27 @@ pub const HeightParams = struct { sea_level: i32 = 64, // Continental zone thresholds - ocean_threshold: f32 = 0.35, + ocean_threshold: f32 = 0.37, continental_deep_ocean_max: f32 = 0.20, - continental_coast_max: f32 = 0.42, - continental_inland_low_max: f32 = 0.60, - continental_inland_high_max: f32 = 0.75, + continental_coast_max: f32 = 0.44, + continental_inland_low_max: f32 = 0.58, + continental_inland_high_max: f32 = 0.72, // Mountains - mount_amp: f32 = 60.0, - mount_cap: f32 = 120.0, - mount_inland_min: f32 = 0.60, - mount_inland_max: f32 = 0.80, - mount_peak_min: f32 = 0.55, - mount_peak_max: f32 = 0.85, - mount_rugged_min: f32 = 0.35, - mount_rugged_max: f32 = 0.75, + mount_amp: f32 = 78.0, + mount_cap: f32 = 140.0, + mount_inland_min: f32 = 0.56, + mount_inland_max: f32 = 0.76, + mount_peak_min: f32 = 0.50, + mount_peak_max: f32 = 0.82, + mount_rugged_min: f32 = 0.32, + mount_rugged_max: f32 = 0.72, // Ridges - ridge_amp: f32 = 25.0, - ridge_inland_min: f32 = 0.50, - ridge_inland_max: f32 = 0.70, - ridge_sparsity: f32 = 0.50, + ridge_amp: f32 = 34.0, + ridge_inland_min: f32 = 0.48, + ridge_inland_max: f32 = 0.68, + ridge_sparsity: f32 = 0.46, // Detail highland_range: f32 = 80.0, @@ -276,7 +276,8 @@ pub const HeightSampler = struct { // ============================================================ // STEP 4: LAND - Combine V7 terrain with continental base // ============================================================ - var height = self.getBaseHeight(noise.continentalness) + v7_terrain - path_effects.depth; + const coastal_ramp = smoothstep(p.ocean_threshold, p.continental_coast_max, noise.continentalness); + var height = self.getBaseHeight(noise.continentalness) + v7_terrain * coastal_ramp - path_effects.depth * coastal_ramp; // ============================================================ // STEP 5: Mountains & Ridges - REGION-CONSTRAINED @@ -302,7 +303,7 @@ pub const HeightSampler = struct { // ============================================================ const erosion_smooth = smoothstep(0.5, 0.75, noise.erosion); const land_factor = smoothstep(p.continental_coast_max, p.continental_inland_low_max, noise.continentalness); - const hills_atten = (1.0 - erosion_smooth) * land_factor * (1.0 - path_effects.slope_suppress); + const hills_atten = (1.0 - erosion_smooth) * land_factor * coastal_ramp * (1.0 - path_effects.slope_suppress); // Small-scale detail const elev01 = clamp01((height - sea) / p.highland_range); @@ -402,8 +403,8 @@ test "HeightSampler ocean detection" { const sampler = HeightSampler.init(); try std.testing.expect(sampler.isOcean(0.0)); - try std.testing.expect(sampler.isOcean(0.34)); - try std.testing.expect(!sampler.isOcean(0.35)); + try std.testing.expect(sampler.isOcean(0.36)); + try std.testing.expect(!sampler.isOcean(0.37)); try std.testing.expect(!sampler.isOcean(0.5)); } diff --git a/modules/world-worldgen/src/height_sampler_tests.zig b/modules/world-worldgen/src/height_sampler_tests.zig index 9e7b7291..4415de6d 100644 --- a/modules/world-worldgen/src/height_sampler_tests.zig +++ b/modules/world-worldgen/src/height_sampler_tests.zig @@ -91,7 +91,8 @@ test "HeightSampler isOcean at deep ocean value" { test "HeightSampler isOcean at exactly threshold" { const sampler = HeightSampler.init(); - try testing.expect(!sampler.isOcean(0.35)); + try testing.expect(sampler.isOcean(0.35)); + try testing.expect(!sampler.isOcean(0.37)); } test "HeightSampler isOcean inland values return false" { diff --git a/modules/world-worldgen/src/noise_sampler.zig b/modules/world-worldgen/src/noise_sampler.zig index 5fcd20b2..8d043c0f 100644 --- a/modules/world-worldgen/src/noise_sampler.zig +++ b/modules/world-worldgen/src/noise_sampler.zig @@ -39,7 +39,7 @@ pub const ClimateConfig = struct { temperature_local_scale: f32 = 1.0 / 200.0, humidity_macro_scale: f32 = 1.0 / 2000.0, humidity_local_scale: f32 = 1.0 / 200.0, - climate_macro_weight: f32 = 0.75, + climate_macro_weight: f32 = 0.65, }; /// Configuration parameters for terrain noise @@ -54,8 +54,8 @@ pub const TerrainConfig = struct { seabed_scale: f32 = 1.0 / 100.0, seabed_amp: f32 = 2.0, river_scale: f32 = 1.0 / 800.0, - river_min: f32 = 0.90, - river_max: f32 = 0.95, + river_min: f32 = 0.86, + river_max: f32 = 0.93, ridge_scale: f32 = 1.0 / 400.0, }; @@ -164,26 +164,26 @@ pub const NoiseSampler = struct { .warp_noise_z = ConfiguredNoise.init(makeNoiseParams(seed, 11, 200, tc.warp_amplitude, 0, 3, 0.5)), // Continental structure - .continentalness_noise = ConfiguredNoise.init(makeNoiseParams(seed, 20, 1500, 1.0, 0, 4, 0.5)), - .erosion_noise = ConfiguredNoise.init(makeNoiseParams(seed, 30, 400, 1.0, 0, 4, 0.5)), - .peaks_noise = ConfiguredNoise.init(makeNoiseParams(seed, 40, 300, 1.0, 0, 5, 0.5)), + .continentalness_noise = ConfiguredNoise.init(makeNoiseParams(seed, 20, 900, 1.0, 0, 4, 0.5)), + .erosion_noise = ConfiguredNoise.init(makeNoiseParams(seed, 30, 360, 1.0, 0, 4, 0.5)), + .peaks_noise = ConfiguredNoise.init(makeNoiseParams(seed, 40, 260, 1.0, 0, 5, 0.5)), // Climate - .temperature_noise = ConfiguredNoise.init(makeNoiseParams(seed, 50, 2000, 1.0, 0, 3, 0.5)), - .humidity_noise = ConfiguredNoise.init(makeNoiseParams(seed, 60, 2000, 1.0, 0, 3, 0.5)), + .temperature_noise = ConfiguredNoise.init(makeNoiseParams(seed, 50, 1400, 1.0, 0, 3, 0.5)), + .humidity_noise = ConfiguredNoise.init(makeNoiseParams(seed, 60, 1400, 1.0, 0, 3, 0.5)), .temperature_local_noise = ConfiguredNoise.init(makeNoiseParams(seed, 70, 200, 1.0, 0, 3, 0.5)), .humidity_local_noise = ConfiguredNoise.init(makeNoiseParams(seed, 80, 200, 1.0, 0, 3, 0.5)), // Terrain detail .detail_noise = ConfiguredNoise.init(makeNoiseParams(seed, 90, 32, tc.detail_amp, 0, 3, 0.5)), - .coast_jitter_noise = ConfiguredNoise.init(makeNoiseParams(seed, 100, 150, 0.03, 0, 2, 0.5)), + .coast_jitter_noise = ConfiguredNoise.init(makeNoiseParams(seed, 100, 130, 0.035, 0, 2, 0.5)), .seabed_noise = ConfiguredNoise.init(makeNoiseParams(seed, 110, 100, tc.seabed_amp, 0, 2, 0.5)), .beach_exposure_noise = ConfiguredNoise.init(makeNoiseParams(seed, 130, 100, 1.0, 0, 3, 0.5)), .filler_depth_noise = ConfiguredNoise.init(makeNoiseParams(seed, 140, 64, 1.0, 0, 3, 0.5)), // Mountains & ridges - .mountain_lift_noise = ConfiguredNoise.init(makeNoiseParams(seed, 150, 400, 1.0, 0, 3, 0.5)), - .ridge_noise = ConfiguredNoise.init(makeNoiseParams(seed, 160, 400, 1.0, 0, 5, 0.5)), + .mountain_lift_noise = ConfiguredNoise.init(makeNoiseParams(seed, 150, 340, 1.0, 0, 3, 0.5)), + .ridge_noise = ConfiguredNoise.init(makeNoiseParams(seed, 160, 340, 1.0, 0, 5, 0.5)), // Rivers .river_noise = ConfiguredNoise.init(makeNoiseParams(seed, 120, 800, 1.0, 0, 4, 0.5)), @@ -247,7 +247,7 @@ pub const NoiseSampler = struct { const macro = self.temperature_noise.get2DNormalizedOctaves(x, z, macro_octaves); const local = self.temperature_local_noise.get2DNormalizedOctaves(x, z, local_octaves); var t = cc.climate_macro_weight * macro + (1.0 - cc.climate_macro_weight) * local; - t = (t - 0.5) * 2.2 + 0.5; + t = (t - 0.5) * 2.45 + 0.5; return clamp01(t); } @@ -260,7 +260,7 @@ pub const NoiseSampler = struct { const macro = self.humidity_noise.get2DNormalizedOctaves(x, z, macro_octaves); const local = self.humidity_local_noise.get2DNormalizedOctaves(x, z, local_octaves); var h = cc.climate_macro_weight * macro + (1.0 - cc.climate_macro_weight) * local; - h = (h - 0.5) * 2.2 + 0.5; + h = (h - 0.5) * 2.45 + 0.5; return clamp01(h); } diff --git a/modules/world-worldgen/src/registry.zig b/modules/world-worldgen/src/registry.zig index 06734603..41d9efdd 100644 --- a/modules/world-worldgen/src/registry.zig +++ b/modules/world-worldgen/src/registry.zig @@ -43,7 +43,7 @@ fn initOverworld(seed: u64, allocator: std.mem.Allocator) RegistryError!Generato OverworldGenerator.initWithParams(seed, allocator, deco_registry.StandardDecorationProvider.provider(), .{ .terrain_shape = .{ .sea_level = if (restore_water) 64 else -1, - .ocean_threshold = if (restore_water) 0.35 else -1.0, + .ocean_threshold = if (restore_water) 0.37 else -1.0, .disable_caves = !restore_caves, }, .basic_chunks_only = !restore_decorations, diff --git a/modules/world-worldgen/src/surface_builder.zig b/modules/world-worldgen/src/surface_builder.zig index 8d030bdf..056885cf 100644 --- a/modules/world-worldgen/src/surface_builder.zig +++ b/modules/world-worldgen/src/surface_builder.zig @@ -37,14 +37,14 @@ pub const SurfaceParams = struct { sea_level: i32 = 64, // Beach constraints - beach_max_height_above_sea: i32 = 3, + beach_max_height_above_sea: i32 = 6, beach_max_slope: i32 = 2, cliff_min_slope: i32 = 5, gravel_erosion_threshold: f32 = 0.7, // Coastal zone (continentalness thresholds) - ocean_threshold: f32 = 0.35, - beach_band: f32 = 0.05, // Width of beach zone in continentalness units + ocean_threshold: f32 = 0.37, + beach_band: f32 = 0.07, // Width of beach zone in continentalness units }; // ============================================================================ @@ -216,7 +216,8 @@ pub const SurfaceBuilder = struct { var block = self.getBlockAt(y, terrain_height, biome, filler_depth, is_ocean_water, is_underwater); const is_surface = (y == terrain_height); - const is_near_surface = (y > terrain_height - 3 and y <= terrain_height); + const coastal_fill_depth = @max(filler_depth, 6); + const is_coastal_fill = (y > terrain_height - coastal_fill_depth and y <= terrain_height); // Apply structural coastal surface types (ocean beaches only) if (is_surface and block != .air and block != .water and block != .bedrock) { @@ -226,7 +227,7 @@ pub const SurfaceBuilder = struct { .cliff => block = .stone, .none => {}, } - } else if (is_near_surface and (coastal_type == .sand_beach or coastal_type == .gravel_beach) and block == .dirt) { + } else if (is_coastal_fill and (coastal_type == .sand_beach or coastal_type == .gravel_beach) and block != .air and block != .water and block != .bedrock) { block = if (coastal_type == .gravel_beach) .gravel else .sand; } @@ -268,6 +269,26 @@ test "SurfaceBuilder coastal type detection" { try std.testing.expectEqual(CoastalSurfaceType.none, high); } +test "SurfaceBuilder beach band matches coastal biome range" { + const builder = SurfaceBuilder.init(); + + const upper_beach = builder.getCoastalSurfaceType(0.41, 1, 70, 0.3); + try std.testing.expectEqual(CoastalSurfaceType.sand_beach, upper_beach); + + const inland = builder.getCoastalSurfaceType(0.45, 1, 70, 0.3); + try std.testing.expectEqual(CoastalSurfaceType.none, inland); +} + +test "SurfaceBuilder coastal beach replaces exposed filler" { + const builder = SurfaceBuilder.init(); + + const deep_fill = builder.getSurfaceBlock(65, 70, .plains, 3, false, false, .sand_beach); + try std.testing.expectEqual(BlockType.sand, deep_fill); + + const below_fill = builder.getSurfaceBlock(63, 70, .plains, 3, false, false, .sand_beach); + try std.testing.expectEqual(BlockType.stone, below_fill); +} + test "SurfaceBuilder bedrock at y=0" { const builder = SurfaceBuilder.init(); const block = builder.getBlockAt(0, 50, .plains, 3, false, false); diff --git a/modules/world-worldgen/src/terrain_report.zig b/modules/world-worldgen/src/terrain_report.zig index 3af0a34b..0ea5a180 100644 --- a/modules/world-worldgen/src/terrain_report.zig +++ b/modules/world-worldgen/src/terrain_report.zig @@ -10,7 +10,7 @@ const Allocator = std.mem.Allocator; const BiomeId = biome_mod.BiomeId; const CHUNK_SIZE_Y = world_core.CHUNK_SIZE_Y; -pub const representative_seeds = [_]u64{ 42, 424242, 987654321 }; +pub const representative_seeds = [_]u64{ 42, 1337, 424242, 8675309, 987654321 }; pub const default_origin_x: i32 = -256; pub const default_origin_z: i32 = -256; pub const default_width: u32 = 512; @@ -478,3 +478,35 @@ test "TerrainReport role profiles preserve region pacing controls" { try std.testing.expect(forest.vegetation_multiplier > boundary.vegetation_multiplier); try std.testing.expect(forest.subbiome_mask > transit.subbiome_mask); } + +test "representative seeds keep varied but readable spawn regions" { + const allocator = std.testing.allocator; + + var total_samples: u32 = 0; + var ocean_samples: u32 = 0; + var forest_samples: u32 = 0; + var wetland_samples: u32 = 0; + var dry_samples: u32 = 0; + var mountain_samples: u32 = 0; + + for (representative_seeds) |seed| { + const report = try sampleRegion(allocator, seed, -128, -128, 256, 256); + try std.testing.expect(report.ocean_ratio <= 0.30); + try std.testing.expect(report.sea_level_coverage <= 0.30); + try std.testing.expect(report.mountain_coverage <= 0.12); + + total_samples += report.sample_count; + ocean_samples += report.biomeCount(.ocean) + report.biomeCount(.warm_ocean) + report.biomeCount(.cold_ocean) + report.biomeCount(.frozen_ocean) + report.biomeCount(.deep_ocean); + forest_samples += report.biomeCount(.forest) + report.biomeCount(.birch_forest) + report.biomeCount(.dark_forest) + report.biomeCount(.flower_forest) + report.biomeCount(.taiga) + report.biomeCount(.snowy_taiga) + report.biomeCount(.old_growth_taiga) + report.biomeCount(.jungle) + report.biomeCount(.bamboo_jungle) + report.biomeCount(.sparse_jungle); + wetland_samples += report.biomeCount(.swamp) + report.biomeCount(.mangrove_swamp); + dry_samples += report.biomeCount(.desert) + report.biomeCount(.savanna) + report.biomeCount(.savanna_plateau) + report.biomeCount(.windswept_savanna) + report.biomeCount(.badlands) + report.biomeCount(.wooded_badlands) + report.biomeCount(.eroded_badlands); + mountain_samples += @intFromFloat(report.mountain_coverage * @as(f64, @floatFromInt(report.sample_count))); + } + + const denominator: f64 = @floatFromInt(total_samples); + try std.testing.expect(@as(f64, @floatFromInt(ocean_samples)) / denominator >= 0.03); + try std.testing.expect(@as(f64, @floatFromInt(forest_samples)) / denominator >= 0.08); + try std.testing.expect(@as(f64, @floatFromInt(wetland_samples)) / denominator >= 0.005); + try std.testing.expect(@as(f64, @floatFromInt(dry_samples)) / denominator >= 0.003); + try std.testing.expect(@as(f64, @floatFromInt(mountain_samples)) / denominator >= 0.002); +} diff --git a/modules/world-worldgen/src/terrain_shape_generator.zig b/modules/world-worldgen/src/terrain_shape_generator.zig index d3f3f3a3..0db11955 100644 --- a/modules/world-worldgen/src/terrain_shape_generator.zig +++ b/modules/world-worldgen/src/terrain_shape_generator.zig @@ -29,10 +29,10 @@ const CoastalGenerator = @import("coastal_generator.zig").CoastalGenerator; pub const Params = struct { temp_lapse: f32 = 0.25, sea_level: i32 = 64, - ocean_threshold: f32 = 0.35, - ridge_inland_min: f32 = 0.50, - ridge_inland_max: f32 = 0.70, - ridge_sparsity: f32 = 0.50, + ocean_threshold: f32 = 0.37, + ridge_inland_min: f32 = 0.48, + ridge_inland_max: f32 = 0.68, + ridge_sparsity: f32 = 0.46, disable_caves: bool = false, }; diff --git a/modules/world-worldgen/src/terrain_shape_generator_tests.zig b/modules/world-worldgen/src/terrain_shape_generator_tests.zig index 5ca2953c..1d206712 100644 --- a/modules/world-worldgen/src/terrain_shape_generator_tests.zig +++ b/modules/world-worldgen/src/terrain_shape_generator_tests.zig @@ -68,10 +68,10 @@ test "Params default values" { const params = Params{}; try testing.expectEqual(@as(f32, 0.25), params.temp_lapse); try testing.expectEqual(@as(i32, 64), params.sea_level); - try testing.expectEqual(@as(f32, 0.35), params.ocean_threshold); - try testing.expectEqual(@as(f32, 0.50), params.ridge_inland_min); - try testing.expectEqual(@as(f32, 0.70), params.ridge_inland_max); - try testing.expectEqual(@as(f32, 0.50), params.ridge_sparsity); + try testing.expectEqual(@as(f32, 0.37), params.ocean_threshold); + try testing.expectEqual(@as(f32, 0.48), params.ridge_inland_min); + try testing.expectEqual(@as(f32, 0.68), params.ridge_inland_max); + try testing.expectEqual(@as(f32, 0.46), params.ridge_sparsity); try testing.expect(!params.disable_caves); } diff --git a/src/worldgen_tests.zig b/src/worldgen_tests.zig index 3806698e..042756ec 100644 --- a/src/worldgen_tests.zig +++ b/src/worldgen_tests.zig @@ -218,9 +218,9 @@ test "WorldGen stable chunk fingerprints for known seed" { }; const expected = [_]u64{ - 1589085686761579315, - 3398558120687224261, - 12563833883354114501, + 11844084116277698429, + 9139389730069537271, + 8491863551076282083, }; for (positions, 0..) |pos, i| { @@ -318,7 +318,7 @@ test "Biome structural constraints - height filter" { const selectBiomeWithConstraints = biome_mod.selectBiomeWithConstraints; const snowy_mountains = getBiomeDefinition(.snowy_mountains); - try testing.expect(snowy_mountains.min_height == 112); + try testing.expect(snowy_mountains.min_height == 84); const climate_low = ClimateParams{ .temperature = 0.3, @@ -350,7 +350,7 @@ test "Biome structural constraints - height filter" { .ridge_mask = 0.3, }; const biome_at_high_elev = selectBiomeWithConstraints(climate_high, structural_high); - try testing.expect(biome_at_high_elev == .snowy_mountains or biome_at_high_elev == .snowy_slopes); + try testing.expect(biome_mod.isMountainFamilyTerrainBiome(biome_at_high_elev)); } test "Biome structural constraints - slope filter" { @@ -863,8 +863,8 @@ test "HeightSampler ocean detection" { const sampler = HeightSampler.init(); try testing.expect(sampler.isOcean(0.0)); - try testing.expect(sampler.isOcean(0.34)); - try testing.expect(!sampler.isOcean(0.35)); + try testing.expect(sampler.isOcean(0.36)); + try testing.expect(!sampler.isOcean(0.37)); try testing.expect(!sampler.isOcean(0.5)); }