Start building data fixture parsers

This commit is contained in:
Savanni D'Gerinel 2021-11-21 11:30:09 -05:00
parent ff18c4a0e7
commit ec759984cd
3 changed files with 250 additions and 177 deletions

19
Cargo.lock generated
View File

@ -191,6 +191,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
"serde_yaml",
"thiserror", "thiserror",
] ]
@ -234,6 +235,12 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "dtoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]] [[package]]
name = "either" name = "either"
version = "1.6.1" version = "1.6.1"
@ -1327,6 +1334,18 @@ dependencies = [
"serde", "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]] [[package]]
name = "sha-1" name = "sha-1"
version = "0.9.8" version = "0.9.8"

View File

@ -6,6 +6,9 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
serde = { version = "1" } serde = { version = "1" }
serde_derive = { version = "1" } serde_derive = { version = "1" }
thiserror = { version = "1" } thiserror = { version = "1" }
[dev-dependencies]
serde_yaml = { version = "*" }

View File

@ -8,43 +8,41 @@ pub enum Error {
TierOutOfRange(u8), 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<CharacterType> for String {
fn from(type_: CharacterType) -> String {
String::from(&type_)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "lowercase")]
pub enum PoolType { pub enum PoolType {
Might, Might,
Speed, Speed,
Intellect, Intellect,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum CharacterTypeEdge {
Flexible,
Static(HashMap<PoolType, u8>),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct CharacterType {
text: String,
starting_pools: HashMap<PoolType, u8>,
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)] #[derive(Debug, Serialize, Deserialize)]
pub enum Cost { pub enum Cost {
Nothing, Nothing,
@ -175,10 +173,7 @@ impl CharacterSheet {
}; };
format!( format!(
"{} {} {} who {}", "{} {} {} who {}",
article, article, self.descriptor, self.character_type.text, self.focus
self.descriptor,
String::from(&self.character_type),
self.focus
) )
} }
@ -196,55 +191,71 @@ impl CharacterSheet {
} }
fn might_pool(&self) -> Pool { fn might_pool(&self) -> Pool {
/*
let (base, edge) = match self.character_type { let (base, edge) = match self.character_type {
CharacterType::Glaive => (11, 1), CharacterType::Glaive => (11, 1),
CharacterType::Jack { CharacterType::Jack {
edge: PoolType::Might, edge: PoolType::Might,
} => (10, 1), } => (10, 1),
CharacterType::Jack { edge: _ } => (10, 0), CharacterType::Jack { edge: _ } => (10, 0),
CharacterType::Nano => (7, 0), CharacterType::Nano => (7, 0),
CharacterType::Arkus => (8, 0), CharacterType::Arkus => (8, 0),
CharacterType::Delve => (9, 0), CharacterType::Delve => (9, 0),
CharacterType::Wright => (9, 0), CharacterType::Wright => (9, 0),
}; };
let max = base + self.initial_points.might; let max = base + self.initial_points.might;
let current = max; let current = max;
*/
let max = 10;
let current = 10;
let edge = 1;
Pool { max, current, edge } Pool { max, current, edge }
} }
fn speed_pool(&self) -> Pool { fn speed_pool(&self) -> Pool {
/*
let (base, edge) = match self.character_type { let (base, edge) = match self.character_type {
CharacterType::Glaive => (10, 1), CharacterType::Glaive => (10, 1),
CharacterType::Jack { CharacterType::Jack {
edge: PoolType::Speed, edge: PoolType::Speed,
} => (10, 1), } => (10, 1),
CharacterType::Jack { edge: _ } => (10, 0), CharacterType::Jack { edge: _ } => (10, 0),
CharacterType::Nano => (9, 0), CharacterType::Nano => (9, 0),
CharacterType::Arkus => (9, 0), CharacterType::Arkus => (9, 0),
CharacterType::Delve => (9, 1), CharacterType::Delve => (9, 1),
CharacterType::Wright => (7, 0), CharacterType::Wright => (7, 0),
}; };
let max = base + self.initial_points.speed; let max = base + self.initial_points.speed;
let current = max; let current = max;
*/
let max = 10;
let current = 10;
let edge = 1;
Pool { max, current, edge } Pool { max, current, edge }
} }
fn intellect_pool(&self) -> Pool { fn intellect_pool(&self) -> Pool {
/*
let (base, edge) = match self.character_type { let (base, edge) = match self.character_type {
CharacterType::Glaive => (7, 0), CharacterType::Glaive => (7, 0),
CharacterType::Jack { CharacterType::Jack {
edge: PoolType::Intellect, edge: PoolType::Intellect,
} => (10, 1), } => (10, 1),
CharacterType::Jack { edge: _ } => (10, 0), CharacterType::Jack { edge: _ } => (10, 0),
CharacterType::Nano => (12, 1), CharacterType::Nano => (12, 1),
CharacterType::Arkus => (11, 1), CharacterType::Arkus => (11, 1),
CharacterType::Delve => (10, 1), CharacterType::Delve => (10, 1),
CharacterType::Wright => (12, 0), CharacterType::Wright => (12, 0),
}; };
let max = base + self.initial_points.intellect; let max = base + self.initial_points.intellect;
let current = max; let current = max;
*/
let max = 10;
let current = 10;
let edge = 1;
Pool { max, current, edge } Pool { max, current, edge }
} }
} }
@ -270,125 +281,165 @@ mod test_data {
use super::*; use super::*;
#[allow(dead_code)] #[allow(dead_code)]
pub fn opal() -> CharacterSheet { pub const GLAIVE_DESCRIPTOR: &str = "text: Glaive
CharacterSheet { starting_pools:
name: "Opal".to_owned(), might: 11
descriptor: "Adaptable".to_owned(), speed: 10
character_type: CharacterType::Jack { intellect: 7
edge: PoolType::Intellect, edge:
}, static:
focus: "Speaks with a Silver Tongue".to_owned(), might: 1
initial_points: PointAllocation { speed: 1";
might: 1, pub const JACK_DESCRIPTOR: &str = "text: Jack
speed: 2, starting_pools:
intellect: 3, might: 10
}, speed: 10
/* intellect: 10
pools: Pools { edge: flexible
might: Pool { ";
current: 11,
max: 11, /*
edge: 0, #[allow(dead_code)]
}, pub fn opal() -> CharacterSheet {
speed: Pool { CharacterSheet {
current: 12, name: "Opal".to_owned(),
max: 12, descriptor: "Adaptable".to_owned(),
edge: 0, character_type: CharacterType::Jack {
}, edge: PoolType::Intellect,
intellect: Pool { },
current: 13, focus: "Speaks with a Silver Tongue".to_owned(),
max: 13, initial_points: PointAllocation {
edge: 1, might: 1,
}, speed: 2,
}, intellect: 3,
*/ },
/* /*
tier: Tier::new(1).unwrap(), pools: Pools {
effort: 1, might: Pool {
cypher_limit: 3, current: 11,
special_abilities: vec![ max: 11,
SpecialAbility { name: "Versatile".to_owned(), edge: 0,
cost: Cost::Nothing, },
description: "+2 to any pool. It can be reassigned after each ten-hour recovery roll.".to_owned() }, speed: Pool {
SpecialAbility { name: "Flex Skill".to_owned(), current: 12,
cost: Cost::Nothing, max: 12,
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() }, edge: 0,
SpecialAbility{ name: "Face Morph".to_owned(), },
cost: Cost::Constant { stat: PoolType::Intellect, cost: 2 }, intellect: Pool {
description: "You alter your features and coloration for one hour.".to_owned() }, current: 13,
], max: 13,
skills: vec![ edge: 1,
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 }, /*
], tier: Tier::new(1).unwrap(),
attacks: vec![ effort: 1,
Attack { weapon: "Crank Crossbow".to_owned(), damage: 4, range: Range::Long, ammo: Some(25), }, cypher_limit: 3,
Attack { weapon: "Rapier".to_owned(), damage: 2, range: Range::Immediate, ammo: None, }, special_abilities: vec![
], SpecialAbility { name: "Versatile".to_owned(),
defenses: vec![ cost: Cost::Nothing,
Defense { description: "+2 to any pool. It can be reassigned after each ten-hour recovery roll.".to_owned() },
armor: "Brigandine".to_owned(), SpecialAbility { name: "Flex Skill".to_owned(),
defense: 2, cost: Cost::Nothing,
speed_cost: 2, 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 },
equipment: vec![ description: "You alter your features and coloration for one hour.".to_owned() },
"A book for recording favorite words, inspiration stories, and speech anecdotes.".to_owned(), ],
"Explorer's pack".to_owned(), skills: vec![
], Skill{ skill: "Perception".to_owned(), rank: SkillRank::Trained },
cyphers: vec![ Skill{ skill: "Resilient".to_owned(), rank: SkillRank::Trained },
Cypher { Skill{ skill: "Social interactions".to_owned(), rank: SkillRank::Trained },
name: "Flying Cap".to_owned(), Skill{ skill: "Pleasant social interactiosn".to_owned(), rank: SkillRank::Specialized },
level: 3, ],
form: "Hat".to_owned(), attacks: vec![
description: "Whatever".to_owned(), 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)] #[cfg(test)]
mod test { mod test {
use super::*; use super::{test_data::*, *};
use serde_yaml;
#[test] #[test]
fn opals_character_sheet() { fn parses_character_type() {
let opal = super::test_data::opal(); let glaive: CharacterType =
assert_eq!(opal.name(), "Opal"); serde_yaml::from_str(GLAIVE_DESCRIPTOR).expect("should deserialize");
assert_eq!( assert_eq!(glaive.text, "Glaive");
opal.description(), assert_eq!(glaive.pool(PoolType::Might), 11);
"an Adaptable Jack who Speaks with a Silver Tongue" assert_eq!(glaive.edge(PoolType::Might), 1);
); assert_eq!(glaive.edge(PoolType::Intellect), 0);
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
}
);
} }
#[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
}
);
}
*/
} }