use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Inventory {
pub slots: Vec<Option<ItemStack>>,
pub max_slots: usize,
pub gold: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ItemStack {
pub item: Item,
pub quantity: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Item {
pub id: String,
pub name: String,
pub description: String,
pub item_type: ItemType,
pub rarity: ItemRarity,
pub value: u32,
pub max_stack: u32,
pub icon_path: Option<String>,
pub stats: HashMap<String, i32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ItemType {
Weapon,
Armor,
Consumable,
Quest,
Material,
Misc,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ItemRarity {
Common,
Uncommon,
Rare,
Epic,
Legendary,
}
impl Inventory {
pub fn new(max_slots: usize) -> Self {
Self {
slots: vec![None; max_slots],
max_slots,
gold: 0,
}
}
pub fn add_item(&mut self, item: Item, quantity: u32) -> bool {
if item.max_stack > 1 {
for slot in &mut self.slots {
if let Some(stack) = slot {
if stack.item.id == item.id && stack.quantity < item.max_stack {
let space = item.max_stack - stack.quantity;
let to_add = quantity.min(space);
stack.quantity += to_add;
if to_add == quantity {
return true;
}
}
}
}
}
for slot in &mut self.slots {
if slot.is_none() {
*slot = Some(ItemStack { item, quantity });
return true;
}
}
false }
pub fn remove_item(&mut self, item_id: &str, quantity: u32) -> bool {
let mut remaining = quantity;
for slot in &mut self.slots {
if let Some(stack) = slot {
if stack.item.id == item_id {
if stack.quantity >= remaining {
stack.quantity -= remaining;
if stack.quantity == 0 {
*slot = None;
}
return true;
} else {
remaining -= stack.quantity;
*slot = None;
}
}
}
}
remaining == 0
}
pub fn has_item(&self, item_id: &str, quantity: u32) -> bool {
let mut count = 0;
for slot in &self.slots {
if let Some(stack) = slot {
if stack.item.id == item_id {
count += stack.quantity;
}
}
}
count >= quantity
}
pub fn get_item_count(&self, item_id: &str) -> u32 {
let mut count = 0;
for slot in &self.slots {
if let Some(stack) = slot {
if stack.item.id == item_id {
count += stack.quantity;
}
}
}
count
}
pub fn swap_slots(&mut self, from: usize, to: usize) -> bool {
if from >= self.max_slots || to >= self.max_slots {
return false;
}
self.slots.swap(from, to);
true
}
pub fn add_gold(&mut self, amount: u32) {
self.gold += amount;
}
pub fn remove_gold(&mut self, amount: u32) -> bool {
if self.gold >= amount {
self.gold -= amount;
true
} else {
false
}
}
pub fn is_full(&self) -> bool {
self.slots.iter().all(|slot| slot.is_some())
}
pub fn empty_slots(&self) -> usize {
self.slots.iter().filter(|slot| slot.is_none()).count()
}
}
impl Item {
pub fn new(id: &str, name: &str) -> Self {
Self {
id: id.to_string(),
name: name.to_string(),
description: String::new(),
item_type: ItemType::Misc,
rarity: ItemRarity::Common,
value: 0,
max_stack: 1,
icon_path: None,
stats: HashMap::new(),
}
}
pub fn weapon(id: &str, name: &str, damage: i32) -> Self {
let mut item = Self::new(id, name);
item.item_type = ItemType::Weapon;
item.stats.insert("damage".to_string(), damage);
item
}
pub fn armor(id: &str, name: &str, defense: i32) -> Self {
let mut item = Self::new(id, name);
item.item_type = ItemType::Armor;
item.stats.insert("defense".to_string(), defense);
item
}
pub fn consumable(id: &str, name: &str, heal: i32) -> Self {
let mut item = Self::new(id, name);
item.item_type = ItemType::Consumable;
item.max_stack = 99;
item.stats.insert("heal".to_string(), heal);
item
}
pub fn get_rarity_color(&self) -> [u8; 4] {
match self.rarity {
ItemRarity::Common => [200, 200, 200, 255],
ItemRarity::Uncommon => [100, 255, 100, 255],
ItemRarity::Rare => [100, 100, 255, 255],
ItemRarity::Epic => [200, 100, 255, 255],
ItemRarity::Legendary => [255, 200, 0, 255],
}
}
}