using System;
namespace IslaApocalypse.Tools
{
///
/// ⭐ THE SOUTHERN STRETCH (chat2/08, EXPLORATION) — the one deliberate relaxation of sea identity,
/// confined to a FIXED feathered latitude band.
///
/// ═══ THE MECHANISM (read from pass 1, chat2/08 diagnostic) ═══
///
/// Pass 1's mask is falloff = ½·ellipse + ½·squircle (+ edge noise · squircle), then the SOUTHERN
/// SINKER adds 0.6 · (y − 0.75N)/(0.25N) for y > 0.75N, BEFORE the 2.5 power; the coast sits
/// where rawBase − falloff^2.5 crosses sea, i.e. near falloff ≈ 0.66. Every term that grows with y
/// is a function of the SOUTHWARD DISTANCE. The stretch compresses that distance inside the band:
///
/// y' = yB + (y − yB) / (1 + stretch · ramp(y)) ramp = smoothstep over the feather
///
/// so a cell at y takes the mask geometry of the row y' north of it — the mass reaches further
/// south AND keeps the elevation profile of the rows it came from (the base noise, edge noise and
/// latitude field keep the real y — texture stays, only the mask's geometry stretches). Where the
/// stretched thin edge drops below sea it fragments organically. Nothing is stamped.
///
/// ⚠ North of the band (y ≤ yB) the caller takes the untouched code path: bit-identical by
/// construction, asserted by the oracle. The band line and feather are constants for a batch;
/// TerrainGenConfig.SouthStretch is the only swept axis.
///
/// The SINKER: TerrainGenConfig.StretchSinker decides whether it rides y' (pushed out with
/// the geometry — held back inside the band) or the real y (keeps pulling the extended mass down
/// where it always did). The chat2/08 diagnostic measured both — see the report.
///
public static class SouthernStretch
{
/// The band's fixed latitude line, fraction of the map. Chosen by the chat2/08 diagnostic (see the report).
public const float DefaultBandStartFrac = 0.70f;
/// The feather width, fraction of the map.
public const float DefaultBandFeatherFrac = 0.05f;
/// Whether the sinker rides the stretched distance by default. Set by the chat2/08 diagnostic.
public const bool DefaultStretchSinker = true;
/// The smoothstep ramp across the feather: 0 at the band line, 1 a feather-width below it.
public static float Ramp(float y, float bandStart, float bandFeather)
{
float t = Math.Clamp((y - bandStart) / bandFeather, 0f, 1f);
return t * t * (3f - 2f * t);
}
/// The y the mask geometry sees. For y ≤ bandStart returns y unchanged.
public static float StretchedY(float y, float bandStart, float bandFeather, float stretch)
{
if (y <= bandStart || stretch <= 0f) return y;
float r = Ramp(y, bandStart, bandFeather);
return bandStart + (y - bandStart) / (1f + stretch * r);
}
}
}