feat(@projects/@magic-civilization): add race/resource filtering to melee unit selection

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-04-18 17:56:24 -07:00
parent fd6d915236
commit 1dc3c3f215
2 changed files with 30 additions and 1 deletions

View file

@ -202,7 +202,12 @@ fn pick_for_city(
// Tier-progression unit selection (p0-39). Highest-tier buildable military
// unit for this player; falls back to `warrior` when the catalog is empty
// (fixtures predating p0-39) or no higher-tier gate is met.
let melee_id = pick_best_melee(&player.researched_techs, unit_catalog).unwrap_or(ids::WARRIOR);
let melee_id = pick_best_melee(
&player.researched_techs,
player.race_id.as_deref(),
&player.strategic_resources,
unit_catalog,
).unwrap_or(ids::WARRIOR);
let early_mil_floor = if turn <= EARLY_MIL_FLOOR_CUTOFF_TURN {
EARLY_MIL_FLOOR
} else {

View file

@ -94,6 +94,18 @@ pub struct TacticalPlayerState {
/// Diplomatic relations per opponent slot. `<0` war, `0` peace, `>0`
/// friend. Self-slot is 0.
pub relations: Vec<i8>,
/// Race id (e.g. `"dwarf"`, `"human"`). `None` for fixtures predating
/// race-gated unit selection. Consumed by
/// `tactical::production::pick_best_melee` to filter units whose
/// `race_required` doesn't match.
#[serde(default)]
pub race_id: Option<String>,
/// Strategic resource ids the player currently controls (tiles they own
/// that provide `iron_ore`, `horses`, etc.). Consumed by
/// `tactical::production::pick_best_melee` to filter units whose
/// `requires_resource` isn't available.
#[serde(default)]
pub strategic_resources: Vec<String>,
/// Clan personality axes on the `1..=10` scale (neutral = 5). Consumed by
/// `tactical::thresholds` for personality-emergent posture / retreat /
/// chase / siege thresholds (p0-37). Empty map = baseline (axis=5 for
@ -152,6 +164,18 @@ pub struct TacticalUnitSpec {
/// Unit-type classification mirroring `units/*.json::unit_type`:
/// `"military"` | `"worker"` | `"founder"` | `"scout"` | …
pub unit_type: String,
/// Strategic resource gate — unit buildable only when the player owns at
/// least one tile providing this resource id (e.g. `"iron_ore"` for
/// cavalry). `None` means no resource requirement. Filtered by
/// `tactical::production::pick_best_melee` to avoid queueing units the
/// engine's strategic-gate check will reject.
#[serde(default)]
pub requires_resource: Option<String>,
/// Race gate — unit buildable only when the player's race matches this id
/// (e.g. `"dwarf"` for berserker / ironwarden / forge_titan). `None`
/// means no race restriction.
#[serde(default)]
pub race_required: Option<String>,
}
/// A city.