334 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			334 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::ship::items::ClientItemId;
 | |
| use libpso::character::character;//::InventoryItem;
 | |
| use crate::entity::item::{ItemEntityId, ItemEntity, ItemDetail, ItemLocation, BankEntity, BankItemEntity, BankName};
 | |
| use crate::entity::character::CharacterEntityId;
 | |
| use crate::entity::item::tool::Tool;
 | |
| use crate::ship::items::inventory::{InventoryItemHandle, InventoryItem};
 | |
| 
 | |
| const BANK_CAPACITY: usize = 200;
 | |
| 
 | |
| #[derive(Debug, Clone)]
 | |
| pub struct IndividualBankItem {
 | |
|     pub entity_id: ItemEntityId,
 | |
|     pub item_id: ClientItemId,
 | |
|     pub item: ItemDetail,
 | |
| }
 | |
| 
 | |
| #[derive(Debug, Clone)]
 | |
| pub struct StackedBankItem {
 | |
|     pub entity_ids: Vec<ItemEntityId>,
 | |
|     pub item_id: ClientItemId,
 | |
|     pub tool: Tool,
 | |
| }
 | |
| 
 | |
| impl StackedBankItem {
 | |
|     pub fn count(&self) -> usize {
 | |
|         self.entity_ids.len()
 | |
|     }
 | |
| 
 | |
|     pub fn take_entity_ids(&mut self, amount: usize) -> Option<Vec<ItemEntityId>> {
 | |
|         if amount <= self.count() {
 | |
|             Some(self.entity_ids.drain(..amount).collect())
 | |
|         }
 | |
|         else {
 | |
|             None
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[derive(Debug, Clone)]
 | |
| pub enum BankItem {
 | |
|     Individual(IndividualBankItem),
 | |
|     Stacked(StackedBankItem),
 | |
| }
 | |
| 
 | |
| 
 | |
| impl std::cmp::PartialEq for BankItem {
 | |
|     fn eq(&self, other: &BankItem) -> bool {
 | |
|         let mut self_bytes = [0u8; 4];
 | |
|         let mut other_bytes = [0u8; 4];
 | |
|         self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]);
 | |
|         other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]);
 | |
| 
 | |
|         let self_value = u32::from_be_bytes(self_bytes);
 | |
|         let other_value = u32::from_be_bytes(other_bytes);
 | |
| 
 | |
|         self_value.eq(&other_value)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl std::cmp::Eq for BankItem {}
 | |
| 
 | |
| impl std::cmp::PartialOrd for BankItem {
 | |
|     fn partial_cmp(&self, other: &BankItem) -> Option<std::cmp::Ordering> {
 | |
|         //let self_bytes = self.as_client_bytes();
 | |
|         //let other_bytes = other.as_client_bytes();
 | |
|         let mut self_bytes = [0u8; 4];
 | |
|         let mut other_bytes = [0u8; 4];
 | |
|         self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]);
 | |
|         other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]);
 | |
| 
 | |
| 
 | |
|         let self_value = u32::from_be_bytes(self_bytes);
 | |
|         let other_value = u32::from_be_bytes(other_bytes);
 | |
| 
 | |
|         self_value.partial_cmp(&other_value)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl std::cmp::Ord for BankItem {
 | |
|     fn cmp(&self, other: &BankItem) -> std::cmp::Ordering {
 | |
|         //let self_bytes = self.as_client_bytes();
 | |
|         //let other_bytes = other.as_client_bytes();
 | |
|         let mut self_bytes = [0u8; 4];
 | |
|         let mut other_bytes = [0u8; 4];
 | |
|         self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]);
 | |
|         other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]);
 | |
| 
 | |
| 
 | |
|         let self_value = u32::from_le_bytes(self_bytes);
 | |
|         let other_value = u32::from_le_bytes(other_bytes);
 | |
| 
 | |
