123 lines
3.6 KiB
Rust
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
|
|
}
|
|
}
|