diff options
| author | Arne Dußin | 2021-04-26 10:06:58 +0200 |
|---|---|---|
| committer | Arne Dußin | 2021-04-26 10:06:58 +0200 |
| commit | 7ae33fba15b2adf9f903869b3c896a7490427b04 (patch) | |
| tree | cc6605131081ee444165e92284c8ffe9fa6b9f63 /src/character | |
| download | cappuccino-7ae33fba15b2adf9f903869b3c896a7490427b04.tar.gz cappuccino-7ae33fba15b2adf9f903869b3c896a7490427b04.zip | |
Initial commit
Diffstat (limited to 'src/character')
| -rw-r--r-- | src/character/mod.rs | 207 | ||||
| -rw-r--r-- | src/character/stats.rs | 117 |
2 files changed, 324 insertions, 0 deletions
diff --git a/src/character/mod.rs b/src/character/mod.rs new file mode 100644 index 0000000..fc67e42 --- /dev/null +++ b/src/character/mod.rs @@ -0,0 +1,207 @@ +pub mod stats; +use std::io; + +use io::BufRead; +pub use stats::*; + +use crate::inventory::Inventory; + +pub const MAX_LEVEL: u8 = 10; + +fn swap_stats_according_to_string(stats: &mut Stats, string: String) +{ + let string = string.trim(); + let parts: Vec<&str> = string.split_whitespace().collect(); + + if parts.len() == 2 && stats.swap(parts[0], parts[1]) { + println!("{} and {} values have been switched.", parts[0], parts[1]); + } + else { + println!("Not switching any stats."); + } +} + +pub fn cli_create_character() -> Character +{ + println!("Starting character creation."); + println!("Rolling initial stats..."); + + let mut stats = Stats::roll_initial(); + println!("Initial stats: {}", stats); + + println!( + "Would you like to swap two stats' values? If so, write the names of them seperated by a \ + whitespace and press enter, if not just press enter." + ); + + let mut buf = String::new(); + + { + let stdin = io::stdin(); + let mut lock = stdin.lock(); + lock.read_line(&mut buf) + .expect("Unable to read from console"); + } + + swap_stats_according_to_string(&mut stats, buf); + + unimplemented!() +} + +#[derive(Clone, Debug)] +pub struct Character +{ + health: u8, + max_health: u8, + stats: Stats, + /// Free text describing the special trait of the character + special_traits: Vec<String>, + /// Total value of experience. The level can be calculated through it + experience: u32, + wealth: u32, + inventory: Inventory, + goals: Vec<String>, +} + +impl Character +{ + pub fn new( + health: u8, + max_health: u8, + stats: Stats, + special_traits: Vec<String>, + experience: u32, + wealth: u32, + inventory: Inventory, + goals: Vec<String>, + ) -> Self + { + Self { + health, + max_health, + stats, + special_traits, + experience, + wealth, + inventory, + goals, + } + } + + pub fn stats(&self) -> &Stats { &self.stats } + pub fn stats_mut(&mut self) -> &mut Stats { &mut self.stats } + + pub fn special_traits(&self) -> &Vec<String> { &self.special_traits } + + pub fn experience(&self) -> u32 { self.experience } + + pub fn wealth(&self) -> u32 { self.wealth } + + pub fn level(&self) -> u8 + { + /* Start iteration at first level */ + let mut level_counter = 1; + let mut xp_remaining = self.experience; + let mut xp_required_for_levelup = 200; + + while level_counter < MAX_LEVEL && xp_remaining >= xp_required_for_levelup { + level_counter += 1; + xp_remaining -= xp_required_for_levelup; + xp_required_for_levelup += 100; + } + + level_counter + } +} + +#[cfg(test)] +mod tests +{ + use super::*; + + const DEFAULT_STATS: Stats = Stats::from_values([10; NUM_STATS]); + + #[test] + fn create_character() + { + let character = Character::new( + 10, + 10, + DEFAULT_STATS.clone(), + Vec::new(), + 1, + 2, + Inventory::new(), + Vec::new(), + ); + + assert_eq!(character.stats(), &DEFAULT_STATS); + assert_eq!(character.special_traits(), &Vec::<String>::new()); + assert_eq!(character.experience(), 1); + assert_eq!(character.wealth, 2); + } + + #[test] + fn min_level_calculation() + { + let character = Character::new( + 10, + 10, + DEFAULT_STATS.clone(), + Vec::new(), + 199, + 0, + Inventory::new(), + Vec::new(), + ); + + assert_eq!(character.level(), 1); + } + + #[test] + fn mid_level_calculation() + { + let character = Character::new( + 10, + 10, + DEFAULT_STATS.clone(), + Vec::new(), + 900, + 0, + Inventory::new(), + Vec::new(), + ); + + assert_eq!(character.level(), 4); + } + + #[test] + fn max_level_calculation() + { + let character = Character::new( + 10, + 10, + DEFAULT_STATS.clone(), + Vec::new(), + 5400, + 0, + Inventory::new(), + Vec::new(), + ); + + assert_eq!(character.level(), 10); + + let character = Character::new( + 10, + 10, + DEFAULT_STATS.clone(), + Vec::new(), + 6500, + 0, + Inventory::new(), + Vec::new(), + ); + + assert_eq!(character.level(), 10); + } +} diff --git a/src/character/stats.rs b/src/character/stats.rs new file mode 100644 index 0000000..d405eb7 --- /dev/null +++ b/src/character/stats.rs @@ -0,0 +1,117 @@ +use std::fmt::{self, Display, Formatter}; + +use rand::prelude::ThreadRng; +use rand::Rng; + +pub const NUM_STATS: usize = 7; +pub const STATS: [&str; NUM_STATS] = [ + "charisma", + "constitution", + "dexterity", + "health", + "intelligence", + "strength", + "wisdom", +]; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Stats +{ + values: [u8; NUM_STATS], +} + +impl Stats +{ + pub const fn from_values(values: [u8; NUM_STATS]) -> Self { Self { values } } + + fn roll_initial_value(rng: &mut ThreadRng) -> u8 + { + let mut v = 0; + for _ in 0..3 { + v += rng.gen_range(1..=6); + } + + v + } + + pub fn roll_initial() -> Self + { + let mut rng = rand::thread_rng(); + let mut values = [0; NUM_STATS]; + for v in &mut values { + *v = Self::roll_initial_value(&mut rng); + } + + Self { values } + } + + pub fn swap(&mut self, val1: &str, val2: &str) -> bool + { + unimplemented!(); + } + + pub fn get(&self, attribute: &str) -> Option<u8> + { + match STATS.binary_search(&attribute) { + Ok(pos) => Some(self.values[pos]), + Err(_) => None, + } + } + + pub fn get_mut(&mut self, attribute: &str) -> Option<&mut u8> + { + match STATS.binary_search(&attribute) { + Ok(pos) => Some(self.values.get_mut(pos).unwrap()), + Err(_) => None, + } + } +} + +impl Display for Stats +{ + fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> + { + writeln!(fmt, "[")?; + for i in 0..NUM_STATS { + writeln!(fmt, " {} = {}", STATS[i], self.values[i])?; + } + writeln!(fmt, "]")?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests +{ + use super::*; + + fn test_stats() -> Stats { Stats::from_values([1, 2, 3, 4, 5, 6, 7]) } + + #[test] + fn swap_same_argument() + { + let mut stats = test_stats(); + assert_eq!(stats.get("intelligence"), Some(5)); + assert!(stats.swap("intelligence", "intelligence")); + assert_eq!(stats.get("intelligence"), Some(5)); + + assert_eq!(stats.get("wisdom"), Some(7)); + assert!(stats.swap("wisdom", "wisdom")); + assert_eq!(stats.get("wisdom"), Some(7)); + } + + #[test] + fn swap_invalid_argument() + { + let mut stats = test_stats(); + assert!(!stats.swap("", "intelligence")); + assert_eq!(stats, test_stats()); + assert!(!stats.swap("intelligence", "")); + assert_eq!(stats, test_stats()); + assert!(!stats.swap("aoeu", "aoeu")); + assert_eq!(stats, test_stats()); + assert!(!stats.swap("", "")); + assert_eq!(stats, test_stats()); + } +} |
