feat(age-dwarves): ✨ Introduce new terrain blend configurations and resource definitions for expanded game content
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
9c4d635df3
commit
4cfedd96aa
11 changed files with 426 additions and 5 deletions
21
public/games/age-of-dwarves/data/resources/bear_pelt.json
Normal file
21
public/games/age-of-dwarves/data/resources/bear_pelt.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"id": "bear_pelt",
|
||||
"category": "luxury",
|
||||
"name": "Bear Pelt",
|
||||
"description": "Thick winter pelts harvested from cave-bear populations. Cold-weather garment, status symbol in clan halls. Supply tracks live cave-bear population — overhunting collapses the resource for decades.",
|
||||
"happiness_per_unique_copy": 4,
|
||||
"source_fauna": ["cave_bear"],
|
||||
"min_population": 50,
|
||||
"harvest_rate": 0.05,
|
||||
"tier": 2,
|
||||
"sprite": "sprites/resources/bear_pelt.png",
|
||||
"encyclopedia": {
|
||||
"category": "luxury",
|
||||
"entry_type": "fauna_product",
|
||||
"detail_route": "/economy/luxuries",
|
||||
"tags": ["fauna", "luxury", "cold_weather"]
|
||||
},
|
||||
"flavor": "Worn by chieftains; the thicker the pelt, the older the bear, the prouder the hunter."
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"id": "harpy_feather",
|
||||
"category": "luxury",
|
||||
"name": "Harpy Feather",
|
||||
"description": "Iridescent flight feathers harvested from harpy roosts. Used in fletching, ceremonial cloaks, and clan banners. Population recovers slowly — heavy harvesting collapses the supply for generations.",
|
||||
"happiness_per_unique_copy": 4,
|
||||
"source_fauna": ["harpy"],
|
||||
"min_population": 40,
|
||||
"harvest_rate": 0.05,
|
||||
"tier": 3,
|
||||
"sprite": "sprites/resources/harpy_feather.png",
|
||||
"encyclopedia": {
|
||||
"category": "luxury",
|
||||
"entry_type": "fauna_product",
|
||||
"detail_route": "/economy/luxuries",
|
||||
"tags": ["fauna", "luxury", "fletching"]
|
||||
},
|
||||
"flavor": "Banners of harpy plume catch the wind and the eye in equal measure."
|
||||
}
|
||||
]
|
||||
21
public/games/age-of-dwarves/data/resources/spider_silk.json
Normal file
21
public/games/age-of-dwarves/data/resources/spider_silk.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"id": "spider_silk",
|
||||
"category": "luxury",
|
||||
"name": "Spider Silk",
|
||||
"description": "Spun threads harvested from giant cave-spider broods. Stronger than steel by weight; woven into ceremonial robes and bowstrings. Supply tied to spider density in tunnel biomes.",
|
||||
"happiness_per_unique_copy": 4,
|
||||
"source_fauna": ["giant_spider"],
|
||||
"min_population": 80,
|
||||
"harvest_rate": 0.06,
|
||||
"tier": 3,
|
||||
"sprite": "sprites/resources/spider_silk.png",
|
||||
"encyclopedia": {
|
||||
"category": "luxury",
|
||||
"entry_type": "fauna_product",
|
||||
"detail_route": "/economy/luxuries",
|
||||
"tags": ["fauna", "luxury", "textile"]
|
||||
},
|
||||
"flavor": "A robe of spider silk weighs less than a feather and turns a dirk blade."
|
||||
}
|
||||
]
|
||||
21
public/games/age-of-dwarves/data/resources/troll_bone.json
Normal file
21
public/games/age-of-dwarves/data/resources/troll_bone.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"id": "troll_bone",
|
||||
"category": "luxury",
|
||||
"name": "Troll Bone",
|
||||
"description": "Dense load-bearing bones recovered from troll kills. Worked into haft cores and ceremonial inlays — only the boldest hunters bring back enough to trade. Supply is gated by local troll population.",
|
||||
"happiness_per_unique_copy": 4,
|
||||
"source_fauna": ["mountain_troll"],
|
||||
"min_population": 30,
|
||||
"harvest_rate": 0.04,
|
||||
"tier": 3,
|
||||
"sprite": "sprites/resources/troll_bone.png",
|
||||
"encyclopedia": {
|
||||
"category": "luxury",
|
||||
"entry_type": "fauna_product",
|
||||
"detail_route": "/economy/luxuries",
|
||||
"tags": ["fauna", "luxury", "craft"]
|
||||
},
|
||||
"flavor": "Each haft is twice the price of the iron it carries. Trolls do not give up their bones easily."
|
||||
}
|
||||
]
|
||||
21
public/games/age-of-dwarves/data/resources/wyvern_scale.json
Normal file
21
public/games/age-of-dwarves/data/resources/wyvern_scale.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"id": "wyvern_scale",
|
||||
"category": "luxury",
|
||||
"name": "Wyvern Scale",
|
||||
"description": "Iridescent scales shed by living wyverns or harvested from kills. Lightweight, blade-resistant; prized by armoursmiths. Rarity drives the luxury bonus — wyvern populations are slow to recover.",
|
||||
"happiness_per_unique_copy": 4,
|
||||
"source_fauna": ["wyvern"],
|
||||
"min_population": 20,
|
||||
"harvest_rate": 0.03,
|
||||
"tier": 4,
|
||||
"sprite": "sprites/resources/wyvern_scale.png",
|
||||
"encyclopedia": {
|
||||
"category": "luxury",
|
||||
"entry_type": "fauna_product",
|
||||
"detail_route": "/economy/luxuries",
|
||||
"tags": ["fauna", "luxury", "armorcraft"]
|
||||
},
|
||||
"flavor": "Scaled mail laced with dragonkin shed catches the lamplight like running water."
|
||||
}
|
||||
]
|
||||
|
|
@ -32,6 +32,15 @@
|
|||
"items": { "type": "string", "minLength": 1 },
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"defeat_pool": {
|
||||
"type": "object",
|
||||
"description": "Per-victory-condition defeat track pool. Mirrors `victory_pool`: when an AI wins by victory_type X, the human hears a defeat track keyed to *how* they were beaten. AudioManager picks at random when multiple track IDs are listed. Falls back to the generic `defeat` track when the victory_type is unmapped or the elimination didn't carry one (e.g. last-unit-destroyed).",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": { "type": "string", "minLength": 1 },
|
||||
"minItems": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,18 @@
|
|||
"era": { "type": ["integer", "null"], "minimum": 1, "maximum": 10 },
|
||||
"effects": {
|
||||
"oneOf": [
|
||||
{ "type": "array", "items": { "type": "object", "required": ["type", "value"], "properties": { "type": { "type": "string" }, "value": { "type": "number" } } } },
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["type"],
|
||||
"properties": {
|
||||
"type": { "type": "string" },
|
||||
"value": { "type": ["number", "boolean", "string"] }
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
{ "type": "object" }
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
"id": { "type": "string", "minLength": 1 },
|
||||
"name": { "type": "string", "minLength": 1 },
|
||||
"description": { "type": "string" },
|
||||
"unit_type": { "type": "string", "enum": ["military", "civilian", "support", "wild", "npc"] },
|
||||
"unit_type": { "type": "string", "enum": ["military", "civilian", "support", "siege", "wild", "npc"] },
|
||||
"school": { "type": ["string", "null"] },
|
||||
"domain": { "type": "string", "enum": ["land", "sea", "air"] },
|
||||
"domain": { "type": "string", "enum": ["land", "sea", "naval", "air"] },
|
||||
"attributes": { "type": "array", "items": { "type": "string" } },
|
||||
"attack_type": { "type": "string" },
|
||||
"tier": { "type": ["integer", "null"], "minimum": 1, "maximum": 10 },
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
"flags": { "type": "array", "items": { "type": "string" } },
|
||||
"mana_cost": { "type": ["number", "null"] },
|
||||
"sprite": { "type": "string" },
|
||||
"gender": { "type": "object" },
|
||||
"gender": { "type": ["object", "null"] },
|
||||
"terrain_bonus": { "type": "object" },
|
||||
"loot_table": { "type": "object" },
|
||||
"encyclopedia": { "type": "object" }
|
||||
|
|
|
|||
275
public/games/age-of-dwarves/data/terrain/land_blends.json
Normal file
275
public/games/age-of-dwarves/data/terrain/land_blends.json
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
{
|
||||
"_doc": "Edge-blend ecotone terrains. These terrain ids appear at hex edges where two distinct centre-tile biomes meet (HEX_GEOMETRY.md §8). They are looked up via terrain_blends.json. Stat values interpolate between the two parent terrains.",
|
||||
"terrains": [
|
||||
{
|
||||
"id": "foothills",
|
||||
"name": "Foothills",
|
||||
"movement_cost": 2,
|
||||
"defense_bonus": 100,
|
||||
"food": 0,
|
||||
"production": 1,
|
||||
"trade": 0,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.10,
|
||||
"flags": ["edge_blend"],
|
||||
"color": [180, 175, 145],
|
||||
"sprite": "sprites/terrain/foothills.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "temperate",
|
||||
"quality_bonuses": { "production": 1 },
|
||||
"terrain_power": {},
|
||||
"albedo": 0.30,
|
||||
"evapotranspiration": 0.003,
|
||||
"description": "Rolling foothills at the base of mountains."
|
||||
},
|
||||
{
|
||||
"id": "shore",
|
||||
"name": "Shore",
|
||||
"movement_cost": 1,
|
||||
"defense_bonus": 0,
|
||||
"food": 2,
|
||||
"production": 0,
|
||||
"trade": 1,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.05,
|
||||
"flags": ["edge_blend", "coastal"],
|
||||
"color": [200, 200, 160],
|
||||
"sprite": "sprites/terrain/shore.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "temperate",
|
||||
"quality_bonuses": { "food": 1 },
|
||||
"terrain_power": {},
|
||||
"albedo": 0.18,
|
||||
"evapotranspiration": 0.004,
|
||||
"description": "Where land meets water — sandy beach and tidal flats."
|
||||
},
|
||||
{
|
||||
"id": "grass_fringe",
|
||||
"name": "Grass Fringe",
|
||||
"movement_cost": 1,
|
||||
"defense_bonus": 25,
|
||||
"food": 1,
|
||||
"production": 1,
|
||||
"trade": 0,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.30,
|
||||
"flags": ["edge_blend"],
|
||||
"color": [120, 175, 75],
|
||||
"sprite": "sprites/terrain/grass_fringe.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "temperate",
|
||||
"quality_bonuses": {},
|
||||
"terrain_power": {},
|
||||
"albedo": 0.20,
|
||||
"evapotranspiration": 0.005,
|
||||
"description": "Open grassland yielding to scattered trees."
|
||||
},
|
||||
{
|
||||
"id": "wooded_foothills",
|
||||
"name": "Wooded Foothills",
|
||||
"movement_cost": 2,
|
||||
"defense_bonus": 125,
|
||||
"food": 1,
|
||||
"production": 1,
|
||||
"trade": 0,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.35,
|
||||
"flags": ["edge_blend"],
|
||||
"color": [110, 145, 110],
|
||||
"sprite": "sprites/terrain/wooded_foothills.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "temperate",
|
||||
"quality_bonuses": { "production": 1 },
|
||||
"terrain_power": {},
|
||||
"albedo": 0.18,
|
||||
"evapotranspiration": 0.006,
|
||||
"description": "Steep slopes covered in old forest."
|
||||
},
|
||||
{
|
||||
"id": "riverside_forest",
|
||||
"name": "Riverside Forest",
|
||||
"movement_cost": 2,
|
||||
"defense_bonus": 50,
|
||||
"food": 2,
|
||||
"production": 1,
|
||||
"trade": 0,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.45,
|
||||
"flags": ["edge_blend"],
|
||||
"color": [70, 140, 100],
|
||||
"sprite": "sprites/terrain/riverside_forest.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "temperate",
|
||||
"quality_bonuses": { "food": 1 },
|
||||
"terrain_power": {},
|
||||
"albedo": 0.12,
|
||||
"evapotranspiration": 0.010,
|
||||
"description": "Lush forest along the water's edge."
|
||||
},
|
||||
{
|
||||
"id": "cliff",
|
||||
"name": "Cliff",
|
||||
"movement_cost": 4,
|
||||
"defense_bonus": 250,
|
||||
"food": 0,
|
||||
"production": 1,
|
||||
"trade": 0,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.0,
|
||||
"flags": ["edge_blend", "impassable_civilian"],
|
||||
"color": [120, 130, 165],
|
||||
"sprite": "sprites/terrain/cliff.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "elevated",
|
||||
"quality_bonuses": {},
|
||||
"terrain_power": {},
|
||||
"albedo": 0.40,
|
||||
"evapotranspiration": 0.001,
|
||||
"description": "Sheer rock face dropping to the water."
|
||||
},
|
||||
{
|
||||
"id": "scrub_edge",
|
||||
"name": "Scrub Edge",
|
||||
"movement_cost": 1,
|
||||
"defense_bonus": 25,
|
||||
"food": 0,
|
||||
"production": 1,
|
||||
"trade": 0,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.15,
|
||||
"flags": ["edge_blend"],
|
||||
"color": [175, 165, 95],
|
||||
"sprite": "sprites/terrain/scrub_edge.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "hot",
|
||||
"quality_bonuses": {},
|
||||
"terrain_power": {},
|
||||
"albedo": 0.30,
|
||||
"evapotranspiration": 0.002,
|
||||
"description": "Hardy thicket between forest and desert."
|
||||
},
|
||||
{
|
||||
"id": "arid_plains",
|
||||
"name": "Arid Plains",
|
||||
"movement_cost": 1,
|
||||
"defense_bonus": 0,
|
||||
"food": 0,
|
||||
"production": 1,
|
||||
"trade": 1,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.12,
|
||||
"flags": ["edge_blend"],
|
||||
"color": [215, 185, 95],
|
||||
"sprite": "sprites/terrain/arid_plains.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "hot",
|
||||
"quality_bonuses": { "trade": 1 },
|
||||
"terrain_power": {},
|
||||
"albedo": 0.35,
|
||||
"evapotranspiration": 0.002,
|
||||
"description": "Dry plains bordering the desert."
|
||||
},
|
||||
{
|
||||
"id": "badlands",
|
||||
"name": "Badlands",
|
||||
"movement_cost": 3,
|
||||
"defense_bonus": 150,
|
||||
"food": 0,
|
||||
"production": 1,
|
||||
"trade": 0,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.05,
|
||||
"flags": ["edge_blend"],
|
||||
"color": [195, 165, 110],
|
||||
"sprite": "sprites/terrain/badlands.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "hot",
|
||||
"quality_bonuses": {},
|
||||
"terrain_power": {},
|
||||
"albedo": 0.40,
|
||||
"evapotranspiration": 0.001,
|
||||
"description": "Eroded canyons between desert and mountains."
|
||||
},
|
||||
{
|
||||
"id": "bog_edge",
|
||||
"name": "Bog Edge",
|
||||
"movement_cost": 2,
|
||||
"defense_bonus": 50,
|
||||
"food": 1,
|
||||
"production": 0,
|
||||
"trade": 0,
|
||||
"culture": 0,
|
||||
"mana_major": null,
|
||||
"mana_minor": [],
|
||||
"infiltration": 0.30,
|
||||
"flags": ["edge_blend"],
|
||||
"color": [80, 105, 65],
|
||||
"sprite": "sprites/terrain/bog_edge.png",
|
||||
"feature_overlay": "",
|
||||
"feature_type": null,
|
||||
"variant_count": 1,
|
||||
"transform_to": null,
|
||||
"transform_turns": null,
|
||||
"climate_zone": "temperate",
|
||||
"quality_bonuses": {},
|
||||
"terrain_power": {},
|
||||
"albedo": 0.16,
|
||||
"evapotranspiration": 0.008,
|
||||
"description": "Mossy wetland under the forest canopy."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"source": "resources/tiles",
|
||||
"includes": ["frozen", "land_common", "land_forest", "land_special", "water_and_wonders"]
|
||||
"includes": ["frozen", "land_common", "land_forest", "land_special", "land_blends", "water_and_wonders"]
|
||||
}
|
||||
|
|
|
|||
21
public/games/age-of-dwarves/data/terrain/terrain_blends.json
Normal file
21
public/games/age-of-dwarves/data/terrain/terrain_blends.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"_doc": "Hex edge ecotone blend table (HEX_GEOMETRY.md §8). Each pair maps an unordered (centre, neighbour) terrain pairing to the derived edge terrain that lives on the shared boundary. Pairs are canonical-sorted alphabetically so lookup is order-independent. Same-terrain pairs and undefined pairs default to the centre terrain unchanged (no transition).",
|
||||
"blends": [
|
||||
{ "pair": ["forest", "plains"], "edge_terrain": "grass_fringe" },
|
||||
{ "pair": ["mountains", "plains"], "edge_terrain": "foothills" },
|
||||
{ "pair": ["coast", "plains"], "edge_terrain": "shore" },
|
||||
{ "pair": ["lake", "plains"], "edge_terrain": "shore" },
|
||||
{ "pair": ["ocean", "plains"], "edge_terrain": "shore" },
|
||||
{ "pair": ["forest", "mountains"], "edge_terrain": "wooded_foothills" },
|
||||
{ "pair": ["coast", "forest"], "edge_terrain": "riverside_forest" },
|
||||
{ "pair": ["forest", "lake"], "edge_terrain": "riverside_forest" },
|
||||
{ "pair": ["forest", "ocean"], "edge_terrain": "riverside_forest" },
|
||||
{ "pair": ["coast", "mountains"], "edge_terrain": "cliff" },
|
||||
{ "pair": ["lake", "mountains"], "edge_terrain": "cliff" },
|
||||
{ "pair": ["mountains", "ocean"], "edge_terrain": "cliff" },
|
||||
{ "pair": ["desert", "forest"], "edge_terrain": "scrub_edge" },
|
||||
{ "pair": ["desert", "plains"], "edge_terrain": "arid_plains" },
|
||||
{ "pair": ["desert", "mountains"], "edge_terrain": "badlands" },
|
||||
{ "pair": ["forest", "swamp"], "edge_terrain": "bog_edge" }
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue