Merge origin/main: ACS-2 reconciliation 2026-04-30
Diverged 2026-04-26 → 2026-04-29 from base 59dea7f35: local 59 commits
(Natalie autocommit), origin 103 commits (apricot autocommit).
458 dual-edit files, 448 byte-identical (same agent generating same
content on both hosts). 10 actual conflicts resolved:
• .project/designs/app/tsconfig.tsbuildinfo — kept HEAD (superset of
tracked files; will regenerate on next tsc).
• public/games/age-of-dwarves/data/buildings/manifest.json — DELETED
per post-p1-40 architecture (single source of truth at
public/resources/<category>/, no override layer in data/<category>/).
• .project/objectives/README.md — kept HEAD (adds p1-41 row + updated
totals 110/155).
• .project/objectives/p1-38-biome-economy-coupling.md — kept HEAD (proof
scene captured 2026-04-29, was [x]).
• .project/objectives/p2-36-data-resources-building-duplicates.md —
kept HEAD (status: done with closure note absorbed by p1-40).
• public/games/age-of-dwarves/data/objectives.json — kept HEAD (later
timestamp 2026-04-30T04:20Z, includes p1-41 entry, totals 110/155).
• tools/audio-batch-12-defeat-pool.tsv — kept HEAD's swap from Action1
to Exploration2 for defeat_domination (Action1 collided with
victory_domination_b — same cue for win + loss of same type).
• src/simulator/crates/mc-core/src/grid/mod.rs — kept HEAD's added
exports (zoc_from_centre, zoc_from_edge, ZocReach).
• src/simulator/crates/mc-core/src/grid/terrain_blend.rs — kept HEAD's
canonical resources/tiles/ path (post-p1-40) over origin's stale
games/<game>/data/terrain/ path.
• src/simulator/crates/mc-core/src/grid/edge.rs — kept HEAD's ZOC
implementation (ZocReach, zoc_from_centre, zoc_from_edge) + 3
accompanying unit tests. Origin lacked them; mod.rs already exports.
No commits dropped. Validation: ./run validate green pre-commit.
This commit is contained in:
commit
dd675b3402
8 changed files with 401 additions and 0 deletions
|
|
@ -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."
|
||||
}
|
||||
]
|
||||
|
|
@ -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."
|
||||
}
|
||||
]
|
||||
|
|
@ -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."
|
||||
}
|
||||
]
|
||||
|
|
@ -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."
|
||||
}
|
||||
]
|
||||
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."
|
||||
}
|
||||
]
|
||||
}
|
||||
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" }
|
||||
]
|
||||
}
|
||||
BIN
public/resources/c/defeat_culture.ogg
Normal file
BIN
public/resources/c/defeat_culture.ogg
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue