325 lines
11 KiB
Rust
325 lines
11 KiB
Rust
use crate::ship::items::ClientItemId;
|
|
use libpso::character::character;//::InventoryItem;
|
|
use crate::entity::item::{ItemEntityId, ItemEntity, ItemDetail, 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,
|
|
}
|
|
}
|
|
|
|
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(&mut self, item_id: ClientItemId) -> Option<BankItemHandle> {
|
|
let (index, _) = self.items.iter()
|
|
.enumerate()
|
|
.find(|(_, item)| {
|
|
item.item_id() == item_id
|
|
})?;
|
|
Some(BankItemHandle {
|
|
bank: self,
|
|
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,
|
|
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,
|
|
item: item.item.clone(),
|
|
})
|
|
},
|
|
BankItem::Stacked(items) => {
|
|
BankItemEntity::Stacked(items.entity_ids.iter()
|
|
.map(|id| {
|
|
ItemEntity {
|
|
id: *id,
|
|
item: ItemDetail::Tool(items.tool)
|
|
}
|
|
})
|
|
.collect())
|
|
},
|
|
}
|
|
})
|
|
.collect()
|
|
}
|
|
}
|
|
}
|
|
|
|
|