|         self_value.cmp(&other_value)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl BankItem {
 | |
|     pub fn set_item_id(&mut self, item_id: ClientItemId) {
 | |
|         match self {
 | |
|             BankItem::Individual(individual_bank_item) => {
 | |
|                 individual_bank_item.item_id = item_id
 | |
|             },
 | |
|             BankItem::Stacked(stacked_bank_item) => {
 | |
|                 stacked_bank_item.item_id = item_id
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn item_id(&self) -> ClientItemId {
 | |
|         match self {
 | |
|             BankItem::Individual(individual_bank_item) => {
 | |
|                 individual_bank_item.item_id
 | |
|             },
 | |
|             BankItem::Stacked(stacked_bank_item) => {
 | |
|                 stacked_bank_item.item_id
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn as_client_bytes(&self) -> [u8; 16] {
 | |
|         match self {
 | |
|             BankItem::Individual(item) => {
 | |
|                 match &item.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(),
 | |
|                     ItemDetail::ESWeapon(e) => e.as_bytes(),
 | |
|                 }
 | |
|             },
 | |
|             BankItem::Stacked(item) => {
 | |
|                 item.tool.as_stacked_bytes(item.entity_ids.len())
 | |
|             },
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| pub struct BankItemHandle<'a> {
 | |
|     bank: &'a mut CharacterBank,
 | |
|     index: usize
 | |
| }
 | |
| 
 | |
| impl<'a> BankItemHandle<'a> {
 | |
|     pub fn item(&'a self) -> Option<&'a BankItem> {
 | |
|         self.bank.items.get(self.index)
 | |
|     }
 | |
| 
 | |
|     pub fn item_mut(&mut self) -> Option<&mut BankItem> {
 | |
|         self.bank.items.get_mut(self.index)
 | |
|     }
 | |
| 
 | |
|     pub fn remove_from_bank(self) {
 | |
|         self.bank.items.remove(self.index);
 | |
|     }
 | |
| }
 | |
| 
 | |
| pub struct CharacterBank {
 | |
|     item_id_counter: u32,
 | |
|     items: Vec<BankItem>
 | |
| }
 | |
| 
 | |
| impl CharacterBank {
 | |
|     pub fn new(mut items: Vec<BankItem>) -> CharacterBank {
 | |
|         items.sort();
 | |
|         CharacterBank {
 | |
|             item_id_counter: 0,
 | |
|             items: items,
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn initialize_item_ids(&mut self, base_item_id: u32) {
 | |
|         for (i, item) in self.items.iter_mut().enumerate() {
 | |
|             item.set_item_id(ClientItemId(base_item_id + i as u32));
 | |
|         }
 | |
|         self.item_id_counter = base_item_id + self.items.len() as u32 + 1;
 | |
|     }
 | |
| 
 | |
|     pub fn get_item_handle_by_id<'a>(&'a mut self, item_id: ClientItemId) -> Option<BankItemHandle<'a>> {
 | |
|         let (index, _) = self.items.iter()
 | |
|             .enumerate()
 | |
|             .filter(|(_, item)| {
 | |
|                 item.item_id() == item_id
 | |
|             })
 | |
|             .nth(0)?;
 | |
|         Some(BankItemHandle {
 | |
|             bank: self,
 | |
|             index: index,
 | |
|         })
 | |
|     }
 | |
| 
 | |
|     pub fn as_client_bank_items(&self) -> character::Bank {
 | |
|         self.items.iter()
 | |
|             .enumerate()
 | |
|             .fold(character::Bank::default(), |mut bank, (slot, item)| {
 | |
|                 bank.item_count = (slot + 1) as u32;
 | |
|                 let bytes = item.as_client_bytes();
 | |
|                 bank.items[slot].data1.copy_from_slice(&bytes[0..12]);
 | |
|                 bank.items[slot].data2.copy_from_slice(&bytes[12..16]);
 | |
|                 bank.items[slot].item_id = item.item_id().0;
 | |
| 
 | |
|                 bank
 | |
|             })
 | |
|     }
 | |
| 
 | |
|     pub fn as_client_bank_request(&self) -> Vec<character::BankItem> {
 | |
|         self.items.iter()
 | |
|             .map(|item| {
 | |
|                 let bytes = item.as_client_bytes();
 | |
|                 let mut data1 = [0; 12];
 | |
|                 let mut data2 = [0; 4];
 | |
|                 data1.copy_from_slice(&bytes[0..12]);
 | |
|                 data2.copy_from_slice(&bytes[12..16]);
 | |
|                 let amount = match item {
 | |
|                     BankItem::Individual(_individual_bank_item) => {
 | |
|                         1
 | |
|                     },
 | |
|                     BankItem::Stacked(stacked_bank_item) => {
 | |
|                         stacked_bank_item.count()
 | |
|                     },
 | |
|                 };
 | |
|                 character::BankItem {
 | |
|                     data1: data1,
 | |
|                     data2: data2,
 | |
|                     item_id: item.item_id().0,
 | |
|                     amount: amount as u16,
 | |
|                     flags: 1,
 | |
|                 }
 | |
|             })
 | |
|             .collect()
 | |
|     }
 | |
| 
 | |
|     pub fn count(&self) -> usize {
 | |
|         self.items.len()
 | |
|     }
 | |
| 
 | |
|     pub fn deposit_item(&mut self, mut inventory_item: InventoryItemHandle, amount: usize) -> Option<&BankItem> {
 | |
|         let remove = match inventory_item.item_mut()? {
 | |
|             InventoryItem::Individual(individual_inventory_item) => {
 | |
|                 if self.items.len() >= BANK_CAPACITY {
 | |
|                     return None
 | |
|                 }
 | |
|                 self.items.push(BankItem::Individual(IndividualBankItem {
 | |
|                     entity_id: individual_inventory_item.entity_id,
 | |
|                     item_id: individual_inventory_item.item_id,
 | |
|                     item: individual_inventory_item.item.clone(),
 | |
|                 }));
 | |
|                 true
 | |
|             },
 | |
|             InventoryItem::Stacked(stacked_inventory_item) => {
 | |
|                 let existing_bank_item = self.items.iter_mut()
 | |
|                     .find_map(|item| {
 | |
|                         if let BankItem::Stacked(stacked_bank_item) = item {
 | |
|                             if stacked_bank_item.tool == stacked_inventory_item.tool {
 | |
|                                 return Some(stacked_bank_item)
 | |
|                             }
 | |
|                         }
 | |
|                         None
 | |
|                     });
 | |
| 
 | |
|                 match existing_bank_item {
 | |
|                     Some(stacked_bank_item) => {
 | |
|                         if stacked_bank_item.count() + stacked_inventory_item.count() > stacked_inventory_item.tool.max_stack() {
 | |
|                             return None
 | |
|                         }
 | |
| 
 | |
|                         let mut deposited_entity_ids = stacked_inventory_item.take_entity_ids(amount)?;
 | |
|                         stacked_bank_item.entity_ids.append(&mut deposited_entity_ids);
 | |
|                     }
 | |
|                     None => {
 | |
|                         if self.items.len() >= BANK_CAPACITY {
 | |
|                             return None
 | |
|                         }
 | |
|                         let deposited_entity_ids = stacked_inventory_item.take_entity_ids(amount)?;
 | |
| 
 | |
|                         self.item_id_counter += 1;
 | |
|                         self.items.push(BankItem::Stacked(StackedBankItem {
 | |
|                             entity_ids: deposited_entity_ids,
 | |
|                             item_id: ClientItemId(self.item_id_counter),
 | |
|                             tool: stacked_inventory_item.tool,
 | |
|                         }))
 | |
|                     }
 | |
|                 }
 | |
|                 stacked_inventory_item.count() == 0
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         if remove {
 | |
|             inventory_item.remove_from_inventory();
 | |
|         }
 | |
| 
 | |
|         self.items.last()
 | |
|     }
 | |
| 
 | |
|     pub fn as_bank_entity(&self, character_id: &CharacterEntityId, bank_name: &BankName) -> BankEntity {
 | |
|         BankEntity {
 | |
|             items: self.items.iter()
 | |
|                 .map(|item| {
 | |
|                     match item {
 | |
|                         BankItem::Individual(item) => {
 | |
|                             BankItemEntity::Individual(ItemEntity {
 | |
|                                 id: item.entity_id,
 | |
|                                 location: ItemLocation::Bank {
 | |
|                                     character_id: *character_id,
 | |
|                                     name: bank_name.clone(),
 | |
|                                 },
 | |
|                                 item: item.item.clone(),
 | |
|                             })
 | |
|                         },
 | |
|                         BankItem::Stacked(items) => {
 | |
|                             BankItemEntity::Stacked(items.entity_ids.iter()
 | |
|                                                          .map(|id| {
 | |
|                                                              ItemEntity {
 | |
|                                                                  id: *id,
 | |
|                                                                  location: ItemLocation::Bank {
 | |
|                                                                      character_id: *character_id,
 | |
|                                                                      name: bank_name.clone(),
 | |
|                                                                  },
 | |
|                                                                  item: ItemDetail::Tool(items.tool)
 | |
|                                                              }
 | |
|                                                          })
 | |
|                                                          .collect())
 | |
|                         },
 | |
|                     }
 | |
|                 })
 | |
|                 .collect()
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 |