feat(engine-core): ✨ Update climate stats dashboard and core simulation engine logic, including physics, map generation, and sprite asset management
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
cfe859bfea
commit
e1880d53b1
8 changed files with 106 additions and 125 deletions
|
|
@ -56,116 +56,67 @@ const PRIMARY_METRICS: MetricDef[] = [
|
|||
{
|
||||
key: 'temp', label: 'Temp', tooltip: 'Average land temperature (0=frozen, 1=scorching). Driven by solar input, albedo, and orbital cycles.', color: '#E85D3A',
|
||||
getValue: (s) => s.avg_temp,
|
||||
formatValue: (v) => v.toFixed(2),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(2),
|
||||
formatValue: fmt2,
|
||||
formatDelta: fmtDelta2,
|
||||
phaseBands: TEMP_PHASE_BANDS,
|
||||
},
|
||||
{
|
||||
key: 'moisture', label: 'Moisture', tooltip: 'Average land moisture (0=bone dry, 1=saturated). Driven by ocean evaporation, wind transport, and precipitation.', color: '#26A69A',
|
||||
getValue: (s) => s.avg_moisture,
|
||||
formatValue: (v) => v.toFixed(2),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(2),
|
||||
formatValue: fmt2,
|
||||
formatDelta: fmtDelta2,
|
||||
},
|
||||
m('sea_level'),
|
||||
]
|
||||
|
||||
// Left column: LAND metrics
|
||||
const COMPACT_LEFT: MetricDef[] = [
|
||||
{
|
||||
key: 'land_flora', label: 'Flora', tooltip: 'Average canopy cover across land tiles (0=barren, 1=full canopy). Forests and jungles are high; deserts and tundra near zero.', color: '#66BB6A',
|
||||
getValue: (s) => s.avg_land_flora,
|
||||
formatValue: (v) => v.toFixed(3),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(3),
|
||||
},
|
||||
{
|
||||
key: 'land_fauna', label: 'Fauna', tooltip: 'Average habitat suitability across land tiles (0=inhospitable, 1=thriving). Combines flora density, moisture, and temperature.', color: '#8D6E63',
|
||||
getValue: (s) => s.avg_land_fauna,
|
||||
formatValue: (v) => v.toFixed(3),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(3),
|
||||
},
|
||||
{
|
||||
key: 'land_quality', label: 'Quality', tooltip: 'Average tile quality across land (1-5). Rises when climate matches ideal biome, falls when it shifts away. Higher = better yields.', color: '#FFD54F',
|
||||
getValue: (s) => s.avg_land_quality,
|
||||
formatValue: (v) => v.toFixed(2),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(2),
|
||||
},
|
||||
{
|
||||
key: 'evapotrans', label: 'ET', tooltip: 'Average evapotranspiration across land tiles. Moisture recycled by vegetation per turn. Forests contribute most; deserts are negative.', color: '#80DEEA',
|
||||
getValue: (s) => s.avg_evapotranspiration,
|
||||
formatValue: (v) => v.toFixed(4),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(4),
|
||||
},
|
||||
// ── Metric catalog (single source of truth) ─────────────────────────────────
|
||||
// Each metric defined ONCE. Dashboard layouts select by key.
|
||||
|
||||
const fmt3 = (v: number) => v.toFixed(3)
|
||||
const fmt2 = (v: number) => v.toFixed(2)
|
||||
const fmt4 = (v: number) => v.toFixed(4)
|
||||
const fmtDelta3 = (d: number) => (d >= 0 ? '+' : '') + d.toFixed(3)
|
||||
const fmtDelta2 = (d: number) => (d >= 0 ? '+' : '') + d.toFixed(2)
|
||||
const fmtDelta4 = (d: number) => (d >= 0 ? '+' : '') + d.toFixed(4)
|
||||
|
||||
const METRIC_CATALOG: Record<string, MetricDef> = {
|
||||
// -- Climate / atmosphere --
|
||||
sea_level: { key: 'sea_level', label: 'Sea Lvl', tooltip: 'Elevation threshold for water. Rises with warming, falls with cooling.', color: '#5C6BC0', getValue: (s) => s.sea_level, formatValue: fmt3, formatDelta: fmtDelta3 },
|
||||
et: { key: 'evapotrans', label: 'ET', tooltip: 'Average evapotranspiration across land. Moisture recycled by vegetation per turn.', color: '#80DEEA', getValue: (s) => s.avg_evapotranspiration, formatValue: fmt4, formatDelta: fmtDelta4 },
|
||||
albedo: { key: 'albedo', label: 'Albedo', tooltip: 'Global average surface reflectivity (0=absorbs all, 1=reflects all). Ice/snow raise it, forests/water lower it.', color: '#BDBDBD', getValue: (s) => s.avg_albedo, formatValue: fmt3, formatDelta: fmtDelta3 },
|
||||
aerosol: { key: 'aerosol', label: 'Aerosol', tooltip: 'Global average sulfate aerosol opacity. Volcanic eruptions inject aerosols that cool and dry the atmosphere.', color: '#90A4AE', getValue: (s) => s.avg_aerosol, formatValue: fmt4, formatDelta: fmtDelta4 },
|
||||
// -- Land ecology --
|
||||
land_canopy: { key: 'land_canopy', label: 'Canopy', tooltip: 'Average tree canopy cover across land (0=barren, 1=full canopy). Drives succession and shading.', color: '#2E7D32', getValue: (s) => s.avg_land_canopy, formatValue: fmt3, formatDelta: fmtDelta3 },
|
||||
land_under: { key: 'land_undergrowth', label: 'Undergrowth', tooltip: 'Average ground vegetation across land (0=bare, 1=dense). Drives food yield and habitat quality.', color: '#66BB6A', getValue: (s) => s.avg_land_undergrowth, formatValue: fmt3, formatDelta: fmtDelta3 },
|
||||
land_fungi: { key: 'land_fungi', label: 'Fungi', tooltip: 'Average mycorrhizal network across land (0=none, 1=dense). Accelerates forest regrowth, boosts ecosystem resilience.', color: '#8D6E63', getValue: (s) => s.avg_land_fungi, formatValue: fmt3, formatDelta: fmtDelta3 },
|
||||
land_habitat: { key: 'land_habitat', label: 'Habitat', tooltip: 'Average habitat suitability across land (0=inhospitable, 1=thriving). Combines flora density, moisture, temperature.', color: '#A1887F', getValue: (s) => s.avg_land_habitat, formatValue: fmt3, formatDelta: fmtDelta3 },
|
||||
land_quality: { key: 'land_quality', label: 'Quality', tooltip: 'Average tile quality across land (1=Prolific, 5=Epic). Ecology composite of flora health, fauna diversity, biome stability.', color: '#FFD54F', getValue: (s) => s.avg_land_quality, formatValue: fmt2, formatDelta: fmtDelta2 },
|
||||
// -- Water ecology --
|
||||
water_reef: { key: 'water_reef', label: 'Reef', tooltip: 'Average reef health across water tiles (0=dead, 1=pristine). Bleaching from high temps (>0.75). Dead reefs halve fish capacity.', color: '#29B6F6', getValue: (s) => s.avg_water_reef, formatValue: fmt3, formatDelta: fmtDelta3 },
|
||||
water_fish: { key: 'water_fish', label: 'Fish', tooltip: 'Average fish stock across water tiles (0=empty, 100+=abundant). Logistic reproduction, temperature-scaled.', color: '#26C6DA', getValue: (s) => s.avg_water_fish, formatValue: fmt2, formatDelta: fmtDelta2 },
|
||||
water_quality:{ key: 'water_quality', label: 'Quality', tooltip: 'Average tile quality across water tiles (1=Prolific, 5=Epic). Reflects marine ecosystem health.', color: '#42A5F5', getValue: (s) => s.avg_water_quality, formatValue: fmt2, formatDelta: fmtDelta2 },
|
||||
}
|
||||
|
||||
const m = (key: string): MetricDef => METRIC_CATALOG[key]
|
||||
|
||||
// Life mode: LAND column (fauna quality first, then flora quality, then details)
|
||||
const LIFE_LEFT: MetricDef[] = [
|
||||
m('land_habitat'), m('land_quality'), m('land_canopy'), m('land_under'), m('land_fungi'),
|
||||
]
|
||||
|
||||
// Right column: WATER + atmosphere metrics
|
||||
const COMPACT_RIGHT: MetricDef[] = [
|
||||
{
|
||||
key: 'marine_flora', label: 'Flora', tooltip: 'Average reef health across coastal tiles (1=healthy coral, 0=dead). Bleaching from high temps (>0.75) destroys reefs. Dead reefs reduce evaporation.', color: '#29B6F6',
|
||||
getValue: (s) => s.avg_marine_flora,
|
||||
formatValue: (v) => v.toFixed(3),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(3),
|
||||
},
|
||||
{
|
||||
key: 'marine_fauna', label: 'Fauna', tooltip: 'Average fish stock across coastal tiles (0=depleted, 1=abundant). Depends on reef health and water temperature.', color: '#26C6DA',
|
||||
getValue: (s) => s.avg_marine_fauna,
|
||||
formatValue: (v) => v.toFixed(3),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(3),
|
||||
},
|
||||
{
|
||||
key: 'water_quality', label: 'Quality', tooltip: 'Average tile quality across water tiles (1-5). Reflects ocean and coastal ecosystem health.', color: '#42A5F5',
|
||||
getValue: (s) => s.avg_water_quality,
|
||||
formatValue: (v) => v.toFixed(2),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(2),
|
||||
},
|
||||
{
|
||||
key: 'sea_level', label: 'Sea Lvl', tooltip: 'Elevation threshold for water. Rises with warming (thermal expansion + ice melt), falls with cooling. Land below this floods.', color: '#5C6BC0',
|
||||
getValue: (s) => s.sea_level,
|
||||
formatValue: (v) => v.toFixed(3),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(3),
|
||||
},
|
||||
// Life mode: WATER column (fauna quality first, then flora quality, then details)
|
||||
const LIFE_RIGHT: MetricDef[] = [
|
||||
m('water_fish'), m('water_quality'), m('water_reef'),
|
||||
]
|
||||
|
||||
// Environment mode right column
|
||||
const ENV_RIGHT_METRICS: MetricDef[] = [
|
||||
{
|
||||
key: 'sea_level', label: 'Sea Lvl', tooltip: 'Elevation threshold for water. Rises with warming (thermal expansion + ice melt), falls with cooling. Land below this floods.', color: '#5C6BC0',
|
||||
getValue: (s) => s.sea_level,
|
||||
formatValue: (v) => v.toFixed(3),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(3),
|
||||
},
|
||||
{
|
||||
key: 'evapotrans', label: 'ET', tooltip: 'Average evapotranspiration across land tiles. Moisture recycled by vegetation per turn.', color: '#80DEEA',
|
||||
getValue: (s) => s.avg_evapotranspiration,
|
||||
formatValue: (v) => v.toFixed(4),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(4),
|
||||
},
|
||||
{
|
||||
key: 'land_quality', label: 'Land Qlty', tooltip: 'Average tile quality across land (1-5). Rises when climate matches ideal biome.', color: '#FFD54F',
|
||||
getValue: (s) => s.avg_land_quality,
|
||||
formatValue: (v) => v.toFixed(2),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(2),
|
||||
},
|
||||
// Environment mode: left column (energy budget)
|
||||
const ENV_LEFT: MetricDef[] = [
|
||||
m('albedo'), m('et'), m('aerosol'),
|
||||
]
|
||||
|
||||
// Environment mode left column: atmosphere
|
||||
const ATMOSPHERE_METRICS: MetricDef[] = [
|
||||
{
|
||||
key: 'solar', label: 'Solar', tooltip: 'Average absorbed solar energy after albedo reflection. The net heat input driving temperature.', color: '#FFA726',
|
||||
getValue: (s) => s.avg_solar,
|
||||
formatValue: (v) => v.toFixed(3),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(3),
|
||||
},
|
||||
{
|
||||
key: 'albedo', label: 'Albedo', tooltip: 'Global average surface reflectivity (0=absorbs all, 1=reflects all). Ice/snow raise it, forests/water lower it.', color: '#BDBDBD',
|
||||
getValue: (s) => s.avg_albedo,
|
||||
formatValue: (v) => v.toFixed(3),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(3),
|
||||
},
|
||||
{
|
||||
key: 'aerosol', label: 'Aerosol', tooltip: 'Sulfate aerosol opacity from volcanic/impact events. Blocks sunlight, causing cooling and drying. Decays over ~20 turns.', color: '#AB47BC',
|
||||
getValue: (s) => s.avg_aerosol,
|
||||
formatValue: (v) => v.toFixed(4),
|
||||
formatDelta: (d) => (d >= 0 ? '+' : '') + d.toFixed(4),
|
||||
},
|
||||
// Environment mode: right column (land/water state)
|
||||
const ENV_RIGHT: MetricDef[] = [
|
||||
m('land_quality'), m('water_quality'),
|
||||
]
|
||||
|
||||
// ── terrain groups ─────────────────────────────────────────────────────────
|
||||
|
|
@ -178,15 +129,17 @@ interface TerrainGroup {
|
|||
}
|
||||
|
||||
const TERRAIN_GROUPS: TerrainGroup[] = [
|
||||
{ label: 'Water', abbr: 'Wtr', ids: ['ocean', 'coast', 'lake', 'inland_sea'], color: 'rgb(61,120,209)' },
|
||||
{ label: 'Frozen', abbr: 'Frz', ids: ['ice', 'snow'], color: 'rgb(224,240,255)' },
|
||||
{ label: 'Ocean', abbr: 'Ocn', ids: ['ocean', 'coast', 'deep_ocean', 'shallow_ocean', 'coral_reef', 'estuary', 'mangrove'], color: 'rgb(61,120,209)' },
|
||||
{ label: 'Fresh', abbr: 'Frs', ids: ['lake', 'pond', 'river', 'inland_sea'], color: 'rgb(100,160,230)' },
|
||||
{ label: 'Ice', abbr: 'Ice', ids: ['permanent_ice', 'ice', 'snow', 'alpine_tundra', 'polar_desert'], color: 'rgb(224,240,255)' },
|
||||
{ label: 'Tundra', abbr: 'Tnd', ids: ['tundra'], color: 'rgb(184,194,166)' },
|
||||
{ label: 'Arid', abbr: 'Ard', ids: ['desert'], color: 'rgb(222,199,128)' },
|
||||
{ label: 'Grassland', abbr: 'Grs', ids: ['plains', 'grassland'], color: 'rgb(141,197,112)' },
|
||||
{ label: 'Forest', abbr: 'For', ids: ['forest', 'boreal_forest', 'jungle', 'enchanted_forest'], color: 'rgb(51,140,64)' },
|
||||
{ label: 'Arid', abbr: 'Ard', ids: ['desert', 'chaparral'], color: 'rgb(222,199,128)' },
|
||||
{ label: 'Grass', abbr: 'Grs', ids: ['plains', 'grassland', 'temperate_grassland', 'savanna', 'alpine_meadow'], color: 'rgb(141,197,112)' },
|
||||
{ label: 'Forest', abbr: 'For', ids: ['forest', 'temperate_forest', 'boreal_forest', 'tropical_rainforest', 'tropical_dry_forest', 'montane_forest', 'cloud_forest', 'jungle', 'enchanted_forest'], color: 'rgb(51,140,64)' },
|
||||
{ label: 'Rough', abbr: 'Rgh', ids: ['hills', 'mountains'], color: 'rgb(158,153,148)' },
|
||||
{ label: 'Wetland', abbr: 'Wet', ids: ['swamp'], color: 'rgb(61,79,36)' },
|
||||
{ label: 'Wetland', abbr: 'Wet', ids: ['swamp', 'bog'], color: 'rgb(61,79,36)' },
|
||||
{ label: 'Volcanic', abbr: 'Vol', ids: ['volcano'], color: 'rgb(191,51,20)' },
|
||||
{ label: 'Cave', abbr: 'Cav', ids: ['subterranean'], color: 'rgb(90,70,60)' },
|
||||
]
|
||||
|
||||
// ── props ──────────────────────────────────────────────────────────────────
|
||||
|
|
@ -236,7 +189,7 @@ export function StatsDashboard({ stats, currentTurn, onScrub, category = 'enviro
|
|||
<CompactColumns>
|
||||
<CompactCol>
|
||||
<ColHeader>Land</ColHeader>
|
||||
{COMPACT_LEFT.map((def) => {
|
||||
{LIFE_LEFT.map((def) => {
|
||||
const val = currentStats ? def.getValue(currentStats) : 0
|
||||
return (
|
||||
<CompactCell key={def.key}>
|
||||
|
|
@ -249,7 +202,7 @@ export function StatsDashboard({ stats, currentTurn, onScrub, category = 'enviro
|
|||
</CompactCol>
|
||||
<CompactCol>
|
||||
<ColHeader>Water</ColHeader>
|
||||
{COMPACT_RIGHT.map((def) => {
|
||||
{LIFE_RIGHT.map((def) => {
|
||||
const val = currentStats ? def.getValue(currentStats) : 0
|
||||
return (
|
||||
<CompactCell key={def.key}>
|
||||
|
|
@ -265,7 +218,7 @@ export function StatsDashboard({ stats, currentTurn, onScrub, category = 'enviro
|
|||
/* Environment mode: atmosphere + sea level metrics */
|
||||
<CompactColumns>
|
||||
<CompactCol>
|
||||
{ATMOSPHERE_METRICS.map((def) => {
|
||||
{ENV_LEFT.map((def) => {
|
||||
const val = currentStats ? def.getValue(currentStats) : 0
|
||||
return (
|
||||
<CompactCell key={def.key}>
|
||||
|
|
@ -277,7 +230,7 @@ export function StatsDashboard({ stats, currentTurn, onScrub, category = 'enviro
|
|||
})}
|
||||
</CompactCol>
|
||||
<CompactCol>
|
||||
{ENV_RIGHT_METRICS.map((def) => {
|
||||
{ENV_RIGHT.map((def) => {
|
||||
const val = currentStats ? def.getValue(currentStats) : 0
|
||||
return (
|
||||
<CompactCell key={def.key}>
|
||||
|
|
@ -406,7 +359,7 @@ function TerrainDistChart({ stats, currentTurn, onScrub }: StatsDashboardProps):
|
|||
|
||||
// Match total height of primary + compact sections
|
||||
// Height matches the tallest possible content (life mode with headers)
|
||||
const maxCompactRows = Math.max(COMPACT_LEFT.length, COMPACT_RIGHT.length) + 1
|
||||
const maxCompactRows = Math.max(LIFE_LEFT.length, LIFE_RIGHT.length) + 1
|
||||
const chartH = PRIMARY_METRICS.length * (PRIMARY_H + 3)
|
||||
+ 6
|
||||
+ maxCompactRows * (COMPACT_H + 3)
|
||||
|
|
|
|||
|
|
@ -390,14 +390,19 @@ function updateHabitatSuitability(
|
|||
function updateFishStock(tiles: TileState[], w: number, h: number): void {
|
||||
for (let i = 0; i < tiles.length; i++) {
|
||||
const tile = tiles[i]
|
||||
if (!isWater(tile) || (tile.fish_stock ?? 0) <= 0) continue
|
||||
if (!isWater(tile)) continue
|
||||
let tempMult = 0.5 // polar
|
||||
if (tile.temperature > 0.55) tempMult = 1.0 // tropical
|
||||
else if (tile.temperature > 0.25) tempMult = 0.8 // temperate
|
||||
let cap = 100.0
|
||||
if (tile.reef_health > 0.5) cap *= 1.5
|
||||
else if (tile.reef_health < 0.1) cap *= 0.5
|
||||
const stock = tile.fish_stock ?? 0
|
||||
let stock = tile.fish_stock ?? 0
|
||||
// Seed fish on water tiles that have none yet (spontaneous colonization)
|
||||
if (stock <= 0) {
|
||||
stock = Math.round(cap * 0.1 * tempMult) // start at 10% of capacity
|
||||
if (stock <= 0) stock = 1
|
||||
}
|
||||
const growth = 0.05 * tempMult * stock * (1.0 - stock / cap)
|
||||
tile.fish_stock = Math.max(0, Math.min(Math.round(stock + growth), cap))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,6 +264,21 @@ class GenMap {
|
|||
wonder_anchor_schools: [],
|
||||
wonder_tier: 0,
|
||||
river_source_type: gt?.river_source_type || undefined,
|
||||
// Ecology fields (initialized to zero, populated by EcologyPhysics)
|
||||
canopy_cover: 0.0,
|
||||
undergrowth: 0.0,
|
||||
fungi_network: 0.0,
|
||||
drought_counter: 0,
|
||||
succession_progress: 0,
|
||||
regrowth_stage: -1,
|
||||
regrowth_turns: 0,
|
||||
habitat_suitability: 0.0,
|
||||
habitat_low_turns: 0,
|
||||
landmark_name: '',
|
||||
substrate_id: '',
|
||||
water_body_id: -1,
|
||||
depth_from_coast: -1,
|
||||
fish_stock: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,11 +144,13 @@ export function computeTurnStats(
|
|||
let moistSum = 0
|
||||
let albedoSum = 0
|
||||
let solarSum = 0
|
||||
let landFloraSum = 0
|
||||
let landFaunaSum = 0
|
||||
let landCanopySum = 0
|
||||
let landUndergrowthSum = 0
|
||||
let landFungiSum = 0
|
||||
let landHabitatSum = 0
|
||||
let landQualitySum = 0
|
||||
let marineFloraSum = 0
|
||||
let marineFaunaSum = 0
|
||||
let waterReefSum = 0
|
||||
let waterFishSum = 0
|
||||
let waterQualitySum = 0
|
||||
let waterCount = 0
|
||||
let aerosolSum = 0
|
||||
|
|
@ -175,14 +177,16 @@ export function computeTurnStats(
|
|||
if (isWater) {
|
||||
waterCount++
|
||||
waterQualitySum += tile.quality ?? 1
|
||||
marineFloraSum += tile.reef_health ?? 0.0
|
||||
marineFaunaSum += tile.fish_stock ?? 0
|
||||
waterReefSum += tile.reef_health ?? 0.0
|
||||
waterFishSum += tile.fish_stock ?? 0
|
||||
} else {
|
||||
landCount++
|
||||
tempSum += tile.temperature
|
||||
moistSum += tile.moisture
|
||||
landFloraSum += tile.canopy_cover ?? 0
|
||||
landFaunaSum += tile.habitat_suitability ?? 0
|
||||
landCanopySum += tile.canopy_cover ?? 0
|
||||
landUndergrowthSum += tile.undergrowth ?? 0
|
||||
landFungiSum += tile.fungi_network ?? 0
|
||||
landHabitatSum += tile.habitat_suitability ?? 0
|
||||
landQualitySum += tile.quality ?? 1
|
||||
const et = (td as Record<string, number> | undefined)?.['evapotranspiration'] ?? 0
|
||||
etSum += et
|
||||
|
|
@ -202,10 +206,12 @@ export function computeTurnStats(
|
|||
sea_level: grid.sea_level,
|
||||
avg_albedo: albedoSum / n,
|
||||
avg_solar: solarSum / n,
|
||||
avg_land_flora: landCount > 0 ? landFloraSum / landCount : 0,
|
||||
avg_land_fauna: landCount > 0 ? landFaunaSum / landCount : 0,
|
||||
avg_marine_flora: waterCount > 0 ? marineFloraSum / waterCount : 1.0,
|
||||
avg_marine_fauna: waterCount > 0 ? marineFaunaSum / waterCount : 0,
|
||||
avg_land_canopy: landCount > 0 ? landCanopySum / landCount : 0,
|
||||
avg_land_undergrowth: landCount > 0 ? landUndergrowthSum / landCount : 0,
|
||||
avg_land_fungi: landCount > 0 ? landFungiSum / landCount : 0,
|
||||
avg_land_habitat: landCount > 0 ? landHabitatSum / landCount : 0,
|
||||
avg_water_reef: waterCount > 0 ? waterReefSum / waterCount : 0,
|
||||
avg_water_fish: waterCount > 0 ? waterFishSum / waterCount : 0,
|
||||
avg_land_quality: landCount > 0 ? landQualitySum / landCount : 1,
|
||||
avg_water_quality: waterCount > 0 ? waterQualitySum / waterCount : 1,
|
||||
avg_aerosol: aerosolSum / n,
|
||||
|
|
|
|||
|
|
@ -67,10 +67,12 @@ export interface TurnStats {
|
|||
sea_level: number // current sea level elevation
|
||||
avg_albedo: number // global average albedo (0=absorbs all, 1=reflects all)
|
||||
avg_solar: number // global average solar input after albedo
|
||||
avg_land_flora: number // average canopy_cover across land tiles
|
||||
avg_land_fauna: number // average habitat_suitability across land tiles
|
||||
avg_marine_flora: number // average reef_health across coast tiles
|
||||
avg_marine_fauna: number // average fish_stock across coast tiles
|
||||
avg_land_canopy: number // average canopy_cover across land tiles
|
||||
avg_land_undergrowth: number // average undergrowth across land tiles
|
||||
avg_land_fungi: number // average fungi_network across land tiles
|
||||
avg_land_habitat: number // average habitat_suitability across land tiles
|
||||
avg_water_reef: number // average reef_health across water tiles
|
||||
avg_water_fish: number // average fish_stock across water tiles
|
||||
avg_land_quality: number // average quality across land tiles (1-5)
|
||||
avg_water_quality: number // average quality across water tiles (1-5)
|
||||
avg_aerosol: number // global average sulfate aerosol opacity
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Add table
Reference in a new issue