feat(@projects/@magic-civilization): add dragon species data and tier-based styling

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-03 19:45:54 -04:00
parent 58ce33bf9c
commit 51f99cecc1
4 changed files with 295 additions and 10 deletions

View file

@ -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 {
<Column>
<ColumnLabel>fauna ({faunaOnTerrain.length})</ColumnLabel>
{faunaOnTerrain.length === 0 && <Empty>none mapped to this terrain</Empty>}
{faunaOnTerrain.map(f => (
<SpeciesRow key={f.id} $accent="#a07cc9">
<SpeciesName>{f.name}</SpeciesName>
<SpeciesMeta>
{f.ecology_tier && <span>tier {f.ecology_tier}</span>}
{f.trophic_level && <span>{f.trophic_level}</span>}
{f.cognitive_profile?.can_hold_grudge && <span style={{ color: "#d95940" }}> grudge int{f.cognitive_profile.intelligence}</span>}
</SpeciesMeta>
</SpeciesRow>
))}
{faunaOnTerrain.map(f => {
const isApex = (f.ecology_tier ?? 0) >= 8;
const accent = isApex ? "#d95940" : (f.combat_profile ? "#e69933" : "#a07cc9");
return (
<SpeciesRow key={f.id} $accent={accent}>
<SpeciesName>
{f.name}{isApex && <span style={{ color: "#d95940", marginLeft: 6 }}> apex</span>}
</SpeciesName>
<SpeciesMeta>
{f.ecology_tier && <span>tier {f.ecology_tier}</span>}
{f.trophic_level && <span>{f.trophic_level}</span>}
{f.migration_range !== undefined && <span style={{ color: "#66bfff" }}>range {f.migration_range}h</span>}
{f.food_consumption_per_turn !== undefined && <span style={{ color: "#e69933" }}>eats {f.food_consumption_per_turn}/t</span>}
{f.combat_profile && <span style={{ color: "#d95940" }}>hp {f.combat_profile.hp}, str {f.combat_profile.strength}</span>}
{f.cognitive_profile?.can_hold_grudge && <span style={{ color: "#d95940" }}> grudge int{f.cognitive_profile.intelligence}</span>}
{f.devastation && <span style={{ color: "#d95940", fontWeight: 600 }}>devastates t{f.devastation.auto_defeat_tier_at_or_below}</span>}
{f.loot_table?.legendary?.length && <span style={{ color: "#ccbf73" }}> {f.loot_table.legendary.length} legendary</span>}
</SpeciesMeta>
</SpeciesRow>
);
})}
</Column>
<Column>

View file

@ -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"
]
}
}

View file

@ -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"
]
}
}

View file

@ -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"
]
}
}