2023-12-30 16:57:03 -08:00
|
|
|
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<String, super::Relationship>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-30 17:39:19 -08:00
|
|
|
/// How two factions should interact with each other.
|
|
|
|
/// Relationships are directional: the relationship of
|
|
|
|
/// `a` to `b` may not equal the relationship of `b` to `a`.
|
|
|
|
///
|
|
|
|
/// Relationships dictate how a ship of THIS faction
|
|
|
|
/// will interact with a ship of the OTHER faction.
|
2023-12-30 16:57:03 -08:00
|
|
|
#[derive(Debug, Deserialize, Clone, Copy)]
|
|
|
|
pub enum Relationship {
|
2023-12-30 17:39:19 -08:00
|
|
|
/// Attack this faction
|
2023-12-30 16:57:03 -08:00
|
|
|
#[serde(rename = "hostile")]
|
|
|
|
Hostile,
|
|
|
|
|
2023-12-30 17:39:19 -08:00
|
|
|
/// Ignore this faction
|
2023-12-30 16:57:03 -08:00
|
|
|
#[serde(rename = "neutral")]
|
|
|
|
Neutral,
|
|
|
|
|
2023-12-30 17:39:19 -08:00
|
|
|
/// Protect this faction
|
|
|
|
#[serde(rename = "friend")]
|
|
|
|
Friend,
|
2023-12-30 16:57:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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,
|
|
|
|
|
2023-12-30 17:39:19 -08:00
|
|
|
/// Relationships between this faction and other factions
|
|
|
|
/// This is guaranteed to contain an entry for ALL factions.
|
2023-12-30 16:57:03 -08:00
|
|
|
pub relationships: HashMap<FactionHandle, Relationship>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl crate::Build for Faction {
|
|
|
|
type InputSyntax = HashMap<String, syntax::Faction>;
|
|
|
|
|
|
|
|
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<String> = factions.keys().map(|x| x.to_owned()).collect();
|
|
|
|
|
2023-12-30 17:39:19 -08:00
|
|
|
// Indexing will break if this is false.
|
|
|
|
assert!(ct.factions.len() == 0);
|
|
|
|
|
2023-12-30 16:57:03 -08:00
|
|
|
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 {},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ct.factions.push(Self {
|
|
|
|
name: faction_name.to_owned(),
|
|
|
|
handle: h,
|
|
|
|
relationships,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|