rpfm_extensions/startpos/cai/
technologies.rs1use std::collections::BTreeMap;
14
15use rpfm_lib::error::Result;
16
17use crate::startpos::tables::StartposTables;
18use crate::startpos::world::FactionEntry;
19
20#[cfg(test)] #[path = "technologies_test.rs"] mod technologies_test;
21
22pub fn faction_technologies(tables: &StartposTables, campaign: &str, faction: &FactionEntry) -> Result<Vec<String>> {
49 let for_campaign = |key: &str| key.is_empty() || key == campaign;
50
51 let mut campaign_sets = vec![];
52 let mut generic_sets = vec![];
53 for row in tables.table("technology_node_sets")?.rows() {
54 let set_campaign = row.str("campaign_key")?;
55 if for_campaign(&set_campaign) {
56 let set = (row.str("key")?.into_owned(), row.str("faction_key")?.into_owned(), row.str("subculture")?.into_owned(), row.str("culture")?.into_owned(), row.str("technology_category")?.into_owned());
57 if set_campaign.is_empty() { generic_sets.push(set) } else { campaign_sets.push(set) }
58 }
59 }
60 let mut chosen = [&campaign_sets, &generic_sets].into_iter()
61 .flat_map(|sets| [
62 sets.iter().filter(|set| set.1 == *faction.key()).collect::<Vec<_>>(),
63 sets.iter().filter(|set| set.1.is_empty() && set.2 == *faction.subculture()).collect(),
64 sets.iter().filter(|set| set.1.is_empty() && set.2.is_empty() && set.3 == *faction.culture()).collect(),
65 ])
66 .find(|sets| !sets.is_empty())
67 .unwrap_or_default();
68 chosen.reverse();
69 chosen.sort_by(|a, b| b.4.cmp(&a.4));
70
71 let nodes = tables.table("technology_nodes")?;
72 let mut technologies: Vec<String> = vec![];
73 for (set, ..) in chosen {
74 let mut slots = BTreeMap::new();
75 for row in nodes.rows() {
76 let node_faction = row.str("faction_key")?;
77 if row.str("technology_node_set")? != *set || !for_campaign(&row.str("campaign_key")?) || !(node_faction.is_empty() || node_faction == *faction.key()) {
78 continue;
79 }
80
81 let slot = (row.int("tier")?, row.int("indent")?);
83 let own = !node_faction.is_empty();
84 let technology = row.str("technology_key")?.into_owned();
85 match slots.get(&slot) {
86 Some((true, _)) if !own => {},
87 _ => { slots.insert(slot, (own, technology)); },
88 }
89 }
90 for (_, technology) in slots.into_values() {
91 if !technologies.contains(&technology) {
92 technologies.push(technology);
93 }
94 }
95 }
96 Ok(technologies)
97}