use anyhow::Result; use serde::Deserialize; use std::collections::HashMap; use crate::{handle::FactionHandle, Content}; pub(crate) mod syntax { use std::collections::HashMap; use serde::Deserialize; // Raw serde syntax structs. // These are never seen by code outside this crate. #[derive(Debug, Deserialize)] pub struct Faction { pub display_name: String, pub relationship: HashMap, } } #[derive(Debug, Deserialize, Clone, Copy)] pub enum Relationship { #[serde(rename = "hostile")] Hostile, #[serde(rename = "neutral")] Neutral, #[serde(rename = "enemy")] Enemy, } /// Represents a game faction #[derive(Debug, Clone)] pub struct Faction { /// The name of this faction pub name: String, /// This faction's handle pub handle: FactionHandle, pub relationships: HashMap, } impl crate::Build for Faction { type InputSyntax = HashMap; fn build(factions: Self::InputSyntax, ct: &mut Content) -> Result<()> { // Keeps track of position in faction array. // This lets us build FactionHandles before finishing all factions. let faction_names: Vec = factions.keys().map(|x| x.to_owned()).collect(); for f_idx in 0..faction_names.len() { let faction_name = &faction_names[f_idx]; let faction = &factions[faction_name]; // Handle for this faction let h = FactionHandle { index: f_idx }; // Compute relationships let mut relationships = HashMap::new(); for i in 0..faction_names.len() { let f_other = &faction_names[i]; let h_other = FactionHandle { index: i }; if let Some(r) = faction.relationship.get(f_other) { relationships.insert(h_other, *r); } else { // Default relationship, if not specified // Look at reverse direction... let other = factions[f_other].relationship.get(faction_name); relationships.insert( h_other, // ... and pick a relationship based on that. match other { Some(Relationship::Hostile) => Relationship::Hostile {}, _ => Relationship::Neutral {}, }, ); } } let relationships = faction .relationship .iter() .map(|x| (h, x.1.clone())) .collect(); ct.factions.push(Self { name: faction_name.to_owned(), handle: h, relationships, }); } return Ok(()); } }