kingslayer 0.5.5

A text adventure dungeon crawler game written in Rust
Documentation
use serde::{Deserialize, Serialize};

use super::{Entity, Item};
use crate::{
    dice_roll,
    types::{Action, CmdResult, EnemyStatus, Items},
};

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Enemy {
    name: String,
    desc: String,
    inspect: String,
    hp: i32,
    ac: i32,
    xp: u32,
    damage: u32,
    status: EnemyStatus,
    #[serde(default)]
    loot: Items,
}

impl Enemy {
    pub fn new(name: &str, inspect: &str, status: EnemyStatus) -> Self {
        Self {
            name: name.to_owned(),
            desc: format!("There is a {} here.", name),
            inspect: inspect.to_owned(),
            hp: 1,
            ac: 0,
            xp: 0,
            damage: 1,
            status,
            loot: Items::new(),
        }
    }
    pub fn new_rats(status: EnemyStatus) -> Self {
        Self {
            name: String::from("swarm of rats"),
            desc: String::from("A swarm of rats raves along the floor."),
            inspect: String::from("The creatures chatter and scrape viciously."),
            hp: 24,
            ac: 0,
            xp: 25,
            damage: 2,
            status,
            loot: Items::new(),
        }
    }

    pub fn new_pirate(status: EnemyStatus) -> Self {
        Self {
            name: String::from("pirate"),
            desc: String::from("There is a pirate here."),
            inspect: String::from("The pirate is armed and smells vile."),
            hp: dice_roll(2, 7) as i32 + 2,
            ac: 10,
            xp: 50,
            damage: 6,
            status,
            loot: Items::new(),
        }
    }

    pub fn with_desc(mut self, desc: &str) -> Self {
        self.desc = String::from(desc);
        self
    }
    pub fn with_inspect(mut self, inspect: &str) -> Self {
        self.inspect = String::from(inspect);
        self
    }
    pub fn with_hp(mut self, hp: i32) -> Self {
        self.hp = hp;
        self
    }
    pub fn with_ac(mut self, ac: i32) -> Self {
        self.ac = ac;
        self
    }
    pub fn with_xp(mut self, xp: u32) -> Self {
        self.xp = xp;
        self
    }
    pub fn with_damage(mut self, damage: u32) -> Self {
        self.damage = damage;
        self
    }
    pub fn with_item(mut self, item: Item) -> Self {
        self.loot.push(Box::new(item));
        self
    }

    pub fn long_desc(&self) -> String {
        match self.status {
            EnemyStatus::Asleep => format!("{} It is asleep.", self.desc),
            _ => self.desc.to_owned(),
        }
    }

    pub const fn xp(&self) -> u32 {
        self.xp
    }

    pub fn damage(&self) -> u32 {
        dice_roll(1, self.damage)
    }

    pub fn is_angry(&self) -> bool {
        self.status == EnemyStatus::Angry
    }

    pub const fn status(&self) -> EnemyStatus {
        self.status
    }

    pub fn make_angry(&mut self) {
        self.status = EnemyStatus::Angry;
    }

    pub const fn loot(&self) -> &Items {
        &self.loot
    }

    pub fn take_damage(&mut self, damage: u32) -> Option<CmdResult> {
        self.make_angry();

        if dice_roll(1, 20) as i32 >= self.ac {
            self.hp -= damage as i32;
            None
        } else {
            match dice_roll(1, 3) {
                0 => Some(CmdResult::new(
                    Action::Active,
                    format!(
                        "\nYou swung at the {}, but it dodged out of the way.",
                        self.name
                    ),
                )),
                1 => Some(CmdResult::new(
                    Action::Active,
                    format!(
                        "\nYou hit the {}, but its armor absorbed the blow.",
                        self.name
                    ),
                )),
                _ => Some(CmdResult::new(
                    Action::Active,
                    format!("\nThe {} deftly blocked your attack.", self.name),
                )),
            }
        }
    }

    pub const fn is_alive(&self) -> bool {
        self.hp > 0
    }

    pub fn drop_loot(&mut self) -> Items {
        self.loot.drain(0..).collect()
    }
}

impl Entity for Enemy {
    fn name(&self) -> &str {
        &self.name
    }

    fn desc(&self) -> &str {
        &self.desc
    }

    fn inspect(&self) -> &str {
        &self.inspect
    }
}