use rand::Rng; use std::cmp::{max, min}; use crate::artifacts::Potion; use crate::position::{HasPosition, Position}; pub struct Player { name: String, position: Position, life: i16, max_life: i16, gold: usize, experience: usize, inventory: Vec, } impl Player { pub fn new(name: &str, max_life: i16) -> Player { Player { name: name.to_string(), position: Position::new(0, 0, 0), life: max_life, max_life, gold: 0, experience: 0, inventory: vec![], } } pub fn get_name(&self) -> String { self.name.clone() } pub fn change_life(&mut self, by: i16) { self.life = max(0, min(self.max_life, self.life + by)); } pub fn get_life(&self) -> i16 { self.life } /// returns true if the player is dead (life <= 0) pub fn is_dead(&self) -> bool { self.life <= 0 } /// returns true if the player's life is at maximum pub fn is_healthy(&self) -> bool { self.life == self.max_life } pub fn get_max_life(&self) -> i16 { self.max_life } /// add the given amount to the players gold stash pub fn retrieve_gold(&mut self, amount: usize) { self.gold += amount } /// return the size of the players gold stash pub fn get_gold(&self) -> usize { self.gold } pub fn gain_experience(&mut self, amount: usize) { self.experience += amount } pub fn get_experience(&self) -> usize { self.experience } pub fn damage(&self) -> usize { rand::thread_rng().gen_range(1..4) } pub fn add_to_inventory(&mut self, potion: &Potion) -> bool { if self.inventory.len() < 10 { self.inventory.push(*potion); true } else { false } } pub fn inventory_size(&self) -> usize { self.inventory.len() } pub fn consume_inventory(&mut self) -> usize { if self.is_healthy() { return 0; } if let Some(potion) = self.inventory.pop() { self.change_life(potion.get_health() as i16); return potion.get_health(); } 0 } } impl HasPosition for Player { fn get_position(&mut self) -> &mut Position { &mut self.position } fn get_immutable_position(&self) -> &Position { &self.position } } #[test] fn test_get_name() { let p = Player { name: "Teddy Tester".to_string(), position: Position::new(0, 1, 1), life: 5, max_life: 10, gold: 0, experience: 0, inventory: vec![], }; assert_eq!(p.get_name(), "Teddy Tester"); } #[test] fn test_can_receive_gold() { let mut p = Player::new("Teddy Tester", 10); assert_eq!(p.get_gold(), 0); p.retrieve_gold(13); p.retrieve_gold(10); assert_eq!(p.get_gold(), 23); } #[test] fn test_change_life() { let mut p = Player { name: "Teddy Tester".to_string(), position: Position::new(0, 1, 1), life: 5, max_life: 10, gold: 0, experience: 0, inventory: vec![], }; assert_eq!(p.get_life(), 5); p.change_life(-2); assert_eq!(p.get_life(), 3); p.change_life(10); assert_eq!(p.get_life(), 10); p.change_life(-12); assert_eq!(p.get_life(), 0); } #[test] fn player_can_move() { let mut p = Player::new("Teddy Tester", 10); assert_eq!(p.get_position(), &Position::new(0, 0, 0)); p.get_position().change(1, 2); assert_eq!(p.get_position(), &Position::new(0, 1, 2)); p.get_position().change(2, 1); assert_eq!(p.get_position(), &Position::new(0, 3, 3)); p.get_position().set(1, 2, 3); p.get_position().change(2, 1); assert_eq!(p.get_position(), &Position::new(1, 4, 4)); assert_eq!(p.get_immutable_position(), &Position::new(1, 4, 4)); } #[test] fn test_max_life() { let p = Player { name: "Teddy Tester".to_string(), position: Position::new(0, 1, 1), life: 5, max_life: 10, gold: 0, experience: 0, inventory: vec![], }; assert_eq!(p.get_max_life(), 10); }