use std::collections::HashMap; use libpso::character::character::InventoryItem; use crate::entity::gateway::EntityGateway; use crate::entity::character::CharacterEntity; use crate::entity::item::{Item, ItemId, ItemDetail, ItemLocation}; use crate::entity::item::weapon::Weapon; use crate::entity::item::armor::Armor; use crate::entity::item::shield::Shield; use crate::entity::item::unit::Unit; use crate::entity::item::tool::Tool; use crate::entity::item::mag::Mag; #[derive(Debug, PartialEq)] pub enum StackedItem { Individual(Item), Stacked(Vec), } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ActiveItemId(u32); #[derive(Debug)] pub struct ActiveItem { id: ActiveItemId, item: StackedItem, } impl ActiveItem { pub fn as_client_bytes(&self) -> [u8; 16] { match &self.item { StackedItem::Individual(i) => { match &i.item { ItemDetail::Weapon(w) => w.as_bytes(), ItemDetail::Armor(a) => a.as_bytes(), ItemDetail::Shield(s) => s.as_bytes(), ItemDetail::Unit(u) => u.as_bytes(), ItemDetail::Tool(t) => t.as_individual_bytes(), ItemDetail::TechniqueDisk(d) => d.as_bytes(), ItemDetail::Mag(m) => m.as_bytes(), } }, StackedItem::Stacked(i) => { let len = i.len(); match &i[0].item { ItemDetail::Tool(t) => t.as_stacked_bytes(len), _ => panic!(), } } } } } pub struct ActiveInventory(Vec); impl ActiveInventory { pub fn as_client_inventory_items(&self) -> [InventoryItem; 30] { self.0.iter() .enumerate() .fold([InventoryItem::default(); 30], |mut inventory, (index, item)| { let bytes = item.as_client_bytes(); inventory[index].data1.copy_from_slice(&bytes[0..12]); inventory[index].data2.copy_from_slice(&bytes[12..16]); inventory[index].item_id = item.id.0; // does this do anything? inventory[index].equipped = match item.item { StackedItem::Individual(Item {location: ItemLocation::Inventory{ equipped: true, ..}, ..}) => 1, _ => 0, }; // because this actually equips the item inventory[index].flags |= match item.item { StackedItem::Individual(Item {location: ItemLocation::Inventory{ equipped: true, ..}, ..}) => 8, _ => 0, }; inventory }) } pub fn count(&self) -> usize { self.0.len() } } fn inventory_item_index(item: &StackedItem) -> usize { match item { StackedItem::Individual(i) => { match i.location { ItemLocation::Inventory{index: index, ..} => index, _ => panic!() } }, StackedItem::Stacked(i) => { match i[0].location { ItemLocation::Inventory{index: index, ..} => index, _ => panic!() } } } } fn stack_items(items: Vec) -> Vec { let mut stacks = HashMap::new(); for item in items { stacks.entry(item.item.item_type()).or_insert(Vec::new()).push(item); } stacks.into_iter() .map(|(itype, items)| { match items[0].item.is_stackable() { true => { vec![StackedItem::Stacked(items)] }, false => { items.into_iter().map(|i| { StackedItem::Individual(i) }).collect() } } }) .flatten() .collect() } struct ActiveBank([Option; 200]); pub struct ActiveItemDatabase { id: u32, } impl ActiveItemDatabase { pub fn new() -> ActiveItemDatabase { ActiveItemDatabase { id: 0, } } fn activate_item(&mut self, item: StackedItem) -> ActiveItem { self.id += 1; ActiveItem { id: ActiveItemId(self.id), item: item, } } // deactivate item pub fn get_character_inventory(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> ActiveInventory { let items = entity_gateway.get_items_by_character(&character); let inventory_items = items.into_iter() .filter(|item| { match item.location { ItemLocation::Inventory{..} => true, _ => false, } }).collect(); let mut stacked = stack_items(inventory_items); stacked.sort_by(|a, b| { inventory_item_index(a).partial_cmp(&inventory_item_index(b)).unwrap() }); let activated = stacked.into_iter().map(|i| self.activate_item(i)); ActiveInventory(activated.take(30).collect()) } } #[cfg(test)] mod test { use super::*; use crate::entity::item; use crate::entity::item::{Item, ItemDetail, ItemEntityId, ItemLocation}; #[test] fn test_stack_items() { let item1 = Item { id: ItemEntityId(1), location: ItemLocation::Inventory { character_id: 0, index: 0, equipped: false, }, item: ItemDetail::Weapon(item::weapon::Weapon { weapon: item::weapon::WeaponType::Saber, grind: 0, special: None, attrs: [None; 3], tekked: true, }) }; let item2 = Item { id: ItemEntityId(2), location: ItemLocation::Inventory { character_id: 0, index: 1, equipped: false, }, item: ItemDetail::Tool(Tool { tool: item::tool::ToolType::Monofluid, }) }; let item3 = Item { id: ItemEntityId(3), location: ItemLocation::Inventory { character_id: 0, index: 2, equipped: false, }, item: ItemDetail::Weapon(item::weapon::Weapon { weapon: item::weapon::WeaponType::Handgun, grind: 12, special: None, attrs: [None; 3], tekked: true, }) }; let item4 = Item { id: ItemEntityId(4), location: ItemLocation::Inventory { character_id: 0, index: 1, equipped: false, }, item: ItemDetail::Tool(Tool { tool: item::tool::ToolType::Monofluid, }) }; let item5 = Item { id: ItemEntityId(5), location: ItemLocation::Inventory { character_id: 0, index: 1, equipped: false, }, item: ItemDetail::Tool(Tool { tool: item::tool::ToolType::Monofluid, }) }; let item6 = Item { id: ItemEntityId(6), location: ItemLocation::Inventory { character_id: 0, index: 3, equipped: false, }, item: ItemDetail::Weapon(item::weapon::Weapon { weapon: item::weapon::WeaponType::Handgun, grind: 12, special: None, attrs: [None; 3], tekked: true, }) }; let item7 = Item { id: ItemEntityId(7), location: ItemLocation::Inventory { character_id: 0, index: 4, equipped: false, }, item: ItemDetail::Tool(Tool { tool: item::tool::ToolType::Monomate, }) }; let item8 = Item { id: ItemEntityId(8), location: ItemLocation::Inventory { character_id: 0, index: 4, equipped: false, }, item: ItemDetail::Tool(Tool { tool: item::tool::ToolType::Monomate, }) }; let item9 = Item { id: ItemEntityId(9), location: ItemLocation::Inventory { character_id: 0, index: 4, equipped: false, }, item: ItemDetail::Tool(Tool { tool: item::tool::ToolType::Monomate, }) }; let item_vec = vec![item1.clone(), item2.clone(), item3.clone(), item4.clone(), item5.clone(), item6.clone(), item7.clone(), item8.clone(), item9.clone()]; let stacked = stack_items(item_vec); assert!(stacked.len() == 5); assert!(stacked.iter().filter(|k| { **k == StackedItem::Individual(item6.clone()) }).count() == 1); assert!(stacked.iter().filter(|k| { **k == StackedItem::Individual(item3.clone()) }).count() == 1); assert!(stacked.iter().filter(|k| { **k == StackedItem::Individual(item1.clone()) }).count() == 1); assert!(stacked.iter().filter(|k| { **k == StackedItem::Stacked(vec![item2.clone(), item4.clone(), item5.clone()]) }).count() == 1); assert!(stacked.iter().filter(|k| { **k == StackedItem::Stacked(vec![item7.clone(), item8.clone(), item9.clone()]) }).count() == 1); } }