Compare commits
5 Commits
f5968582b1
...
df135e1c3c
Author | SHA1 | Date | |
---|---|---|---|
df135e1c3c | |||
24639496da | |||
414b3d2ce5 | |||
0fa3f4ea19 | |||
60802d3377 |
@ -2,7 +2,8 @@ use libpso::character::character;
|
||||
use crate::common::leveltable::CharacterStats;
|
||||
use crate::entity::character::CharacterEntity;
|
||||
//use crate::ship::items::{CharacterInventory, CharacterBank};
|
||||
use crate::ship::items::state::{InventoryState, BankState};
|
||||
use crate::ship::items::bank::BankState;
|
||||
use crate::ship::items::inventory::InventoryState;
|
||||
use crate::entity::item::Meseta;
|
||||
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
// TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency
|
||||
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::{Meseta, ItemNote};
|
||||
use std::future::Future;
|
||||
@ -7,16 +6,16 @@ use std::pin::Pin;
|
||||
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
||||
use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateAction, ItemAction, ItemStateError, FloorItem, InventoryItem, AddItemResult, FloorItemDetail,
|
||||
StackedItemDetail, BankItem, BankItemDetail, InventoryItemDetail, IndividualItemDetail};
|
||||
use crate::entity::gateway::EntityGatewayTransaction;
|
||||
use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail};
|
||||
use crate::ship::items::bank::{BankItem, BankItemDetail};
|
||||
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||
use crate::ship::items::floor::{FloorItem, FloorItemDetail};
|
||||
use crate::ship::items::apply_item::apply_item;
|
||||
use crate::entity::item::{ItemDetail, NewItemEntity, TradeId};
|
||||
use crate::entity::item::tool::Tool;
|
||||
use crate::entity::item::ItemModifier;
|
||||
use crate::ship::shops::ShopItem;
|
||||
use crate::ship::trade::TradeItem;
|
||||
use crate::ship::location::AreaClient;
|
||||
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||
|
||||
pub enum TriggerCreateItem {
|
||||
@ -24,7 +23,7 @@ pub enum TriggerCreateItem {
|
||||
No
|
||||
}
|
||||
|
||||
fn take_item_from_floor(character_id: CharacterEntityId, item_id: ClientItemId)
|
||||
pub(super) fn take_item_from_floor(character_id: CharacterEntityId, item_id: ClientItemId)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -39,7 +38,7 @@ fn take_item_from_floor(character_id: CharacterEntityId, item_id: ClientItemId)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_floor_item_to_inventory(character: &CharacterEntity)
|
||||
pub(super) fn add_floor_item_to_inventory(character: &CharacterEntity)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), TriggerCreateItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -81,28 +80,8 @@ fn add_floor_item_to_inventory(character: &CharacterEntity)
|
||||
}
|
||||
|
||||
|
||||
pub async fn pick_up_item<EG>(
|
||||
item_state: &mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId)
|
||||
-> Result<TriggerCreateItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_item_from_floor(character.id, *item_id))
|
||||
.act(add_floor_item_to_inventory(character))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
fn take_item_from_inventory(character_id: CharacterEntityId, item_id: ClientItemId, amount: u32)
|
||||
pub(super) fn take_item_from_inventory(character_id: CharacterEntityId, item_id: ClientItemId, amount: u32)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -120,7 +99,7 @@ fn take_item_from_inventory(character_id: CharacterEntityId, item_id: ClientItem
|
||||
}
|
||||
|
||||
|
||||
fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId, map_area: MapArea, drop_position: (f32, f32, f32))
|
||||
pub(super) fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId, map_area: MapArea, drop_position: (f32, f32, f32))
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -147,55 +126,8 @@ fn add_inventory_item_to_shared_floor(character_id: CharacterEntityId, map_area:
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn drop_item<EG>(
|
||||
item_state: &mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
map_area: MapArea,
|
||||
drop_position: (f32, f32, f32))
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_item_from_inventory(character.id, *item_id, 0))
|
||||
.act(add_inventory_item_to_shared_floor(character.id, map_area, drop_position))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
pub async fn drop_partial_item<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
map_area: MapArea,
|
||||
drop_position: (f32, f32),
|
||||
amount: u32)
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_item_from_inventory(character.id, *item_id, amount))
|
||||
.act(add_inventory_item_to_shared_floor(character.id, map_area, (drop_position.0, 0.0, drop_position.1)))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
fn take_meseta_from_inventory(character_id: CharacterEntityId, amount: u32)
|
||||
pub(super) fn take_meseta_from_inventory(character_id: CharacterEntityId, amount: u32)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -211,7 +143,7 @@ fn take_meseta_from_inventory(character_id: CharacterEntityId, amount: u32)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_meseta_to_inventory(character_id: CharacterEntityId, amount: u32)
|
||||
pub(super) fn add_meseta_to_inventory(character_id: CharacterEntityId, amount: u32)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -227,7 +159,7 @@ fn add_meseta_to_inventory(character_id: CharacterEntityId, amount: u32)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_meseta_to_shared_floor(character_id: CharacterEntityId, amount: u32, map_area: MapArea, drop_position: (f32, f32))
|
||||
pub(super) fn add_meseta_to_shared_floor(character_id: CharacterEntityId, amount: u32, map_area: MapArea, drop_position: (f32, f32))
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -252,31 +184,7 @@ fn add_meseta_to_shared_floor(character_id: CharacterEntityId, amount: u32, map_
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn drop_meseta<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
map_area: MapArea,
|
||||
drop_position: (f32, f32),
|
||||
amount: u32)
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_meseta_from_inventory(character.id, amount))
|
||||
.act(add_meseta_to_shared_floor(character.id, amount, map_area, drop_position))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
fn take_meseta_from_bank(character_id: CharacterEntityId, amount: u32)
|
||||
pub(super) fn take_meseta_from_bank(character_id: CharacterEntityId, amount: u32)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -291,7 +199,7 @@ fn take_meseta_from_bank(character_id: CharacterEntityId, amount: u32)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_meseta_from_bank_to_inventory(character_id: CharacterEntityId, amount: u32)
|
||||
pub(super) fn add_meseta_from_bank_to_inventory(character_id: CharacterEntityId, amount: u32)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -307,28 +215,7 @@ fn add_meseta_from_bank_to_inventory(character_id: CharacterEntityId, amount: u3
|
||||
}
|
||||
|
||||
|
||||
pub async fn withdraw_meseta<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
amount: u32)
|
||||
-> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_meseta_from_bank(character.id, amount))
|
||||
.act(add_meseta_from_bank_to_inventory(character.id, amount))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
fn add_meseta_to_bank(character_id: CharacterEntityId, amount: u32)
|
||||
pub(super) fn add_meseta_to_bank(character_id: CharacterEntityId, amount: u32)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -343,28 +230,8 @@ fn add_meseta_to_bank(character_id: CharacterEntityId, amount: u32)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn deposit_meseta<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
amount: u32)
|
||||
-> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||
.act(take_meseta_from_inventory(character.id, amount))
|
||||
.act(add_meseta_to_bank(character.id, amount))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, ()))
|
||||
}).await
|
||||
}
|
||||
|
||||
fn take_item_from_bank(character_id: CharacterEntityId, item_id: ClientItemId, amount: u32)
|
||||
pub(super) fn take_item_from_bank(character_id: CharacterEntityId, item_id: ClientItemId, amount: u32)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), BankItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -380,7 +247,7 @@ fn take_item_from_bank(character_id: CharacterEntityId, item_id: ClientItemId, a
|
||||
}
|
||||
}
|
||||
|
||||
fn add_bank_item_to_inventory(character: &CharacterEntity)
|
||||
pub(super) fn add_bank_item_to_inventory(character: &CharacterEntity)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), BankItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -426,31 +293,8 @@ fn add_bank_item_to_inventory(character: &CharacterEntity)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn withdraw_item<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
amount: u32)
|
||||
-> Result<InventoryItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_item_from_bank(character.id, *item_id, amount))
|
||||
//.act(bank_item_to_inventory_item)
|
||||
//.act(add_item_to_inventory)
|
||||
.act(add_bank_item_to_inventory(character))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
fn add_inventory_item_to_bank(character_id: CharacterEntityId)
|
||||
pub(super) fn add_inventory_item_to_bank(character_id: CharacterEntityId)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -479,29 +323,8 @@ fn add_inventory_item_to_bank(character_id: CharacterEntityId)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn deposit_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
amount: u32)
|
||||
-> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_item_from_inventory(character.id, *item_id, amount))
|
||||
.act(add_inventory_item_to_bank(character.id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
fn equip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId, equip_slot: u8)
|
||||
pub(super) fn equip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId, equip_slot: u8)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -517,29 +340,8 @@ fn equip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn equip_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
equip_slot: u8,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(equip_inventory_item(character.id, *item_id, equip_slot))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
fn unequip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId)
|
||||
pub(super) fn unequip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -555,28 +357,9 @@ fn unequip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn unequip_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(unequip_inventory_item(character.id, *item_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
fn sort_inventory_items(character_id: CharacterEntityId, item_ids: Vec<ClientItemId>)
|
||||
pub(super) fn sort_inventory_items(character_id: CharacterEntityId, item_ids: Vec<ClientItemId>)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ()), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -593,28 +376,8 @@ fn sort_inventory_items(character_id: CharacterEntityId, item_ids: Vec<ClientIte
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn sort_inventory<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_ids: Vec<ClientItemId>,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(sort_inventory_items(character.id, item_ids))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
fn use_consumed_item(character: CharacterEntity)
|
||||
pub(super) fn use_consumed_item(character: CharacterEntity)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), CharacterEntity), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -634,30 +397,8 @@ fn use_consumed_item(character: CharacterEntity)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn use_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &mut CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
amount: u32,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), new_character) = ItemStateAction::default()
|
||||
.act(take_item_from_inventory(character.id, *item_id, amount))
|
||||
.act(use_consumed_item(character.clone()))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
*character = new_character;
|
||||
Ok((transaction, ()))
|
||||
}).await
|
||||
}
|
||||
|
||||
fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemId)
|
||||
pub(super) fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemId)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), CharacterEntity), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -704,30 +445,7 @@ fn feed_mag_item(character: CharacterEntity, mag_item_id: ClientItemId)
|
||||
}
|
||||
|
||||
|
||||
pub async fn feed_mag<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
mag_item_id: &ClientItemId,
|
||||
tool_item_id: &ClientItemId,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||
.act(take_item_from_inventory(character.id, *tool_item_id, 1))
|
||||
.act(feed_mag_item(character.clone(), *mag_item_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, ()))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
fn add_bought_item_to_inventory<'a>(character_id: CharacterEntityId,
|
||||
pub(super) fn add_bought_item_to_inventory<'a>(character_id: CharacterEntityId,
|
||||
shop_item: &'a (dyn ShopItem + Send + Sync),
|
||||
item_id: ClientItemId,
|
||||
amount: u32)
|
||||
@ -787,34 +505,8 @@ fn add_bought_item_to_inventory<'a>(character_id: CharacterEntityId,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn buy_shop_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
shop_item: &'a (dyn ShopItem + Send + Sync),
|
||||
item_id: ClientItemId,
|
||||
amount: u32,
|
||||
) -> Result<InventoryItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
let item_price = shop_item.price() as u32 * amount;
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_meseta_from_inventory(character.id, item_price))
|
||||
//.act(bought_item_to_inventory_item)
|
||||
//.act(add_item_to_inventory)
|
||||
.act(add_bought_item_to_inventory(character.id, shop_item, item_id, amount))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
fn sell_inventory_item<'a>(character_id: CharacterEntityId)
|
||||
pub(super) fn sell_inventory_item<'a>(character_id: CharacterEntityId)
|
||||
-> impl Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -836,27 +528,6 @@ fn sell_inventory_item<'a>(character_id: CharacterEntityId)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn sell_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: ClientItemId,
|
||||
amount: u32,
|
||||
) -> Result<InventoryItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(take_item_from_inventory(character.id, item_id, amount))
|
||||
.act(sell_inventory_item(character.id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
#[async_recursion::async_recursion]
|
||||
async fn iterate_inner<'a, I, O, T, F, FR>(state: (ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>),
|
||||
@ -887,7 +558,7 @@ where
|
||||
Ok((state, output))
|
||||
}
|
||||
|
||||
pub fn iterate<'k, I, O, T, F, FR>(
|
||||
pub(super) fn iterate<'k, I, O, T, F, FR>(
|
||||
input: Vec<I>,
|
||||
func: F)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), T)
|
||||
@ -939,7 +610,7 @@ where
|
||||
Ok((state, output))
|
||||
}
|
||||
|
||||
pub fn foreach<'k, O, T, F>(func: F)
|
||||
pub(super) fn foreach<'k, O, T, F>(func: F)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<T>)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<O>), ItemStateError>> + Send + 'a>>
|
||||
where
|
||||
@ -960,7 +631,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn insert<'a, T: Send + Clone + 'a>(element: T)
|
||||
pub(super) fn insert<'a, T: Send + Clone + 'a>(element: T)
|
||||
-> impl Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), T), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -972,7 +643,7 @@ fn insert<'a, T: Send + Clone + 'a>(element: T)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_item_to_inventory(character: CharacterEntity)
|
||||
pub(super) fn add_item_to_inventory(character: CharacterEntity)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>> + Clone
|
||||
{
|
||||
@ -996,7 +667,7 @@ fn add_item_to_inventory(character: CharacterEntity)
|
||||
}
|
||||
}
|
||||
|
||||
fn record_trade(trade_id: TradeId, character_to: CharacterEntityId, character_from: CharacterEntityId)
|
||||
pub(super) fn record_trade(trade_id: TradeId, character_to: CharacterEntityId, character_from: CharacterEntityId)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<InventoryItem>)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), Vec<InventoryItem>), ItemStateError>> + Send + 'a>> + Clone
|
||||
{
|
||||
@ -1019,7 +690,7 @@ fn record_trade(trade_id: TradeId, character_to: CharacterEntityId, character_fr
|
||||
}
|
||||
|
||||
|
||||
fn assign_new_item_id()
|
||||
pub(super) fn assign_new_item_id()
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>> + Clone
|
||||
{
|
||||
@ -1031,98 +702,8 @@ fn assign_new_item_id()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn trade_items<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
p1: (&AreaClient, &CharacterEntity, &Vec<TradeItem>, Meseta),
|
||||
p2: (&AreaClient, &CharacterEntity, &Vec<TradeItem>, Meseta))
|
||||
-> Result<(Vec<InventoryItem>, Vec<InventoryItem>), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
let p1_trade_items = p1.2
|
||||
.iter()
|
||||
.map(|item| {
|
||||
match item {
|
||||
TradeItem::Individual(item_id) => (*item_id, 1),
|
||||
TradeItem::Stacked(item_id, amount) => (*item_id, *amount as u32),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let p2_trade_items = p2.2
|
||||
.iter()
|
||||
.map(|item| {
|
||||
match item {
|
||||
TradeItem::Individual(item_id) => (*item_id, 1),
|
||||
TradeItem::Stacked(item_id, amount) => (*item_id, *amount as u32),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
entity_gateway.with_transaction(|mut transaction| async move {
|
||||
let p1_id = p1.1.id;
|
||||
let p2_id = p2.1.id;
|
||||
let trade = transaction.gateway().create_trade(&p1_id, &p2_id).await?;
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), p1_removed_items) = ItemStateAction::default()
|
||||
.act(iterate(p1_trade_items, move |p1_trade_item| take_item_from_inventory(p1_id, p1_trade_item.0, p1_trade_item.1) ))
|
||||
.act(foreach(assign_new_item_id()))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
let ((item_state_proxy, transaction), p2_removed_items) = ItemStateAction::default()
|
||||
.act(iterate(p2_trade_items, move |p2_trade_item| take_item_from_inventory(p2_id, p2_trade_item.0, p2_trade_item.1) ))
|
||||
.act(foreach(assign_new_item_id()))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
let ((item_state_proxy, transaction), p2_new_items) = ItemStateAction::default()
|
||||
.act(insert(p1_removed_items))
|
||||
.act(foreach(add_item_to_inventory(p2.1.clone())))
|
||||
.act(record_trade(trade.id, p1_id, p2_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
let ((item_state_proxy, transaction), p1_new_items) = ItemStateAction::default()
|
||||
.act(insert(p2_removed_items))
|
||||
.act(foreach(add_item_to_inventory(p1.1.clone())))
|
||||
.act(record_trade(trade.id, p2_id, p1_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||
.act(take_meseta_from_inventory(p1_id, p1.3.0))
|
||||
.act(take_meseta_from_inventory(p2_id, p2.3.0))
|
||||
.act(add_meseta_to_inventory(p1_id, p2.3.0))
|
||||
.act(add_meseta_to_inventory(p2_id, p1.3.0))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, (p1_new_items, p2_new_items)))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn take_meseta<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character_id: &CharacterEntityId,
|
||||
meseta: Meseta)
|
||||
-> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||
.act(take_meseta_from_inventory(*character_id, meseta.0))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, ()))
|
||||
}).await
|
||||
}
|
||||
|
||||
fn convert_item_drop_to_floor_item(character_id: CharacterEntityId, item_drop: ItemDrop)
|
||||
pub(super) fn convert_item_drop_to_floor_item(character_id: CharacterEntityId, item_drop: ItemDrop)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>> + Clone
|
||||
{
|
||||
@ -1219,7 +800,7 @@ fn convert_item_drop_to_floor_item(character_id: CharacterEntityId, item_drop: I
|
||||
}
|
||||
}
|
||||
|
||||
fn add_item_to_local_floor(character_id: CharacterEntityId)
|
||||
pub(super) fn add_item_to_local_floor(character_id: CharacterEntityId)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), FloorItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -1234,29 +815,7 @@ fn add_item_to_local_floor(character_id: CharacterEntityId)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn enemy_drops_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character_id: CharacterEntityId,
|
||||
item_drop: ItemDrop)
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default()
|
||||
.act(convert_item_drop_to_floor_item(character_id, item_drop))
|
||||
.act(add_item_to_local_floor(character_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, floor_item))
|
||||
}).await
|
||||
}
|
||||
|
||||
fn apply_modifier_to_inventory_item(modifier: ItemModifier)
|
||||
pub(super) fn apply_modifier_to_inventory_item(modifier: ItemModifier)
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -1276,7 +835,7 @@ fn apply_modifier_to_inventory_item(modifier: ItemModifier)
|
||||
}
|
||||
}
|
||||
|
||||
fn as_individual_item()
|
||||
pub(super) fn as_individual_item()
|
||||
-> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem)
|
||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), IndividualItemDetail), ItemStateError>> + Send + 'a>>
|
||||
{
|
||||
@ -1291,29 +850,3 @@ fn as_individual_item()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn apply_modifier<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: ClientItemId,
|
||||
modifier: ItemModifier)
|
||||
-> Result<IndividualItemDetail, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), item) = ItemStateAction::default()
|
||||
.act(take_item_from_inventory(character.id, item_id, 1))
|
||||
.act(apply_modifier_to_inventory_item(modifier))
|
||||
.act(add_item_to_inventory(character.clone()))
|
||||
.act(as_individual_item())
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, item))
|
||||
}).await
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ use crate::entity::character::CharacterEntity;
|
||||
use crate::entity::item::mag::{MagCell, MagCellError};
|
||||
use crate::entity::item::tool::ToolType;
|
||||
use crate::entity::item::{ItemDetail, ItemEntityId};
|
||||
use crate::ship::items::state::{ItemStateProxy, InventoryItem, InventoryItemDetail, ItemStateError};
|
||||
use crate::ship::items::state::{ItemStateProxy, ItemStateError};
|
||||
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
340
src/ship/items/bank.rs
Normal file
340
src/ship/items/bank.rs
Normal file
@ -0,0 +1,340 @@
|
||||
use std::cmp::Ordering;
|
||||
use libpso::character::character;
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity, BankName};
|
||||
use std::future::Future;
|
||||
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use crate::ship::items::state::ItemStateError;
|
||||
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
||||
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum BankError {
|
||||
#[error("bank full")]
|
||||
BankFull,
|
||||
#[error("stack full")]
|
||||
StackFull,
|
||||
#[error("meseta full")]
|
||||
MesetaFull,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BankItemDetail {
|
||||
Individual(IndividualItemDetail),
|
||||
Stacked(StackedItemDetail),
|
||||
}
|
||||
|
||||
impl BankItemDetail {
|
||||
fn stacked_mut(&mut self) -> Option<&mut StackedItemDetail> {
|
||||
match self {
|
||||
BankItemDetail::Stacked(sitem) => Some(sitem),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_client_bytes(&self) -> [u8; 16] {
|
||||
match self {
|
||||
BankItemDetail::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(),
|
||||
}
|
||||
},
|
||||
BankItemDetail::Stacked(item) => {
|
||||
item.tool.as_stacked_bytes(item.entity_ids.len())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BankItem {
|
||||
pub item_id: ClientItemId,
|
||||
pub item: BankItemDetail,
|
||||
}
|
||||
|
||||
impl BankItem {
|
||||
pub async fn with_entity_id<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, ItemStateError>
|
||||
where
|
||||
F: FnMut(T, ItemEntityId) -> Fut,
|
||||
Fut: Future<Output=Result<T, ItemStateError>>,
|
||||
{
|
||||
match &self.item {
|
||||
BankItemDetail::Individual(individual_item) => {
|
||||
param = func(param, individual_item.entity_id).await?;
|
||||
},
|
||||
BankItemDetail::Stacked(stacked_item) => {
|
||||
for entity_id in &stacked_item.entity_ids {
|
||||
param = func(param, *entity_id).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(param)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Bank(Vec<BankItem>);
|
||||
|
||||
impl Bank {
|
||||
pub fn new(items: Vec<BankItem>) -> Bank {
|
||||
Bank(items)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BankState {
|
||||
pub character_id: CharacterEntityId,
|
||||
pub item_id_counter: u32,
|
||||
pub name: BankName,
|
||||
pub bank: Bank,
|
||||
pub meseta: Meseta,
|
||||
}
|
||||
|
||||
impl BankState {
|
||||
pub fn new(character_id: CharacterEntityId, name: BankName, mut bank: Bank, meseta: Meseta) -> BankState {
|
||||
bank.0.sort();
|
||||
BankState {
|
||||
character_id,
|
||||
item_id_counter: 0,
|
||||
name,
|
||||
bank,
|
||||
meseta,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count(&self) -> usize {
|
||||
self.bank.0.len()
|
||||
}
|
||||
|
||||
pub fn initialize_item_ids(&mut self, base_item_id: u32) {
|
||||
for (i, item) in self.bank.0.iter_mut().enumerate() {
|
||||
item.item_id = ClientItemId(base_item_id + i as u32);
|
||||
}
|
||||
self.item_id_counter = base_item_id + self.bank.0.len() as u32;
|
||||
}
|
||||
|
||||
pub fn add_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> {
|
||||
if self.meseta.0 + amount > 999999 {
|
||||
return Err(ItemStateError::FullOfMeseta)
|
||||
}
|
||||
self.meseta.0 += amount;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> {
|
||||
if amount > self.meseta.0 {
|
||||
return Err(ItemStateError::InvalidMesetaRemoval(amount))
|
||||
}
|
||||
self.meseta.0 -= amount;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_inventory_item(&mut self, item: InventoryItem) -> Result<AddItemResult, BankError> {
|
||||
match item.item {
|
||||
InventoryItemDetail::Individual(iitem) => {
|
||||
if self.bank.0.len() >= 30 {
|
||||
Err(BankError::BankFull)
|
||||
}
|
||||
else {
|
||||
self.bank.0.push(BankItem {
|
||||
item_id: item.item_id,
|
||||
item: BankItemDetail::Individual(iitem)
|
||||
});
|
||||
self.bank.0.sort();
|
||||
Ok(AddItemResult::NewItem)
|
||||
}
|
||||
},
|
||||
InventoryItemDetail::Stacked(sitem) => {
|
||||
let existing_stack = self.bank.0
|
||||
.iter_mut()
|
||||
.filter_map(|item| item.item.stacked_mut())
|
||||
.find(|item| {
|
||||
item.tool == sitem.tool
|
||||
});
|
||||
match existing_stack {
|
||||
Some(existing_stack) => {
|
||||
if existing_stack.entity_ids.len() + sitem.entity_ids.len() > sitem.tool.max_stack() {
|
||||
Err(BankError::StackFull)
|
||||
}
|
||||
else {
|
||||
existing_stack.entity_ids.append(&mut sitem.entity_ids.clone());
|
||||
Ok(AddItemResult::AddToStack)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if self.bank.0.len() >= 30 {
|
||||
Err(BankError::BankFull)
|
||||
}
|
||||
else {
|
||||
self.bank.0.push(BankItem {
|
||||
item_id: item.item_id,
|
||||
item: BankItemDetail::Stacked(sitem)
|
||||
});
|
||||
self.bank.0.sort();
|
||||
Ok(AddItemResult::NewItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<BankItem> {
|
||||
let idx = self.bank.0
|
||||
.iter()
|
||||
.position(|i| i.item_id == *item_id)?;
|
||||
match &mut self.bank.0[idx].item {
|
||||
BankItemDetail::Individual(_individual_item) => {
|
||||
Some(self.bank.0.remove(idx))
|
||||
},
|
||||
BankItemDetail::Stacked(stacked_item) => {
|
||||
let remove_all = match stacked_item.entity_ids.len().cmp(&(amount as usize)) {
|
||||
Ordering::Equal => true,
|
||||
Ordering::Greater => false,
|
||||
Ordering::Less => return None,
|
||||
};
|
||||
|
||||
if remove_all {
|
||||
Some(self.bank.0.remove(idx))
|
||||
}
|
||||
else {
|
||||
let entity_ids = stacked_item.entity_ids.drain(..(amount as usize)).collect();
|
||||
self.item_id_counter += 1;
|
||||
Some(BankItem {
|
||||
item_id: ClientItemId(self.item_id_counter),
|
||||
item: BankItemDetail::Stacked(StackedItemDetail {
|
||||
entity_ids,
|
||||
tool: stacked_item.tool,
|
||||
})})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_client_bank_items(&self) -> character::Bank {
|
||||
self.bank.0.iter()
|
||||
.enumerate()
|
||||
.fold(character::Bank::default(), |mut bank, (slot, item)| {
|
||||
bank.item_count = (slot + 1) as u32;
|
||||
let bytes = item.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.bank.0.iter()
|
||||
.map(|item| {
|
||||
let bytes = item.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.item {
|
||||
BankItemDetail::Individual(_individual_bank_item) => {
|
||||
1
|
||||
},
|
||||
BankItemDetail::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 as_bank_entity(&self) -> BankEntity {
|
||||
BankEntity {
|
||||
items: self.bank.0.iter()
|
||||
.map(|item| {
|
||||
match &item.item {
|
||||
BankItemDetail::Individual(item) => {
|
||||
BankItemEntity::Individual(ItemEntity {
|
||||
id: item.entity_id,
|
||||
item: item.item.clone(),
|
||||
})
|
||||
},
|
||||
BankItemDetail::Stacked(items) => {
|
||||
BankItemEntity::Stacked(items.entity_ids.iter()
|
||||
.map(|id| {
|
||||
ItemEntity {
|
||||
id: *id,
|
||||
item: ItemDetail::Tool(items.tool)
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.item.as_client_bytes()[0..4]);
|
||||
other_bytes.copy_from_slice(&other.item.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 mut self_bytes = [0u8; 4];
|
||||
let mut other_bytes = [0u8; 4];
|
||||
self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]);
|
||||
other_bytes.copy_from_slice(&other.item.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 mut self_bytes = [0u8; 4];
|
||||
let mut other_bytes = [0u8; 4];
|
||||
self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]);
|
||||
other_bytes.copy_from_slice(&other.item.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)
|
||||
}
|
||||
}
|
||||
|
139
src/ship/items/floor.rs
Normal file
139
src/ship/items/floor.rs
Normal file
@ -0,0 +1,139 @@
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail};
|
||||
use std::future::Future;
|
||||
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use crate::entity::item::mag::Mag;
|
||||
|
||||
use crate::ship::items::state::ItemStateError;
|
||||
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail};
|
||||
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||
|
||||
pub enum FloorType {
|
||||
Local,
|
||||
Shared,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FloorItemDetail {
|
||||
Individual(IndividualItemDetail),
|
||||
Stacked(StackedItemDetail),
|
||||
Meseta(Meseta),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FloorItem {
|
||||
pub item_id: ClientItemId,
|
||||
pub item: FloorItemDetail,
|
||||
pub map_area: MapArea,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
}
|
||||
|
||||
impl FloorItem {
|
||||
pub async fn with_entity_id<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, ItemStateError>
|
||||
where
|
||||
F: FnMut(T, ItemEntityId) -> Fut,
|
||||
Fut: Future<Output=Result<T, ItemStateError>>,
|
||||
{
|
||||
match &self.item {
|
||||
FloorItemDetail::Individual(individual_item) => {
|
||||
param = func(param, individual_item.entity_id).await?;
|
||||
},
|
||||
FloorItemDetail::Stacked(stacked_item) => {
|
||||
for entity_id in &stacked_item.entity_ids {
|
||||
param = func(param, *entity_id).await?;
|
||||
}
|
||||
},
|
||||
FloorItemDetail::Meseta(_meseta) => {},
|
||||
}
|
||||
|
||||
Ok(param)
|
||||
}
|
||||
|
||||
pub async fn with_mag<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, ItemStateError>
|
||||
where
|
||||
F: FnMut(T, ItemEntityId, Mag) -> Fut,
|
||||
Fut: Future<Output=Result<T, ItemStateError>>,
|
||||
{
|
||||
if let FloorItemDetail::Individual(individual_item) = &self.item {
|
||||
if let ItemDetail::Mag(mag) = &individual_item.item {
|
||||
param = func(param, individual_item.entity_id, mag.clone()).await?;
|
||||
}
|
||||
}
|
||||
Ok(param)
|
||||
}
|
||||
|
||||
pub fn as_client_bytes(&self) -> [u8; 16] {
|
||||
match &self.item {
|
||||
FloorItemDetail::Individual(individual_floor_item) => {
|
||||
individual_floor_item.item.as_client_bytes()
|
||||
},
|
||||
FloorItemDetail::Stacked(stacked_floor_item) => {
|
||||
stacked_floor_item.tool.as_stacked_bytes(stacked_floor_item.entity_ids.len())
|
||||
},
|
||||
FloorItemDetail::Meseta(meseta_floor_item) => {
|
||||
meseta_floor_item.as_bytes()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct LocalFloor(pub Vec<FloorItem>);
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SharedFloor(pub Vec<FloorItem>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FloorState {
|
||||
pub character_id: CharacterEntityId,
|
||||
pub local: LocalFloor,
|
||||
pub shared: SharedFloor,
|
||||
}
|
||||
|
||||
impl FloorState {
|
||||
pub fn take_item(&mut self, item_id: &ClientItemId) -> Option<FloorItem> {
|
||||
let item = self.local.0
|
||||
.drain_filter(|item| {
|
||||
item.item_id == *item_id
|
||||
})
|
||||
.next();
|
||||
item.or_else(|| {
|
||||
self.shared.0
|
||||
.drain_filter(|item| {
|
||||
item.item_id == *item_id
|
||||
})
|
||||
.next()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_inventory_item(&mut self, inventory_item: InventoryItem, map_area: MapArea, position: (f32, f32, f32)) -> &FloorItem {
|
||||
let floor_item = FloorItem {
|
||||
item_id: inventory_item.item_id,
|
||||
item: match inventory_item.item {
|
||||
InventoryItemDetail::Individual(individual_item) => FloorItemDetail::Individual(individual_item),
|
||||
InventoryItemDetail::Stacked(stacked_item) => FloorItemDetail::Stacked(stacked_item),
|
||||
},
|
||||
map_area,
|
||||
x: position.0,
|
||||
y: position.1,
|
||||
z: position.2,
|
||||
};
|
||||
|
||||
self.shared.0.push(floor_item);
|
||||
&self.shared.0[self.shared.0.len()-1]
|
||||
}
|
||||
|
||||
pub fn add_shared_item(&mut self, floor_item: FloorItem) -> &FloorItem {
|
||||
self.shared.0.push(floor_item);
|
||||
&self.shared.0[self.shared.0.len()-1]
|
||||
}
|
||||
|
||||
pub fn add_local_item(&mut self, floor_item: FloorItem) -> &FloorItem {
|
||||
self.local.0.push(floor_item);
|
||||
&self.local.0[self.local.0.len()-1]
|
||||
}
|
||||
}
|
||||
|
529
src/ship/items/inventory.rs
Normal file
529
src/ship/items/inventory.rs
Normal file
@ -0,0 +1,529 @@
|
||||
use std::cmp::Ordering;
|
||||
use libpso::character::character;
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity};
|
||||
use std::future::Future;
|
||||
|
||||
use crate::entity::character::CharacterEntityId;
|
||||
use crate::entity::item::tool::ToolType;
|
||||
use crate::entity::item::mag::Mag;
|
||||
use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem};
|
||||
use crate::ship::items::state::ItemStateError;
|
||||
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
||||
use crate::ship::items::floor::{FloorItem, FloorItemDetail};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum InventoryItemDetail {
|
||||
Individual(IndividualItemDetail),
|
||||
Stacked(StackedItemDetail),
|
||||
}
|
||||
|
||||
impl InventoryItemDetail {
|
||||
// TODO: rename as_stacked for consistency
|
||||
pub fn stacked(&self) -> Option<&StackedItemDetail> {
|
||||
match self {
|
||||
InventoryItemDetail::Stacked(sitem) => Some(sitem),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
// TODO: rename as_stacked_mut for consistency
|
||||
pub fn stacked_mut(&mut self) -> Option<&mut StackedItemDetail> {
|
||||
match self {
|
||||
InventoryItemDetail::Stacked(sitem) => Some(sitem),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_individual(&self) -> Option<&IndividualItemDetail> {
|
||||
match self {
|
||||
InventoryItemDetail::Individual(iitem) => Some(iitem),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_individual_mut(&mut self) -> Option<&mut IndividualItemDetail> {
|
||||
match self {
|
||||
InventoryItemDetail::Individual(iitem) => Some(iitem),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_client_bytes(&self) -> [u8; 16] {
|
||||
match self {
|
||||
InventoryItemDetail::Individual(item) => {
|
||||
item.as_client_bytes()
|
||||
},
|
||||
InventoryItemDetail::Stacked(item) => {
|
||||
item.tool.as_stacked_bytes(item.entity_ids.len())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should probably go somewhere a bit more fundamental like ItemDetail
|
||||
pub fn sell_price(&self) -> Result<u32, ItemStateError> {
|
||||
match self {
|
||||
InventoryItemDetail::Individual(individual_item) => {
|
||||
match &individual_item.item {
|
||||
// TODO: can wrapped items be sold?
|
||||
ItemDetail::Weapon(w) => {
|
||||
if !w.tekked {
|
||||
return Ok(1u32)
|
||||
}
|
||||
if w.is_rare_item() {
|
||||
return Ok(10u32)
|
||||
}
|
||||
Ok((WeaponShopItem::from(w).price() / 8) as u32)
|
||||
},
|
||||
ItemDetail::Armor(a) => {
|
||||
if a.is_rare_item() {
|
||||
return Ok(10u32)
|
||||
}
|
||||
Ok((ArmorShopItem::from(a).price() / 8) as u32)
|
||||
},
|
||||
ItemDetail::Shield(s) => {
|
||||
if s.is_rare_item() {
|
||||
return Ok(10u32)
|
||||
}
|
||||
Ok((ArmorShopItem::from(s).price() / 8) as u32)
|
||||
},
|
||||
ItemDetail::Unit(u) => {
|
||||
if u.is_rare_item() {
|
||||
return Ok(10u32)
|
||||
}
|
||||
Ok((ArmorShopItem::from(u).price() / 8) as u32)
|
||||
},
|
||||
ItemDetail::Tool(t) => {
|
||||
if !matches!(t.tool, ToolType::PhotonDrop | ToolType::PhotonSphere | ToolType::PhotonCrystal) && t.is_rare_item() {
|
||||
return Ok(10u32)
|
||||
}
|
||||
Ok((ToolShopItem::from(t).price() / 8) as u32)
|
||||
},
|
||||
ItemDetail::TechniqueDisk(d) => {
|
||||
Ok((ToolShopItem::from(d).price() / 8) as u32)
|
||||
},
|
||||
ItemDetail::Mag(_m) => {
|
||||
Err(ItemStateError::ItemNotSellable)
|
||||
},
|
||||
ItemDetail::ESWeapon(_e) => {
|
||||
Ok(10u32)
|
||||
},
|
||||
}
|
||||
},
|
||||
// the number of stacked items sold is handled by the caller. this is just the price of 1
|
||||
InventoryItemDetail::Stacked(stacked_item) => {
|
||||
Ok(((ToolShopItem::from(&stacked_item.tool).price() / 8) as u32) * stacked_item.count() as u32)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InventoryItem {
|
||||
pub item_id: ClientItemId,
|
||||
pub item: InventoryItemDetail,
|
||||
}
|
||||
|
||||
impl InventoryItem {
|
||||
pub async fn with_entity_id<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, ItemStateError>
|
||||
where
|
||||
F: FnMut(T, ItemEntityId) -> Fut,
|
||||
Fut: Future<Output=Result<T, ItemStateError>>,
|
||||
{
|
||||
match &self.item {
|
||||
InventoryItemDetail::Individual(individual_item) => {
|
||||
param = func(param, individual_item.entity_id).await?;
|
||||
},
|
||||
InventoryItemDetail::Stacked(stacked_item) => {
|
||||
for entity_id in &stacked_item.entity_ids {
|
||||
param = func(param, *entity_id).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(param)
|
||||
}
|
||||
|
||||
pub async fn with_mag<F, Fut, T>(&self, mut param: T, mut func: F) -> Result<T, ItemStateError>
|
||||
where
|
||||
F: FnMut(T, ItemEntityId, Mag) -> Fut,
|
||||
Fut: Future<Output=Result<T, ItemStateError>>,
|
||||
{
|
||||
if let InventoryItemDetail::Individual(individual_item) = &self.item {
|
||||
if let ItemDetail::Mag(mag) = &individual_item.item {
|
||||
param = func(param, individual_item.entity_id, mag.clone()).await?;
|
||||
}
|
||||
}
|
||||
Ok(param)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Inventory(Vec<InventoryItem>);
|
||||
|
||||
impl Inventory {
|
||||
pub fn new(items: Vec<InventoryItem>) -> Inventory {
|
||||
Inventory(items)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum InventoryError {
|
||||
#[error("inventory full")]
|
||||
InventoryFull,
|
||||
#[error("stack full")]
|
||||
StackFull,
|
||||
#[error("meseta full")]
|
||||
MesetaFull,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InventoryState {
|
||||
pub character_id: CharacterEntityId,
|
||||
pub item_id_counter: u32,
|
||||
pub inventory: Inventory,
|
||||
pub equipped: EquippedEntity,
|
||||
pub meseta: Meseta,
|
||||
}
|
||||
|
||||
impl InventoryState {
|
||||
pub fn initialize_item_ids(&mut self, base_item_id: u32) {
|
||||
for (i, item) in self.inventory.0.iter_mut().enumerate() {
|
||||
item.item_id = ClientItemId(base_item_id + i as u32);
|
||||
}
|
||||
self.item_id_counter = base_item_id + self.inventory.0.len() as u32 + 1;
|
||||
}
|
||||
|
||||
pub fn new_item_id(&mut self) -> ClientItemId {
|
||||
self.item_id_counter += 1;
|
||||
ClientItemId(self.item_id_counter)
|
||||
}
|
||||
|
||||
pub fn count(&self) -> usize {
|
||||
self.inventory.0.len()
|
||||
}
|
||||
|
||||
pub fn add_floor_item(&mut self, item: FloorItem) -> Result<AddItemResult, InventoryError> {
|
||||
match item.item {
|
||||
FloorItemDetail::Individual(iitem) => {
|
||||
if self.inventory.0.len() >= 30 {
|
||||
Err(InventoryError::InventoryFull)
|
||||
}
|
||||
else {
|
||||
self.inventory.0.push(InventoryItem {
|
||||
item_id: item.item_id,
|
||||
item: InventoryItemDetail::Individual(iitem)
|
||||
});
|
||||
Ok(AddItemResult::NewItem)
|
||||
}
|
||||
},
|
||||
FloorItemDetail::Stacked(sitem) => {
|
||||
let existing_stack = self.inventory.0
|
||||
.iter_mut()
|
||||
.filter_map(|item| item.item.stacked_mut())
|
||||
.find(|item| {
|
||||
item.tool == sitem.tool
|
||||
});
|
||||
match existing_stack {
|
||||
Some(existing_stack) => {
|
||||
if existing_stack.entity_ids.len() + sitem.entity_ids.len() > sitem.tool.max_stack() {
|
||||
Err(InventoryError::StackFull)
|
||||
}
|
||||
else {
|
||||
existing_stack.entity_ids.append(&mut sitem.entity_ids.clone());
|
||||
Ok(AddItemResult::AddToStack)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if self.inventory.0.len() >= 30 {
|
||||
Err(InventoryError::InventoryFull)
|
||||
}
|
||||
else {
|
||||
self.inventory.0.push(InventoryItem {
|
||||
item_id: item.item_id,
|
||||
item: InventoryItemDetail::Stacked(sitem)
|
||||
});
|
||||
Ok(AddItemResult::NewItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
FloorItemDetail::Meseta(meseta) => {
|
||||
if self.meseta == Meseta(999999) {
|
||||
Err(InventoryError::MesetaFull)
|
||||
}
|
||||
else {
|
||||
self.meseta.0 = std::cmp::min(self.meseta.0 + meseta.0, 999999);
|
||||
Ok(AddItemResult::Meseta)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_item(&mut self, item: InventoryItem) -> Result<(AddItemResult, InventoryItem), InventoryError> {
|
||||
match &item.item {
|
||||
InventoryItemDetail::Individual(_) => {
|
||||
if self.inventory.0.len() >= 30 {
|
||||
Err(InventoryError::InventoryFull)
|
||||
}
|
||||
else {
|
||||
self.inventory.0.push(item);
|
||||
Ok((
|
||||
AddItemResult::NewItem,
|
||||
self.inventory.0
|
||||
.last()
|
||||
.unwrap()
|
||||
.clone()
|
||||
))
|
||||
}
|
||||
},
|
||||
InventoryItemDetail::Stacked(sitem) => {
|
||||
let existing_stack = self.inventory.0
|
||||
.iter_mut()
|
||||
.filter_map(|item| item.item.stacked_mut())
|
||||
.find(|item| {
|
||||
item.tool == sitem.tool
|
||||
});
|
||||
match existing_stack {
|
||||
Some(existing_stack) => {
|
||||
if existing_stack.entity_ids.len() + sitem.entity_ids.len() > sitem.tool.max_stack() {
|
||||
Err(InventoryError::StackFull)
|
||||
}
|
||||
else {
|
||||
existing_stack.entity_ids.append(&mut sitem.entity_ids.clone());
|
||||
Ok((
|
||||
AddItemResult::AddToStack,
|
||||
self.inventory.0[self.inventory.0
|
||||
.iter()
|
||||
.filter_map(|item| item.item.stacked())
|
||||
.position(|item| item.tool == sitem.tool)
|
||||
.unwrap()]
|
||||
.clone()
|
||||
))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if self.inventory.0.len() >= 30 {
|
||||
Err(InventoryError::InventoryFull)
|
||||
}
|
||||
else {
|
||||
self.inventory.0.push(item);
|
||||
Ok((
|
||||
AddItemResult::NewItem,
|
||||
self.inventory.0
|
||||
.last()
|
||||
.unwrap()
|
||||
.clone()
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_item(&mut self, item_id: &ClientItemId, amount: u32) -> Option<InventoryItem> {
|
||||
let idx = self.inventory.0
|
||||
.iter()
|
||||
.position(|i| i.item_id == *item_id)?;
|
||||
match &mut self.inventory.0[idx].item {
|
||||
InventoryItemDetail::Individual(_individual_item) => {
|
||||
Some(self.inventory.0.remove(idx))
|
||||
},
|
||||
InventoryItemDetail::Stacked(stacked_item) => {
|
||||
let remove_all = (amount == 0) || match stacked_item.entity_ids.len().cmp(&(amount as usize)) {
|
||||
Ordering::Equal => true,
|
||||
Ordering::Greater => false,
|
||||
Ordering::Less => return None,
|
||||
};
|
||||
|
||||
if remove_all {
|
||||
Some(self.inventory.0.remove(idx))
|
||||
}
|
||||
else {
|
||||
let entity_ids = stacked_item.entity_ids.drain(..(amount as usize)).collect();
|
||||
self.item_id_counter += 1;
|
||||
Some(InventoryItem {
|
||||
item_id: ClientItemId(self.item_id_counter),
|
||||
item: InventoryItemDetail::Stacked(StackedItemDetail {
|
||||
entity_ids,
|
||||
tool: stacked_item.tool,
|
||||
})})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: rename get_item_by_client_id
|
||||
pub fn get_by_client_id(&self, item_id: &ClientItemId) -> Option<&InventoryItem> {
|
||||
self.inventory.0
|
||||
.iter()
|
||||
.find(|i| i.item_id == *item_id)
|
||||
}
|
||||
|
||||
pub fn get_by_client_id_mut(&mut self, item_id: &ClientItemId) -> Option<&mut InventoryItem> {
|
||||
self.inventory.0
|
||||
.iter_mut()
|
||||
.find(|i| i.item_id == *item_id)
|
||||
}
|
||||
|
||||
pub fn add_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> {
|
||||
if self.meseta.0 == 999999 {
|
||||
return Err(ItemStateError::FullOfMeseta)
|
||||
}
|
||||
self.meseta.0 = std::cmp::min(self.meseta.0 + amount, 999999);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_meseta_no_overflow(&mut self, amount: u32) -> Result<(), ItemStateError> {
|
||||
if self.meseta.0 + amount > 999999 {
|
||||
return Err(ItemStateError::FullOfMeseta)
|
||||
}
|
||||
self.meseta.0 += amount;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> {
|
||||
if amount > self.meseta.0 {
|
||||
return Err(ItemStateError::InvalidMesetaRemoval(amount))
|
||||
}
|
||||
self.meseta.0 -= amount;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn equip(&mut self, item_id: &ClientItemId, equip_slot: u8) {
|
||||
for item in &self.inventory.0 {
|
||||
if let InventoryItemDetail::Individual(inventory_item) = &item.item {
|
||||
if item.item_id == *item_id {
|
||||
match inventory_item.item {
|
||||
ItemDetail::Weapon(_) => self.equipped.weapon = Some(inventory_item.entity_id),
|
||||
ItemDetail::Armor(_) => self.equipped.armor = Some(inventory_item.entity_id),
|
||||
ItemDetail::Shield(_) => self.equipped.shield = Some(inventory_item.entity_id),
|
||||
ItemDetail::Unit(_) => {
|
||||
if let Some(unit) = self.equipped.unit.get_mut(equip_slot as usize) {
|
||||
*unit = Some(inventory_item.entity_id)
|
||||
}
|
||||
}
|
||||
ItemDetail::Mag(_) => self.equipped.mag = Some(inventory_item.entity_id),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unequip(&mut self, item_id: &ClientItemId) {
|
||||
for item in &self.inventory.0 {
|
||||
if let InventoryItemDetail::Individual(inventory_item) = &item.item {
|
||||
if item.item_id == *item_id {
|
||||
match inventory_item.item {
|
||||
ItemDetail::Weapon(_) => self.equipped.weapon = None,
|
||||
ItemDetail::Armor(_) => {
|
||||
self.equipped.armor = None;
|
||||
self.equipped.unit = [None; 4];
|
||||
}
|
||||
ItemDetail::Shield(_) => self.equipped.shield = None,
|
||||
ItemDetail::Unit(_) => {
|
||||
for unit in self.equipped.unit.iter_mut() {
|
||||
if *unit == Some(inventory_item.entity_id) {
|
||||
*unit = None
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemDetail::Mag(_) => self.equipped.mag = Some(inventory_item.entity_id),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn equipped_mag_mut(&mut self) -> Option<(ItemEntityId, &mut Mag)> {
|
||||
let mag_id = self.equipped.mag?;
|
||||
self.inventory.0
|
||||
.iter_mut()
|
||||
.filter_map(|i| {
|
||||
let individual = i.item.as_individual_mut()?;
|
||||
let entity_id = individual.entity_id;
|
||||
Some((entity_id, individual.as_mag_mut()?))
|
||||
})
|
||||
.find(|(entity_id, _)| *entity_id == mag_id)
|
||||
}
|
||||
|
||||
pub fn sort(&mut self, item_ids: &[ClientItemId]) {
|
||||
self.inventory.0.sort_by(|a, b| {
|
||||
let a_index = item_ids.iter().position(|item_id| *item_id == a.item_id);
|
||||
let b_index = item_ids.iter().position(|item_id| *item_id == b.item_id);
|
||||
|
||||
match (a_index, b_index) {
|
||||
(Some(a_index), Some(b_index)) => {
|
||||
a_index.cmp(&b_index)
|
||||
},
|
||||
_ => Ordering::Equal
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn as_inventory_entity(&self, _character_id: &CharacterEntityId) -> InventoryEntity {
|
||||
InventoryEntity {
|
||||
items: self.inventory.0.iter()
|
||||
.map(|item| {
|
||||
match &item.item {
|
||||
InventoryItemDetail::Individual(item) => {
|
||||
InventoryItemEntity::Individual(ItemEntity {
|
||||
id: item.entity_id,
|
||||
item: item.item.clone(),
|
||||
})
|
||||
},
|
||||
InventoryItemDetail::Stacked(items) => {
|
||||
InventoryItemEntity::Stacked(items.entity_ids.iter()
|
||||
.map(|id| {
|
||||
ItemEntity {
|
||||
id: *id,
|
||||
item: ItemDetail::Tool(items.tool)
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_equipped_entity(&self) -> EquippedEntity {
|
||||
self.equipped.clone()
|
||||
}
|
||||
|
||||
|
||||
pub fn as_client_inventory_items(&self) -> [character::InventoryItem; 30] {
|
||||
self.inventory.0.iter()
|
||||
.enumerate()
|
||||
.fold([character::InventoryItem::default(); 30], |mut inventory, (slot, item)| {
|
||||
let bytes = item.item.as_client_bytes();
|
||||
inventory[slot].data1.copy_from_slice(&bytes[0..12]);
|
||||
inventory[slot].data2.copy_from_slice(&bytes[12..16]);
|
||||
inventory[slot].item_id = item.item_id.0;
|
||||
inventory[slot].equipped = 0;
|
||||
inventory[slot].flags = 0;
|
||||
|
||||
if let InventoryItemDetail::Individual(individual_item) = &item.item {
|
||||
if self.equipped.is_equipped(&individual_item.entity_id) {
|
||||
if let ItemDetail::Unit(_) = individual_item.item {
|
||||
inventory[slot].data1[4] = self.equipped.unit.iter()
|
||||
.enumerate()
|
||||
.find(|(_, u_id)| **u_id == Some(individual_item.entity_id))
|
||||
.map(|(a, _)| a)
|
||||
.unwrap_or(0) as u8
|
||||
}
|
||||
inventory[slot].equipped = 1;
|
||||
inventory[slot].flags |= 8;
|
||||
}
|
||||
}
|
||||
inventory
|
||||
})
|
||||
}
|
||||
}
|
137
src/ship/items/itemstateaction.rs
Normal file
137
src/ship/items/itemstateaction.rs
Normal file
@ -0,0 +1,137 @@
|
||||
use std::future::Future;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait ItemAction {
|
||||
type Input;
|
||||
type Output;
|
||||
type Start;
|
||||
type Error;
|
||||
|
||||
async fn action(&self, s: Self::Start, i: Self::Input) -> Result<(Self::Start, Self::Output), Self::Error>;
|
||||
async fn commit(&self, v: Self::Start) -> Result<(Self::Start, Self::Output), Self::Error>;
|
||||
}
|
||||
|
||||
|
||||
pub struct ItemStateAction<T, S, E> {
|
||||
_t: std::marker::PhantomData<T>,
|
||||
_s: std::marker::PhantomData<S>,
|
||||
_e: std::marker::PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<T, S, E> Default for ItemStateAction<T, S, E> {
|
||||
fn default() -> ItemStateAction<T, S, E> {
|
||||
ItemStateAction {
|
||||
_t: std::marker::PhantomData,
|
||||
_s: std::marker::PhantomData,
|
||||
_e: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, E> ItemStateAction<T, S, E>
|
||||
where
|
||||
T: Send + Sync,
|
||||
S: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
pub fn act<O, F, Fut>(self, f: F) -> ItemActionStage<O, ItemStateAction<T, S, E>, F, Fut, S, E>
|
||||
where
|
||||
F: Fn(S, ()) -> Fut + Send + Sync,
|
||||
Fut: Future<Output=Result<(S, O), E>> + Send
|
||||
{
|
||||
ItemActionStage {
|
||||
_s: Default::default(),
|
||||
_e: std::marker::PhantomData,
|
||||
prev: self,
|
||||
actionf: f,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ItemActionStage<O, P, F, Fut, S, E>
|
||||
where
|
||||
P: ItemAction,
|
||||
F: Fn(S, P::Output) -> Fut + Send + Sync,
|
||||
Fut: Future<Output=Result<(S, O) , E>> + Send,
|
||||
{
|
||||
_s: std::marker::PhantomData<S>,
|
||||
_e: std::marker::PhantomData<E>,
|
||||
prev: P,
|
||||
actionf: F,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<O, P: ItemAction, F, Fut, S, E> ItemAction for ItemActionStage<O, P, F, Fut, S, E>
|
||||
where
|
||||
P: ItemAction + ItemAction<Start = S, Error = E> + Send + Sync,
|
||||
F: Fn(S, P::Output) -> Fut + Send + Sync,
|
||||
Fut: Future<Output=Result<(S, O), E>> + Send,
|
||||
S: Send + Sync,
|
||||
P::Output: Send + Sync,
|
||||
E: Send + Sync,
|
||||
O: Send + Sync,
|
||||
P::Error: Send + Sync,
|
||||
{
|
||||
type Input = P::Output;
|
||||
type Output = O;
|
||||
type Start = S;
|
||||
type Error = P::Error;
|
||||
|
||||
async fn action(&self, s: Self::Start, i: Self::Input) -> Result<(Self::Start, Self::Output), Self::Error> {
|
||||
(self.actionf)(s, i).await
|
||||
}
|
||||
|
||||
async fn commit(&self, i: Self::Start) -> Result<(Self::Start, Self::Output), Self::Error> {
|
||||
let (i, prev) = self.prev.commit(i).await?;
|
||||
self.action(i, prev).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<O, P: ItemAction, F, Fut, S, E> ItemActionStage<O, P, F, Fut, S, E>
|
||||
where
|
||||
P: ItemAction<Start = S, Error = E> + Send + Sync,
|
||||
F: Fn(S, P::Output) -> Fut + Send + Sync,
|
||||
Fut: Future<Output=Result<(S, O), E>> + Send,
|
||||
S: Send + Sync,
|
||||
P::Output: Send + Sync,
|
||||
E: Send + Sync,
|
||||
O: Send + Sync,
|
||||
P::Error: Send + Sync,
|
||||
{
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn act<O2, G, GFut>(self, g: G) -> ItemActionStage<O2, ItemActionStage<O, P, F, Fut, S, E>, G, GFut, S, E>
|
||||
where
|
||||
S: Send + Sync,
|
||||
G: Fn(S, <ItemActionStage<O, P, F, Fut, S, E> as ItemAction>::Output) -> GFut + Send + Sync,
|
||||
GFut: Future<Output=Result<(S, O2), E>> + Send,
|
||||
O2: Send + Sync,
|
||||
{
|
||||
ItemActionStage {
|
||||
_s: Default::default(),
|
||||
_e: Default::default(),
|
||||
prev: self,
|
||||
actionf: g,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T, S, E> ItemAction for ItemStateAction<T, S, E>
|
||||
where
|
||||
T: Send + Sync,
|
||||
S: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
type Input = T;
|
||||
type Output = ();
|
||||
type Start = T;
|
||||
type Error = E;
|
||||
|
||||
async fn action(&self, s: Self::Start, _i: Self::Input) -> Result<(Self::Start, Self::Output), Self::Error> {
|
||||
Ok((s, ()))
|
||||
}
|
||||
|
||||
async fn commit(&self, i: Self::Start) -> Result<(Self::Start, Self::Output), Self::Error> {
|
||||
Ok((i, ()))
|
||||
}
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
pub mod state;
|
||||
pub mod actions;
|
||||
pub mod apply_item;
|
||||
use serde::{Serialize, Deserialize};
|
||||
pub mod itemstateaction;
|
||||
pub mod inventory;
|
||||
pub mod floor;
|
||||
pub mod bank;
|
||||
pub mod tasks;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, derive_more::Display)]
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Display)]
|
||||
pub struct ClientItemId(pub u32);
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
500
src/ship/items/tasks.rs
Normal file
500
src/ship/items/tasks.rs
Normal file
@ -0,0 +1,500 @@
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::entity::item::Meseta;
|
||||
|
||||
use crate::ship::map::MapArea;
|
||||
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateError, IndividualItemDetail};
|
||||
use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction};
|
||||
use crate::ship::items::inventory::InventoryItem;
|
||||
use crate::ship::items::floor::FloorItem;
|
||||
use crate::entity::item::ItemModifier;
|
||||
use crate::ship::shops::ShopItem;
|
||||
use crate::ship::trade::TradeItem;
|
||||
use crate::ship::location::AreaClient;
|
||||
use crate::ship::drops::ItemDrop;
|
||||
|
||||
use crate::ship::items::actions;
|
||||
|
||||
pub async fn pick_up_item<EG>(
|
||||
item_state: &mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId)
|
||||
-> Result<actions::TriggerCreateItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::take_item_from_floor(character.id, *item_id))
|
||||
.act(actions::add_floor_item_to_inventory(character))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
pub async fn drop_item<EG>(
|
||||
item_state: &mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
map_area: MapArea,
|
||||
drop_position: (f32, f32, f32))
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::take_item_from_inventory(character.id, *item_id, 0))
|
||||
.act(actions::add_inventory_item_to_shared_floor(character.id, map_area, drop_position))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
pub async fn drop_partial_item<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
map_area: MapArea,
|
||||
drop_position: (f32, f32),
|
||||
amount: u32)
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
||||
.act(actions::add_inventory_item_to_shared_floor(character.id, map_area, (drop_position.0, 0.0, drop_position.1)))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub async fn drop_meseta<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
map_area: MapArea,
|
||||
drop_position: (f32, f32),
|
||||
amount: u32)
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::take_meseta_from_inventory(character.id, amount))
|
||||
.act(actions::add_meseta_to_shared_floor(character.id, amount, map_area, drop_position))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn withdraw_meseta<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
amount: u32)
|
||||
-> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::take_meseta_from_bank(character.id, amount))
|
||||
.act(actions::add_meseta_from_bank_to_inventory(character.id, amount))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn deposit_meseta<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
amount: u32)
|
||||
-> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||
.act(actions::take_meseta_from_inventory(character.id, amount))
|
||||
.act(actions::add_meseta_to_bank(character.id, amount))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, ()))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn withdraw_item<'a, EG>(
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
amount: u32)
|
||||
-> Result<InventoryItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::take_item_from_bank(character.id, *item_id, amount))
|
||||
//.act(bank_item_to_inventory_item)
|
||||
//.act(add_item_to_inventory)
|
||||
.act(actions::add_bank_item_to_inventory(character))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn deposit_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
amount: u32)
|
||||
-> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
||||
.act(actions::add_inventory_item_to_bank(character.id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
pub async fn equip_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
equip_slot: u8,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::equip_inventory_item(character.id, *item_id, equip_slot))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn unequip_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::unequip_inventory_item(character.id, *item_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn sort_inventory<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_ids: Vec<ClientItemId>,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::sort_inventory_items(character.id, item_ids))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn use_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &mut CharacterEntity,
|
||||
item_id: &ClientItemId,
|
||||
amount: u32,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), new_character) = ItemStateAction::default()
|
||||
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
||||
.act(actions::use_consumed_item(character.clone()))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
*character = new_character;
|
||||
Ok((transaction, ()))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn feed_mag<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
mag_item_id: &ClientItemId,
|
||||
tool_item_id: &ClientItemId,
|
||||
) -> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||
.act(actions::take_item_from_inventory(character.id, *tool_item_id, 1))
|
||||
.act(actions::feed_mag_item(character.clone(), *mag_item_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, ()))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn buy_shop_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
shop_item: &'a (dyn ShopItem + Send + Sync),
|
||||
item_id: ClientItemId,
|
||||
amount: u32,
|
||||
) -> Result<InventoryItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
let item_price = shop_item.price() as u32 * amount;
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::take_meseta_from_inventory(character.id, item_price))
|
||||
//.act(bought_item_to_inventory_item)
|
||||
//.act(add_item_to_inventory)
|
||||
.act(actions::add_bought_item_to_inventory(character.id, shop_item, item_id, amount))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn sell_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: ClientItemId,
|
||||
amount: u32,
|
||||
) -> Result<InventoryItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||
.act(actions::take_item_from_inventory(character.id, item_id, amount))
|
||||
.act(actions::sell_inventory_item(character.id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, result))
|
||||
}).await
|
||||
}
|
||||
pub async fn trade_items<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
p1: (&AreaClient, &CharacterEntity, &Vec<TradeItem>, Meseta),
|
||||
p2: (&AreaClient, &CharacterEntity, &Vec<TradeItem>, Meseta))
|
||||
-> Result<(Vec<InventoryItem>, Vec<InventoryItem>), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
let p1_trade_items = p1.2
|
||||
.iter()
|
||||
.map(|item| {
|
||||
match item {
|
||||
TradeItem::Individual(item_id) => (*item_id, 1),
|
||||
TradeItem::Stacked(item_id, amount) => (*item_id, *amount as u32),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let p2_trade_items = p2.2
|
||||
.iter()
|
||||
.map(|item| {
|
||||
match item {
|
||||
TradeItem::Individual(item_id) => (*item_id, 1),
|
||||
TradeItem::Stacked(item_id, amount) => (*item_id, *amount as u32),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
entity_gateway.with_transaction(|mut transaction| async move {
|
||||
let p1_id = p1.1.id;
|
||||
let p2_id = p2.1.id;
|
||||
let trade = transaction.gateway().create_trade(&p1_id, &p2_id).await?;
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), p1_removed_items) = ItemStateAction::default()
|
||||
.act(actions::iterate(p1_trade_items, move |p1_trade_item| actions::take_item_from_inventory(p1_id, p1_trade_item.0, p1_trade_item.1) ))
|
||||
.act(actions::foreach(actions::assign_new_item_id()))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
let ((item_state_proxy, transaction), p2_removed_items) = ItemStateAction::default()
|
||||
.act(actions::iterate(p2_trade_items, move |p2_trade_item| actions::take_item_from_inventory(p2_id, p2_trade_item.0, p2_trade_item.1) ))
|
||||
.act(actions::foreach(actions::assign_new_item_id()))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
let ((item_state_proxy, transaction), p2_new_items) = ItemStateAction::default()
|
||||
.act(actions::insert(p1_removed_items))
|
||||
.act(actions::foreach(actions::add_item_to_inventory(p2.1.clone())))
|
||||
.act(actions::record_trade(trade.id, p1_id, p2_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
let ((item_state_proxy, transaction), p1_new_items) = ItemStateAction::default()
|
||||
.act(actions::insert(p2_removed_items))
|
||||
.act(actions::foreach(actions::add_item_to_inventory(p1.1.clone())))
|
||||
.act(actions::record_trade(trade.id, p2_id, p1_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||
.act(actions::take_meseta_from_inventory(p1_id, p1.3.0))
|
||||
.act(actions::take_meseta_from_inventory(p2_id, p2.3.0))
|
||||
.act(actions::add_meseta_to_inventory(p1_id, p2.3.0))
|
||||
.act(actions::add_meseta_to_inventory(p2_id, p1.3.0))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, (p1_new_items, p2_new_items)))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn take_meseta<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character_id: &CharacterEntityId,
|
||||
meseta: Meseta)
|
||||
-> Result<(), ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||
.act(actions::take_meseta_from_inventory(*character_id, meseta.0))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, ()))
|
||||
}).await
|
||||
}
|
||||
|
||||
pub async fn enemy_drops_item<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character_id: CharacterEntityId,
|
||||
item_drop: ItemDrop)
|
||||
-> Result<FloorItem, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default()
|
||||
.act(actions::convert_item_drop_to_floor_item(character_id, item_drop))
|
||||
.act(actions::add_item_to_local_floor(character_id))
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, floor_item))
|
||||
}).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn apply_modifier<'a, EG> (
|
||||
item_state: &'a mut ItemState,
|
||||
entity_gateway: &mut EG,
|
||||
character: &CharacterEntity,
|
||||
item_id: ClientItemId,
|
||||
modifier: ItemModifier)
|
||||
-> Result<IndividualItemDetail, ItemStateError>
|
||||
where
|
||||
EG: EntityGateway,
|
||||
{
|
||||
entity_gateway.with_transaction(|transaction| async move {
|
||||
let item_state_proxy = ItemStateProxy::new(item_state);
|
||||
let ((item_state_proxy, transaction), item) = ItemStateAction::default()
|
||||
.act(actions::take_item_from_inventory(character.id, item_id, 1))
|
||||
.act(actions::apply_modifier_to_inventory_item(modifier))
|
||||
.act(actions::add_item_to_inventory(character.clone()))
|
||||
.act(actions::as_individual_item())
|
||||
.commit((item_state_proxy, transaction))
|
||||
.await?;
|
||||
|
||||
item_state_proxy.commit();
|
||||
Ok((transaction, item))
|
||||
}).await
|
||||
}
|
@ -4,7 +4,10 @@ use crate::entity::item;
|
||||
use crate::common::leveltable::CharacterStats;
|
||||
use crate::ship::ship::{ShipError};
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::ship::items::state::{InventoryItem, FloorItem, BankState, IndividualItemDetail};
|
||||
use crate::ship::items::inventory::InventoryItem;
|
||||
use crate::ship::items::state::IndividualItemDetail;
|
||||
use crate::ship::items::bank::BankState;
|
||||
use crate::ship::items::floor::FloorItem;
|
||||
use crate::ship::location::AreaClient;
|
||||
use std::convert::TryInto;
|
||||
use crate::ship::shops::ShopItem;
|
||||
|
@ -14,8 +14,10 @@ use crate::entity::item;
|
||||
use libpso::utf8_to_utf16_array;
|
||||
use crate::ship::packet::builder;
|
||||
use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem};
|
||||
use crate::ship::items::state::{ItemState, ItemStateError, FloorType, FloorItemDetail};
|
||||
use crate::ship::items::actions::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, take_meseta, apply_modifier, TriggerCreateItem};
|
||||
use crate::ship::items::state::{ItemState, ItemStateError};
|
||||
use crate::ship::items::floor::{FloorType, FloorItemDetail};
|
||||
use crate::ship::items::actions::TriggerCreateItem;
|
||||
use crate::ship::items::tasks::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, enemy_drops_item, take_meseta, apply_modifier};
|
||||
|
||||
const BANK_ACTION_DEPOSIT: u8 = 0;
|
||||
const BANK_ACTION_WITHDRAW: u8 = 1;
|
||||
|
@ -9,7 +9,7 @@ use crate::ship::location::{ClientLocation, ClientLocationError};
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::ship::packet::builder;
|
||||
use crate::ship::items::state::ItemState;
|
||||
use crate::ship::items::actions::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item, feed_mag, sell_item, take_meseta};
|
||||
use crate::ship::items::tasks::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item, feed_mag, sell_item, take_meseta};
|
||||
|
||||
pub async fn request_exp<EG: EntityGateway>(id: ClientId,
|
||||
request_exp: &RequestExp,
|
||||
|
@ -5,11 +5,12 @@ use crate::common::serverstate::ClientId;
|
||||
use crate::ship::ship::{SendShipPacket, ShipError, Clients};
|
||||
use crate::ship::location::{ClientLocation, ClientLocationError};
|
||||
use crate::ship::items::ClientItemId;
|
||||
use crate::ship::items::state::{ItemState, ItemStateError, InventoryItemDetail};
|
||||
use crate::ship::items::state::{ItemState, ItemStateError};
|
||||
use crate::ship::items::inventory::InventoryItemDetail;
|
||||
use crate::ship::trade::{TradeItem, TradeState, TradeStatus};
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use crate::ship::packet::builder;
|
||||
use crate::ship::items::actions::trade_items;
|
||||
use crate::ship::items::tasks::trade_items;
|
||||
use crate::ship::location::{AreaClient, RoomId};
|
||||
use crate::entity::item::Meseta;
|
||||
|
||||
|
@ -5,7 +5,8 @@ use elseware::entity::item;
|
||||
use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError};
|
||||
use elseware::entity::item::{Meseta, ItemEntity};
|
||||
use elseware::ship::packet::handler::trade::TradeError;
|
||||
use elseware::ship::items::state::{ItemStateError, InventoryError};
|
||||
use elseware::ship::items::state::ItemStateError;
|
||||
use elseware::ship::items::inventory::InventoryError;
|
||||
|
||||
use libpso::packet::ship::*;
|
||||
use libpso::packet::messages::*;
|
||||
|
Loading…
x
Reference in New Issue
Block a user