Files
Ransom-s-wake/tools/sites/terrain_showcase_recipe.gd
T
OlivierandClaude Fable 5.1 d91e6bd02f fix(tools): canyons impose a floor material through rock outcrops; tighten showcase contracts
Review findings: the mesa forced rock onto the canyon bed, two runners
declared the wrong TEST_COUNT, and the escarpment check could pass on the
slope alone. Canyon gains floor_material, the showcase is re-baked with sand
beds, the contract measures the step across the crest band, counts distinct
ledges, and probes the crevasse against the open plateau. Degenerate recipe
parameters now fail an assert.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 22:00:24 +02:00

114 lines
5.5 KiB
GDScript

extends RefCounted
## Catalogue site « Jardin des Formes »: one quarter per reference landform
## (docs/briefs/terrain-varied-landforms.md §5). No wreck, no route; a single
## mooring beacon at the centre. Field 512 x 512 m at 1 m, +X east, +Z south.
const SiteTerrainBaker = preload("res://tools/site_terrain_baker.gd")
const SonarMaterial = preload("res://game/domain/sonar/sonar_material.gd")
const SiteTerrainData = preload("res://game/domain/sites/site_terrain_data.gd")
const DiveSiteDefinition = preload("res://game/domain/sites/dive_site_definition.gd")
const SitePlacement = preload("res://game/domain/sites/site_placement.gd")
# North-west: stratified canyon cut through a mesa.
const MESA_CENTRE := Vector2(-120.0, -130.0)
const CANYON_PATH: Array[Vector2] = [
Vector2(-205.0, -85.0), Vector2(-150.0, -120.0), Vector2(-110.0, -150.0), Vector2(-60.0, -200.0),
]
const CANYON_HALF_WIDTH_M := 14.0
const CANYON_DEPTH_M := 20.0
# North-east: crevasse between two buttes.
const WEST_BUTTE_CENTRE := Vector2(80.0, -120.0)
const EAST_BUTTE_CENTRE := Vector2(165.0, -125.0)
const CREVASSE_PATH: Array[Vector2] = [
Vector2(122.0, -200.0), Vector2(118.0, -160.0), Vector2(124.0, -120.0), Vector2(119.0, -80.0), Vector2(123.0, -40.0),
]
const CREVASSE_HALF_WIDTH_M := 3.0
const CREVASSE_DEPTH_M := 20.0
# South-west: boulder field on rippled sand.
const BOULDER_FIELD_CENTRE := Vector2(-120.0, 110.0)
const BOULDER_FIELD_RADIUS_M := 75.0
# South-east: two rock spurs framing a sand channel.
const WEST_SPUR_CENTRE := Vector2(80.0, 120.0)
const EAST_SPUR_CENTRE := Vector2(170.0, 125.0)
const CHANNEL_CENTRE := Vector2(125.0, 120.0)
# South: sinuous escarpment with rounded knolls on the slope below.
const ESCARPMENT_PATH: Array[Vector2] = [
Vector2(-270.0, 215.0), Vector2(-150.0, 205.0), Vector2(-40.0, 225.0), Vector2(60.0, 205.0),
Vector2(170.0, 228.0), Vector2(270.0, 210.0),
]
const ESCARPMENT_DROP_M := 22.0
static func recipe() -> SiteTerrainBaker.Recipe:
var result := SiteTerrainBaker.Recipe.new()
result.columns = 513
result.rows = 513
result.cell_size_m = 1.0
result.origin_x_m = -256.0
result.origin_z_m = -256.0
result.floor_elevation_m = -80.0
result.rock_slope_degrees = 20.0
result.rock_reflectivity = 0.72
result.sand_reflectivity = 0.45
result.primitives = [
# Base plateau: 30 m deep at the centre, 4 m deeper over the 500 m southward.
SiteTerrainBaker.SlopedPlane.new(30.0, 0.0, -0.008, 0.0, 0.0),
# NW — la Mesa fendue: flat rock plateau 6 m high, 20 m deep canyon with a
# 14 m wide flat floor, 55 degree walls cut into 4 m ledges by the Strata
# modifier (one ledge every 2.8 m across, resolvable at 1 m per cell), rippled
# sand on the floor.
SiteTerrainBaker.Outcrop.new(MESA_CENTRE, 95.0, 85.0, 6.0, 10.0, 101, 6.0, true),
SiteTerrainBaker.Canyon.new(PackedVector2Array(CANYON_PATH), CANYON_HALF_WIDTH_M, CANYON_DEPTH_M, 7.0, 102, 2.0, SonarMaterial.Value.SAND),
SiteTerrainBaker.Ripples.new(Vector2(0.8, -0.6), 4.0, 0.25, Vector2(-130.0, -140.0), 70.0),
# NE — la Fente: two buttes 8-9 m high with a 6 m wide, 20 m deep slot between them.
SiteTerrainBaker.Outcrop.new(WEST_BUTTE_CENTRE, 38.0, 70.0, 8.0, 8.0, 201, 5.0, true),
SiteTerrainBaker.Outcrop.new(EAST_BUTTE_CENTRE, 38.0, 75.0, 9.0, 8.0, 202, 5.0, true),
SiteTerrainBaker.Canyon.new(PackedVector2Array(CREVASSE_PATH), CREVASSE_HALF_WIDTH_M, CREVASSE_DEPTH_M, 1.0, 203, 1.0, SonarMaterial.Value.SAND),
# SW — le Chaos: ninety boulders of 2-6 m radius plus six coral heads, on rippled sand.
SiteTerrainBaker.BoulderField.new(BOULDER_FIELD_CENTRE, BOULDER_FIELD_RADIUS_M, 301, 90, 2.0, 6.0, 0.7),
SiteTerrainBaker.BoulderField.new(Vector2(-100.0, 130.0), 40.0, 302, 6, 6.0, 9.0, 0.6),
SiteTerrainBaker.Ripples.new(Vector2(1.0, 0.3), 3.5, 0.3, BOULDER_FIELD_CENTRE, 110.0),
# SE — les Éperons: two pitted rock spurs 6-7 m high framing a 20 m sand channel
# littered with small blocks.
SiteTerrainBaker.Outcrop.new(WEST_SPUR_CENTRE, 30.0, 60.0, 7.0, 5.0, 401, 7.0, true),
SiteTerrainBaker.Outcrop.new(EAST_SPUR_CENTRE, 30.0, 55.0, 6.0, 5.0, 402, 7.0, true),
SiteTerrainBaker.BoulderField.new(CHANNEL_CENTRE, 50.0, 403, 12, 1.5, 3.0, 0.8),
# S — la Corniche: sinuous 22 m escarpment, then a 42 degree slope to the 80 m floor,
# with rounded knolls on the slope.
SiteTerrainBaker.Escarpment.new(PackedVector2Array(ESCARPMENT_PATH), ESCARPMENT_DROP_M, 6.0, 0.9, 501, 8.0),
SiteTerrainBaker.Outcrop.new(Vector2(-60.0, 240.0), 12.0, 10.0, 5.0, 10.0, 502, 2.0, true),
SiteTerrainBaker.Outcrop.new(Vector2(40.0, 236.0), 10.0, 9.0, 4.0, 9.0, 503, 2.0, true),
SiteTerrainBaker.Outcrop.new(Vector2(130.0, 245.0), 14.0, 11.0, 6.0, 11.0, 504, 2.0, true),
# Roughness: broad undulation plus cell-scale pitting.
SiteTerrainBaker.Roughness.new(1933, 0.02, 0.6),
SiteTerrainBaker.Roughness.new(2027, 0.15, 0.2),
]
result.modifiers = [
# Strata on the mesa flanks and canyon walls only: 4 m ledges.
SiteTerrainBaker.Strata.new(4.0, 0.85, 30.0, 50.0, MESA_CENTRE, 130.0),
]
return result
static func definition(terrain: SiteTerrainData) -> DiveSiteDefinition:
var result := DiveSiteDefinition.new()
result.site_id = &"terrain_showcase"
result.display_name = "Jardin des Formes"
result.terrain = terrain
result.playable_bounds_m = Rect2(-220.0, -220.0, 440.0, 440.0)
result.spawn_position_m = Vector3(0.0, -12.0, 0.0)
result.spawn_yaw_radians = 0.0
var anchor := SitePlacement.new()
anchor.placement_id = &"vessel_anchor"
anchor.kind = SitePlacement.Kind.VESSEL_ANCHOR
anchor.position_m = Vector3(0.0, -16.0, 0.0)
result.placements = [anchor]
return result