diff --git a/src/items.rs b/src/items.rs index 0910b79..4b48381 100644 --- a/src/items.rs +++ b/src/items.rs @@ -8,7 +8,7 @@ pub use armor::ItemArmor; pub use weapon::ItemWeapon; // === ENUMS === -#[derive(Clone, Debug, Deserialize)] +#[derive(Debug, Deserialize)] pub enum ItemType { Weapon, OffHand, @@ -23,10 +23,10 @@ pub enum ItemType { // === STRUCTS === #[derive(Deserialize)] pub struct Item { - id: String, - name: String, - value: u32, - item_type: ItemType, + pub id: String, + pub name: String, + pub value: u32, + pub item_type: ItemType, } /// Rohform einer Item-Datei. Jede TOML nutzt `[[items]]` als Wurzel, @@ -43,33 +43,6 @@ pub struct ItemCatalog { pub armors: Vec, } -// === TRAITS === -pub trait ItemTrait { - fn get_id(&self) -> String; - fn get_name(&self) -> String; - fn get_value(&self) -> u32; - fn get_type(&self) -> ItemType; -} - -// === IMPLEMENTS === -impl ItemTrait for Item { - fn get_id(&self) -> String { - self.id.clone() - } - - fn get_name(&self) -> String { - self.name.clone() - } - - fn get_value(&self) -> u32 { - self.value - } - - fn get_type(&self) -> ItemType { - self.item_type.clone() - } -} - // === FUNCTIONS === pub fn load_items() -> ItemCatalog { ItemCatalog { @@ -87,12 +60,13 @@ fn parse(raw: &str, file: &str) -> Vec { /// Rahmen um beliebig viele Zeilen. Wird von jedem `print_values` genutzt. pub(crate) fn print_box(lines: &[String]) { let longest: usize = lines.iter().map(|l| l.chars().count()).max().unwrap_or(0); + let border: String = format!("+-{}-+", "-".repeat(longest)); - println!("+-{}-+", "-".repeat(longest)); + println!("{}", border); for line in lines { println!("| {}{} |", line, " ".repeat(longest - line.chars().count())); } - println!("+-{}-+", "-".repeat(longest)); + println!("{}", border); } #[cfg(test)] diff --git a/src/items/armor.rs b/src/items/armor.rs index dd6bf29..5a1c751 100644 --- a/src/items/armor.rs +++ b/src/items/armor.rs @@ -1,46 +1,22 @@ use serde::Deserialize; -use super::{Item, ItemTrait, ItemType, print_box}; +use super::{Item, print_box}; #[derive(Deserialize)] pub struct ItemArmor { - armor: u32, + pub armor: u32, #[serde(flatten)] - item: Item, -} - -impl ItemTrait for ItemArmor { - fn get_id(&self) -> String { - self.item.get_id() - } - - fn get_name(&self) -> String { - self.item.get_name() - } - - fn get_value(&self) -> u32 { - self.item.get_value() - } - - fn get_type(&self) -> ItemType { - self.item.get_type() - } + pub item: Item, } impl ItemArmor { - pub fn get_armor(&self) -> u32 { - self.armor - } - pub fn print_values(&self) { - let lines: Vec = vec![ - format!("Stats for {} ", self.get_name()), - format!("ID: {}", self.get_id()), - format!("Slot: {:?}", self.get_type()), - format!("Armor: {}", self.get_armor()), - format!("Value: {}", self.get_value()), - ]; - - print_box(&lines); + print_box(&[ + format!("Stats for {} ", self.item.name), + format!("ID: {}", self.item.id), + format!("Slot: {:?}", self.item.item_type), + format!("Armor: {}", self.armor), + format!("Value: {}", self.item.value), + ]); } } diff --git a/src/items/weapon.rs b/src/items/weapon.rs index 9ca559a..29c4e60 100644 --- a/src/items/weapon.rs +++ b/src/items/weapon.rs @@ -1,62 +1,26 @@ use serde::Deserialize; -use super::{Item, ItemTrait, ItemType, print_box}; +use super::{Item, print_box}; #[derive(Deserialize)] pub struct ItemWeapon { - base_damage: u32, - critical_factor: f32, + pub base_damage: u32, + pub critical_factor: f32, #[serde(flatten)] - item: Item, -} - -impl ItemTrait for ItemWeapon { - fn get_id(&self) -> String { - self.item.get_id() - } - - fn get_name(&self) -> String { - self.item.get_name() - } - - fn get_value(&self) -> u32 { - self.item.get_value() - } - - fn get_type(&self) -> ItemType { - self.item.get_type() - } + pub item: Item, } impl ItemWeapon { - pub fn get_base_damage(&self) -> u32 { - self.base_damage - } - - pub fn get_critical_factor(&self) -> f32 { - self.critical_factor - } - - pub fn get_critical_factor_readable(&self) -> String { - let factor: i32 = ((self.get_critical_factor() - 1.0) * 100.0).round() as i32; - format!("{}%", factor) - } - pub fn print_values(&self) { - let crit_dmg: u32 = - (self.get_base_damage() as f32 * self.get_critical_factor()).ceil() as u32; + let crit_damage: u32 = (self.base_damage as f32 * self.critical_factor).ceil() as u32; + let crit_percent: i32 = ((self.critical_factor - 1.0) * 100.0).round() as i32; - let lines: Vec = vec![ - format!("Stats for {} ", self.get_name()), - format!("ID: {}", self.get_id()), - format!("Base Damage: {} ({})", self.get_base_damage(), crit_dmg), - format!( - "Critical Factor: {}", - self.get_critical_factor_readable() - ), - format!("Value: {}", self.get_value()), - ]; - - print_box(&lines); + print_box(&[ + format!("Stats for {} ", self.item.name), + format!("ID: {}", self.item.id), + format!("Base Damage: {} ({})", self.base_damage, crit_damage), + format!("Critical Factor: {}%", crit_percent), + format!("Value: {}", self.item.value), + ]); } } diff --git a/src/player.rs b/src/player.rs index 909a91e..c6dc8f9 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,20 +1,11 @@ -use std::fmt::format; - -use crate::stats::{Stats, StatsTrait}; +use crate::items::print_box; +use crate::stats::Stats; pub struct Player { - name: String, - stats: Stats, - next_level_exp: usize, - current_exp: usize, -} - -pub trait PlayerTrait { - fn get_name(&self) -> String; - fn set_name(&mut self, name: String); - fn get_current_exp(&self) -> usize; - fn get_next_level_exp(&self) -> usize; - fn show_stats(&self); + pub name: String, + pub stats: Stats, + pub next_level_exp: usize, + pub current_exp: usize, } impl Player { @@ -26,119 +17,21 @@ impl Player { current_exp: 0, } } -} -impl PlayerTrait for Player { - fn get_name(&self) -> String { - self.name.clone() - } + pub fn show_stats(&self) { + let stats: &Stats = &self.stats; - fn set_name(&mut self, name: String) { - self.name = name; - } - - fn show_stats(&self) { - let name: String = format!("Name: {}", self.get_name()); - let level: String = format!( - "Level: {} ({}/{})", - self.get_level(), - self.get_current_exp(), - self.get_next_level_exp() - ); - let strength: String = format!("Strength: {}", self.get_strengh()); - let dexterity: String = format!("Dexterity: {}", self.get_dexterity()); - let constitution: String = format!("Constitution: {}", self.get_constitution()); - let charisma: String = format!("Charisma: {}", self.get_charisma()); - let luck: String = format!("Luck: {}", self.get_luck()); - - let stats_data: [&String; 7] = [ - &name, - &level, - &strength, - &dexterity, - &constitution, - &charisma, - &luck, - ]; - let mut longest: usize = 0; - for data in stats_data { - let length: usize = data.chars().count(); - longest = length.max(longest); - } - - let spacer: String = format!("+-{}-+", "-".repeat(longest)); - - println!("{}", spacer); - for data in stats_data { - let length: usize = data.chars().count(); - println!("| {}{} |", data, " ".repeat(longest - length)); - } - println!("{}", spacer); - } - - fn get_current_exp(&self) -> usize { - self.current_exp - } - - fn get_next_level_exp(&self) -> usize { - self.next_level_exp - } -} - -impl StatsTrait for Player { - fn get_max_health(&self) -> f32 { - self.stats.get_max_health() - } - - fn get_current_health(&self) -> f32 { - self.stats.get_current_health() - } - - fn set_current_health(&mut self, value: f32) { - self.stats.set_current_health(value); - } - - fn is_dead(&self) -> bool { - self.stats.is_dead() - } - - fn get_max_stamina(&self) -> f32 { - self.stats.get_max_stamina() - } - - fn get_current_stamina(&self) -> f32 { - self.stats.get_current_stamina() - } - - fn set_current_stamina(&mut self, value: f32) { - self.stats.set_current_stamina(value); - } - - fn get_strengh(&self) -> usize { - self.stats.get_strengh() - } - - fn get_dexterity(&self) -> usize { - self.stats.get_dexterity() - } - - fn get_constitution(&self) -> usize { - self.stats.get_constitution() - } - - fn get_charisma(&self) -> usize { - self.stats.get_charisma() - } - - fn get_luck(&self) -> usize { - self.stats.get_luck() - } - - fn get_level(&self) -> usize { - self.stats.get_level() - } - - fn level_up(&mut self) { - self.stats.level_up(); + print_box(&[ + format!("Name: {}", self.name), + format!( + "Level: {} ({}/{})", + stats.level, self.current_exp, self.next_level_exp + ), + format!("Strength: {}", stats.strength), + format!("Dexterity: {}", stats.dexterity), + format!("Constitution: {}", stats.constitution), + format!("Charisma: {}", stats.charisma), + format!("Luck: {}", stats.luck), + ]); } } diff --git a/src/stats.rs b/src/stats.rs index 090b792..bbc6be9 100644 --- a/src/stats.rs +++ b/src/stats.rs @@ -1,31 +1,14 @@ pub struct Stats { - max_health: f32, - current_health: f32, - max_stamina: f32, - current_stamina: f32, - strength: usize, // Determines base_damage modifier - dexterity: usize, // Determines Critical Factor Modifier - constitution: usize, // Determines Max Health Bonuses - charisma: usize, // Determines Shop Prices - luck: usize, // Determines Loot Drop & Critical Chance - level: usize, -} - -pub trait StatsTrait { - fn get_max_health(&self) -> f32; - fn get_current_health(&self) -> f32; - fn set_current_health(&mut self, value: f32); - fn is_dead(&self) -> bool; - fn get_max_stamina(&self) -> f32; - fn get_current_stamina(&self) -> f32; - fn set_current_stamina(&mut self, value: f32); - fn get_strengh(&self) -> usize; - fn get_dexterity(&self) -> usize; - fn get_constitution(&self) -> usize; - fn get_charisma(&self) -> usize; - fn get_luck(&self) -> usize; - fn get_level(&self) -> usize; - fn level_up(&mut self); + pub max_health: f32, + pub current_health: f32, + pub max_stamina: f32, + pub current_stamina: f32, + pub strength: usize, // Determines base_damage modifier + pub dexterity: usize, // Determines Critical Factor Modifier + pub constitution: usize, // Determines Max Health Bonuses + pub charisma: usize, // Determines Shop Prices + pub luck: usize, // Determines Loot Drop & Critical Chance + pub level: usize, } impl Stats { @@ -45,64 +28,41 @@ impl Stats { level: 1, } } -} -impl StatsTrait for Stats { - fn get_max_health(&self) -> f32 { - self.max_health + /// Delta auf die aktuelle Health: positiv heilt, negativ verletzt. + pub fn change_health(&mut self, delta: f32) { + self.current_health = (self.current_health + delta).clamp(0.0, self.max_health); } - fn get_current_health(&self) -> f32 { - self.current_health + /// Delta auf die aktuelle Stamina: positiv regeneriert, negativ verbraucht. + // TODO: noch ungenutzt — wird vom Kampfsystem aufgerufen, sobald es existiert. + pub fn change_stamina(&mut self, delta: f32) { + self.current_stamina = (self.current_stamina + delta).clamp(0.0, self.max_stamina); } - fn set_current_health(&mut self, value: f32) { - let new_val: f32 = self.current_health + value; - self.current_health = new_val.clamp(0.0, self.max_health); - } - - fn is_dead(&self) -> bool { + pub fn is_dead(&self) -> bool { self.current_health <= 0.0 } - fn get_max_stamina(&self) -> f32 { - self.max_stamina - } - - fn get_current_stamina(&self) -> f32 { - self.current_stamina - } - - fn set_current_stamina(&mut self, value: f32) { - let new_val: f32 = self.current_stamina + value; - self.current_stamina = new_val.clamp(0.0, self.max_stamina); - } - - fn get_strengh(&self) -> usize { - self.strength - } - - fn get_dexterity(&self) -> usize { - self.dexterity - } - - fn get_constitution(&self) -> usize { - self.constitution - } - - fn get_charisma(&self) -> usize { - self.charisma - } - - fn get_luck(&self) -> usize { - self.luck - } - - fn get_level(&self) -> usize { - self.level - } - - fn level_up(&mut self) { + // TODO: noch ungenutzt — wird vom Exp-/Level-System aufgerufen, sobald es existiert. + pub fn level_up(&mut self) { self.level = (self.level + 1).clamp(1, 50); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn health_clamps_at_both_ends() { + let mut stats: Stats = Stats::new(); + + stats.change_health(50.0); + assert_eq!(stats.current_health, stats.max_health); + + stats.change_health(-500.0); + assert_eq!(stats.current_health, 0.0); + assert!(stats.is_dead()); + } +}