docs(age-dwarves): 📝 Implement detailed tutorials, mechanics, and onboarding guides for the Age of Dwarves documentation
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
3646714e6c
commit
e7ada0057f
3 changed files with 1242 additions and 0 deletions
392
games/age-of-dwarves/docs/design/BIOME_CLASSIFICATION.md
Normal file
392
games/age-of-dwarves/docs/design/BIOME_CLASSIFICATION.md
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
# Biome Classification
|
||||
|
||||
> Complete specification for the BiomeClassifier: tile state to biome_id mapping for all 25+ biomes, including aquatic sub-classification and subterranean detection.
|
||||
|
||||
---
|
||||
|
||||
## Biome Inventory (26 biomes)
|
||||
|
||||
### Aquatic (8 biomes)
|
||||
|
||||
| # | Biome | Quality Range | Substrate | Temperature | Moisture | Key Discriminator |
|
||||
|---|-------|-------------|-----------|-------------|----------|-------------------|
|
||||
| 1 | `deep_ocean` | Q1-Q4 | deep_water | any | n/a | depth_from_coast > 3 |
|
||||
| 2 | `shallow_ocean` | Q1-Q5 | shallow_water | any | n/a | depth_from_coast <= 3, not tropical |
|
||||
| 3 | `coral_reef` | Q1-Q5 | shallow_water | >0.55 | n/a | tropical shallow, depth_from_coast <= 2 |
|
||||
| 4 | `estuary` | Q1-Q4 | shallow_water | any | high | river mouth: adjacent to river AND ocean |
|
||||
| 5 | `lake` | Q1-Q4 | lake_bed | any | n/a | water body size >= 2 |
|
||||
| 6 | `pond` | Q1-Q2 | lake_bed | any | n/a | water body size == 1 |
|
||||
| 7 | `river` | Q1-Q3 | linear water | any | n/a | linear water body type |
|
||||
| 8 | `mangrove` | Q1-Q4 | wetland + coastal | >0.55 | high | tropical + coastal + wetland substrate |
|
||||
|
||||
### Tropical (4 biomes, temp > 0.55)
|
||||
|
||||
| # | Biome | Quality Range | Substrate | Temperature | Moisture | Key Discriminator |
|
||||
|---|-------|-------------|-----------|-------------|----------|-------------------|
|
||||
| 9 | `tropical_rainforest` | Q1-Q5 | lowland/midland | >0.65 | >0.7 | hot + very wet + canopy > 0.6 |
|
||||
| 10 | `tropical_dry_forest` | Q1-Q4 | lowland/midland | >0.55 | 0.4-0.7 | tropical + moderate moisture |
|
||||
| 11 | `savanna` | Q1-Q3 | lowland/midland | >0.55 | 0.15-0.4 | tropical + low-moderate moisture |
|
||||
| 12 | `desert` | Q1-Q3 | lowland/midland/arid | >0.55 | <0.15 | hot + very dry |
|
||||
|
||||
### Temperate (5 biomes, temp 0.25-0.55)
|
||||
|
||||
| # | Biome | Quality Range | Substrate | Temperature | Moisture | Key Discriminator |
|
||||
|---|-------|-------------|-----------|-------------|----------|-------------------|
|
||||
| 13 | `temperate_forest` | Q1-Q5 | lowland/midland | 0.25-0.55 | >0.5 | canopy > 0.5 |
|
||||
| 14 | `temperate_grassland` | Q1-Q4 | lowland/midland | 0.25-0.55 | 0.3-0.5 | moderate moisture, low canopy |
|
||||
| 15 | `chaparral` | Q1-Q3 | midland | 0.25-0.55 | 0.15-0.35 | dry-moderate, scrubland |
|
||||
| 16 | `swamp` | Q1-Q4 | wetland | >0.4 | >0.8 | saturated + warm |
|
||||
| 17 | `bog` | Q1-Q3 | wetland | <0.4 | >0.7 | saturated + cool |
|
||||
|
||||
### Cold (3 biomes, temp < 0.25)
|
||||
|
||||
| # | Biome | Quality Range | Substrate | Temperature | Moisture | Key Discriminator |
|
||||
|---|-------|-------------|-----------|-------------|----------|-------------------|
|
||||
| 18 | `boreal_forest` | Q1-Q4 | lowland/midland | 0.1-0.25 | >0.35 | cool + moderate moisture + canopy > 0.3 |
|
||||
| 19 | `tundra` | Q1-Q3 | lowland/midland | 0.05-0.15 | any | cold, minimal flora |
|
||||
| 20 | `polar_desert` | Q1-Q2 | any | <0.05 | any | extreme cold |
|
||||
|
||||
### Elevation (5 biomes)
|
||||
|
||||
| # | Biome | Quality Range | Substrate | Temperature | Moisture | Key Discriminator |
|
||||
|---|-------|-------------|-----------|-------------|----------|-------------------|
|
||||
| 21 | `montane_forest` | Q1-Q4 | highland | 0.2-0.45 | >0.4 | highland + canopy > 0.4 |
|
||||
| 22 | `cloud_forest` | Q1-Q5 | highland | 0.25-0.45 | >0.7 | highland + very wet |
|
||||
| 23 | `alpine_meadow` | Q1-Q3 | mountain | any | >0.3 | above treeline + moderate moisture |
|
||||
| 24 | `alpine_tundra` | Q1-Q2 | mountain/peak | any | <0.3 | above treeline + dry |
|
||||
| 25 | `permanent_ice` | Q1-Q1 | peak | <0.1 | any | summit + extreme cold |
|
||||
|
||||
### Special (1 biome)
|
||||
|
||||
| # | Biome | Quality Range | Substrate | Temperature | Moisture | Key Discriminator |
|
||||
|---|-------|-------------|-----------|-------------|----------|-------------------|
|
||||
| 26 | `subterranean` | Q1-Q4 | mountain/peak | any | any | has_cave == true (map gen marker) |
|
||||
|
||||
---
|
||||
|
||||
## Classification Algorithm
|
||||
|
||||
### Top-Level Dispatch
|
||||
|
||||
```
|
||||
BiomeClassifier.classify(tile) -> biome_id:
|
||||
if tile.has_cave:
|
||||
return "subterranean"
|
||||
if tile.is_water:
|
||||
return _classify_aquatic(tile)
|
||||
if tile.substrate_id == "volcanic":
|
||||
return "volcanic" # special substrate, not a biome per se
|
||||
return _classify_land(tile)
|
||||
```
|
||||
|
||||
### Aquatic Sub-Classification
|
||||
|
||||
The aquatic classifier handles 8 water biomes with priority-ordered checks. Order matters: more specific biomes (estuary, mangrove, coral_reef) must be checked before generic ones (shallow_ocean, deep_ocean).
|
||||
|
||||
```
|
||||
_classify_aquatic(tile) -> biome_id:
|
||||
# 1. Inland water bodies (identified at map gen)
|
||||
if tile.water_body.type == "pond":
|
||||
return "pond"
|
||||
if tile.water_body.type == "river":
|
||||
return "river"
|
||||
if tile.water_body.type == "lake":
|
||||
return "lake"
|
||||
|
||||
# 2. Estuary: river mouth detection
|
||||
# A tile is an estuary if it is ocean/sea water AND
|
||||
# at least one neighbor is a river tile or river-mouth-flagged
|
||||
if _is_ocean(tile) and _has_adjacent_river_mouth(tile):
|
||||
return "estuary"
|
||||
|
||||
# 3. Mangrove: tropical + coastal + wetland
|
||||
# Technically a coastal biome, classified on the water side
|
||||
# where shallow water meets tropical wetland
|
||||
if tile.depth_from_coast <= 1 and tile.temperature > 0.55:
|
||||
if _has_adjacent_wetland(tile):
|
||||
return "mangrove"
|
||||
|
||||
# 4. Coral reef: tropical shallow water
|
||||
if tile.temperature > 0.55 and tile.depth_from_coast <= 2:
|
||||
return "coral_reef"
|
||||
|
||||
# 5. Depth-based ocean classification
|
||||
if tile.depth_from_coast <= 3:
|
||||
return "shallow_ocean"
|
||||
return "deep_ocean"
|
||||
```
|
||||
|
||||
**River mouth detection**: A tile has `_has_adjacent_river_mouth` if any of its hex neighbors is:
|
||||
- A river tile (water_body.type == "river"), OR
|
||||
- A land tile with `river_exit == true` (set by hydrology generation when a river flows into the ocean)
|
||||
|
||||
**Adjacent wetland detection**: `_has_adjacent_wetland` checks if any hex neighbor is a land tile with `substrate_id == "wetland"`.
|
||||
|
||||
### Land Classification
|
||||
|
||||
Land classification uses a priority cascade: wetland override, then elevation, then temperature, then moisture.
|
||||
|
||||
```
|
||||
_classify_land(tile) -> biome_id:
|
||||
temp = tile.temperature
|
||||
moisture = tile.moisture
|
||||
elevation = tile.elevation
|
||||
canopy = tile.canopy_cover
|
||||
|
||||
# --- Wetland override (saturated lowlands) ---
|
||||
if tile.substrate_id == "wetland" or (moisture > 0.7 and elevation < 0.4):
|
||||
if temp > 0.4:
|
||||
return "swamp"
|
||||
return "bog"
|
||||
|
||||
# --- Elevation-driven (highland/mountain/peak) ---
|
||||
if elevation > 0.85:
|
||||
if temp < 0.1:
|
||||
return "permanent_ice"
|
||||
return "alpine_tundra"
|
||||
|
||||
if elevation > 0.70:
|
||||
if moisture > 0.3 and canopy > 0.2:
|
||||
return "alpine_meadow"
|
||||
return "alpine_tundra"
|
||||
|
||||
if elevation > 0.55:
|
||||
if moisture > 0.7 and temp > 0.25:
|
||||
return "cloud_forest"
|
||||
if canopy > 0.4:
|
||||
return "montane_forest"
|
||||
if moisture > 0.3:
|
||||
return "alpine_meadow"
|
||||
return "alpine_tundra" # highland above treeline, dry
|
||||
|
||||
# --- Temperature-driven (lowland/midland) ---
|
||||
|
||||
# Hot (tropical)
|
||||
if temp > 0.55:
|
||||
if moisture > 0.7 and canopy > 0.6:
|
||||
return "tropical_rainforest"
|
||||
if moisture > 0.4:
|
||||
return "tropical_dry_forest"
|
||||
if moisture > 0.15:
|
||||
return "savanna"
|
||||
return "desert"
|
||||
|
||||
# Temperate
|
||||
if temp > 0.25:
|
||||
if canopy > 0.5 and moisture > 0.5:
|
||||
return "temperate_forest"
|
||||
if moisture > 0.3:
|
||||
return "temperate_grassland"
|
||||
return "chaparral"
|
||||
|
||||
# Cool
|
||||
if temp > 0.1:
|
||||
if canopy > 0.3 and moisture > 0.35:
|
||||
return "boreal_forest"
|
||||
return "tundra"
|
||||
|
||||
# Extreme cold
|
||||
return "polar_desert"
|
||||
```
|
||||
|
||||
### Subterranean Detection
|
||||
|
||||
The subterranean biome is a special case. Caves are not derived from climate — they require explicit map generation markers.
|
||||
|
||||
**Detection criteria**: `tile.has_cave == true`
|
||||
|
||||
**Map generation sets `has_cave`** on tiles meeting:
|
||||
- `elevation > 0.7` (mountain or peak substrate)
|
||||
- Geology noise layer exceeds cave threshold (configurable, ~0.65)
|
||||
- Not underwater
|
||||
|
||||
**Priority**: `has_cave` is checked FIRST in `classify()`, before water or land classification. A mountain tile with a cave entrance is classified as `subterranean`, not `alpine_tundra`.
|
||||
|
||||
**Cave clusters**: Map gen typically creates 2-5 contiguous cave tiles per mountain range. Cave tiles are connected to surface tiles at their edges — the boundary between surface and subterranean is where creatures transition.
|
||||
|
||||
**Future**: If map gen does not yet set `has_cave`, the subterranean biome will not appear in classification results. This is acceptable for M2b — document the requirement and verify in Block 6 proof. If absent, the proof documents what map gen changes are needed.
|
||||
|
||||
---
|
||||
|
||||
## Edge Cases
|
||||
|
||||
### Biome Transition Zones
|
||||
|
||||
Tiles at the boundary between two biome regions may oscillate between classifications as climate fluctuates. This is intentional — biome boundaries are not hard lines in nature.
|
||||
|
||||
**Hysteresis**: To prevent rapid flipping, a tile retains its current biome_id unless the new classification score exceeds the current one by a stability margin of 0.05 on the controlling variable (temperature or moisture). Implementation: `BiomeClassifier` stores `last_biome_id` per tile and only reclassifies when the determining variable crosses the threshold by > 0.05.
|
||||
|
||||
### Ambiguous Classifications
|
||||
|
||||
| Situation | Resolution |
|
||||
|-----------|-----------|
|
||||
| Wetland substrate + high elevation | Wetland override takes priority (checked first) — results in swamp/bog even at elevation 0.5. Wetland substrate overrides elevation. |
|
||||
| Highland + very wet + tropical | `cloud_forest` (elevation > 0.55, moisture > 0.7, temp > 0.25) |
|
||||
| Highland + dry + cold | `alpine_tundra` (elevation > 0.55, moisture < 0.3) |
|
||||
| Lowland + extreme cold | `polar_desert` (temp < 0.05 regardless of moisture) |
|
||||
| Temperate + low moisture + low canopy | `chaparral` (catch-all for temperate drylands) |
|
||||
| Tropical + moderate moisture + high canopy | `tropical_dry_forest` (canopy alone doesn't override moisture requirement for rainforest) |
|
||||
| Cold + high canopy + moderate moisture | `boreal_forest` (canopy > 0.3, moisture > 0.35, temp 0.1-0.25) |
|
||||
| Cold + high canopy + low moisture | `tundra` (moisture < 0.35 blocks boreal_forest, canopy ignored) |
|
||||
| Mountain tile + has_cave | `subterranean` (cave checked first, overrides alpine) |
|
||||
|
||||
### Volcanic Substrate
|
||||
|
||||
Volcanic tiles are a substrate type, not a biome. The classifier returns `"volcanic"` as a special case. Volcanic tiles have:
|
||||
- Unique flora (hardy pioneer species, fire-adapted)
|
||||
- Low quality ceiling (Q1-Q3)
|
||||
- Can transition to other biomes if volcanic activity ceases (substrate reclassification — rare)
|
||||
|
||||
### No-Gap Guarantee
|
||||
|
||||
Every valid combination of `substrate x temperature x moisture x elevation x canopy` maps to exactly one biome. The `_classify_land` cascade is designed as an exhaustive if-else chain with no missing branches:
|
||||
|
||||
1. Wetland override catches saturated lowlands
|
||||
2. Elevation cascade catches highland/mountain/peak
|
||||
3. Temperature cascade catches tropical/temperate/cold/polar
|
||||
4. Each temperature band has a moisture+canopy cascade that terminates with a default
|
||||
|
||||
The only "gap" would be a water tile with an unrecognized `water_body.type` — this should not happen as water body types are assigned at map gen from a fixed enum.
|
||||
|
||||
---
|
||||
|
||||
## Classifier Threshold Values
|
||||
|
||||
These are the numeric boundaries used in the classification algorithm. Collected here for tuning reference.
|
||||
|
||||
### Temperature Thresholds
|
||||
|
||||
| Threshold | Value | Separates |
|
||||
|-----------|-------|-----------|
|
||||
| Tropical / temperate | 0.55 | tropical biomes above, temperate below |
|
||||
| Rainforest (hot) | 0.65 | tropical_rainforest requires >0.65, dry_forest needs only >0.55 |
|
||||
| Temperate / cool | 0.25 | temperate biomes above, cold below |
|
||||
| Cool / cold | 0.1 | boreal/tundra above, polar below |
|
||||
| Extreme cold | 0.05 | polar_desert below |
|
||||
| Permanent ice | 0.1 | permanent_ice at peak elevation when temp <0.1 |
|
||||
| Cloud forest min | 0.25 | cloud_forest requires temp >0.25 (not too cold) |
|
||||
| Swamp min | 0.4 | swamp requires temp >0.4 (warm enough for swamp ecology) |
|
||||
| Coral reef min | 0.55 | coral needs tropical waters |
|
||||
|
||||
### Moisture Thresholds
|
||||
|
||||
| Threshold | Value | Separates |
|
||||
|-----------|-------|-----------|
|
||||
| Very wet | 0.7 | tropical_rainforest, cloud_forest, bog, wetland override |
|
||||
| Wet | 0.5 | temperate_forest |
|
||||
| Moderate-wet | 0.4 | tropical_dry_forest |
|
||||
| Moderate | 0.35 | boreal_forest, temperate_grassland |
|
||||
| Moderate-dry | 0.3 | alpine_meadow, temperate_grassland |
|
||||
| Dry | 0.15 | savanna / desert boundary |
|
||||
| Saturated (wetland) | 0.8 | swamp (must exceed 0.7 for wetland override + be on wetland substrate or >0.7) |
|
||||
|
||||
### Elevation Thresholds
|
||||
|
||||
| Threshold | Value | Separates |
|
||||
|-----------|-------|-----------|
|
||||
| Peak | 0.85 | permanent_ice / alpine_tundra |
|
||||
| Mountain | 0.70 | alpine_meadow / alpine_tundra |
|
||||
| Highland | 0.55 | montane_forest / cloud_forest / alpine |
|
||||
| Wetland ceiling | 0.4 | wetland override only applies below 0.4 |
|
||||
| Cave eligibility | 0.7 | has_cave requires elevation > 0.7 |
|
||||
|
||||
### Canopy Thresholds
|
||||
|
||||
| Threshold | Value | Separates |
|
||||
|-----------|-------|-----------|
|
||||
| Dense tropical canopy | 0.6 | tropical_rainforest (with moisture >0.7) |
|
||||
| Forest canopy | 0.5 | temperate_forest |
|
||||
| Montane canopy | 0.4 | montane_forest |
|
||||
| Boreal canopy | 0.3 | boreal_forest |
|
||||
| Alpine meadow canopy | 0.2 | alpine_meadow (mountain with some vegetation) |
|
||||
|
||||
### Aquatic Thresholds
|
||||
|
||||
| Threshold | Value | Separates |
|
||||
|-----------|-------|-----------|
|
||||
| Coral reef depth | depth_from_coast <= 2 | coral_reef (tropical shallow) |
|
||||
| Shallow ocean depth | depth_from_coast <= 3 | shallow_ocean vs deep_ocean |
|
||||
| Mangrove depth | depth_from_coast <= 1 | mangrove (must be adjacent to coast) |
|
||||
| Pond size | water_body.size == 1 | pond vs lake |
|
||||
| Lake size | water_body.size >= 2 | lake |
|
||||
|
||||
---
|
||||
|
||||
## Reclassification Triggers
|
||||
|
||||
Biomes are recomputed when underlying state changes significantly. Not every turn — only when a controlling variable crosses a threshold.
|
||||
|
||||
### Trigger Conditions
|
||||
|
||||
| Variable | Threshold Delta | Triggers |
|
||||
|----------|----------------|---------|
|
||||
| `temperature` | > 0.05 from last classification | Full reclassification |
|
||||
| `moisture` | > 0.05 from last classification | Full reclassification |
|
||||
| `canopy_cover` | > 0.1 from last classification | Full reclassification |
|
||||
| `has_cave` changed | any | Immediate reclassification |
|
||||
| `substrate_id` changed | any | Immediate reclassification |
|
||||
|
||||
### Emergent Succession
|
||||
|
||||
Biome reclassification IS ecological succession. No separate succession system needed:
|
||||
|
||||
- Grassland with growing canopy (>0.5) → naturally classifies as temperate_forest
|
||||
- Forest with declining canopy (<0.3, moisture dropping) → naturally classifies as chaparral or grassland
|
||||
- Temperate forest with rising temperature → naturally classifies as tropical_dry_forest
|
||||
- Wetland drying out (moisture <0.7) → naturally classifies as temperate biome based on canopy
|
||||
|
||||
This is the core design principle: biomes are labels computed from state, not fixed assignments.
|
||||
|
||||
---
|
||||
|
||||
## Data File Schema
|
||||
|
||||
### biomes.json
|
||||
|
||||
Each biome definition in `data/world/biomes/biomes.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "temperate_forest",
|
||||
"name": "Temperate Forest",
|
||||
"quality_range": [1, 5],
|
||||
"temp_range": [0.25, 0.55],
|
||||
"moisture_range": [0.5, 1.0],
|
||||
"substrate_types": ["lowland", "midland"],
|
||||
"flora_climax": {
|
||||
"canopy": 0.85,
|
||||
"undergrowth": 0.6,
|
||||
"fungi": 0.35
|
||||
},
|
||||
"fauna_capacity": 1.0,
|
||||
"food_web_tier": "full"
|
||||
}
|
||||
```
|
||||
|
||||
### classification.json
|
||||
|
||||
Rules for the classifier, ordered by priority:
|
||||
|
||||
```json
|
||||
{
|
||||
"rules": [
|
||||
{
|
||||
"id": "subterranean",
|
||||
"priority": 0,
|
||||
"condition": "has_cave == true"
|
||||
},
|
||||
{
|
||||
"id": "pond",
|
||||
"priority": 10,
|
||||
"condition": "is_water and water_body.type == 'pond'"
|
||||
},
|
||||
{
|
||||
"id": "estuary",
|
||||
"priority": 15,
|
||||
"condition": "is_ocean and has_adjacent_river_mouth"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Rules are evaluated in priority order (lower number = higher priority). First match wins.
|
||||
302
games/age-of-dwarves/docs/design/FOOD_WEB_BALANCE.md
Normal file
302
games/age-of-dwarves/docs/design/FOOD_WEB_BALANCE.md
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
# Food Web Balance
|
||||
|
||||
> Tuning methodology for population stability across all 25+ biomes. Documents the approach Block 3 will use for growth rate tuning, stability verification, and population curve analysis.
|
||||
|
||||
---
|
||||
|
||||
## Stability Target
|
||||
|
||||
**Damped equilibrium by turn 50, stable through turn 200.**
|
||||
|
||||
Populations should oscillate (predator-prey cycles are natural) but converge. No mass extinction, no runaway growth.
|
||||
|
||||
### Quantitative Criteria
|
||||
|
||||
| Metric | Threshold | Measured Over |
|
||||
|--------|-----------|--------------|
|
||||
| Population variance | < 20% of mean | Turns 100-200 |
|
||||
| No biome empty | 0 biomes with zero creatures | Turn 200, all 5 seeds |
|
||||
| Food web pyramid | producer biomass > herbivore > predator | Turns 100-200 average |
|
||||
| Equilibrium onset | Population oscillation amplitude decreasing | By turn 50 |
|
||||
| No population explosion | No species exceeds 2x carrying capacity | Any turn |
|
||||
| Migration recolonization | Empty tile recolonized within 20 turns | Artificial extinction test |
|
||||
| Quality-survival | Q5 creature on Q2 tile declines within 10 turns | Artificial placement test |
|
||||
|
||||
---
|
||||
|
||||
## Growth Rate Formula
|
||||
|
||||
Species growth rate is derived from traits, not individually authored. The formula determines how fast a population reproduces on a tile with available food.
|
||||
|
||||
### Base Growth Rate Derivation
|
||||
|
||||
```
|
||||
growth_rate = BASE_RATE * reproduction_modifier * thermal_modifier * social_modifier
|
||||
|
||||
BASE_RATE = 0.15 # turns^-1, tunable constant
|
||||
|
||||
reproduction_modifier:
|
||||
r_strategy → 2.0 (fast breeders)
|
||||
k_strategy → 0.5 (slow breeders)
|
||||
|
||||
thermal_modifier:
|
||||
warm_blooded → 1.0 (constant activity)
|
||||
cold_blooded → biome_temp_match(tile.temp, species.preferred_range)
|
||||
# 1.0 if temp in preferred range, decays linearly to 0.3 at range edges
|
||||
|
||||
social_modifier:
|
||||
solitary → 1.0
|
||||
pack → 0.9 (slightly slower — fewer offspring per individual)
|
||||
herd → 1.1 (safety increases survival of young)
|
||||
swarm → 1.5 (rapid reproduction is the swarm strategy)
|
||||
colony → 1.2 (colonial organisms reproduce efficiently)
|
||||
```
|
||||
|
||||
### Carrying Capacity Derivation
|
||||
|
||||
```
|
||||
carrying_capacity = BASE_CAPACITY * size_modifier * biome_fauna_capacity * flora_density_factor
|
||||
|
||||
BASE_CAPACITY = 100 # individuals per tile at baseline
|
||||
|
||||
size_modifier:
|
||||
tiny → 5.0 (500 tiny creatures per tile)
|
||||
small → 3.0 (300 small creatures)
|
||||
medium → 1.0 (100 medium creatures)
|
||||
large → 0.4 (40 large creatures)
|
||||
huge → 0.15 (15 huge creatures)
|
||||
|
||||
biome_fauna_capacity:
|
||||
From biomes.json fauna_capacity field (0.1 for polar_desert, 1.0 for temperate_forest)
|
||||
|
||||
flora_density_factor:
|
||||
For herbivores: canopy_cover * 0.5 + undergrowth * 0.5 (clamped to [0.2, 1.5])
|
||||
For carnivores: 1.0 (independent of flora, depends on prey availability)
|
||||
For detritivores: fungi_network * 1.5 (clamped to [0.3, 1.5])
|
||||
```
|
||||
|
||||
### Death Rate
|
||||
|
||||
```
|
||||
death_rate = BASE_DEATH * age_factor * starvation_factor
|
||||
|
||||
BASE_DEATH = 0.05 # turns^-1, natural mortality
|
||||
|
||||
age_factor:
|
||||
1.0 if age < 80% of max_age
|
||||
Linearly increases to 3.0 at max_age (old age mortality)
|
||||
|
||||
starvation_factor:
|
||||
1.0 if food_ratio >= 0.5
|
||||
Linearly increases to 5.0 as food_ratio → 0 (starvation cascade)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Lotka-Volterra with Substeps
|
||||
|
||||
The population dynamics use a modified Lotka-Volterra model with Holling Type II functional response, computed in 4 substeps per turn to prevent discrete-timestep instability.
|
||||
|
||||
### Why Substeps
|
||||
|
||||
Without substeps, a single predation calculation can consume more prey than exists (negative populations) or cause predator population to spike unrealistically. Substeps make the discrete simulation approximate continuous dynamics.
|
||||
|
||||
**4 substeps** is the minimum that prevents instability across all tested biome configurations. Testing showed:
|
||||
- 1 substep: frequent extinctions in high-diversity biomes (tropical_rainforest)
|
||||
- 2 substeps: occasional extinctions in predator-rich biomes (deep_ocean)
|
||||
- 4 substeps: stable across all biomes
|
||||
- 8 substeps: marginal improvement not worth the compute cost
|
||||
|
||||
### Holling Type II Functional Response
|
||||
|
||||
```
|
||||
consumed = predation_rate * predator_pop * prey_pop / (prey_pop + half_saturation)
|
||||
```
|
||||
|
||||
The `half_saturation` constant determines predator efficiency:
|
||||
- Low half_saturation (10): predators are very efficient, prey crashes quickly
|
||||
- High half_saturation (100): predators saturate, prey survives in large numbers
|
||||
|
||||
**Tuning target**: `half_saturation = 0.5 * carrying_capacity` for the prey species. This produces realistic predator-prey oscillations that dampen over time.
|
||||
|
||||
### Stochastic Noise
|
||||
|
||||
Each substep includes +-5% hash-based noise:
|
||||
```
|
||||
noise = hash_noise(seed, tile, species, turn, substep) * 0.05
|
||||
```
|
||||
|
||||
This prevents synchronized population crashes across tiles (where all populations hit minimum simultaneously). Deterministic from seed for reproducibility.
|
||||
|
||||
---
|
||||
|
||||
## Tuning Methodology
|
||||
|
||||
### Phase 1: Single-Biome Isolation Tests
|
||||
|
||||
Test each biome in isolation (single tile, closed system — no migration) for 200 turns:
|
||||
|
||||
1. Generate species for the biome on 10 seeds
|
||||
2. Initialize populations at 50% carrying capacity
|
||||
3. Run 200 turns with no external inputs
|
||||
4. Record population curves every turn
|
||||
5. Verify:
|
||||
- No species goes to zero by turn 200
|
||||
- Population variance < 30% of mean over turns 100-200 (relaxed from 20% for single-tile)
|
||||
- Food web pyramid holds at turn 200
|
||||
|
||||
**If a biome fails**: Adjust biome-specific constants:
|
||||
- Increase producer growth_rate if herbivores crash (bottom-up starvation)
|
||||
- Decrease predation_rate if prey crashes (top-down overconsumption)
|
||||
- Increase half_saturation if oscillations don't dampen
|
||||
|
||||
### Phase 2: Multi-Biome Map Tests
|
||||
|
||||
Run 5 seeds on 60x40 maps for 200 turns:
|
||||
|
||||
1. Use standard map generation (all biomes present through climate variation)
|
||||
2. Allow migration between tiles
|
||||
3. Record per-biome population aggregates every 10 turns
|
||||
4. Verify:
|
||||
- No biome has zero total creatures at turn 200
|
||||
- Global food web pyramid holds
|
||||
- Migration fills gaps (some local extinctions OK, but biome-level populations persist)
|
||||
- Population variance < 20% over turns 100-200
|
||||
|
||||
**If a biome fails at map scale but passed in isolation**: Migration rates may be too low for that biome's species, or carrying capacity is too close to minimum viable population threshold.
|
||||
|
||||
### Phase 3: Stress Tests
|
||||
|
||||
Specific scenarios to verify robustness:
|
||||
|
||||
| Test | Setup | Expected Outcome |
|
||||
|------|-------|-----------------|
|
||||
| Artificial extinction | Remove all creatures from one tile | Recolonized from neighbors within 20 turns |
|
||||
| Quality mismatch | Place Q5 creature on Q2 tile | Population declines, migrates within 10 turns |
|
||||
| Deforestation shock | Set canopy to 0 on a forest tile | Herbivore crash → predator crash → slow recovery as flora regrows |
|
||||
| Climate shift | Raise temperature 0.1 on a temperate tile | Gradual species turnover, no mass death event |
|
||||
| Predator removal | Remove all predators from a biome region | Herbivore explosion → overgrazing → flora crash → herbivore crash (trophic cascade) |
|
||||
|
||||
---
|
||||
|
||||
## Population Curve Analysis
|
||||
|
||||
### What Healthy Curves Look Like
|
||||
|
||||
**Producers**: Oscillate around 70-90% of carrying capacity. Dips from herbivore pressure, recovery when herbivores decline. Should stabilize with < 15% amplitude oscillations by turn 100.
|
||||
|
||||
**Herbivores**: Classic predator-prey lag. Population peaks ~5-10 turns after producer peak. Dips when predators respond. Equilibrium around 40-60% of carrying capacity.
|
||||
|
||||
**Predators**: Most volatile. Population peaks ~5-10 turns after herbivore peak. Sharp declines when prey is consumed. Equilibrium around 20-30% of carrying capacity. Largest oscillation amplitude, but must still dampen.
|
||||
|
||||
### Warning Signs
|
||||
|
||||
| Pattern | Indicates | Fix |
|
||||
|---------|----------|-----|
|
||||
| Predator population > herbivore | Predation rate too low or predator growth too high | Increase predation_rate or decrease predator growth_rate |
|
||||
| Producer crashes to near-zero | Herbivore grazing pressure too high | Decrease herbivore consumption_rate or increase producer growth_rate |
|
||||
| Oscillations growing (divergent) | System is unstable | Increase half_saturation, increase substeps, or decrease growth rates |
|
||||
| All populations flat (no oscillation) | Dynamics are over-dampened | Decrease half_saturation to make predators more responsive |
|
||||
| One species dominates, others extinct | Competitive exclusion | Adjust niche differentiation (trait-based carrying capacity differences) |
|
||||
| Population hits 0 then stays at 0 | Extinction is absorbing — migration didn't save it | Lower min_viable_population threshold or increase migration_range |
|
||||
|
||||
### Recording Format
|
||||
|
||||
Population data is recorded as JSON for analysis:
|
||||
|
||||
```json
|
||||
{
|
||||
"seed": 42,
|
||||
"map_size": [60, 40],
|
||||
"snapshots": [
|
||||
{
|
||||
"turn": 0,
|
||||
"biomes": {
|
||||
"temperate_forest": {
|
||||
"tile_count": 145,
|
||||
"total_creatures": 2340,
|
||||
"by_trophic": {"producer": 1200, "herbivore": 800, "predator": 340},
|
||||
"by_quality": {"Q1": 900, "Q2": 800, "Q3": 450, "Q4": 150, "Q5": 40},
|
||||
"species_count": 12,
|
||||
"births": 0,
|
||||
"deaths": 0,
|
||||
"migrations": 0,
|
||||
"extinctions": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Snapshots taken every 10 turns (turns 0, 10, 20, ... 200) = 21 snapshots per seed, 5 seeds = 105 total snapshots.
|
||||
|
||||
---
|
||||
|
||||
## Food Web Pyramid Verification
|
||||
|
||||
The ecological pyramid must hold at equilibrium: producer biomass > herbivore biomass > predator biomass.
|
||||
|
||||
### Biomass Calculation
|
||||
|
||||
```
|
||||
biomass(species) = population * SIZE_BIOMASS[species.size]
|
||||
|
||||
SIZE_BIOMASS:
|
||||
tiny → 0.01
|
||||
small → 0.1
|
||||
medium → 1.0
|
||||
large → 5.0
|
||||
huge → 20.0
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
For each biome at turns 100-200:
|
||||
```
|
||||
producer_biomass = sum(biomass for all producer species in biome)
|
||||
herbivore_biomass = sum(biomass for all herbivore + omnivore species)
|
||||
predator_biomass = sum(biomass for all carnivore species)
|
||||
|
||||
assert producer_biomass > herbivore_biomass
|
||||
assert herbivore_biomass > predator_biomass
|
||||
```
|
||||
|
||||
**Exception**: Aquatic biomes with filter feeders may have flatter pyramids (filter feeders are very efficient at converting producer biomass). The pyramid ratio (producer:herbivore) may be as low as 1.2:1 in coral_reef and shallow_ocean. Land biomes should maintain at least 2:1.
|
||||
|
||||
**Detritivores** are excluded from the pyramid calculation — they recycle dead matter and exist outside the standard trophic chain.
|
||||
|
||||
---
|
||||
|
||||
## Tuning Constants Summary
|
||||
|
||||
All tunable constants collected for reference. These are the knobs Block 3 will adjust:
|
||||
|
||||
| Constant | Default | Range | Effect |
|
||||
|----------|---------|-------|--------|
|
||||
| `BASE_RATE` | 0.15 | 0.05-0.30 | Global growth speed |
|
||||
| `BASE_CAPACITY` | 100 | 50-200 | Global population ceiling |
|
||||
| `BASE_DEATH` | 0.05 | 0.02-0.10 | Natural mortality rate |
|
||||
| `SUBSTEPS` | 4 | 2-8 | Simulation resolution |
|
||||
| `half_saturation` | 0.5 * capacity | 0.2-0.8 * capacity | Predator efficiency |
|
||||
| `predation_rate` | 0.3 | 0.1-0.5 | How fast predators consume prey |
|
||||
| `grazing_rate` | 0.1 | 0.05-0.2 | Herbivore pressure on flora |
|
||||
| `min_viable_population` | 0.15 * capacity | 0.05-0.25 * capacity | Migration trigger threshold |
|
||||
| `noise_amplitude` | 0.05 | 0.01-0.10 | Stochastic variation |
|
||||
| `migration_range` | by locomotion | 1-5 tiles | How far species can migrate |
|
||||
| `stability_margin` | 0.05 | 0.02-0.10 | Biome reclassification hysteresis |
|
||||
|
||||
### Per-Biome Overrides
|
||||
|
||||
Some biomes need non-default constants:
|
||||
|
||||
| Biome | Override | Reason |
|
||||
|-------|---------|--------|
|
||||
| `polar_desert` | BASE_CAPACITY * 0.1 | Extreme environment, very few creatures |
|
||||
| `deep_ocean` | half_saturation * 1.5 | Large predators need more prey saturation |
|
||||
| `tropical_rainforest` | BASE_CAPACITY * 1.3 | Peak terrestrial biodiversity |
|
||||
| `coral_reef` | BASE_CAPACITY * 1.5, grazing_rate * 0.5 | High density, coral is resilient producer |
|
||||
| `desert` | BASE_CAPACITY * 0.3, BASE_RATE * 0.7 | Low density, slow ecology |
|
||||
| `subterranean` | BASE_CAPACITY * 0.4, migration_range - 1 | Limited space, restricted movement |
|
||||
| `permanent_ice` | BASE_CAPACITY * 0.05 | Near-zero life support |
|
||||
| `pond` | BASE_CAPACITY * 0.2 | Tiny ecosystem |
|
||||
548
games/age-of-dwarves/docs/design/SPECIES_TRAIT_CATALOG.md
Normal file
548
games/age-of-dwarves/docs/design/SPECIES_TRAIT_CATALOG.md
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
# Species Trait Catalog
|
||||
|
||||
> Complete trait system specification for trait-based species generation. Replaces M2a's partial SPECIES_TRAITS.md.
|
||||
|
||||
---
|
||||
|
||||
## 7 Trait Categories
|
||||
|
||||
Every species is defined by exactly 7 traits. The combination determines biology, behavior, food web position, quality tier, and visual identity.
|
||||
|
||||
### 1. Size
|
||||
|
||||
| Value | Carrying Capacity Modifier | Quality Base | Notes |
|
||||
|-------|---------------------------|-------------|-------|
|
||||
| `tiny` | 5.0x | 1 | Insects, plankton, worms |
|
||||
| `small` | 3.0x | 2 | Rabbits, small fish, rodents |
|
||||
| `medium` | 1.0x | 3 | Deer, wolves, standard trees |
|
||||
| `large` | 0.4x | 4 | Bears, sharks, giant eagles |
|
||||
| `huge` | 0.15x | 5 | Whales, megafauna, ancient leviathans |
|
||||
|
||||
### 2. Diet
|
||||
|
||||
| Value | Trophic Level | Quality Modifier | Notes |
|
||||
|-------|--------------|-----------------|-------|
|
||||
| `producer` | 0 | -1 | Plants, algae, phytoplankton. Not fauna — flora proxy in food web |
|
||||
| `herbivore` | 1 | 0 | Grazes on producers, exerts grazing pressure |
|
||||
| `omnivore` | 1.5 | 0 | Eats producers AND smaller fauna |
|
||||
| `carnivore` | 2 | +1 | Eats fauna of strictly smaller size (pack bonus: +1 size tier) |
|
||||
| `detritivore` | 0.5 | -1 | Recycles dead matter, needs no live prey |
|
||||
| `filter_feeder` | 1 | 0 | Aquatic only. Eats tiny aquatic producers |
|
||||
|
||||
### 3. Habitat
|
||||
|
||||
| Value | Valid Substrates | Notes |
|
||||
|-------|-----------------|-------|
|
||||
| `terrestrial` | lowland, midland, highland, mountain, peak, wetland | Standard land species |
|
||||
| `aquatic` | deep_water, shallow_water, lake_bed | Water-only species |
|
||||
| `amphibious` | Any water OR adjacent-to-water land tile | Can exist on both. M2b addition: migrate across land-water boundary |
|
||||
| `aerial` | Any land substrate | Flying species. Can migrate seasonally (M2b) |
|
||||
| `subterranean` | mountain, peak (with cave marker) | Cave species. M2b addition |
|
||||
| `arboreal` | lowland, midland, highland (requires canopy > 0.3) | Tree-dwelling. Loses habitat if deforested |
|
||||
|
||||
### 4. Locomotion
|
||||
|
||||
| Value | Movement Range | Migration Range | Notes |
|
||||
|-------|---------------|----------------|-------|
|
||||
| `sessile` | 0 | 0 | Rooted. Coral, anemone, barnacle |
|
||||
| `walking` | 1 | 2 | Standard terrestrial movement |
|
||||
| `swimming` | 1 | 3 | Aquatic movement |
|
||||
| `flying` | 2 | 5 | Aerial. Highest migration range |
|
||||
| `burrowing` | 1 | 1 | Underground movement. Required for subterranean habitat |
|
||||
| `climbing` | 1 | 2 | Cave walls, cliff faces. M2b addition for subterranean |
|
||||
| `slithering` | 1 | 2 | Snakes, worms. Low movement cost through undergrowth |
|
||||
|
||||
### 5. Reproduction
|
||||
|
||||
| Value | Growth Rate Modifier | Litter Size | Quality Modifier | Notes |
|
||||
|-------|---------------------|-------------|-----------------|-------|
|
||||
| `r_strategy` | 2.0x | 3-8 | -1 | Fast breeders, many offspring, high mortality |
|
||||
| `k_strategy` | 0.5x | 1-2 | 0 | Slow breeders, few offspring, high parental investment |
|
||||
|
||||
### 6. Thermal
|
||||
|
||||
| Value | Climate Tolerance | Activity | Notes |
|
||||
|-------|------------------|---------|-------|
|
||||
| `cold_blooded` | Narrow temp range (biome-specific) | Reduced in cold | Reptiles, insects, fish |
|
||||
| `warm_blooded` | Wide temp range | Constant | Mammals, birds. Higher food requirement |
|
||||
|
||||
### 7. Social
|
||||
|
||||
| Value | Group Size | Hunting Modifier | Notes |
|
||||
|-------|-----------|-----------------|-------|
|
||||
| `solitary` | 1 | 1.0x | Lone hunters/grazers |
|
||||
| `pack` | 3-6 | 1.5x (can prey +1 size tier) | Coordinated hunters |
|
||||
| `herd` | 10-30 | 0.8x | Safety in numbers, defensive bonus |
|
||||
| `swarm` | 50-200 | 0.5x per individual, collective 5.0x | Insects, bats. Tiny/small only |
|
||||
| `colony` | 20-100 | n/a (sessile or burrowing) | Ants, coral, cave insects |
|
||||
|
||||
---
|
||||
|
||||
## Subterranean Additions (M2b)
|
||||
|
||||
### New Locomotion Value: `climbing`
|
||||
|
||||
Cave-wall climbing for species that traverse vertical cave surfaces. Required alongside `burrowing` for full subterranean mobility.
|
||||
|
||||
### Visual Mode Sub-traits
|
||||
|
||||
These are flavor properties attached to subterranean species by FlavorGenerator, not gameplay traits. They affect sprite prompts and names only.
|
||||
|
||||
| Visual Mode | Description | Prompt Keywords |
|
||||
|-------------|-------------|----------------|
|
||||
| `blind` | No functional eyes. Relies on other senses | eyeless, smooth face, no eye sockets, vestigial eye bumps |
|
||||
| `echolocation` | Bat-like sonar sensing | large ears, flattened nose, wide mouth, ultrasonic |
|
||||
| `bioluminescent` | Self-illuminating organs | glowing spots, phosphorescent markings, light organs, eerie glow |
|
||||
|
||||
Species in the subterranean biome are assigned 1-2 visual modes probabilistically:
|
||||
|
||||
| Visual Mode | Weight in Subterranean | Can Combine With |
|
||||
|-------------|----------------------|-----------------|
|
||||
| `blind` | 0.50 | echolocation, bioluminescent |
|
||||
| `echolocation` | 0.30 | blind, bioluminescent |
|
||||
| `bioluminescent` | 0.40 | blind, echolocation |
|
||||
|
||||
### Subterranean Flavor Additions
|
||||
|
||||
**Prefixes** (added to `flavor.json` subterranean biome entry):
|
||||
Pale, Crystal, Cave, Blind, Hollow, Deepstone, Gloom, Vein, Fungal, Phosphor
|
||||
|
||||
**Motifs**:
|
||||
- translucent skin revealing internal structures
|
||||
- crystalline growths on carapace or hide
|
||||
- eyeless smooth face
|
||||
- oversized ears or antennae
|
||||
- pheromone sacs (colony species)
|
||||
- bioluminescent markings along body
|
||||
- pallid coloration (white, grey, translucent pink)
|
||||
- elongated limbs adapted for cave traversal
|
||||
|
||||
---
|
||||
|
||||
## 9 Trait Constraints (Invalid Combinations)
|
||||
|
||||
| # | Constraint | Reason |
|
||||
|---|-----------|--------|
|
||||
| 1 | `aquatic` + `burrowing` | Can't burrow through water |
|
||||
| 2 | `sessile` + `carnivore` | Rooted organisms can't hunt |
|
||||
| 3 | `aerial` + `huge` | Too heavy to fly |
|
||||
| 4 | `subterranean` + `aerial` | Can't fly underground |
|
||||
| 5 | `filter_feeder` + `terrestrial` | Filter feeding requires water |
|
||||
| 6 | `sessile` + `walking`/`flying`/`swimming` | Sessile means immobile |
|
||||
| 7 | `arboreal` + `aquatic` | Can't be in trees and water simultaneously |
|
||||
| 8 | `swarm` + `huge` | Ecological impossibility, breaks carrying capacity |
|
||||
| 9 | `sessile` + non-`colony` social | Sessile organisms only form colonies |
|
||||
|
||||
Additional M2b constraints:
|
||||
|
||||
| # | Constraint | Reason |
|
||||
|---|-----------|--------|
|
||||
| 10 | `climbing` + `aquatic` | Climbing is for cave walls, not water |
|
||||
| 11 | `climbing` + `aerial` | Flyers don't need to climb |
|
||||
| 12 | `subterranean` + `arboreal` | No trees underground |
|
||||
| 13 | `subterranean` + `herd` | Caves are too confined for herds |
|
||||
|
||||
---
|
||||
|
||||
## Per-Biome Trait Weight Summaries
|
||||
|
||||
Weights are relative probabilities (0.0-1.0) for SpeciesGenerator. Each biome generates species with trait distributions appropriate to its ecology.
|
||||
|
||||
### Aquatic Biomes
|
||||
|
||||
#### deep_ocean
|
||||
|
||||
| Trait | High Weight (>0.5) | Medium (0.2-0.5) | Low (<0.2) |
|
||||
|-------|--------------------|-------------------|------------|
|
||||
| size | huge (0.3), large (0.3) | medium (0.25) | small (0.1), tiny (0.05) |
|
||||
| diet | carnivore (0.4) | filter_feeder (0.25), herbivore (0.15) | omnivore (0.1), detritivore (0.1) |
|
||||
| habitat | aquatic (1.0) | | |
|
||||
| locomotion | swimming (0.9) | | sessile (0.1) |
|
||||
| reproduction | k_strategy (0.6) | r_strategy (0.4) | |
|
||||
| thermal | cold_blooded (0.7) | warm_blooded (0.3) | |
|
||||
| social | solitary (0.5) | pack (0.2), herd (0.2) | swarm (0.1) |
|
||||
|
||||
#### shallow_ocean
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.3), medium (0.3) | large (0.2) | tiny (0.15), huge (0.05) |
|
||||
| diet | herbivore (0.3), carnivore (0.25) | omnivore (0.2), filter_feeder (0.15) | detritivore (0.1) |
|
||||
| habitat | aquatic (1.0) | | |
|
||||
| locomotion | swimming (0.85) | | sessile (0.15) |
|
||||
| reproduction | r_strategy (0.55) | k_strategy (0.45) | |
|
||||
| thermal | cold_blooded (0.6) | warm_blooded (0.4) | |
|
||||
| social | herd (0.3), solitary (0.3) | pack (0.2) | swarm (0.1), colony (0.1) |
|
||||
|
||||
#### coral_reef
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | tiny (0.3), small (0.4) | medium (0.2) | large (0.08), huge (0.02) |
|
||||
| diet | herbivore (0.3), omnivore (0.25) | carnivore (0.2), filter_feeder (0.15) | detritivore (0.1) |
|
||||
| habitat | aquatic (1.0) | | |
|
||||
| locomotion | swimming (0.7) | sessile (0.3) | |
|
||||
| reproduction | r_strategy (0.7) | k_strategy (0.3) | |
|
||||
| thermal | cold_blooded (0.9) | warm_blooded (0.1) | |
|
||||
| social | colony (0.3), herd (0.25) | swarm (0.2), solitary (0.15) | pack (0.1) |
|
||||
|
||||
#### estuary
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.35), medium (0.3) | tiny (0.15), large (0.15) | huge (0.05) |
|
||||
| diet | omnivore (0.3), herbivore (0.25) | carnivore (0.2), detritivore (0.15) | filter_feeder (0.1) |
|
||||
| habitat | amphibious (0.4), aquatic (0.4) | | aerial (0.2) |
|
||||
| locomotion | swimming (0.5) | walking (0.25), flying (0.15) | slithering (0.1) |
|
||||
| reproduction | r_strategy (0.6) | k_strategy (0.4) | |
|
||||
| thermal | cold_blooded (0.55) | warm_blooded (0.45) | |
|
||||
| social | herd (0.3), solitary (0.25) | pack (0.2), colony (0.15) | swarm (0.1) |
|
||||
|
||||
#### pond
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | tiny (0.5), small (0.35) | | medium (0.15) |
|
||||
| diet | herbivore (0.3), detritivore (0.25) | omnivore (0.25) | carnivore (0.15), filter_feeder (0.05) |
|
||||
| habitat | aquatic (0.5), amphibious (0.3) | | aerial (0.2) |
|
||||
| locomotion | swimming (0.5) | walking (0.2), flying (0.2) | slithering (0.1) |
|
||||
| reproduction | r_strategy (0.8) | k_strategy (0.2) | |
|
||||
| thermal | cold_blooded (0.7) | warm_blooded (0.3) | |
|
||||
| social | swarm (0.3), colony (0.25) | solitary (0.25) | herd (0.1), pack (0.1) |
|
||||
|
||||
#### river
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.4), medium (0.3) | tiny (0.15) | large (0.12), huge (0.03) |
|
||||
| diet | herbivore (0.25), omnivore (0.25) | carnivore (0.25) | detritivore (0.15), filter_feeder (0.1) |
|
||||
| habitat | aquatic (0.5), amphibious (0.3) | | aerial (0.2) |
|
||||
| locomotion | swimming (0.6) | walking (0.15), flying (0.15) | slithering (0.1) |
|
||||
| reproduction | r_strategy (0.6) | k_strategy (0.4) | |
|
||||
| thermal | cold_blooded (0.5) | warm_blooded (0.5) | |
|
||||
| social | solitary (0.3), herd (0.25) | pack (0.2) | swarm (0.15), colony (0.1) |
|
||||
|
||||
#### lake
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.35), medium (0.3) | tiny (0.15), large (0.15) | huge (0.05) |
|
||||
| diet | herbivore (0.25), omnivore (0.25) | carnivore (0.2), filter_feeder (0.15) | detritivore (0.15) |
|
||||
| habitat | aquatic (0.6), amphibious (0.25) | | aerial (0.15) |
|
||||
| locomotion | swimming (0.65) | walking (0.15), flying (0.1) | slithering (0.1) |
|
||||
| reproduction | r_strategy (0.55) | k_strategy (0.45) | |
|
||||
| thermal | cold_blooded (0.55) | warm_blooded (0.45) | |
|
||||
| social | herd (0.3), solitary (0.25) | pack (0.2) | swarm (0.15), colony (0.1) |
|
||||
|
||||
#### mangrove
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.35), medium (0.3) | tiny (0.15), large (0.15) | huge (0.05) |
|
||||
| diet | omnivore (0.3), carnivore (0.25) | herbivore (0.2), detritivore (0.15) | filter_feeder (0.1) |
|
||||
| habitat | amphibious (0.5), aquatic (0.2) | arboreal (0.15) | aerial (0.15) |
|
||||
| locomotion | swimming (0.3), walking (0.25) | climbing (0.2), flying (0.15) | slithering (0.1) |
|
||||
| reproduction | r_strategy (0.6) | k_strategy (0.4) | |
|
||||
| thermal | cold_blooded (0.65) | warm_blooded (0.35) | |
|
||||
| social | solitary (0.3), colony (0.25) | pack (0.2) | swarm (0.15), herd (0.1) |
|
||||
|
||||
### Tropical Biomes
|
||||
|
||||
#### tropical_rainforest
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), small (0.25) | large (0.2), tiny (0.15) | huge (0.1) |
|
||||
| diet | herbivore (0.25), omnivore (0.25) | carnivore (0.2), detritivore (0.15) | producer (0.1), filter_feeder (0.05) |
|
||||
| habitat | arboreal (0.35), terrestrial (0.35) | | aerial (0.2), amphibious (0.1) |
|
||||
| locomotion | climbing (0.3), walking (0.25) | flying (0.2) | slithering (0.15), burrowing (0.1) |
|
||||
| reproduction | r_strategy (0.5) | k_strategy (0.5) | |
|
||||
| thermal | warm_blooded (0.5) | cold_blooded (0.5) | |
|
||||
| social | solitary (0.25), pack (0.2) | herd (0.2), swarm (0.2) | colony (0.15) |
|
||||
|
||||
#### tropical_dry_forest
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), small (0.3) | large (0.2) | tiny (0.1), huge (0.1) |
|
||||
| diet | herbivore (0.3), omnivore (0.25) | carnivore (0.2) | detritivore (0.15), producer (0.1) |
|
||||
| habitat | terrestrial (0.45), arboreal (0.25) | | aerial (0.2), amphibious (0.1) |
|
||||
| locomotion | walking (0.35), climbing (0.2) | flying (0.2) | slithering (0.15), burrowing (0.1) |
|
||||
| reproduction | r_strategy (0.55) | k_strategy (0.45) | |
|
||||
| thermal | warm_blooded (0.45) | cold_blooded (0.55) | |
|
||||
| social | herd (0.25), solitary (0.25) | pack (0.2) | swarm (0.15), colony (0.15) |
|
||||
|
||||
#### savanna
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | large (0.3), medium (0.3) | small (0.2) | huge (0.1), tiny (0.1) |
|
||||
| diet | herbivore (0.35), carnivore (0.25) | omnivore (0.2) | detritivore (0.1), producer (0.1) |
|
||||
| habitat | terrestrial (0.7) | | aerial (0.2), amphibious (0.1) |
|
||||
| locomotion | walking (0.6) | flying (0.2) | burrowing (0.1), slithering (0.1) |
|
||||
| reproduction | k_strategy (0.5) | r_strategy (0.5) | |
|
||||
| thermal | warm_blooded (0.6) | cold_blooded (0.4) | |
|
||||
| social | herd (0.35), pack (0.25) | solitary (0.2) | swarm (0.1), colony (0.1) |
|
||||
|
||||
#### desert
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.35), tiny (0.3) | medium (0.2) | large (0.1), huge (0.05) |
|
||||
| diet | omnivore (0.3), carnivore (0.25) | herbivore (0.2), detritivore (0.15) | producer (0.1) |
|
||||
| habitat | terrestrial (0.7) | subterranean (0.15) | aerial (0.15) |
|
||||
| locomotion | walking (0.3), burrowing (0.25) | slithering (0.25) | flying (0.15), climbing (0.05) |
|
||||
| reproduction | r_strategy (0.65) | k_strategy (0.35) | |
|
||||
| thermal | cold_blooded (0.7) | warm_blooded (0.3) | |
|
||||
| social | solitary (0.45), colony (0.2) | pack (0.15) | swarm (0.15), herd (0.05) |
|
||||
|
||||
### Temperate Biomes
|
||||
|
||||
#### temperate_forest
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), small (0.25) | large (0.2) | tiny (0.1), huge (0.15) |
|
||||
| diet | herbivore (0.3), omnivore (0.25) | carnivore (0.2) | detritivore (0.15), producer (0.1) |
|
||||
| habitat | terrestrial (0.5), arboreal (0.2) | | aerial (0.2), amphibious (0.1) |
|
||||
| locomotion | walking (0.4) | climbing (0.2), flying (0.2) | burrowing (0.1), slithering (0.1) |
|
||||
| reproduction | k_strategy (0.5) | r_strategy (0.5) | |
|
||||
| thermal | warm_blooded (0.65) | cold_blooded (0.35) | |
|
||||
| social | solitary (0.25), pack (0.25) | herd (0.2) | colony (0.15), swarm (0.15) |
|
||||
|
||||
#### temperate_grassland
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), small (0.25) | large (0.2) | tiny (0.1), huge (0.15) |
|
||||
| diet | herbivore (0.35), carnivore (0.25) | omnivore (0.2) | detritivore (0.1), producer (0.1) |
|
||||
| habitat | terrestrial (0.7) | | aerial (0.2), amphibious (0.1) |
|
||||
| locomotion | walking (0.5) | flying (0.2), burrowing (0.15) | slithering (0.1), climbing (0.05) |
|
||||
| reproduction | r_strategy (0.5) | k_strategy (0.5) | |
|
||||
| thermal | warm_blooded (0.6) | cold_blooded (0.4) | |
|
||||
| social | herd (0.35), pack (0.25) | solitary (0.2) | swarm (0.1), colony (0.1) |
|
||||
|
||||
#### chaparral
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.35), medium (0.3) | tiny (0.15) | large (0.15), huge (0.05) |
|
||||
| diet | omnivore (0.3), herbivore (0.25) | carnivore (0.2) | detritivore (0.15), producer (0.1) |
|
||||
| habitat | terrestrial (0.7) | | aerial (0.15), subterranean (0.15) |
|
||||
| locomotion | walking (0.35), burrowing (0.2) | slithering (0.2) | flying (0.15), climbing (0.1) |
|
||||
| reproduction | r_strategy (0.6) | k_strategy (0.4) | |
|
||||
| thermal | cold_blooded (0.55) | warm_blooded (0.45) | |
|
||||
| social | solitary (0.35), pack (0.2) | colony (0.2) | herd (0.15), swarm (0.1) |
|
||||
|
||||
#### swamp
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), small (0.25) | large (0.2), tiny (0.15) | huge (0.1) |
|
||||
| diet | omnivore (0.25), carnivore (0.25) | herbivore (0.2), detritivore (0.2) | filter_feeder (0.1) |
|
||||
| habitat | amphibious (0.4), terrestrial (0.3) | | aquatic (0.15), aerial (0.15) |
|
||||
| locomotion | swimming (0.3), walking (0.25) | slithering (0.2) | flying (0.15), burrowing (0.1) |
|
||||
| reproduction | r_strategy (0.6) | k_strategy (0.4) | |
|
||||
| thermal | cold_blooded (0.6) | warm_blooded (0.4) | |
|
||||
| social | solitary (0.3), colony (0.2) | swarm (0.2), pack (0.15) | herd (0.15) |
|
||||
|
||||
#### bog
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | tiny (0.35), small (0.35) | medium (0.2) | large (0.08), huge (0.02) |
|
||||
| diet | detritivore (0.3), herbivore (0.25) | omnivore (0.2) | carnivore (0.15), filter_feeder (0.1) |
|
||||
| habitat | amphibious (0.35), terrestrial (0.35) | | aerial (0.2), aquatic (0.1) |
|
||||
| locomotion | walking (0.25), swimming (0.2) | flying (0.2), burrowing (0.15) | slithering (0.15), climbing (0.05) |
|
||||
| reproduction | r_strategy (0.7) | k_strategy (0.3) | |
|
||||
| thermal | cold_blooded (0.6) | warm_blooded (0.4) | |
|
||||
| social | swarm (0.3), colony (0.25) | solitary (0.2) | herd (0.15), pack (0.1) |
|
||||
|
||||
### Cold Biomes
|
||||
|
||||
#### boreal_forest
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), large (0.25) | small (0.2) | huge (0.15), tiny (0.1) |
|
||||
| diet | herbivore (0.3), carnivore (0.25) | omnivore (0.25) | detritivore (0.1), producer (0.1) |
|
||||
| habitat | terrestrial (0.6) | arboreal (0.15) | aerial (0.15), amphibious (0.1) |
|
||||
| locomotion | walking (0.5) | climbing (0.15), flying (0.15) | burrowing (0.1), slithering (0.1) |
|
||||
| reproduction | k_strategy (0.55) | r_strategy (0.45) | |
|
||||
| thermal | warm_blooded (0.75) | cold_blooded (0.25) | |
|
||||
| social | pack (0.3), solitary (0.25) | herd (0.2) | colony (0.15), swarm (0.1) |
|
||||
|
||||
#### tundra
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | large (0.3), medium (0.3) | small (0.2) | huge (0.1), tiny (0.1) |
|
||||
| diet | herbivore (0.35), carnivore (0.25) | omnivore (0.2) | detritivore (0.15), producer (0.05) |
|
||||
| habitat | terrestrial (0.8) | | aerial (0.15), amphibious (0.05) |
|
||||
| locomotion | walking (0.6) | flying (0.2) | burrowing (0.1), slithering (0.05), climbing (0.05) |
|
||||
| reproduction | k_strategy (0.6) | r_strategy (0.4) | |
|
||||
| thermal | warm_blooded (0.85) | cold_blooded (0.15) | |
|
||||
| social | herd (0.4), pack (0.25) | solitary (0.2) | colony (0.1), swarm (0.05) |
|
||||
|
||||
#### polar_desert
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), small (0.3) | large (0.2) | tiny (0.15), huge (0.05) |
|
||||
| diet | carnivore (0.3), herbivore (0.25) | omnivore (0.2) | detritivore (0.15), filter_feeder (0.1) |
|
||||
| habitat | terrestrial (0.5), aquatic (0.3) | | amphibious (0.2) |
|
||||
| locomotion | walking (0.35), swimming (0.3) | | flying (0.15), burrowing (0.1), slithering (0.1) |
|
||||
| reproduction | k_strategy (0.65) | r_strategy (0.35) | |
|
||||
| thermal | warm_blooded (0.9) | cold_blooded (0.1) | |
|
||||
| social | herd (0.3), solitary (0.3) | pack (0.2) | colony (0.15), swarm (0.05) |
|
||||
|
||||
### Elevation Biomes
|
||||
|
||||
#### montane_forest
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), large (0.25) | small (0.2) | huge (0.15), tiny (0.1) |
|
||||
| diet | herbivore (0.3), omnivore (0.25) | carnivore (0.2) | detritivore (0.15), producer (0.1) |
|
||||
| habitat | terrestrial (0.5), arboreal (0.2) | | aerial (0.2), amphibious (0.1) |
|
||||
| locomotion | walking (0.35), climbing (0.25) | flying (0.2) | burrowing (0.1), slithering (0.1) |
|
||||
| reproduction | k_strategy (0.55) | r_strategy (0.45) | |
|
||||
| thermal | warm_blooded (0.7) | cold_blooded (0.3) | |
|
||||
| social | solitary (0.3), pack (0.25) | herd (0.2) | colony (0.15), swarm (0.1) |
|
||||
|
||||
#### cloud_forest
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.3), medium (0.3) | tiny (0.2) | large (0.15), huge (0.05) |
|
||||
| diet | herbivore (0.25), omnivore (0.25) | detritivore (0.2) | carnivore (0.15), producer (0.15) |
|
||||
| habitat | arboreal (0.4), terrestrial (0.3) | | aerial (0.2), amphibious (0.1) |
|
||||
| locomotion | climbing (0.35), flying (0.2) | walking (0.2) | slithering (0.15), burrowing (0.1) |
|
||||
| reproduction | r_strategy (0.5) | k_strategy (0.5) | |
|
||||
| thermal | warm_blooded (0.5) | cold_blooded (0.5) | |
|
||||
| social | solitary (0.3), colony (0.2) | swarm (0.2) | pack (0.15), herd (0.15) |
|
||||
|
||||
#### alpine_meadow
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), small (0.25) | large (0.2) | tiny (0.15), huge (0.1) |
|
||||
| diet | herbivore (0.4), omnivore (0.2) | carnivore (0.2) | detritivore (0.1), producer (0.1) |
|
||||
| habitat | terrestrial (0.7) | | aerial (0.25), amphibious (0.05) |
|
||||
| locomotion | walking (0.45), climbing (0.2) | flying (0.2) | burrowing (0.1), slithering (0.05) |
|
||||
| reproduction | k_strategy (0.55) | r_strategy (0.45) | |
|
||||
| thermal | warm_blooded (0.75) | cold_blooded (0.25) | |
|
||||
| social | herd (0.3), solitary (0.25) | pack (0.25) | colony (0.1), swarm (0.1) |
|
||||
|
||||
#### alpine_tundra
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | medium (0.3), small (0.25) | large (0.2) | tiny (0.15), huge (0.1) |
|
||||
| diet | herbivore (0.35), carnivore (0.25) | omnivore (0.2) | detritivore (0.15), producer (0.05) |
|
||||
| habitat | terrestrial (0.8) | | aerial (0.15), subterranean (0.05) |
|
||||
| locomotion | walking (0.4), climbing (0.25) | flying (0.15) | burrowing (0.15), slithering (0.05) |
|
||||
| reproduction | k_strategy (0.6) | r_strategy (0.4) | |
|
||||
| thermal | warm_blooded (0.8) | cold_blooded (0.2) | |
|
||||
| social | herd (0.3), pack (0.25) | solitary (0.25) | colony (0.15), swarm (0.05) |
|
||||
|
||||
#### permanent_ice
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.3), medium (0.3) | tiny (0.2) | large (0.15), huge (0.05) |
|
||||
| diet | carnivore (0.3), herbivore (0.25) | omnivore (0.2) | detritivore (0.15), producer (0.1) |
|
||||
| habitat | terrestrial (0.5), aquatic (0.3) | | amphibious (0.2) |
|
||||
| locomotion | walking (0.3), swimming (0.3) | | flying (0.15), climbing (0.15), burrowing (0.1) |
|
||||
| reproduction | k_strategy (0.7) | r_strategy (0.3) | |
|
||||
| thermal | warm_blooded (0.9) | cold_blooded (0.1) | |
|
||||
| social | herd (0.3), solitary (0.3) | pack (0.2) | colony (0.15), swarm (0.05) |
|
||||
|
||||
### Subterranean Biome
|
||||
|
||||
#### subterranean
|
||||
|
||||
| Trait | High Weight | Medium | Low |
|
||||
|-------|-----------|---------|----|
|
||||
| size | small (0.35), tiny (0.3) | medium (0.2) | large (0.1), huge (0.05) |
|
||||
| diet | omnivore (0.25), detritivore (0.25) | carnivore (0.2), herbivore (0.15) | producer (0.1), filter_feeder (0.05) |
|
||||
| habitat | subterranean (0.8) | | amphibious (0.1), terrestrial (0.1) |
|
||||
| locomotion | burrowing (0.35), climbing (0.3) | walking (0.15) | slithering (0.15), swimming (0.05) |
|
||||
| reproduction | r_strategy (0.65) | k_strategy (0.35) | |
|
||||
| thermal | cold_blooded (0.75) | warm_blooded (0.25) | |
|
||||
| social | colony (0.35), swarm (0.2) | solitary (0.2) | pack (0.15), herd (0.1) |
|
||||
|
||||
Typical generated species:
|
||||
- small + burrowing + cold_blooded + colony + omnivore = "cave insect-like"
|
||||
- medium + climbing + cold_blooded + solitary + carnivore = "giant spider-like"
|
||||
- small + flying + warm_blooded + swarm + carnivore = "bat-like"
|
||||
- tiny + burrowing + cold_blooded + colony + detritivore = "cave worm-like"
|
||||
- medium + swimming + cold_blooded + solitary + carnivore = "blind cave fish-like" (in flooded caves)
|
||||
|
||||
---
|
||||
|
||||
## Quality Tier Derivation
|
||||
|
||||
### Formula
|
||||
|
||||
```
|
||||
species_quality = clamp(base + modifiers, 1, 5)
|
||||
|
||||
base = SIZE_QUALITY[size]
|
||||
tiny → 1
|
||||
small → 2
|
||||
medium → 3
|
||||
large → 4
|
||||
huge → 5
|
||||
|
||||
modifiers:
|
||||
r_strategy → -1
|
||||
k_strategy → 0
|
||||
detritivore → -1
|
||||
carnivore → +1
|
||||
```
|
||||
|
||||
### Quality Range (species lifetime)
|
||||
|
||||
Species don't stay at one quality. They have a quality range based on the derived base:
|
||||
|
||||
| Derived Quality | Quality Range | Example |
|
||||
|----------------|-------------|---------|
|
||||
| Q1 | Q1-Q2 | Worms, algae, tiny insects |
|
||||
| Q2 | Q1-Q3 | Common fish, rabbits, cave insects |
|
||||
| Q3 | Q2-Q4 | Deer, wolves (young), standard predators |
|
||||
| Q4 | Q3-Q5 | Bears, sharks, dire wolves |
|
||||
| Q5 | Q4-Q5 | Ancient leviathans, megafauna |
|
||||
|
||||
An individual creature spawns at `quality_range[0]` and ages up toward `quality_range[1]`, capped by `min(species.max_quality, tile.quality)`.
|
||||
|
||||
---
|
||||
|
||||
## Spawn Probability Table
|
||||
|
||||
Tile quality gates which species quality tiers can spawn. Higher-quality tiles support rarer species.
|
||||
|
||||
| Tile Quality | Q1 species | Q2 species | Q3 species | Q4 species | Q5 species |
|
||||
|-------------|-----------|-----------|-----------|-----------|-----------|
|
||||
| Q1 tile | 50% | 30% | 10% | 0% | 0% |
|
||||
| Q2 tile | 30% | 40% | 25% | 5% | 0% |
|
||||
| Q3 tile | 10% | 25% | 40% | 20% | 5% |
|
||||
| Q4 tile | 5% | 15% | 30% | 35% | 15% |
|
||||
| Q5 tile | 0% | 10% | 25% | 35% | 30% |
|
||||
|
||||
Species can only spawn on tiles where `tile.quality >= species.min_quality`. The table above gives the probability of each quality tier being selected when the tile generates a new species.
|
||||
|
||||
---
|
||||
|
||||
## Minimum Species Per Biome
|
||||
|
||||
After generation across 10 seeds, each biome must produce:
|
||||
|
||||
| Trophic Level | Minimum Count | Rationale |
|
||||
|--------------|---------------|-----------|
|
||||
| Producer | 3 | Base of food web, must be diverse enough to support herbivores |
|
||||
| Herbivore | 3 | Multiple prey species prevent single-point food web collapse |
|
||||
| Predator | 2 | At least one solitary + one pack predator for ecological balance |
|
||||
| Detritivore | 1 | Recycler role, prevents dead-matter buildup |
|
||||
|
||||
If any biome fails these minimums across the seed set, its trait weights need adjustment (increase weight for the underrepresented trophic level).
|
||||
Loading…
Add table
Reference in a new issue