5 Commits

Author SHA1 Message Date
ab2c4024f8 Civ growth rebalance: urban crowding plateau, plagues, good-year cap
Cities used to climb a hugely stacked carrying capacity (K up to 20-40M
for the best trade hubs -- civMaxPopulation x habitability x siteQuality
x conditions x trade) at ~2%/yr for millennia: bounded in principle,
endless in practice. Three fixes, all population-only + derived vectors
(pure hashes, no RNG, no save-version bump, step-back exact):

- Urban crowding: mortality rises with the square of city size
  (civCrowdingLoss x (P/civMetropolisPop)^2 per year), so the best hubs
  PLATEAU at a historical metropolis scale (~1-1.5M) instead of chasing
  K; negligible below ~50k, not a clamp.
- Good-year cap (civCondBoomCap): a lucky harvest no longer inflates the
  K target by 70% (the logistic chased booms at full rate while famine
  corrected busts slowly -- an upward ratchet); droughts stay uncapped.
- Plagues (civPlague*): rare deterministic epidemics (1-3-year waves,
  20-40% deaths at full exposure) strike cities (exposure 0 below ~30k),
  harder when trade-connected -- contagion travels the routes, the
  historical check on big hubs. Derived sCivPlague + cell-info PLAGUE
  line + "Plague ravages X" / "Plague shrinks X" kind-3 events.

Retuned: civMaxPopulation 2e6 -> 1e6 (it is a capacity SCALE, not a
cap -- comment fixed), civEmpirePop 5e6 -> 2.5e6 for the new sizes.

test_civ gains a plateau/plague section: with the new model the largest
city settles ~1.1M vs 3.7M-and-climbing without it; villages never
plague; waves are deterministic, twin-identical and rewind exactly.
All 16 suites pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 15:52:27 +02:00
1090d2d46e Harden save/load state validation 2026-07-02 19:11:06 +02:00
868cc90667 Civ: cluster settlement placement (habitability-weighted, irregular)
Placement used greedy farthest-first with a hard minimum spacing, so settlements
came out as a near-uniform lattice (unrealistic). Now placeSettlements() does
habitability-weighted random sampling (weight = habitability^civClusterExp) with
a soft Gaussian suppression (civMinSpacingRadians) around each pick, so towns
cluster on good land (rivers/coasts/fertile valleys) at irregular spacing and
leave empty stretches between. Nearest-neighbour distances now span ~0.04..0.39
rad (was ~uniform) and placement concentrates on the better cells.

- New knob civClusterExp (3.0; higher = tighter clustering on the best land);
  civMinSpacingRadians repurposed as the soft suppression scale (0.10 -> 0.06).
- Separate sCivRng + deterministic, so determinism / RNG isolation hold.
- test_civ: replaced the hard-spacing assertion with clustering checks
  (nearest-neighbour spacing varies; placed cells beat the habitable mean).

All 10 suites pass; GUI build clean. Docs updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 13:25:25 +02:00
3655dc0661 Civ settlements: environment-driven dynamic growth (droughts, harvests, storms)
Settlements were static -- every town grew with one global rate to the same
habitability cap (frozen in Live World), so they grew "the same amount
everywhere". Now stepCivilization(dtHours, liveTime) is environment-driven and
time-varying. All drivers are deterministic functions of (region, year, seed),
so step-back replays them with no new saved/snapshot state (population is
already snapshotted).

- Differentiated growth: rate scales with habitability (fertile boom, marginal
  crawl); capacity K = maxPop * habitability * siteQuality * conditions.
- Site quality: max city size varies by an order of magnitude with location --
  a great river (log-scaled discharge) or coast hosts a metropolis, a dry inland
  cell a town (civSiteVariety). This spreads final sizes ~8-9x instead of all
  saturating equally.
- Conditions (per ~20deg region, per year): multi-year droughts (worse in arid
  regions), year-to-year harvests (bigger swings inland), rare cold years, river
  floods, and the existing volcano ash. Regional, so different parts of a
  continent have different fortunes.
- Storms kill directly: a system within its radius of a town deals deaths scaled
  by strength (hurricanes x civHurricaneDeathMult) -- a parked hurricane can gut
  a coastal city. Reads the already-snapshotted storms().
- Famine: accelerated loss when food < population; sustained drought / acute
  disaster can collapse a settlement to ruins (revives when conditions return).
- Viewer: markers withered-tinted by hardship (3D + 2D), cell-info "drought/
  conditions" line, and cause-attributed kind=3 events ("Hurricane X devastates
  Y", "Famine shrinks Y to a Town", tier up/down/abandon).

New civ* knobs (self-describing config -> no save bump). test_civ extended:
sizes vary widely (not uniform), bad-year declines, a hurricane over a town
kills its population. All 10 suites pass; GUI build clean. Docs updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 11:26:56 +02:00
2351fb79a5 Ecoregions atlas + Civilizations Step 2 (habitability & settlements, save v20)
Two features (the ecoregions layer was authored locally and was still
uncommitted; civilization Step 2 builds on top and is intermingled in shared
files, so they land together):

Ecoregions (v19, PlanetEcoregions.*, key E):
- generateEcoregions() flood-fills cells sharing biome + land/water context +
  productivity band into named ecological provinces (dominant flora/fauna/funga
  + per-kind productivity), a separate sEcoRng. ColorMode::Ecoregion + an Eco
  tab + cell-info dominants. Saved v19 (v18 geography reshuffle salt already in).

Civilizations Step 2 (v20, PlanetCiv.*, keys U/I):
- computeHabitability(): derived per-cell food/livability (climate comfort +
  water access (rivers/lakes/coast) + food (flora/fauna + ecoregion
  productivity), gated by freezing winters / high terrain). ColorMode::
  Habitability (key I).
- placeSettlements() (key U, "the dawn"): one-time greedy placement on the best
  well-spaced fertile cells (separate sCivRng; named from the continent's
  NameGen bank). The set is fixed, so the only mutable per-step state is each
  settlement's population.
- stepCivilization(): logistic growth toward K = civMaxPopulation*habitability,
  cut where an active volcano ashes the area, so settlements grow / decline /
  are abandoned (floored at 1 so a site can revive). Tiers village->town->city.
  Runs in liveAdvance; detectLiveEvents logs kind=3 events.
- Step-back snapshots only the population vector (WeatherSnapshot.settlementPop).
  3D + 2D tier-sized markers + city/town labels, a Civ tab, cell-info line.
  buildGeometry() clears settlements on reseed. Save v20; sCellSettlement
  rebuilt on load. civ* config knobs.

New test_ecoregions.cpp + test_civ.cpp; all 10 headless suites pass; GUI build
clean. CLAUDE.md / design-notes / BUILD.md updated (roadmap Step 2 done).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 09:01:43 +02:00