feat(simulation): Layer-1 topography pipeline — features, sub-biome, orchestrator (#953)
Wire the empty-world topography cascade (D-208/209/210): - generator.rs: add SubBiomeVariant (11 variants, D-210) + sub_biome and terrain_modification_cost fields on GeographicAttractor; AttractorType is now Copy. - features.rs (new, D-209): extract the 7 attractor tags from heightmap + drainage. Coast/lake derived from the heightmap (D-209/D-223 reconciliation — markers are names-only now, no polygons). Deterministic (sorted seeds, integer keys, bucket-grid thinning); strength-capped at MAX_ATTRACTORS preserving type diversity. Shared TerrainAnalysis (masks/slope/moisture/percentile) feeds both extraction and sub-biome. - subbiome.rs (new, D-210): classify sub-biome + terrain_modification_cost from elevation/slope/moisture/latitude. Volcanic stays in the enum but is not emitted (no heightmap signal). - layer1.rs (new): run_layer1 orchestrator + attach_feature_names (D-223 pool names to largest rivers / Alpine peaks). - attractor_matching constructors updated for the new fields. 76 atlas tests pass; run_layer1 determinism verified. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -371,7 +371,7 @@ pub enum TerritorialStatus {
|
||||
|
||||
/// The type of terrain feature that attracts settlement placement.
|
||||
/// Source: D-195, D-209
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum AttractorType {
|
||||
/// Where a river meets sea level or coastline. Historically high-value.
|
||||
RiverMouth,
|
||||
@@ -389,8 +389,29 @@ pub enum AttractorType {
|
||||
PlainCenter,
|
||||
}
|
||||
|
||||
/// Fine-grained terrain classification carried by each `GeographicAttractor`.
|
||||
/// Classifies the local terrain more finely than the top-level `SettingType`;
|
||||
/// drives ZonePalette modifier selection (D-101) and `terrain_modification_cost`.
|
||||
/// Source: D-210
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum SubBiomeVariant {
|
||||
TropicalWet,
|
||||
TemperateForest,
|
||||
TemperateGrassland,
|
||||
BorealForest,
|
||||
Tundra,
|
||||
Desert,
|
||||
Savanna,
|
||||
Alpine,
|
||||
Wetland,
|
||||
CoastalLowland,
|
||||
/// No heightmap-derivable signal in the Layer-1 inputs (elevation, slope,
|
||||
/// moisture, latitude); reserved for a future volcanic data source (D-210).
|
||||
Volcanic,
|
||||
}
|
||||
|
||||
/// A terrain feature at a specific map position that influences city placement scoring.
|
||||
/// Source: D-195, D-209
|
||||
/// Source: D-195, D-209, D-210
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct GeographicAttractor {
|
||||
/// Pixel position in heightmap space [row, col].
|
||||
@@ -398,6 +419,12 @@ pub struct GeographicAttractor {
|
||||
pub attractor_type: AttractorType,
|
||||
/// Normalized strength 0.0–1.0. Derived from flow accumulation or habitability score.
|
||||
pub strength: f32,
|
||||
/// Fine-grained terrain classification at this position (D-210).
|
||||
pub sub_biome: SubBiomeVariant,
|
||||
/// Infrastructure-build cost multiplier (1.0 = baseline grassland; higher =
|
||||
/// more expensive). Derived from `sub_biome` + local slope. Consumed by the
|
||||
/// attractor-matching pipeline (D-211) to penalize marginal cities. (D-210)
|
||||
pub terrain_modification_cost: f32,
|
||||
}
|
||||
|
||||
/// Compatibility weights between economic roles and attractor types.
|
||||
|
||||
Reference in New Issue
Block a user