use rand::Rng; use ratatui::style::Color; use crate::player::Player; use crate::position::Position; pub trait Artifact { //! An artifact that can be collected by the player fn get_representation(&self) -> (&str, Color); /// get the position of the artifact in the level fn get_immutable_position(&self) -> &Position; /// call to apply the effects of the artifact to the player fn collect(&mut self, player: &mut Player, messages: &mut Vec); /// returns if the artifact was collected and can be removed from the level fn was_collected(&self) -> bool; } pub struct Chest { /// a chest that contains some gold position: Position, gold: usize, } impl Chest { pub fn new(position: Position) -> Self { let min_gold = 10 * (position.get_level() + 1); let max_gold = min_gold + 10 * position.get_level(); Self { position, gold: rand::thread_rng().gen_range(min_gold..=max_gold), } } } impl Artifact for Chest { fn get_representation(&self) -> (&str, Color) { ("C", Color::Blue) } fn get_immutable_position(&self) -> &Position { &self.position } fn collect(&mut self, player: &mut Player, messages: &mut Vec) { player.retrieve_gold(self.gold); messages.insert( 0, format!("opened chest and collected {} gold.", self.gold).to_string(), ); self.gold = 0; } fn was_collected(&self) -> bool { self.gold == 0 } } #[derive(Clone, Copy)] pub struct Potion { /// a potion that restores some health position: Position, health: usize, was_collected: bool, } impl Potion { pub fn new(position: Position) -> Self { let min_health_gain = 5 + position.get_level(); let max_health_gain = min_health_gain + 3 * position.get_level(); Self { position, health: rand::thread_rng().gen_range(min_health_gain..=max_health_gain), was_collected: false, } } pub fn get_health(&self) -> usize { self.health } } impl Artifact for Potion { fn get_representation(&self) -> (&str, Color) { ("P", Color::Green) } fn get_immutable_position(&self) -> &Position { &self.position } fn collect(&mut self, player: &mut Player, messages: &mut Vec) { // only consume potion of the player can gain at least one health point if !player.is_healthy() { let old = player.get_life(); player.change_life(self.health.try_into().unwrap()); let new = player.get_life(); messages.insert( 0, format!("picked up potion and gained {} health.", new - old).to_string(), ); self.health = 0; self.was_collected = true; } else if player.add_to_inventory(self) { messages.insert(0, "move potion to inventory.".to_string()); self.was_collected = true; } else { messages.insert(0, "inventory is full.".to_string()); } } fn was_collected(&self) -> bool { self.was_collected } }