mirror of
https://github.com/guezoloic/BakersAdventure.git
synced 2026-01-25 10:34:07 +00:00
feat: assemble weapon and potions into item file
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
use crate::weapon::Weapon;
|
||||
use std::f64::consts::E;
|
||||
|
||||
use crate::items::Item;
|
||||
|
||||
/// # Character
|
||||
///
|
||||
@@ -24,67 +26,72 @@ use crate::weapon::Weapon;
|
||||
/// for method chaining.
|
||||
/// - `get_name` is only an accessor of `name`
|
||||
pub struct Character {
|
||||
life: u8,
|
||||
pub life: u8,
|
||||
name: &'static str,
|
||||
weapon: Option<Box<Weapon>>,
|
||||
item: Option<Box<dyn Item>>,
|
||||
}
|
||||
|
||||
impl Character {
|
||||
/// Creates a new `Character` with the given attributes.
|
||||
/// Acts as a "static constructor" returning the
|
||||
/// initialized struct.
|
||||
pub fn new(life: u8, name: &'static str, weapon: Option<Box<Weapon>>) -> Self {
|
||||
Character { life, name, weapon }
|
||||
pub fn new(name: &'static str, life: u8, item: Option<Box<dyn Item>>) -> Self {
|
||||
Character { life, name, item }
|
||||
}
|
||||
|
||||
pub fn new_no_weapon(life: u8, name: &'static str) -> Self {
|
||||
pub fn new_no_weapon(name: &'static str, life: u8) -> Self {
|
||||
Character {
|
||||
life,
|
||||
name,
|
||||
weapon: None,
|
||||
item: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attacks another character, reducing their `life` by
|
||||
/// self.damage. Returns `self` to allow method chaining.
|
||||
pub fn attack(&mut self, other: &mut Self) -> &mut Self {
|
||||
if let Some(w) = &mut self.weapon {
|
||||
other.life = w
|
||||
.if_not_broken(|damage: u8| other.life - damage)
|
||||
.unwrap_or(0);
|
||||
w.consume();
|
||||
pub fn use_item(&mut self, other: Option<&mut Character>) -> () {
|
||||
let mut item: Option<Box<dyn Item>> = self.item.take(); // pop item and replace to None
|
||||
if let Some(i) = &mut item {
|
||||
i.apply(other.unwrap_or(self));
|
||||
}
|
||||
self
|
||||
self.item = item;
|
||||
}
|
||||
|
||||
/// Returns the character's name.
|
||||
pub fn get_name(&self) -> &str {
|
||||
self.name
|
||||
}
|
||||
|
||||
pub fn set_item(&mut self, item: Option<Box<dyn Item>>) -> &mut Self {
|
||||
self.item = item;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::items::{Potion, Weapon};
|
||||
|
||||
#[test]
|
||||
/// Tests that a character is correctly initialized.
|
||||
fn character_build() {
|
||||
let c = Character::new_no_weapon(100, "test");
|
||||
let c = Character::new_no_weapon("test", 100);
|
||||
assert_eq!(c.life, 100);
|
||||
assert_eq!(c.name, c.get_name());
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests that attacking reduces the target's life correctly.
|
||||
fn character_attack() {
|
||||
let w = Box::new(Weapon::new("test", 10, 100));
|
||||
let mut c1 = Character::new(100, "test1", Option::Some(w));
|
||||
let mut c2 = Character::new_no_weapon(200, "test2");
|
||||
fn character_item() {
|
||||
let w = Box::new(Weapon::new("testw", 10, 100));
|
||||
let p = Box::new(Potion::new("testp", 50));
|
||||
|
||||
c1.attack(&mut c2);
|
||||
assert_eq!(c2.life, 190);
|
||||
Character::attack(&mut c2, &mut c1);
|
||||
assert_eq!(c1.life, 100);
|
||||
let mut c: Character = Character::new_no_weapon("testc", 100);
|
||||
c.set_item(Some(p)).use_item(None);
|
||||
|
||||
assert_eq!(c.life, 150);
|
||||
|
||||
c.set_item(Some(w)).use_item(None);
|
||||
|
||||
assert_eq!(c.life, 140);
|
||||
}
|
||||
}
|
||||
|
||||
80
src/items.rs
Normal file
80
src/items.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use crate::character::Character;
|
||||
|
||||
pub trait Item {
|
||||
fn apply(&mut self, char: &mut Character) -> ();
|
||||
fn get_name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
pub struct Weapon {
|
||||
name: &'static str,
|
||||
damage: u8,
|
||||
durability: u8,
|
||||
}
|
||||
|
||||
// #[warn(dead_code)]
|
||||
impl Weapon {
|
||||
pub fn new(name: &'static str, damage: u8, durability: u8) -> Self {
|
||||
Weapon {
|
||||
name,
|
||||
damage,
|
||||
durability,
|
||||
}
|
||||
}
|
||||
|
||||
fn reduce_durability(&mut self) -> () {
|
||||
self.durability = self.durability.saturating_sub(self.damage / 2);
|
||||
}
|
||||
|
||||
pub fn is_broken(&self) -> bool {
|
||||
self.durability == 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Item for Weapon {
|
||||
fn apply(&mut self, char: &mut Character) -> () {
|
||||
if !self.is_broken() {
|
||||
char.life = char.life.saturating_sub(self.damage);
|
||||
self.reduce_durability();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_name(&self) -> &'static str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Potion {
|
||||
name: &'static str,
|
||||
heal: u8,
|
||||
}
|
||||
|
||||
impl Potion {
|
||||
pub fn new(name: &'static str, heal: u8) -> Self {
|
||||
Potion { name, heal }
|
||||
}
|
||||
}
|
||||
|
||||
impl Item for Potion {
|
||||
fn apply(&mut self, char: &mut Character) -> () {
|
||||
char.life += self.heal;
|
||||
}
|
||||
|
||||
fn get_name(&self) -> &'static str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
mod weapon {
|
||||
use super::super::*;
|
||||
|
||||
#[test]
|
||||
fn build() {
|
||||
let w = Weapon::new("test", 10, 100);
|
||||
assert_eq!(w.damage, 10);
|
||||
assert_eq!(w.durability, 100);
|
||||
assert_eq!(w.get_name(), w.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
pub mod character;
|
||||
pub mod weapon;
|
||||
pub mod items;
|
||||
@@ -1 +1,6 @@
|
||||
fn main() {}
|
||||
use bakersadventure::items::{Item, Weapon};
|
||||
|
||||
fn main() {
|
||||
let mut list: [Box<dyn Item>; 1] = [Box::new(Weapon::new("name", 1, 1))];
|
||||
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
pub struct Weapon {
|
||||
name: &'static str,
|
||||
damage: u8,
|
||||
durability: u8,
|
||||
}
|
||||
|
||||
impl Weapon {
|
||||
pub fn new(name: &'static str, damage: u8, durability: u8) -> Self {
|
||||
Weapon {
|
||||
name,
|
||||
damage,
|
||||
durability,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume(&mut self) -> &mut Self {
|
||||
self.durability -= (self.damage / 2) as u8;
|
||||
self
|
||||
}
|
||||
|
||||
fn is_broken(&self) -> bool {
|
||||
self.durability <= 0
|
||||
}
|
||||
|
||||
pub fn if_not_broken<F, T>(&mut self, fun: F) -> Option<T>
|
||||
where
|
||||
F: FnOnce(u8) -> T,
|
||||
{
|
||||
if !self.is_broken() {
|
||||
Some(fun(self.damage))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> &'static str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn weapon_build() {
|
||||
let w = Weapon::new("test", 10, 100);
|
||||
assert_eq!(w.damage, 10);
|
||||
assert_eq!(w.durability, 100);
|
||||
assert_eq!(w.get_name(), w.name);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weapon_consumption() {
|
||||
let mut w = Weapon::new("test", 10, 100);
|
||||
w.consume();
|
||||
assert_eq!(w.durability, 95);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weapon_if_not_broken() {
|
||||
let mut w = Weapon::new("test", 10, 100);
|
||||
let val: u8 = 50;
|
||||
assert_eq!(w.if_not_broken(|d: u8| { val - d }).unwrap(), 40);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user