el_diablo/src/artifacts.rs

123 lines
3.6 KiB
Rust

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<String>);
/// 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<String>) {
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<String>) {
//! 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
}
}