130 lines
3.3 KiB
Rust
130 lines
3.3 KiB
Rust
use anyhow::{bail, Result};
|
|
use serde::Deserialize;
|
|
use std::collections::HashMap;
|
|
|
|
use crate::{handle::FactionHandle, Content, ContentBuildContext};
|
|
|
|
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 color: [f32; 3],
|
|
pub relationship: HashMap<String, super::Relationship>,
|
|
}
|
|
}
|
|
|
|
/// 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.
|
|
#[derive(Debug, Deserialize, Clone, Copy)]
|
|
pub enum Relationship {
|
|
/// Attack this faction
|
|
#[serde(rename = "hostile")]
|
|
Hostile,
|
|
|
|
/// Ignore this faction
|
|
#[serde(rename = "neutral")]
|
|
Neutral,
|
|
|
|
/// Protect this faction
|
|
#[serde(rename = "friend")]
|
|
Friend,
|
|
}
|
|
|
|
/// Represents a game faction
|
|
#[derive(Debug, Clone)]
|
|
pub struct Faction {
|
|
/// The name of this faction
|
|
pub name: String,
|
|
|
|
/// This faction's color.
|
|
/// Format is RGB, with each color between 0 and 1.
|
|
pub color: [f32; 3],
|
|
|
|
/// This faction's handle
|
|
pub handle: FactionHandle,
|
|
|
|
/// Relationships between this faction and other factions
|
|
/// This is guaranteed to contain an entry for ALL factions.
|
|
pub relationships: HashMap<FactionHandle, Relationship>,
|
|
}
|
|
|
|
impl crate::Build for Faction {
|
|
type InputSyntaxType = HashMap<String, syntax::Faction>;
|
|
|
|
fn build(
|
|
factions: Self::InputSyntaxType,
|
|
_build_context: &mut ContentBuildContext,
|
|
content: &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();
|
|
|
|
// Indexing will break if this is false.
|
|
assert!(content.factions.len() == 0);
|
|
|
|
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 {},
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
if faction.color[0] > 1.0
|
|
|| faction.color[0] < 0.0
|
|
|| faction.color[1] > 1.0
|
|
|| faction.color[1] < 0.0
|
|
|| faction.color[2] > 1.0
|
|
|| faction.color[2] < 0.0
|
|
{
|
|
bail!(
|
|
"Invalid color for faction `{}`. Value out of range.",
|
|
faction_name
|
|
);
|
|
}
|
|
|
|
content.factions.push(Self {
|
|
name: faction_name.to_owned(),
|
|
handle: h,
|
|
relationships,
|
|
color: faction.color,
|
|
});
|
|
}
|
|
|
|
return Ok(());
|
|
}
|
|
}
|