Skip to content

Commit

Permalink
Merge pull request #4 from Ablesius/blood
Browse files Browse the repository at this point in the history
Blood
  • Loading branch information
Ablesius authored Nov 4, 2024
2 parents a3d59d6 + 3c5b16a commit 602ec8f
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 7 deletions.
38 changes: 34 additions & 4 deletions src/character.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod blood;
pub mod skills;
pub mod stats;

use crate::character::blood::BloodPotency;
use crate::character::stats::{Damage, Health, Humanity, Willpower};
use anyhow::Result;
pub use attributes::Attribute;
Expand All @@ -24,11 +25,16 @@ pub struct Character {

pub damage: Damage,
pub willpower_damage: Damage,

pub humanity: Humanity,
pub blood_potency: BloodPotency,
}

impl Character {
/// Create a new Character.
/// Create a new Character with mostly default values.
///
/// This function will just construct a Character instance, but it is assumed that you will use other ways of actually creating one, like using the `create` command or the GUI. (TODO: not implemented yet)
///
/// You can provide attributes and skills or leave them blank (by explicitly passing `None`);
/// with `None`, the default values will be set (0 for attributes and (0, None) for skills;
/// see [Skills].
Expand All @@ -41,6 +47,8 @@ impl Character {
chronicle: String,
attributes: Option<Attributes>,
skills: Option<Skills>,
// TODO: add other defaults here as well
blood_potency: Option<BloodPotency>,
) -> Self {
Self {
player_name,
Expand All @@ -51,6 +59,8 @@ impl Character {
damage: Damage::default(),
willpower_damage: Damage::default(),
humanity: Humanity::default(),
// TODO add hunger
blood_potency: blood_potency.unwrap_or_default(),
}
}

Expand Down Expand Up @@ -82,9 +92,23 @@ impl Character {

pub fn print(&self) {
println!("Player: {}", self.player_name);
println!("Character: {}", self.character_name);
println!("Chronicle: {}", self.chronicle);
// TODO: print all the fields

println!("Character: {}", self.character_name);

// TODO: print all the fields? or just most important?
println!("Attributes: {:?}", self.attributes);
println!("Skills: {:?}", self.skills);
println!(
"Health & Damage: {:?}",
Health::from_character(
self,
Some(self.damage.superficial),
Some(self.damage.aggravated)
)
);
// TODO println!("Hunger: {:?}", self.hunger);
// println!("Blood Potency: {:?}", self.blood_potency);
}

//TODO do we need this rather?
Expand Down Expand Up @@ -114,6 +138,7 @@ mod tests {
String::from("Test Chronicle by Night"),
None,
None,
None,
);

assert_eq!(
Expand All @@ -127,6 +152,7 @@ mod tests {
damage: Damage::default(),
willpower_damage: Damage::default(),
humanity: Humanity::default(),
blood_potency: BloodPotency::default(),
}
);
}
Expand All @@ -150,6 +176,7 @@ mod tests {
String::from("Test Chronicle by Night"),
Some(attributes),
None,
None,
);

let expected = Character {
Expand All @@ -171,6 +198,7 @@ mod tests {
damage: Damage::default(),
willpower_damage: Damage::default(),
humanity: Humanity::default(),
blood_potency: BloodPotency::default(),
};

assert_eq!(test_char, expected);
Expand Down Expand Up @@ -212,8 +240,9 @@ mod tests {
String::from(""),
String::from(""),
String::from(""),
Some(Attributes::default()),
None,
Some(skills),
None,
);

let expected = Character {
Expand Down Expand Up @@ -253,6 +282,7 @@ mod tests {
damage: Damage::default(),
willpower_damage: Damage::default(),
humanity: Humanity::default(),
blood_potency: BloodPotency::default(),
};

assert_eq!(test_char, expected);
Expand Down
59 changes: 59 additions & 0 deletions src/character/blood.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;

#[derive(PartialEq, PartialOrd, Debug)]
pub struct Hunger(u8);

Expand Down Expand Up @@ -47,6 +50,35 @@ impl Hunger {
}
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Default)]
pub struct BloodPotency(u8);

impl From<u8> for BloodPotency {
fn from(value: u8) -> Self {
Self(value)
}
}

impl PartialOrd for BloodPotency {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.cmp(&other.0).into()
}
}

impl BloodPotency {
//TODO refactor so that it's used
pub(crate) fn from_generation(generation: &u8) -> Self {
match generation {
10..=11 => 2,
12..=13 => 1,
14.. => 0,
//TODO refactor so that we won't be able to reach panic
_ => panic!("invalid generation selected, choose between 9 and 16"),
}
.into()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -59,4 +91,31 @@ mod tests {
let hunger2 = Hunger(6);
assert!(!hunger2.is_in_range())
}

#[test]
fn u8_into_blood_potency() {
let bp: BloodPotency = 3.into();
let expected = BloodPotency(3);

assert_eq!(bp, expected)
}

#[test]
fn blood_potency_from_u8() {
let bp = BloodPotency::from(3);
let expected = BloodPotency(3);

assert_eq!(bp, expected)
}

#[test]
fn blood_potency_from_generation() {
let generation = 10;
let bp = BloodPotency::from_generation(&generation);

// for 10th generation, BP should be at least 2
let expected = BloodPotency(2);

assert!(bp >= expected)
}
}
2 changes: 2 additions & 0 deletions src/character/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ mod tests {
String::from("Cthulhu by Night"),
Some(attributes),
None,
None,
);

let health = Health::from_character(&char, None, None);
Expand Down Expand Up @@ -187,6 +188,7 @@ mod tests {
value: 6,
stains: 0,
},
blood_potency: Default::default(),
};

let expected_humanity = Humanity {
Expand Down
33 changes: 33 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod character;

use crate::character::attributes::Attributes;
use crate::character::blood::BloodPotency;
use crate::character::stats::{Health, Willpower};
use crate::character::Character;
use anyhow::{Context, Result};
Expand Down Expand Up @@ -112,12 +113,44 @@ pub fn create_character() -> Result<()> {

println!();

// TODO: choose skill distribution and then consequently skills

//TODO implement sea of time later if we even need it at all
/*
{
let sea_of_time_choice = read_user_input(r#"Please choose whether you'll be playing as a
1. "childe": Embraced within the last 15 years, 14th generation or higher (thin-bloods), blood potency 0;\
2. "neonate": embraced between 1940 and about a decade ago, 12th or 13th generation, blood potency 1, 15 free XP;
3. "ancilla": embraced between 1780 and 1940, 10th or 11th generation, blood potency 2, additional 2 points of Advantages, 2 of Flaws, -1 to Humanity, 35 free XP
Please type one of the quoted terms:
"#
)?;
match sea_of_time_choice {
"childe" => todo!(),
"neonate" => todo!(),
"ancilla" => todo!(),
_ => format_err!("You did not pick one of the allowed choices!")
};
}
*/

//TODO refactor both generation parsing and blood potency from generation to own functions
let generation: u8 = read_user_input("Input the generation you would like to set for your character. Remember that *higher* generation number means weaker!")?
.parse()
.expect("couldn't read generation, did you input a number or text?");

let blood_potency = BloodPotency::from_generation(&generation);

let character = Character::new(
input_player_name,
input_char_name,
input_chronicle,
Some(attributes),
None,
Some(blood_potency),
);

// we'll see whether this is actually useful to do like this at some point
Expand Down
2 changes: 1 addition & 1 deletion tests/integration_test_characters/test_character.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"player_name":"Test player","character_name":"Test character","chronicle":"Test chronicle","attributes":{"strength":2,"dexterity":4,"stamina":2,"charisma":3,"manipulation":3,"composure":2,"intelligence":3,"wits":2,"resolve":1},"skills":{"athletics":[1,null],"brawl":[2,null],"craft":[3,"carpenter"],"drive":[0,null],"firearms":[0,null],"larceny":[0,null],"melee":[1,null],"stealth":[0,null],"survival":[1,"foraging"],"animal_ken":[2,null],"etiquette":[0,null],"insight":[1,null],"intimidation":[2,null],"leadership":[1,"practicality"],"performance":[0,null],"persuasion":[1,null],"streetwise":[1,null],"subterfuge":[0,null],"academics":[0,null],"awareness":[3,null],"finance":[0,null],"investigation":[2,null],"medicine":[1,null],"occult":[0,null],"politics":[0,null],"science":[0,null],"technology":[0,null]},"damage":{"superficial":0,"aggravated":0},"willpower_damage":{"superficial":0,"aggravated":0},"humanity":{"value":7,"stains":0}}
{"player_name":"Test player","character_name":"Test character","chronicle":"Test chronicle","attributes":{"strength":2,"dexterity":4,"stamina":2,"charisma":3,"manipulation":3,"composure":2,"intelligence":3,"wits":2,"resolve":1},"skills":{"athletics":[1,null],"brawl":[2,null],"craft":[3,"carpenter"],"drive":[0,null],"firearms":[0,null],"larceny":[0,null],"melee":[1,null],"stealth":[0,null],"survival":[1,"foraging"],"animal_ken":[2,null],"etiquette":[0,null],"insight":[1,null],"intimidation":[2,null],"leadership":[1,"practicality"],"performance":[0,null],"persuasion":[1,null],"streetwise":[1,null],"subterfuge":[0,null],"academics":[0,null],"awareness":[3,null],"finance":[0,null],"investigation":[2,null],"medicine":[1,null],"occult":[0,null],"politics":[0,null],"science":[0,null],"technology":[0,null]},"damage":{"superficial":0,"aggravated":0},"willpower_damage":{"superficial":0,"aggravated":0},"humanity":{"value":7,"stains":0},"blood_potency":2}
6 changes: 6 additions & 0 deletions tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ fn new_char_from_sample_json() {
value: 7,
stains: 1,
},
blood_potency: 1.into(),
};

let char = Character::from_file(PathBuf::from("tests/sample_character_dir/sample_char.json"))
Expand Down Expand Up @@ -110,6 +111,7 @@ fn new_char_from_sample_2() {
damage: Default::default(),
willpower_damage: Default::default(),
humanity: Default::default(),
blood_potency: 1.into(),
};

let char = Character::from_file(PathBuf::from(
Expand Down Expand Up @@ -143,6 +145,7 @@ fn new_char_from_sample_3() {
value: 7,
stains: 1,
},
blood_potency: 2.into(),
};

let char = Character::from_file(PathBuf::from(
Expand Down Expand Up @@ -203,12 +206,15 @@ fn new_char_to_file() {
technology: (0, None),
};

let bp = 2;

let char = Character::new(
String::from("Test player"),
String::from("Test character"),
String::from("Test chronicle"),
Some(attributes),
Some(skills),
Some(bp.into()),
);

char.to_file(PathBuf::from(
Expand Down
3 changes: 2 additions & 1 deletion tests/sample_character_dir/sample_char_2.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,6 @@
"humanity": {
"value": 7,
"stains": 0
}
},
"blood_potency": 1
}
3 changes: 2 additions & 1 deletion tests/sample_character_dir/sample_char_3.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,6 @@
"humanity": {
"value": 7,
"stains": 1
}
},
"blood_potency": 2
}

0 comments on commit 602ec8f

Please sign in to comment.