use crate::get_user_input;
use crate::items::Item;
use crate::weapons::{self, Weapon};
use std::io::BufRead;
pub mod monsters;
pub trait Entity {
fn take_damage(&mut self, amount: i32);
fn decrease_damage(&mut self, amount: i32);
fn get_current_health(&self) -> i32;
fn get_max_health(&self) -> i32;
fn is_dead(&self) -> bool {
self.get_current_health() <= 0
}
fn get_name(&self) -> &str;
fn heal_damage(&mut self, amount: i32) {
if self.get_current_health() + amount >= self.get_max_health() {
self.take_damage(-(self.get_current_health() + amount - self.get_max_health()));
} else {
self.take_damage(-amount);
}
}
}
pub trait User {
fn get_action(&mut self, target: &mut Enemy) -> ();
fn user_select_ith_index_from_vec(&mut self) -> usize;
}
pub struct Hero {
pub name: String,
pub max_health: i32,
pub current_health: i32,
pub items: Vec<Item>,
pub weapon: Weapon,
}
impl Entity for Hero {
fn take_damage(&mut self, amount: i32) {
self.current_health -= amount;
}
fn decrease_damage(&mut self, amount: i32) {
self.weapon.damage -= amount;
if self.weapon.damage < 0 {
self.weapon.damage = 0;
}
}
fn get_max_health(&self) -> i32 {
self.max_health
}
fn get_current_health(&self) -> i32 {
self.current_health
}
fn get_name(&self) -> &str {
&self.name
}
}
impl User for Hero {
fn user_select_ith_index_from_vec(&mut self) -> usize {
let mut user_input = String::new();
println!("Choose from the selection:");
for (index, item) in self.items.iter().enumerate() {
println!("{}-{}", index, item.name);
}
std::io::stdin().read_line(&mut user_input).unwrap();
let user_input: usize = user_input.trim().parse().unwrap();
return user_input;
}
fn get_action(&mut self, target: &mut Enemy) -> () {
let mut user_input = String::new();
println!("Choose an action for {}:", self.name);
println!("1-Attack");
println!("2-Use Item");
std::io::stdin().read_line(&mut user_input).unwrap();
let decision = user_input.trim();
match decision {
"1" => {
self.weapon.apply(target);
}
"2" => {
if self.items.is_empty() {
println!("No items to use");
self.get_action(target);
}
println!("Select an item to use:");
for (index, item) in self.items.iter().enumerate() {
println!("{}-{}", index, item.name);
}
let user_input = get_user_input("");
let mut user_input = user_input.trim().parse::<usize>().unwrap_or_default();
if user_input >= self.items.len() {
println!("Invalid input, selecting 1st item");
user_input = 0;
}
let item = self.items.remove(user_input as usize);
item.apply(target);
}
_ => {
println!("Invalid input");
self.get_action(target);
}
}
}
}
impl Hero {
pub fn new(name: String, max_health: i32, items: Vec<Item>, weapon: Weapon) -> Hero {
Hero {
name,
max_health,
current_health: max_health,
items,
weapon,
}
}
pub fn update_weapon(&mut self, weapon: Weapon) {
self.weapon = weapon;
}
}
impl Default for Hero {
fn default() -> Self {
Hero {
name: "Default Hero".to_string(),
max_health: 100,
current_health: 100,
items: vec![],
weapon: Weapon::default(),
}
}
}
#[derive(Clone)]
pub struct Enemy {
pub name: String,
pub max_health: i32,
pub current_health: i32,
pub items: Vec<Item>,
pub weapon: Weapon,
}
impl Entity for Enemy {
fn take_damage(&mut self, amount: i32) {
self.current_health -= amount;
}
fn get_max_health(&self) -> i32 {
self.max_health
}
fn get_current_health(&self) -> i32 {
self.current_health
}
fn get_name(&self) -> &str {
&self.name
}
fn decrease_damage(&mut self, amount: i32) {
self.weapon.damage -= amount;
if self.weapon.damage < 0 {
self.weapon.damage = 0;
}
}
}
impl Enemy {
pub fn make_decision(&mut self, target: &mut Hero) {
let decision = rand::Rng::gen_range(&mut rand::thread_rng(), 0..2);
match decision {
0 => {
self.weapon.apply(target);
}
1 => {
let item = self.items.pop();
match item {
Some(item) => {
item.apply(target);
}
None => {
self.weapon.apply(target);
}
}
}
_ => {
println!("Invalid decision");
}
}
}
pub fn get_name(&self) -> &str {
&self.name
}
}
impl Default for Enemy {
fn default() -> Self {
Enemy {
name: "Training Dummy".to_string(),
max_health: 999999,
current_health: 999999,
items: vec![],
weapon: Weapon::default(),
}
}
}
mod tests {
mod user {
use crate::{
entity::{Hero, User},
items::Item,
};
#[test]
#[ignore]
fn test_user_select_ith_index_from_vec() {
let mut hero = Hero::default();
hero.items.push(Item::default());
hero.items.push(Item::default());
hero.items.push(Item::default());
let selected_index = hero.user_select_ith_index_from_vec();
assert_eq!(selected_index, 1);
}
}
mod enemy {
use crate::entity::Entity;
use crate::weapons::Weapon;
#[test]
fn successful_interaction() {
let mut hero = super::super::Hero::default();
let attack_weapon = Weapon::new("Attack Weapon", 10, |target| target.take_damage(10));
hero.weapon = attack_weapon;
let mut enemy = super::super::Enemy::default();
let initial_health = enemy.get_current_health();
hero.weapon.apply(&mut enemy);
let final_health = enemy.get_current_health();
assert_eq!(initial_health - 20, final_health);
}
}
mod entity {
use crate::entity::Entity;
use crate::weapons::Weapon;
#[test]
fn successful_interaction() {
let mut hero = super::super::Hero::default();
let attack_weapon = Weapon::new("Attack Weapon", 10, |target| target.take_damage(10));
hero.weapon = attack_weapon;
let mut enemy = super::super::Enemy::default();
let initial_health = enemy.get_current_health();
hero.weapon.apply(&mut enemy);
let final_health = enemy.get_current_health();
assert_eq!(initial_health - 20, final_health);
}
}
}