summaryrefslogtreecommitdiff
path: root/src/character
diff options
context:
space:
mode:
authorArne Dußin2021-04-26 10:06:58 +0200
committerArne Dußin2021-04-26 10:06:58 +0200
commit7ae33fba15b2adf9f903869b3c896a7490427b04 (patch)
treecc6605131081ee444165e92284c8ffe9fa6b9f63 /src/character
downloadcappuccino-7ae33fba15b2adf9f903869b3c896a7490427b04.tar.gz
cappuccino-7ae33fba15b2adf9f903869b3c896a7490427b04.zip
Initial commit
Diffstat (limited to 'src/character')
-rw-r--r--src/character/mod.rs207
-rw-r--r--src/character/stats.rs117
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());
+ }
+}