feat: curve v4 — spatially modulated shelves (terrain-water task 08)
Per the task-07 gate: the terraces work but uniform anchors put a flat ring at exactly 100 m and 220 m on every mountain. v4 keeps v3's structure (frozen toe/rise, three risers, per-seed u4 spike to 420 m) and turns the shelf anchors into smooth spatial fields: bench 100+-12 m and plateau 220+-20 m via two decorrelated very-low-freq Simplex fields (~3 undulations per island width), plus a strength field (~5/island) blending each shelf's output span between ~2 m (pronounced flat) and ~25 m (barely a hint) — the optional strength modulation shipped, ordering-safe by construction (worst-case bench top 0.6962 < plateau min 0.9468). Field seeds derive from the RESOLVED noise seed + fixed offsets (7101/7207/7303) — no config knob. Apply is per-column with all modulated values as pure parameters (D-035); the classify path never sees them. Monotonicity assertion now sweeps all 8 modulation-extreme corners x per-seed spikeMax. TerrainCurve gate "off"|"v4" (default v4); v1-v3 retired loudly. TCRV extended (+36 B when version>=4: amplitudes, span range, frequencies, seed offsets — length-framed section makes the layout change safe; parser dispatches on the curve version byte; harness compares the extension). Note: MapGenerator.cs also carries the developer's editor whitespace normalization (spaces->tabs, git diff -w empty before this change). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a046486a58
commit
4d2e024b2f
6 changed files with 292 additions and 183 deletions
|
|
@ -132,6 +132,16 @@ namespace IslaApocalypse.Core
|
|||
writer.Write(c.Sea); writer.Write(c.OrangeCeil); writer.Write(c.RedCeil);
|
||||
writer.Write(c.PlateauLo); writer.Write(c.PlateauHi); writer.Write(c.PeakCap);
|
||||
writer.Write(c.TailSlope);
|
||||
|
||||
// v4+ extension: shelf-modulation parameters.
|
||||
if (c.Version >= 4)
|
||||
{
|
||||
writer.Write(c.BenchAmp); writer.Write(c.PlateauAmp);
|
||||
writer.Write(c.ShelfSpanMin); writer.Write(c.ShelfSpanMax);
|
||||
writer.Write(c.ElevFreqIslands); writer.Write(c.StrengthFreqIslands);
|
||||
writer.Write(c.BenchSeedOffset); writer.Write(c.PlateauSeedOffset);
|
||||
writer.Write(c.StrengthSeedOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteWaterBodyIds(BinaryWriter writer, WorldBlueprint bp)
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ namespace IslaApocalypse.Core // Change this if your namespace is different
|
|||
public static string SeaLevelModel = "flat";
|
||||
public static float SeaLevelValue = 0.15f;
|
||||
|
||||
// Height-redistribution curve (tasks 05/06/07, graduation M-7): "v3" applies
|
||||
// the terraced-ascent curve with the per-seed peak spike (HeightCurve.cs);
|
||||
// "off" is the raw legacy profile. "v1"/"v2" were retired by their successor
|
||||
// recalibrations (old blueprints are regenerable). Biome classification is
|
||||
// curve-invariant by construction either way. Default: v3.
|
||||
public static string TerrainCurve = "v3";
|
||||
// Height-redistribution curve (tasks 05–08, graduation M-7): "v4" applies the
|
||||
// terraced-ascent curve with spatially modulated shelves and the per-seed peak
|
||||
// spike (HeightCurve.cs); "off" is the raw legacy profile. "v1"–"v3" were
|
||||
// retired by successor recalibrations (old blueprints are regenerable). Biome
|
||||
// classification is curve-invariant by construction either way. Default: v4.
|
||||
public static string TerrainCurve = "v4";
|
||||
|
||||
public static void LoadConfig()
|
||||
{
|
||||
|
|
@ -106,10 +106,10 @@ namespace IslaApocalypse.Core // Change this if your namespace is different
|
|||
if (data.ContainsKey("TerrainCurve"))
|
||||
{
|
||||
string curve = (string)data["TerrainCurve"];
|
||||
if (curve == "off" || curve == "v3")
|
||||
if (curve == "off" || curve == "v4")
|
||||
TerrainCurve = curve;
|
||||
else if (curve == "v1" || curve == "v2")
|
||||
GD.PrintErr($"[ConfigManager] TerrainCurve '{curve}' was retired by a later recalibration (v3, task 07). Keeping '{TerrainCurve}' — use \"v3\" or \"off\".");
|
||||
else if (curve == "v1" || curve == "v2" || curve == "v3")
|
||||
GD.PrintErr($"[ConfigManager] TerrainCurve '{curve}' was retired by a later recalibration (v4, task 08). Keeping '{TerrainCurve}' — use \"v4\" or \"off\".");
|
||||
else
|
||||
GD.PrintErr($"[ConfigManager] Unknown TerrainCurve '{curve}'. Keeping '{TerrainCurve}'.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@ namespace IslaApocalypse.Core
|
|||
// constants alone, which is exactly why it is recorded here.
|
||||
public float T1, T2, T3, T4, SpikeMax;
|
||||
public float Sea, OrangeCeil, RedCeil, PlateauLo, PlateauHi, PeakCap, TailSlope; // output bands
|
||||
|
||||
// v4 extension — shelf-modulation parameters (record layout versioned by the
|
||||
// curve Version byte; zero-valued when parsing an older record).
|
||||
public float BenchAmp, PlateauAmp, ShelfSpanMin, ShelfSpanMax;
|
||||
public float ElevFreqIslands, StrengthFreqIslands;
|
||||
public int BenchSeedOffset, PlateauSeedOffset, StrengthSeedOffset;
|
||||
}
|
||||
|
||||
public class WorldBlueprint
|
||||
|
|
@ -399,6 +405,17 @@ namespace IslaApocalypse.Core
|
|||
c.RedCeil = reader.ReadSingle(); c.PlateauLo = reader.ReadSingle();
|
||||
c.PlateauHi = reader.ReadSingle(); c.PeakCap = reader.ReadSingle();
|
||||
c.TailSlope = reader.ReadSingle();
|
||||
|
||||
// v4+ extension: shelf-modulation parameters (older records simply end here —
|
||||
// the section is length-framed, so the version byte is the dispatcher).
|
||||
if (c.Version >= 4)
|
||||
{
|
||||
c.BenchAmp = reader.ReadSingle(); c.PlateauAmp = reader.ReadSingle();
|
||||
c.ShelfSpanMin = reader.ReadSingle(); c.ShelfSpanMax = reader.ReadSingle();
|
||||
c.ElevFreqIslands = reader.ReadSingle(); c.StrengthFreqIslands = reader.ReadSingle();
|
||||
c.BenchSeedOffset = reader.ReadInt32(); c.PlateauSeedOffset = reader.ReadInt32();
|
||||
c.StrengthSeedOffset = reader.ReadInt32();
|
||||
}
|
||||
blueprint.TerrainCurve = c;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue