Start building data fixture parsers
This commit is contained in:
parent
ff18c4a0e7
commit
ec759984cd
|
@ -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"
|
||||||
|
|
|
@ -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 = "*" }
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue