mod entity;
mod game;
mod items;
mod locations;
mod weapons;
use std::{io, io::Write};
use crate::entity::{Hero, Entity};
use crate::game::battle;
use items::Item;
use rand::{seq::SliceRandom, Rng};
pub fn create_hero() -> Hero {
let name = get_user_input("Enter hero name: ");
let weapon_name = "Flimsy Wooden Sword".to_string();
let weapon_damage: i32 = 10;
let mut items = Vec::new();
let weapon = weapons::Weapon::new(&weapon_name, weapon_damage, |target| {
println!("Flimsy Wooden Sword Splinters. 1 extra damage!");
target.take_damage(1)
});
items.push(Item::new("Healing Potion", |target| {
println!("Healing Potion applied. 50 health restored");
target.heal_damage(50);
}));
Hero::new(name, 100, items, weapon)
}
pub fn generate_encounter(possible_enemies: Vec<entity::Enemy>) -> Vec<entity::Enemy> {
let mut rng = rand::thread_rng();
let num_enemies = rng.gen_range(1..4);
let mut encounter_enemies: Vec<entity::Enemy> = Vec::new();
for _ in 0..num_enemies {
let enemy = possible_enemies.choose(&mut rng).unwrap();
encounter_enemies.push((*enemy).clone());
}
return encounter_enemies;
}
pub fn generate_loot(possible_loot: Vec<weapons::Weapon>) -> weapons::Weapon {
let mut rng = rand::thread_rng();
possible_loot.choose(&mut rng).unwrap().clone()
}
pub fn get_user_input(prompt: &str) -> String {
print!("{}", prompt);
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
input.trim().to_string()
}
pub fn start_game(mut hero_party: Vec<Hero>) {
println!("And so the adventure begins!");
let locations = locations::load_locations();
let mut hero_holder = Vec::new();
for hero in hero_party.iter_mut() {
hero_holder.push(Box::new(hero));
}
for location in locations.iter() {
let possible_enemies = (location.load_entities)();
println!("You are at the {}", location.name);
loop {
let mut enemy_holder = Vec::new();
let mut encounter_enemies = generate_encounter(possible_enemies.clone());
for enemy in encounter_enemies.iter_mut() {
enemy_holder.push(Box::new(enemy));
}
println!("You have encountered {} enemies!", enemy_holder.len());
let battle_outcome = battle(&mut hero_holder, &mut enemy_holder);
match battle_outcome {
game::BattleOutcome::Win => {
let loot = generate_loot((location.load_loot)());
println!("You have defeated the enemies!");
println!("You have found a {}", loot.name);
println!("Would you like to equip the weapon? (y/n)");
let user_input = get_user_input("");
match &user_input as &str {
"y" => {
println!("Which hero would you like to equip the weapon to?");
for (index, hero) in hero_holder.iter().enumerate() {
println!("{}-{}", index, hero.get_name());
}
let user_input = get_user_input("");
match user_input.trim().parse::<usize>() {
Ok(index) => {
if index >= hero_holder.len() {
println!("Invalid input, weapon not equipped");
} else {
hero_holder[index].update_weapon(loot);}
}
Err(_) => {
println!("Invalid input, weapon not equipped");
}
}
}
"n" => {
println!("{}", user_input);
println!("You have chosen not to equip the weapon");
}
_ => {
println!("Invalid input, weapon not equipped");
}
}
println!("Would you like to continue to the next location? (y/n)");
let user_input = get_user_input("");
match &user_input as &str {
"y" => {
break;
}
"n" => {
continue;
}
_ => {
end_game(String::from("Invalid input, ending your adventure"));
}
}
}
game::BattleOutcome::Loss => {
end_game(String::from("You have won!"));
}
}
}
}
println!("Congratulations! You have completed the adventure!");
}
fn end_game(reason: String) {
println!("Your adventure has ended because:");
panic!("{}", reason);
}
#[cfg(test)]
mod tests {
use crate::weapons;
#[test]
fn overall_test() {
let mut hero = super::Hero::default();
hero.update_weapon(weapons::Weapon::new("Wendigo Claw", 30, |target| {
println!("Wendigo Bleed Applied");
target.take_damage(5)
}));
let hero_party = vec![hero];
super::start_game(hero_party);
assert!(true);
}
}