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 /// get the character and color used to draw the artifact into the level 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; } /// An artifact that contains a random amount of gold pieces. pub struct Chest { /// the chests position position: Position, /// the chests value gold: usize, } impl Chest { /// create a chest at the given position with a random amount of gold. /// The gold amount depends on the level, the deeper you go, the more you get. 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::Cyan) } 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)] /// An artifact that gives the player some health on consumption. 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) { //! called when the player walked on to a potion. //! //! Depending on health status and inventory usage the potion will //! be consumed directly or moved to inventory. 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 } }