use bevy::prelude::*;
use crate::core::item::ItemId;
#[derive(Component, Default)]
pub struct Player;
#[derive(Component, Clone, Debug, Reflect)]
pub struct PlayerName(pub String);
impl Default for PlayerName {
fn default() -> Self {
Self("Chara".to_string())
}
}
#[derive(Component, Clone, Debug, Default, Reflect)]
pub struct Level {
pub lv: usize,
pub exp: usize,
pub next_exp: usize,
}
impl Level {
pub fn new(lv: usize, exp: usize, next_exp: usize) -> Self {
Self { lv, exp, next_exp }
}
pub fn can_level_up(&self) -> bool {
self.exp >= self.next_exp
}
}
#[derive(Component, Clone, Debug, Default, Reflect)]
pub struct Health {
pub current: usize,
pub max: usize,
}
impl Health {
pub fn new(current: usize, max: usize) -> Self {
Self { current, max }
}
pub fn is_alive(&self) -> bool {
self.current > 0
}
pub fn percentage(&self) -> f32 {
if self.max == 0 {
0.0
} else {
self.current as f32 / self.max as f32
}
}
pub fn take_damage(&mut self, amount: usize) -> usize {
let actual = amount.min(self.current);
self.current = self.current.saturating_sub(amount);
actual
}
pub fn heal(&mut self, amount: usize) -> usize {
let headroom = self.max.saturating_sub(self.current);
let actual = amount.min(headroom);
self.current += actual;
actual
}
}
#[derive(Component, Clone, Debug, Default, Reflect)]
pub struct Stats {
pub attack: usize,
pub defense: usize,
}
impl Stats {
pub fn new(attack: usize, defense: usize) -> Self {
Self { attack, defense }
}
}
#[derive(Component, Clone, Debug, Default, Reflect)]
pub struct Gold(pub usize);
impl Gold {
pub fn new(amount: usize) -> Self {
Self(amount)
}
pub fn add(&mut self, amount: usize) -> usize {
self.0 = self.0.saturating_add(amount);
self.0
}
pub fn spend(&mut self, amount: usize) -> bool {
if self.0 >= amount {
self.0 -= amount;
true
} else {
false
}
}
}
#[derive(Component, Clone, Debug, Reflect)]
pub struct Equipment {
pub weapon: ItemId,
pub armor: ItemId,
}
impl Default for Equipment {
fn default() -> Self {
Self {
weapon: ItemId("stick".to_string()),
armor: ItemId("bandage".to_string()),
}
}
}
#[derive(Component, Clone, Debug, Reflect)]
pub struct Inventory {
pub items: Vec<ItemId>,
pub capacity: usize,
}
impl Default for Inventory {
fn default() -> Self {
Self {
items: vec![
ItemId("monster_candy".to_string()),
ItemId("monster_candy".to_string()),
ItemId("monster_candy".to_string()),
ItemId("monster_candy".to_string()),
ItemId("monster_candy".to_string()),
ItemId("UNDEFITEM".to_string()),
],
capacity: 8,
}
}
}
impl Inventory {
pub fn has_space(&self) -> bool {
self.items.len() < self.capacity
}
pub fn add_item(&mut self, item: ItemId) -> bool {
if self.has_space() {
self.items.push(item);
true
} else {
false
}
}
pub fn remove_item(&mut self, index: usize) -> Option<ItemId> {
if index < self.items.len() {
Some(self.items.remove(index))
} else {
None
}
}
pub fn count(&self) -> usize {
self.items.len()
}
}
#[derive(Bundle, Default)]
pub struct PlayerBundle {
pub player: Player,
pub name: PlayerName,
pub level: Level,
pub health: Health,
pub stats: Stats,
pub gold: Gold,
pub equipment: Equipment,
pub inventory: Inventory,
}
impl PlayerBundle {
pub fn new() -> Self {
Self {
player: Player,
name: PlayerName::default(),
level: Level::new(1, 0, 10),
health: Health::new(20, 20),
stats: Stats::new(0, 0),
gold: Gold::new(42),
equipment: Equipment::default(),
inventory: Inventory::default(),
}
}
}