rpfm_extensions/startpos/cai/
plan.rs1use getset::{CopyGetters, Getters};
22
23use std::collections::{HashMap, HashSet};
24
25use super::interface::{CENTRAL_DESIRES, DIRECTOR_BELIEFS, DIRECTOR_DESIRES};
26use super::managers::ManagerKind;
27use super::map::MapRegion;
28use super::world_view::WorldView;
29
30#[cfg(test)] #[path = "plan_test.rs"] mod plan_test;
31
32pub const ROOT_ID: u32 = 2;
34
35const WORLD_COMPONENTS: u32 = 2;
37
38const FORCE_AGENTS: [&str; 2] = ["general", "colonel"];
40
41#[derive(Debug, Clone, Default, Getters, CopyGetters)]
47pub struct CaiPlan {
48
49 #[getset(get_copy = "pub")]
51 next_id: u32,
52
53 #[getset(get_copy = "pub")]
55 first_central_desire: u32,
56
57 #[getset(get_copy = "pub")]
59 theatre: u32,
60
61 #[getset(get = "pub")]
63 regions: Vec<RegionIds>,
64
65 #[getset(get = "pub")]
67 factions: Vec<FactionIds>,
68
69 #[getset(get = "pub")]
71 settlements: HashMap<usize, SettlementIds>,
72
73 #[getset(get_copy = "pub")]
75 first_trade_segment: u32,
76
77 #[getset(get = "pub")]
79 boundaries: Vec<BoundaryIds>,
80
81 #[getset(get = "pub")]
83 characters: Vec<Vec<CharacterIds>>,
84
85 #[getset(get = "pub")]
87 provinces: Vec<ProvinceIds>,
88
89 #[getset(get = "pub")]
91 faction_seas: Vec<Vec<u32>>,
92
93 #[getset(get = "pub")]
95 governorships: Vec<u32>,
96
97 #[getset(get = "pub")]
99 posts: Vec<Vec<u32>>,
100
101 #[getset(get = "pub")]
104 managers: Vec<ManagerIds>,
105
106 #[getset(get = "pub")]
108 manager_kinds: Vec<ManagerKind>,
109
110 #[getset(get = "pub")]
112 director: Vec<u32>,
113
114 #[getset(get_copy = "pub")]
116 first_trade_route: u32,
117}
118
119#[derive(Debug, Clone, Copy)]
121pub struct PlanInputs<'a> {
122
123 pub map_regions: &'a [MapRegion],
125
126 pub world: &'a WorldView,
128
129 pub technology_counts: &'a [usize],
131
132 pub trade_splines: usize,
134
135 pub playable: &'a [bool],
137
138 pub trade_routes: usize,
140}
141
142#[derive(Debug, Clone, Default, Getters, CopyGetters)]
144pub struct ManagerIds {
145
146 #[getset(get_copy = "pub")]
148 faction: usize,
149
150 #[getset(get = "pub")]
152 desires: Vec<u32>,
153
154 #[getset(get_copy = "pub")]
156 intention: u32,
157
158 #[getset(get_copy = "pub")]
160 beliefs: Option<(u32, u32)>,
161
162 #[getset(get = "pub")]
164 character_intentions: Vec<u32>,
165
166 #[getset(get = "pub")]
168 mobile_intentions: Vec<u32>,
169}
170
171#[derive(Debug, Clone, Default, Getters, CopyGetters)]
173pub struct FactionIds {
174
175 #[getset(get_copy = "pub")]
177 faction: u32,
178
179 #[getset(get_copy = "pub")]
181 cai_faction: u32,
182
183 #[getset(get_copy = "pub")]
185 tree: Option<u32>,
186
187 #[getset(get = "pub")]
189 technologies: Vec<u32>,
190}
191
192#[derive(Debug, Clone, Default, Getters, CopyGetters)]
194pub struct SettlementIds {
195
196 #[getset(get = "pub")]
198 slots: Vec<u32>,
199
200 #[getset(get_copy = "pub")]
202 settlement: u32,
203}
204
205#[derive(Debug, Clone, Default, CopyGetters)]
207#[getset(get_copy = "pub")]
208pub struct BoundaryIds {
209
210 id: u32,
212
213 region: usize,
215
216 other: usize,
218
219 value: u32,
221}
222
223#[derive(Debug, Clone, Default, Getters, CopyGetters)]
225pub struct CharacterIds {
226
227 #[getset(get_copy = "pub")]
229 character: u32,
230
231 #[getset(get_copy = "pub")]
233 mobile: Option<u32>,
234
235 #[getset(get = "pub")]
237 horde_slots: Vec<u32>,
238
239 #[getset(get = "pub")]
241 units: Vec<u32>,
242}
243
244#[derive(Debug, Clone, Default, Getters, CopyGetters)]
246pub struct ProvinceIds {
247
248 #[getset(get_copy = "pub")]
250 province: u32,
251
252 #[getset(get = "pub")]
254 faction_provinces: Vec<u32>,
255}
256
257#[derive(Debug, Clone, Default, Getters, CopyGetters)]
259pub struct RegionIds {
260
261 #[getset(get_copy = "pub")]
263 id: u32,
264
265 #[getset(get = "pub")]
267 hlcis: Vec<u32>,
268}
269
270impl CaiPlan {
275
276 pub fn new(inputs: &PlanInputs) -> Self {
278 let world = inputs.world;
279 let mut plan = Self { next_id: ROOT_ID + 1 + WORLD_COMPONENTS, ..Default::default() };
280 plan.first_central_desire = plan.take(CENTRAL_DESIRES.len() as u32);
281 plan.theatre = plan.take(1);
282 plan.regions = inputs.map_regions.iter().map(|region| {
283 let id = plan.take(1);
284 let hlcis = (0..region.hlcis().len()).map(|_| plan.take(1)).collect();
285 RegionIds { id, hlcis }
286 }).collect();
287
288 for count in inputs.technology_counts.iter().take(world.factions().len()) {
289 let faction = plan.take(1);
290 let cai_faction = plan.take(1);
291 let tree = Some(plan.take(1));
292 let technologies = (0..*count).map(|_| plan.take(1)).collect();
293 plan.factions.push(FactionIds { faction, cai_faction, tree, technologies });
294 }
295 let faction = plan.take(1);
296 let cai_faction = plan.take(1);
297 plan.factions.push(FactionIds { faction, cai_faction, tree: None, technologies: vec![] });
298
299 for (index, map_region) in inputs.map_regions.iter().enumerate() {
300 if let Some(region) = world.regions().iter().find(|region| region.key() == map_region.key()) {
301 let slots = region.slots().iter().map(|_| plan.take(1)).collect();
302 let settlement = plan.take(1);
303 plan.settlements.insert(index, SettlementIds { slots, settlement });
304 }
305 }
306
307 plan.first_trade_segment = plan.take(inputs.trade_splines as u32);
308 plan.boundaries = boundaries(inputs.map_regions).into_iter()
309 .map(|(region, other, value)| BoundaryIds { id: plan.take(1), region, other, value })
310 .collect();
311
312 for faction in world.factions() {
313 let characters = faction.characters().iter().map(|character| {
314 let id = plan.take(1);
315 let force = faction.forces().iter().find(|force| character.force() != 0 && force.id() == character.force());
316 let (mobile, horde_slots, units) = match force {
317 Some(force) => (
318 Some(plan.take(1)),
319 force.horde_slots().iter().map(|_| plan.take(1)).collect(),
320 force.units().iter().map(|_| plan.take(1)).collect(),
321 ),
322 None if !FORCE_AGENTS.contains(&character.agent().as_str()) => (Some(plan.take(1)), vec![], vec![]),
323 None => (None, vec![], vec![]),
324 };
325 CharacterIds { character: id, mobile, horde_slots, units }
326 }).collect();
327 plan.characters.push(characters);
328 }
329
330 plan.provinces = world.provinces().iter().map(|province| {
331 let id = plan.take(1);
332 let faction_provinces = province.managers().iter().map(|_| plan.take(1)).collect();
333 ProvinceIds { province: id, faction_provinces }
334 }).collect();
335 plan.faction_seas = world.seas().iter().map(|sea| sea.managers().iter().map(|_| plan.take(1)).collect()).collect();
336 plan.governorships = world.factions().iter().map(|_| plan.take(1)).collect();
337 plan.posts = world.factions().iter().map(|faction| faction.posts().iter().map(|_| plan.take(1)).collect()).collect();
338
339 plan.manager_kinds = (0..world.factions().len())
340 .map(|position| if inputs.playable.get(position).copied().unwrap_or_default() { ManagerKind::Human } else { ManagerKind::Ai })
341 .chain(std::iter::once(ManagerKind::Rebels))
342 .collect();
343
344 let owners = world.regions().iter().map(|region| region.owner()).collect::<HashSet<_>>();
345 let counts = plan.characters.iter()
346 .map(|characters| (characters.len(), characters.iter().filter(|character| character.mobile().is_some()).count()))
347 .collect::<Vec<_>>();
348 for (position, (faction, (characters, mobiles))) in world.factions().iter().zip(counts).enumerate() {
349 if !owners.contains(&faction.id()) && mobiles == 0 {
350 continue;
351 }
352
353 let kind = plan.manager_kinds[position];
355 let (characters, mobiles) = if kind == ManagerKind::Ai { (characters, mobiles) } else { (0, 0) };
356 let desires = kind.desires().iter().map(|_| plan.take(1)).collect();
357 let intention = plan.take(1);
358 let beliefs = Some((plan.take(1), plan.take(1)));
359 let character_intentions = (0..characters).map(|_| plan.take(1)).collect();
360 let mobile_intentions = (0..mobiles).map(|_| plan.take(1)).collect();
361 plan.managers.push(ManagerIds { faction: position, desires, intention, beliefs, character_intentions, mobile_intentions });
362 }
363 let desires = ManagerKind::Rebels.desires().iter().map(|_| plan.take(1)).collect();
364 let intention = plan.take(1);
365 plan.managers.push(ManagerIds { faction: plan.factions.len() - 1, desires, intention, ..Default::default() });
366
367 plan.director = (0..DIRECTOR_BELIEFS.len() + DIRECTOR_DESIRES.len()).map(|_| plan.take(1)).collect();
368 plan.first_trade_route = plan.take(inputs.trade_routes as u32);
369 plan
370 }
371
372 fn take(&mut self, count: u32) -> u32 {
378 let first = self.next_id;
379 self.next_id += count;
380 first
381 }
382}
383
384fn boundaries(map_regions: &[MapRegion]) -> Vec<(usize, usize, u32)> {
387 let mut values = HashMap::new();
388 for (index, region) in map_regions.iter().enumerate() {
389 for (other, value) in region.connections() {
390 *values.entry((index.min(*other), index.max(*other))).or_insert(0) += value;
391 }
392 }
393
394 let mut boundaries = vec![];
395 let mut seen = HashSet::new();
396 for (index, region) in map_regions.iter().enumerate() {
397 for (other, _) in region.connections() {
398 let pair = (index.min(*other), index.max(*other));
399 if seen.insert(pair) {
400 boundaries.push((index, *other, values[&pair]));
401 }
402 }
403 }
404 boundaries
405}