refactor: getter-traits durch pub-felder ersetzen, print_box wiederverwenden

This commit is contained in:
2026-08-11 14:39:59 +02:00
parent eacf0c1a01
commit 290d985bc6
5 changed files with 88 additions and 321 deletions

View File

@@ -8,7 +8,7 @@ pub use armor::ItemArmor;
pub use weapon::ItemWeapon; pub use weapon::ItemWeapon;
// === ENUMS === // === ENUMS ===
#[derive(Clone, Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub enum ItemType { pub enum ItemType {
Weapon, Weapon,
OffHand, OffHand,
@@ -23,10 +23,10 @@ pub enum ItemType {
// === STRUCTS === // === STRUCTS ===
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Item { pub struct Item {
id: String, pub id: String,
name: String, pub name: String,
value: u32, pub value: u32,
item_type: ItemType, pub item_type: ItemType,
} }
/// Rohform einer Item-Datei. Jede TOML nutzt `[[items]]` als Wurzel, /// Rohform einer Item-Datei. Jede TOML nutzt `[[items]]` als Wurzel,
@@ -43,33 +43,6 @@ pub struct ItemCatalog {
pub armors: Vec<ItemArmor>, pub armors: Vec<ItemArmor>,
} }
// === 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 === // === FUNCTIONS ===
pub fn load_items() -> ItemCatalog { pub fn load_items() -> ItemCatalog {
ItemCatalog { ItemCatalog {
@@ -87,12 +60,13 @@ fn parse<T: DeserializeOwned>(raw: &str, file: &str) -> Vec<T> {
/// Rahmen um beliebig viele Zeilen. Wird von jedem `print_values` genutzt. /// Rahmen um beliebig viele Zeilen. Wird von jedem `print_values` genutzt.
pub(crate) fn print_box(lines: &[String]) { pub(crate) fn print_box(lines: &[String]) {
let longest: usize = lines.iter().map(|l| l.chars().count()).max().unwrap_or(0); 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 { for line in lines {
println!("| {}{} |", line, " ".repeat(longest - line.chars().count())); println!("| {}{} |", line, " ".repeat(longest - line.chars().count()));
} }
println!("+-{}-+", "-".repeat(longest)); println!("{}", border);
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -1,46 +1,22 @@
use serde::Deserialize; use serde::Deserialize;
use super::{Item, ItemTrait, ItemType, print_box}; use super::{Item, print_box};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct ItemArmor { pub struct ItemArmor {
armor: u32, pub armor: u32,
#[serde(flatten)] #[serde(flatten)]
item: Item, pub 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()
}
} }
impl ItemArmor { impl ItemArmor {
pub fn get_armor(&self) -> u32 {
self.armor
}
pub fn print_values(&self) { pub fn print_values(&self) {
let lines: Vec<String> = vec![ print_box(&[
format!("Stats for {} ", self.get_name()), format!("Stats for {} ", self.item.name),
format!("ID: {}", self.get_id()), format!("ID: {}", self.item.id),
format!("Slot: {:?}", self.get_type()), format!("Slot: {:?}", self.item.item_type),
format!("Armor: {}", self.get_armor()), format!("Armor: {}", self.armor),
format!("Value: {}", self.get_value()), format!("Value: {}", self.item.value),
]; ]);
print_box(&lines);
} }
} }

View File

@@ -1,62 +1,26 @@
use serde::Deserialize; use serde::Deserialize;
use super::{Item, ItemTrait, ItemType, print_box}; use super::{Item, print_box};
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct ItemWeapon { pub struct ItemWeapon {
base_damage: u32, pub base_damage: u32,
critical_factor: f32, pub critical_factor: f32,
#[serde(flatten)] #[serde(flatten)]
item: Item, pub 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()
}
} }
impl ItemWeapon { 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) { pub fn print_values(&self) {
let crit_dmg: u32 = let crit_damage: u32 = (self.base_damage as f32 * self.critical_factor).ceil() as u32;
(self.get_base_damage() as f32 * self.get_critical_factor()).ceil() as u32; let crit_percent: i32 = ((self.critical_factor - 1.0) * 100.0).round() as i32;
let lines: Vec<String> = vec![ print_box(&[
format!("Stats for {} ", self.get_name()), format!("Stats for {} ", self.item.name),
format!("ID: {}", self.get_id()), format!("ID: {}", self.item.id),
format!("Base Damage: {} ({})", self.get_base_damage(), crit_dmg), format!("Base Damage: {} ({})", self.base_damage, crit_damage),
format!( format!("Critical Factor: {}%", crit_percent),
"Critical Factor: {}", format!("Value: {}", self.item.value),
self.get_critical_factor_readable() ]);
),
format!("Value: {}", self.get_value()),
];
print_box(&lines);
} }
} }

View File

@@ -1,20 +1,11 @@
use std::fmt::format; use crate::items::print_box;
use crate::stats::Stats;
use crate::stats::{Stats, StatsTrait};
pub struct Player { pub struct Player {
name: String, pub name: String,
stats: Stats, pub stats: Stats,
next_level_exp: usize, pub next_level_exp: usize,
current_exp: usize, pub 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);
} }
impl Player { impl Player {
@@ -26,119 +17,21 @@ impl Player {
current_exp: 0, current_exp: 0,
} }
} }
}
impl PlayerTrait for Player { pub fn show_stats(&self) {
fn get_name(&self) -> String { let stats: &Stats = &self.stats;
self.name.clone()
}
fn set_name(&mut self, name: String) { print_box(&[
self.name = name; format!("Name: {}", self.name),
} format!(
fn show_stats(&self) {
let name: String = format!("Name: {}", self.get_name());
let level: String = format!(
"Level: {} ({}/{})", "Level: {} ({}/{})",
self.get_level(), stats.level, self.current_exp, self.next_level_exp
self.get_current_exp(), ),
self.get_next_level_exp() format!("Strength: {}", stats.strength),
); format!("Dexterity: {}", stats.dexterity),
let strength: String = format!("Strength: {}", self.get_strengh()); format!("Constitution: {}", stats.constitution),
let dexterity: String = format!("Dexterity: {}", self.get_dexterity()); format!("Charisma: {}", stats.charisma),
let constitution: String = format!("Constitution: {}", self.get_constitution()); format!("Luck: {}", stats.luck),
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();
} }
} }

View File

@@ -1,31 +1,14 @@
pub struct Stats { pub struct Stats {
max_health: f32, pub max_health: f32,
current_health: f32, pub current_health: f32,
max_stamina: f32, pub max_stamina: f32,
current_stamina: f32, pub current_stamina: f32,
strength: usize, // Determines base_damage modifier pub strength: usize, // Determines base_damage modifier
dexterity: usize, // Determines Critical Factor Modifier pub dexterity: usize, // Determines Critical Factor Modifier
constitution: usize, // Determines Max Health Bonuses pub constitution: usize, // Determines Max Health Bonuses
charisma: usize, // Determines Shop Prices pub charisma: usize, // Determines Shop Prices
luck: usize, // Determines Loot Drop & Critical Chance pub luck: usize, // Determines Loot Drop & Critical Chance
level: usize, pub 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);
} }
impl Stats { impl Stats {
@@ -45,64 +28,41 @@ impl Stats {
level: 1, level: 1,
} }
} }
/// 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);
} }
impl StatsTrait for Stats { /// Delta auf die aktuelle Stamina: positiv regeneriert, negativ verbraucht.
fn get_max_health(&self) -> f32 { // TODO: noch ungenutzt — wird vom Kampfsystem aufgerufen, sobald es existiert.
self.max_health pub fn change_stamina(&mut self, delta: f32) {
self.current_stamina = (self.current_stamina + delta).clamp(0.0, self.max_stamina);
} }
fn get_current_health(&self) -> f32 { pub fn is_dead(&self) -> bool {
self.current_health
}
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 {
self.current_health <= 0.0 self.current_health <= 0.0
} }
fn get_max_stamina(&self) -> f32 { // TODO: noch ungenutzt — wird vom Exp-/Level-System aufgerufen, sobald es existiert.
self.max_stamina pub fn level_up(&mut self) {
}
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) {
self.level = (self.level + 1).clamp(1, 50); 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());
}
}