diff --git a/.project/designs/app/src/pages/TerrainEcology.tsx b/.project/designs/app/src/pages/TerrainEcology.tsx index d8e488c6..f6807cfe 100644 --- a/.project/designs/app/src/pages/TerrainEcology.tsx +++ b/.project/designs/app/src/pages/TerrainEcology.tsx @@ -39,7 +39,14 @@ interface FaunaSpecies { ecology_tier?: number; trophic_level?: string; terrain_affinity?: string[]; + migration_range?: number; + carrying_capacity?: number; + food_consumption_per_turn?: number; + habitat_min?: number; + combat_profile?: { hp: number; strength: number; dexterity: number; constitution: number }; cognitive_profile?: { intelligence: number; can_hold_grudge: boolean }; + devastation?: { auto_defeat_tier_at_or_below: number; description: string }; + loot_table?: { legendary?: string[]; rare?: string[]; common?: string[] }; } interface WildUnit { @@ -356,16 +363,27 @@ export function TerrainEcologyPage(): ReactElement { fauna ({faunaOnTerrain.length}) {faunaOnTerrain.length === 0 && none mapped to this terrain} - {faunaOnTerrain.map(f => ( - - {f.name} - - {f.ecology_tier && tier {f.ecology_tier}} - {f.trophic_level && {f.trophic_level}} - {f.cognitive_profile?.can_hold_grudge && ✦ grudge int{f.cognitive_profile.intelligence}} - - - ))} + {faunaOnTerrain.map(f => { + const isApex = (f.ecology_tier ?? 0) >= 8; + const accent = isApex ? "#d95940" : (f.combat_profile ? "#e69933" : "#a07cc9"); + return ( + + + {f.name}{isApex && ★ apex} + + + {f.ecology_tier && tier {f.ecology_tier}} + {f.trophic_level && {f.trophic_level}} + {f.migration_range !== undefined && range {f.migration_range}h} + {f.food_consumption_per_turn !== undefined && eats {f.food_consumption_per_turn}/t} + {f.combat_profile && hp {f.combat_profile.hp}, str {f.combat_profile.strength}} + {f.cognitive_profile?.can_hold_grudge && ✦ grudge int{f.cognitive_profile.intelligence}} + {f.devastation && devastates ≤t{f.devastation.auto_defeat_tier_at_or_below}} + {f.loot_table?.legendary?.length && ★ {f.loot_table.legendary.length} legendary} + + + ); + })} diff --git a/public/resources/ecology/fauna/species/ancient_green_dragon.json b/public/resources/ecology/fauna/species/ancient_green_dragon.json new file mode 100644 index 00000000..01cd3793 --- /dev/null +++ b/public/resources/ecology/fauna/species/ancient_green_dragon.json @@ -0,0 +1,91 @@ +{ + "id": "ancient_green_dragon", + "name": "Ancient Green Dragon", + "description": "A wyrm of canopy and cunning — the smallest of the great dragons by mass, the largest by malice. Speaks dwarven, elf-tongue, kobold; lies in all four.", + "tags": [ + "fauna", + "tier_10", + "apex_predator", + "boss", + "poison_breath", + "cunning" + ], + "domain": "land_air", + "trophic_level": "apex_predator", + "lineage": "true_dragon", + "ecology_tier": 10, + "traits": [ + "poison_immune", + "flying", + "venom_breath_acid", + "deceiver", + "ancient" + ], + "habitat_min": 0.5, + "migration_range": 12, + "carrying_capacity": 0.35, + "food_consumption_per_turn": 5, + "lifecycle": { + "mature_age_turns": 3500, + "max_age_turns": null + }, + "terrain_affinity": [ + "jungle", + "tropical_rainforest", + "enchanted_forest", + "swamp", + "bog" + ], + "combat_profile": { + "hp": 680, + "strength": 24, + "dexterity": 18, + "constitution": 22, + "attack_type": "acid_breath", + "range": 4, + "defense": 18, + "breath_weapon": { + "damage": 45, + "area_radius": 1, + "cooldown_turns": 2 + } + }, + "cognitive_profile": { + "intelligence": 10, + "hostility": "hunting", + "can_hold_grudge": true, + "grudge_memory_turns": 200 + }, + "devastation": { + "auto_defeat_tier_at_or_below": 5, + "description": "Cunning beyond intimidation — manipulates lesser creatures, sets traps, recruits goblins as pawns. May parley if approached at tier 8+ with appropriate tribute (gold + slaves traditionally)." + }, + "loot_table": { + "legendary": [ + "green_dragon_scale", + "green_dragon_heart", + "venomous_hoard" + ], + "rare": [ + "acid_fang", + "wisdom_codex_lost" + ], + "common": [ + "acid_etched_bone" + ] + }, + "flavor": "It has been planning your death for sixty years. It will not appear hurried about it.", + "encyclopedia": { + "category": "fauna", + "entry_type": "species", + "detail_route": "/bestiary", + "tags": [ + "fauna", + "tier_10", + "boss", + "dragon", + "poison", + "intelligent" + ] + } +} diff --git a/public/resources/ecology/fauna/species/ancient_red_dragon.json b/public/resources/ecology/fauna/species/ancient_red_dragon.json new file mode 100644 index 00000000..a5e2ac9d --- /dev/null +++ b/public/resources/ecology/fauna/species/ancient_red_dragon.json @@ -0,0 +1,87 @@ +{ + "id": "ancient_red_dragon", + "name": "Ancient Red Dragon", + "description": "An ageless wyrm of fire and avarice. Hunts entire valleys; sleeps on hoards built across centuries. Anything below the iron age is prey.", + "tags": [ + "fauna", + "tier_10", + "apex_predator", + "boss", + "fire_breath" + ], + "domain": "land_air", + "trophic_level": "apex_predator", + "lineage": "true_dragon", + "ecology_tier": 10, + "traits": [ + "fire_immune", + "flying", + "venom_breath_fire", + "treasure_hoarder", + "ancient" + ], + "habitat_min": 0.6, + "migration_range": 18, + "carrying_capacity": 0.45, + "food_consumption_per_turn": 8, + "lifecycle": { + "mature_age_turns": 5000, + "max_age_turns": null + }, + "terrain_affinity": [ + "mountains", + "volcano" + ], + "combat_profile": { + "hp": 850, + "strength": 32, + "dexterity": 12, + "constitution": 26, + "attack_type": "fire_breath", + "range": 4, + "defense": 22, + "breath_weapon": { + "damage": 60, + "area_radius": 2, + "cooldown_turns": 3 + } + }, + "cognitive_profile": { + "intelligence": 9, + "hostility": "hunting", + "can_hold_grudge": true, + "grudge_memory_turns": 100, + "pack_behavior": null + }, + "devastation": { + "auto_defeat_tier_at_or_below": 5, + "description": "Any unit of tier 5 or lower facing this dragon alone is destroyed without contest. Tier 6-7 stand a chance only with prepared positions and ranged support. Tier 8+ (steam-era weapons, mithril alloys) can engage as a coordinated company." + }, + "loot_table": { + "legendary": [ + "red_dragon_scale", + "red_dragon_heart", + "ancient_hoard_treasure" + ], + "rare": [ + "dragon_fang", + "dragon_fire_gland" + ], + "common": [ + "scorched_bone" + ] + }, + "flavor": "It does not raid the village. It owns the village. The villagers simply weren't told.", + "encyclopedia": { + "category": "fauna", + "entry_type": "species", + "detail_route": "/bestiary", + "tags": [ + "fauna", + "tier_10", + "boss", + "dragon", + "fire" + ] + } +} diff --git a/public/resources/ecology/fauna/species/ancient_white_dragon.json b/public/resources/ecology/fauna/species/ancient_white_dragon.json new file mode 100644 index 00000000..2a99434c --- /dev/null +++ b/public/resources/ecology/fauna/species/ancient_white_dragon.json @@ -0,0 +1,89 @@ +{ + "id": "ancient_white_dragon", + "name": "Ancient White Dragon", + "description": "A wyrm of glacier and silence. Stalks the frozen wastes, freezing prey solid. Cold older than the dwarven kingdoms.", + "tags": [ + "fauna", + "tier_10", + "apex_predator", + "boss", + "cold_breath" + ], + "domain": "land_air", + "trophic_level": "apex_predator", + "lineage": "true_dragon", + "ecology_tier": 10, + "traits": [ + "cold_immune", + "flying", + "venom_breath_cold", + "stealth_snow", + "ancient" + ], + "habitat_min": 0.7, + "migration_range": 14, + "carrying_capacity": 0.3, + "food_consumption_per_turn": 6, + "lifecycle": { + "mature_age_turns": 4000, + "max_age_turns": null + }, + "terrain_affinity": [ + "ice", + "snow", + "polar_desert", + "alpine_tundra", + "tundra" + ], + "combat_profile": { + "hp": 720, + "strength": 28, + "dexterity": 14, + "constitution": 24, + "attack_type": "cold_breath", + "range": 4, + "defense": 20, + "breath_weapon": { + "damage": 50, + "area_radius": 2, + "cooldown_turns": 3 + } + }, + "cognitive_profile": { + "intelligence": 7, + "hostility": "hunting", + "can_hold_grudge": true, + "grudge_memory_turns": 80 + }, + "devastation": { + "auto_defeat_tier_at_or_below": 5, + "description": "Cold breath shatters armor. Pre-iron units freeze without dealing a strike." + }, + "loot_table": { + "legendary": [ + "white_dragon_scale", + "white_dragon_heart", + "frozen_hoard" + ], + "rare": [ + "frost_fang", + "frostmaw_gland" + ], + "common": [ + "ice_riven_bone" + ] + }, + "flavor": "You hear the wing-beat. Then nothing. The cold takes your hearing first.", + "encyclopedia": { + "category": "fauna", + "entry_type": "species", + "detail_route": "/bestiary", + "tags": [ + "fauna", + "tier_10", + "boss", + "dragon", + "cold" + ] + } +}