using Godot;
using IslaApocalypse.Core;
namespace IslaApocalypse.Tools
{
///
/// ⭐⭐ THE CROWN JEWEL — the terrain noise configuration, ported and PINNED.
/// → D-050 ("port, don't re-derive"), `Design - Rewrite - Extraction Manifest.md`.
///
/// ═══ WHAT THE REFERENCE ACTUALLY SET, AND WHAT IT DID NOT ═══
///
/// The reference (MapGenerator._Ready ~:141-144) set exactly THREE properties:
///
/// _noise = new FastNoiseLite();
/// _noise.Seed = ConfigManager.WorldSeed == 0 ? (int)GD.Randi() : ConfigManager.WorldSeed;
/// _noise.NoiseType = FastNoiseLite.NoiseTypeEnum.Simplex;
/// _noise.Frequency = 0.004f / scaleFactor;
///
/// That is all four lines. There is no fifth. Fractal type, octaves, gain, lacunarity and
/// weighted-strength were NEVER SET anywhere in that codebase — so the island's entire fractal
/// character was Godot 4.7.1's `FastNoiseLite` CONSTRUCTOR DEFAULTS, and nothing recorded what
/// they were. (chat1/00 §2.1, §4.1.)
///
/// ═══ ⚠⚠ WHY EVERY VALUE IS PINNED EXPLICITLY BELOW ═══
///
/// Because a default is not a decision, and this project no longer rides one. The terrain must
/// not change when the engine version changes, and it must not change when this code is ported
/// off Godot's FastNoiseLite to a C++ or hand-rolled implementation — which D-049 explicitly
/// anticipates ("C++-ready seams... port path-by-path when settled and hot"). An unpinned
/// default would move the island silently, and nothing in the source would say what moved.
///
/// Measured on Godot 4.7.2.stable.mono (Tools/Scenes/NoiseDefaultsProbe.tscn):
/// FractalType Fbm · Octaves 5 · Gain 0.5 · Lacunarity 2.0 · WeightedStrength 0.0
/// These MATCH the Godot 4 documented defaults the reference rode on 4.7.1 — so pinning them
/// reproduces the reference look exactly, with no delta to reconcile.
///
/// ⚠ Note NoiseType is the one place the reference did NOT ride the default: the constructor
/// default is SimplexSmooth, and the reference explicitly chose Simplex. Different noise.
///
/// Run NoiseDefaultsProbe after any engine upgrade. It cannot change the terrain — this file
/// pins it — but it makes a drifting default visible instead of silent.
///
public static class TerrainNoise
{
// ---- the pinned fractal character (was 4.7.1 constructor defaults) ----
public const FastNoiseLite.NoiseTypeEnum PinnedNoiseType = FastNoiseLite.NoiseTypeEnum.Simplex;
public const FastNoiseLite.FractalTypeEnum PinnedFractalType = FastNoiseLite.FractalTypeEnum.Fbm;
public const int PinnedOctaves = 5;
public const float PinnedGain = 0.5f;
public const float PinnedLacunarity = 2.0f;
public const float PinnedWeightedStrength = 0.0f;
///
/// The base frequency, stated at the 1024 baseline. The reference wrote
/// 0.004f / scaleFactor; here the division is 's
/// job, so the literal never reaches a call site. → `Design - Tooling - Scaling Discipline.md`.
///
public const float BaselineFrequency = 0.004f;
///
/// Build the one terrain noise field. ⚠ ONE INSTANCE, deliberately.
///
/// The reference sampled the latitude wobble, the coastline edge roughness and the base
/// height from the SAME `_noise` object — three correlated slices of one field, at three
/// different coordinate transforms. That correlation is part of the look, so the port keeps
/// one instance rather than "tidying" it into three seeded fields.
///
public static FastNoiseLite Create(int seed, GenerationScale scale)
{
var noise = new FastNoiseLite();
// --- ported verbatim from the reference ---
noise.Seed = seed;
noise.NoiseType = PinnedNoiseType;
noise.Frequency = scale.NoiseFrequency(BaselineFrequency); // = 0.004f / scaleFactor
// --- PINNED: the reference left these to the engine. We do not. ---
noise.FractalType = PinnedFractalType;
noise.FractalOctaves = PinnedOctaves;
noise.FractalGain = PinnedGain;
noise.FractalLacunarity = PinnedLacunarity;
noise.FractalWeightedStrength = PinnedWeightedStrength;
return noise;
}
/// The pinned configuration as one line, for a run header.
public static string Describe(int seed, GenerationScale scale) =>
$"Simplex · Fbm · octaves {PinnedOctaves} · gain {PinnedGain} · lacunarity {PinnedLacunarity} · " +
$"weighted {PinnedWeightedStrength} · freq {scale.NoiseFrequency(BaselineFrequency):G6} " +
$"(= {BaselineFrequency} / {scale.ScaleFactor:F3}) · seed {seed}";
}
}