From ec759984cd7940fffc5ccc2175d6647aaea7280c Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 21 Nov 2021 11:30:09 -0500 Subject: [PATCH] Start building data fixture parsers --- Cargo.lock | 19 ++ common/Cargo.toml | 9 +- common/src/types/character.rs | 399 +++++++++++++++++++--------------- 3 files changed, 250 insertions(+), 177 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 444c9f1..d3443da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,6 +191,7 @@ version = "0.1.0" dependencies = [ "serde", "serde_derive", + "serde_yaml", "thiserror", ] @@ -234,6 +235,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + [[package]] name = "either" version = "1.6.1" @@ -1327,6 +1334,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" +dependencies = [ + "dtoa", + "indexmap", + "serde", + "yaml-rust", +] + [[package]] name = "sha-1" version = "0.9.8" diff --git a/common/Cargo.toml b/common/Cargo.toml index 53742b8..8dc262a 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -6,6 +6,9 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = { version = "1" } -serde_derive = { version = "1" } -thiserror = { version = "1" } +serde = { version = "1" } +serde_derive = { version = "1" } +thiserror = { version = "1" } + +[dev-dependencies] +serde_yaml = { version = "*" } diff --git a/common/src/types/character.rs b/common/src/types/character.rs index cb78ed9..62c83ac 100644 --- a/common/src/types/character.rs +++ b/common/src/types/character.rs @@ -8,43 +8,41 @@ pub enum Error { TierOutOfRange(u8), } -#[derive(Debug, Serialize, Deserialize)] -pub enum CharacterType { - Arkus, - Delve, - Glaive, - Jack { edge: PoolType }, - Nano, - Wright, -} - -impl From<&CharacterType> for String { - fn from(type_: &CharacterType) -> String { - match type_ { - CharacterType::Arkus => "Arkus", - CharacterType::Delve => "Delve", - CharacterType::Glaive => "Glaive", - CharacterType::Jack { .. } => "Jack", - CharacterType::Nano => "Nano", - CharacterType::Wright => "Wright", - } - .to_string() - } -} - -impl From for String { - fn from(type_: CharacterType) -> String { - String::from(&type_) - } -} - #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[serde(rename_all = "lowercase")] pub enum PoolType { Might, Speed, Intellect, } +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum CharacterTypeEdge { + Flexible, + Static(HashMap), +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct CharacterType { + text: String, + starting_pools: HashMap, + edge: CharacterTypeEdge, +} + +impl CharacterType { + fn pool(&self, type_: PoolType) -> u8 { + self.starting_pools.get(&type_).unwrap().clone() + } + + fn edge(&self, type_: PoolType) -> u8 { + match self.edge { + CharacterTypeEdge::Flexible => 0, + CharacterTypeEdge::Static(ref edge) => edge.get(&type_).unwrap_or(&0).clone(), + } + } +} + #[derive(Debug, Serialize, Deserialize)] pub enum Cost { Nothing, @@ -175,10 +173,7 @@ impl CharacterSheet { }; format!( "{} {} {} who {}", - article, - self.descriptor, - String::from(&self.character_type), - self.focus + article, self.descriptor, self.character_type.text, self.focus ) } @@ -196,55 +191,71 @@ impl CharacterSheet { } fn might_pool(&self) -> Pool { + /* let (base, edge) = match self.character_type { - CharacterType::Glaive => (11, 1), - CharacterType::Jack { - edge: PoolType::Might, - } => (10, 1), - CharacterType::Jack { edge: _ } => (10, 0), - CharacterType::Nano => (7, 0), - CharacterType::Arkus => (8, 0), - CharacterType::Delve => (9, 0), - CharacterType::Wright => (9, 0), + CharacterType::Glaive => (11, 1), + CharacterType::Jack { + edge: PoolType::Might, + } => (10, 1), + CharacterType::Jack { edge: _ } => (10, 0), + CharacterType::Nano => (7, 0), + CharacterType::Arkus => (8, 0), + CharacterType::Delve => (9, 0), + CharacterType::Wright => (9, 0), }; let max = base + self.initial_points.might; let current = max; + */ + let max = 10; + let current = 10; + let edge = 1; Pool { max, current, edge } } fn speed_pool(&self) -> Pool { + /* let (base, edge) = match self.character_type { - CharacterType::Glaive => (10, 1), - CharacterType::Jack { - edge: PoolType::Speed, - } => (10, 1), - CharacterType::Jack { edge: _ } => (10, 0), - CharacterType::Nano => (9, 0), - CharacterType::Arkus => (9, 0), - CharacterType::Delve => (9, 1), - CharacterType::Wright => (7, 0), + CharacterType::Glaive => (10, 1), + CharacterType::Jack { + edge: PoolType::Speed, + } => (10, 1), + CharacterType::Jack { edge: _ } => (10, 0), + CharacterType::Nano => (9, 0), + CharacterType::Arkus => (9, 0), + CharacterType::Delve => (9, 1), + CharacterType::Wright => (7, 0), }; let max = base + self.initial_points.speed; let current = max; + */ + + let max = 10; + let current = 10; + let edge = 1; Pool { max, current, edge } } fn intellect_pool(&self) -> Pool { + /* let (base, edge) = match self.character_type { - CharacterType::Glaive => (7, 0), - CharacterType::Jack { - edge: PoolType::Intellect, - } => (10, 1), - CharacterType::Jack { edge: _ } => (10, 0), - CharacterType::Nano => (12, 1), - CharacterType::Arkus => (11, 1), - CharacterType::Delve => (10, 1), - CharacterType::Wright => (12, 0), + CharacterType::Glaive => (7, 0), + CharacterType::Jack { + edge: PoolType::Intellect, + } => (10, 1), + CharacterType::Jack { edge: _ } => (10, 0), + CharacterType::Nano => (12, 1), + CharacterType::Arkus => (11, 1), + CharacterType::Delve => (10, 1), + CharacterType::Wright => (12, 0), }; let max = base + self.initial_points.intellect; let current = max; + */ + let max = 10; + let current = 10; + let edge = 1; Pool { max, current, edge } } } @@ -270,125 +281,165 @@ mod test_data { use super::*; #[allow(dead_code)] - pub fn opal() -> CharacterSheet { - CharacterSheet { - name: "Opal".to_owned(), - descriptor: "Adaptable".to_owned(), - character_type: CharacterType::Jack { - edge: PoolType::Intellect, - }, - focus: "Speaks with a Silver Tongue".to_owned(), - initial_points: PointAllocation { - might: 1, - speed: 2, - intellect: 3, - }, - /* - pools: Pools { - might: Pool { - current: 11, - max: 11, - edge: 0, - }, - speed: Pool { - current: 12, - max: 12, - edge: 0, - }, - intellect: Pool { - current: 13, - max: 13, - edge: 1, - }, - }, - */ - /* - tier: Tier::new(1).unwrap(), - effort: 1, - cypher_limit: 3, - special_abilities: vec![ - SpecialAbility { name: "Versatile".to_owned(), - cost: Cost::Nothing, - description: "+2 to any pool. It can be reassigned after each ten-hour recovery roll.".to_owned() }, - SpecialAbility { name: "Flex Skill".to_owned(), - cost: Cost::Nothing, - description: "at the beginning of each day, choose one skill (other than attack or defense). For the rest of the day, you are trained in that skill.".to_owned() }, - SpecialAbility{ name: "Face Morph".to_owned(), - cost: Cost::Constant { stat: PoolType::Intellect, cost: 2 }, - description: "You alter your features and coloration for one hour.".to_owned() }, - ], - skills: vec![ - Skill{ skill: "Perception".to_owned(), rank: SkillRank::Trained }, - Skill{ skill: "Resilient".to_owned(), rank: SkillRank::Trained }, - Skill{ skill: "Social interactions".to_owned(), rank: SkillRank::Trained }, - Skill{ skill: "Pleasant social interactiosn".to_owned(), rank: SkillRank::Specialized }, - ], - attacks: vec![ - Attack { weapon: "Crank Crossbow".to_owned(), damage: 4, range: Range::Long, ammo: Some(25), }, - Attack { weapon: "Rapier".to_owned(), damage: 2, range: Range::Immediate, ammo: None, }, - ], - defenses: vec![ - Defense { - armor: "Brigandine".to_owned(), - defense: 2, - speed_cost: 2, - } - ], - equipment: vec![ - "A book for recording favorite words, inspiration stories, and speech anecdotes.".to_owned(), - "Explorer's pack".to_owned(), - ], - cyphers: vec![ - Cypher { - name: "Flying Cap".to_owned(), - level: 3, - form: "Hat".to_owned(), - description: "Whatever".to_owned(), - } - ], - */ - } + pub const GLAIVE_DESCRIPTOR: &str = "text: Glaive +starting_pools: + might: 11 + speed: 10 + intellect: 7 +edge: + static: + might: 1 + speed: 1"; + pub const JACK_DESCRIPTOR: &str = "text: Jack +starting_pools: + might: 10 + speed: 10 + intellect: 10 +edge: flexible + "; + + /* + #[allow(dead_code)] + pub fn opal() -> CharacterSheet { + CharacterSheet { + name: "Opal".to_owned(), + descriptor: "Adaptable".to_owned(), + character_type: CharacterType::Jack { + edge: PoolType::Intellect, + }, + focus: "Speaks with a Silver Tongue".to_owned(), + initial_points: PointAllocation { + might: 1, + speed: 2, + intellect: 3, + }, + /* + pools: Pools { + might: Pool { + current: 11, + max: 11, + edge: 0, + }, + speed: Pool { + current: 12, + max: 12, + edge: 0, + }, + intellect: Pool { + current: 13, + max: 13, + edge: 1, + }, + }, + */ + /* + tier: Tier::new(1).unwrap(), + effort: 1, + cypher_limit: 3, + special_abilities: vec![ + SpecialAbility { name: "Versatile".to_owned(), + cost: Cost::Nothing, + description: "+2 to any pool. It can be reassigned after each ten-hour recovery roll.".to_owned() }, + SpecialAbility { name: "Flex Skill".to_owned(), + cost: Cost::Nothing, + description: "at the beginning of each day, choose one skill (other than attack or defense). For the rest of the day, you are trained in that skill.".to_owned() }, + SpecialAbility{ name: "Face Morph".to_owned(), + cost: Cost::Constant { stat: PoolType::Intellect, cost: 2 }, + description: "You alter your features and coloration for one hour.".to_owned() }, + ], + skills: vec![ + Skill{ skill: "Perception".to_owned(), rank: SkillRank::Trained }, + Skill{ skill: "Resilient".to_owned(), rank: SkillRank::Trained }, + Skill{ skill: "Social interactions".to_owned(), rank: SkillRank::Trained }, + Skill{ skill: "Pleasant social interactiosn".to_owned(), rank: SkillRank::Specialized }, + ], + attacks: vec![ + Attack { weapon: "Crank Crossbow".to_owned(), damage: 4, range: Range::Long, ammo: Some(25), }, + Attack { weapon: "Rapier".to_owned(), damage: 2, range: Range::Immediate, ammo: None, }, + ], + defenses: vec![ + Defense { + armor: "Brigandine".to_owned(), + defense: 2, + speed_cost: 2, + } + ], + equipment: vec![ + "A book for recording favorite words, inspiration stories, and speech anecdotes.".to_owned(), + "Explorer's pack".to_owned(), + ], + cyphers: vec![ + Cypher { + name: "Flying Cap".to_owned(), + level: 3, + form: "Hat".to_owned(), + description: "Whatever".to_owned(), + } + ], + */ } + } + */ } #[cfg(test)] mod test { - use super::*; + use super::{test_data::*, *}; + use serde_yaml; #[test] - fn opals_character_sheet() { - let opal = super::test_data::opal(); - assert_eq!(opal.name(), "Opal"); - assert_eq!( - opal.description(), - "an Adaptable Jack who Speaks with a Silver Tongue" - ); - let pools = opal.pools(); - assert_eq!( - pools.might(), - &Pool { - current: 11, - max: 11, - edge: 0 - } - ); - - assert_eq!( - pools.speed(), - &Pool { - current: 12, - max: 12, - edge: 0 - } - ); - - assert_eq!( - pools.intellect(), - &Pool { - current: 13, - max: 13, - edge: 1 - } - ); + fn parses_character_type() { + let glaive: CharacterType = + serde_yaml::from_str(GLAIVE_DESCRIPTOR).expect("should deserialize"); + assert_eq!(glaive.text, "Glaive"); + assert_eq!(glaive.pool(PoolType::Might), 11); + assert_eq!(glaive.edge(PoolType::Might), 1); + assert_eq!(glaive.edge(PoolType::Intellect), 0); } + + #[test] + fn parses_character_type_with_flexible_edge() { + let jack: CharacterType = + serde_yaml::from_str(JACK_DESCRIPTOR).expect("should deserialize"); + assert_eq!(jack.text, "Jack"); + } + + /* + #[test] + fn opals_character_sheet() { + let opal = super::test_data::opal(); + assert_eq!(opal.name(), "Opal"); + assert_eq!( + opal.description(), + "an Adaptable Jack who Speaks with a Silver Tongue" + ); + let pools = opal.pools(); + assert_eq!( + pools.might(), + &Pool { + current: 11, + max: 11, + edge: 0 + } + ); + + assert_eq!( + pools.speed(), + &Pool { + current: 12, + max: 12, + edge: 0 + } + ); + + assert_eq!( + pools.intellect(), + &Pool { + current: 13, + max: 13, + edge: 1 + } + ); + } + */ }