using Godot; /// /// The terrain DETAIL passes (terrain-water task 10) — pure numeric functions /// (D-035; a named future C++ candidate, kept standalone): /// /// PASS A — shelf micro-relief: a medium-frequency noise skin (±ShelfReliefAmp, /// default 3 m) weighted by shelf-ness, so the compressed shelves get their /// rolling texture back while risers and peaks stay untouched. /// /// PASS B — shelf-edge variation: a per-column shift of the shelf/riser KNOT /// BLOCK (K3/K4/K5) by a low-frequency noise field, so the boundary where a /// shelf meets its riser wanders in and out instead of tracing a clean height /// contour — organic notches, coves and peninsulas at the shelf edge. /// /// Both are output-height only; the classify map never sees either of them. /// /// NOTE — what this file deliberately does NOT contain: the task-10 draft's D8 /// flow routing / accumulation / drainage incision. It shipped, produced the /// canonical grid artifact (thousands of straight, disconnected, pooling /// scratches along the D8 neighbour directions) and was reverted whole. Rivers /// and erosion are Phase C work — a hydraulic-erosion pass over FINAL terrain, /// not a per-cell steepest-descent carve on a grid. /// public static class TerrainDetailPass { // The TDTL body version is owned by the format (Core); the pass just stamps it. public const ushort VERSION = IslaApocalypse.Core.BlueprintFormat.TDTL_VERSION; // Pass A — micro-relief. public const float RELIEF_AMP_DEFAULT_M = 3f; // config dial: ShelfReliefAmp (metres) public const float RELIEF_FREQ_ISLANDS = 40f; // ~40 undulations per island width (~200 m features) public const int RELIEF_SEED_OFFSET = 7409; // Pass B — shelf-edge variation. The amplitude is stated in metres of INPUT // height (raw × 251): it is how far, in raw-height terms, a shelf boundary // contour is displaced — not an output elevation change. What the eye sees is // the LATERAL wander, which is that displacement divided by the local raw // gradient. Measured on seed 1375359975: |∇raw| at the K3/K4/K5 contours is // p50 0.00088 raw/px, so 12 m of input height buys a median peak displacement // of ~54 px and a mean of ~8 px along the boundary — coves and notches, which // is where the developer's sketch sits. 5 m (the first try) moved the boundary // a mean 3.7 px and was invisible at map scale. public const float EDGE_AMP_DEFAULT_M = 12f; // config dial: ShelfEdgeVariation (metres of input height) public const float EDGE_FREQ_ISLANDS = 20f; // ~410 px wavelength at 8K — coves and notches at the public const int EDGE_SEED_OFFSET = 7507; // scale of the sketch, not a fringe of teeth // The shift squeezes whichever of the foothill riser / plateau bands it moves // into. Bounding it at 2/3 of the smaller band means that band never compresses // below a THIRD of its nominal width — i.e. its slope never more than triples, // even where peak noise lands on a boundary. That is the real constraint; knot // ordering follows from it. public const float EDGE_SAFETY_FRACTION = 2f / 3f; /// /// The largest per-column knot shift this preset allows: bounded by the band /// squeeze above, which also keeps the knot set strictly ordered /// (K2 < K3+d, K5+d < K6) with a third of each band to spare. K1/K2/K6 never /// move, so the toe, the orange/red bands and the summit spike are /// bit-identical whatever the warp does — which is what makes the red-ceiling /// floor and the 420 m cap exact rather than statistical. /// public static float MaxEdgeShift(CurveKnots k) { return EDGE_SAFETY_FRACTION * Mathf.Min(k.K3 - k.K2, k.K6 - k.K5); } /// /// Shelf-ness weight from the RAW input height: 1 mid-shelf, feathering to 0 /// through the risers (feather extends 30 % of the band half-width past each /// shelf edge). Covers both shelves. is the same /// per-column warp the curve is evaluated with, so the micro-relief skin /// follows the shelf wherever pass B has moved its boundary. /// public static float ShelfWeight(float raw, CurveKnots k, float edgeShift) { return Mathf.Max(BandBump(raw, k.K3 + edgeShift, k.K4 + edgeShift), BandBump(raw, k.K5 + edgeShift, k.K6)); } private static float BandBump(float h, float lo, float hi) { float half = (hi - lo) * 0.5f; float t = Mathf.Abs(h - (lo + half)) / half; // 0 centre, 1 at band edge // full inside 60 % of the band, linear feather to zero at 130 % return Mathf.Clamp(1f - (t - 0.6f) / 0.7f, 0f, 1f); } }