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 = [
"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"

View File

@ -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 = "*" }

View File

@ -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<CharacterType> 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<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)]
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
}
);
}
*/
}