Browse Source

buy items from shop

pull/112/head
jake 2 years ago
committed by andy
parent
commit
eb9fdb485b
  1. 88
      src/ship/items/actions.rs
  2. 28
      src/ship/items/state.rs
  3. 6
      src/ship/packet/builder/message.rs
  4. 17
      src/ship/packet/handler/direct_message.rs
  5. 13
      src/ship/packet/handler/message.rs
  6. 4
      src/ship/ship.rs

88
src/ship/items/actions.rs

@ -9,8 +9,9 @@ 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::ship::items::apply_item::apply_item;
use crate::entity::item::ItemDetail;
use crate::entity::item::{ItemDetail, ItemEntity, NewItemEntity};
use crate::entity::item::tool::Tool;
use crate::ship::shops::ShopItem;
@ -701,3 +702,88 @@ where
Ok((transaction, ()))
}).await
}
fn add_bought_item_to_inventory<'a>(character_id: CharacterEntityId,
shop_item: &'a (dyn ShopItem + Send + Sync),
item_id: ClientItemId,
amount: u32)
-> impl Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), ())
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem), ItemStateError>> + Send + 'a>>
{
move |(mut item_state, mut transaction), _| {
Box::pin(async move {
let mut inventory = item_state.inventory(&character_id)?;
let bought_item = shop_item.as_item();
let inventory_item = match bought_item {
ItemDetail::Tool(tool) if tool.is_stackable() => {
let mut item_entities = Vec::new();
for _ in 0..amount {
let item_entity = transaction.gateway().create_item(NewItemEntity {
item: ItemDetail::Tool(tool),
}).await?;
transaction.gateway().add_item_note(&item_entity.id, ItemNote::BoughtAtShop {
character_id: character_id,
}).await?;
item_entities.push(item_entity);
}
let inventory_item = InventoryItem {
item_id,
item: InventoryItemDetail::Stacked(StackedItemDetail {
entity_ids: item_entities.into_iter().map(|i| i.id).collect(),
tool: tool,
})
};
inventory.add_item(inventory_item)?.1
},
item_detail => {
let item_entity = transaction.gateway().create_item(NewItemEntity {
item: item_detail.clone(),
}).await?;
transaction.gateway().add_item_note(&item_entity.id, ItemNote::BoughtAtShop {
character_id: character_id,
}).await?;
let inventory_item = InventoryItem {
item_id,
item: InventoryItemDetail::Individual(IndividualItemDetail {
entity_id: item_entity.id,
item: item_detail,
})
};
inventory.add_item(inventory_item)?.1
},
};
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
item_state.set_inventory(inventory);
Ok(((item_state, transaction), inventory_item))
})
}
}
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(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
}

28
src/ship/items/state.rs

@ -600,7 +600,7 @@ impl InventoryState {
}
}
pub fn add_item(&mut self, item: InventoryItem) -> Result<AddItemResult, InventoryError> {
pub fn add_item(&mut self, item: InventoryItem) -> Result<(AddItemResult, InventoryItem), InventoryError> {
match &item.item {
InventoryItemDetail::Individual(_) => {
if self.inventory.0.len() >= 30 {
@ -608,7 +608,13 @@ impl InventoryState {
}
else {
self.inventory.0.push(item);
Ok(AddItemResult::NewItem)
Ok((
AddItemResult::NewItem,
self.inventory.0
.last()
.unwrap()
.clone()
))
}
},
InventoryItemDetail::Stacked(sitem) => {
@ -625,7 +631,15 @@ impl InventoryState {
}
else {
existing_stack.entity_ids.append(&mut sitem.entity_ids.clone());
Ok(AddItemResult::AddToStack)
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 => {
@ -634,7 +648,13 @@ impl InventoryState {
}
else {
self.inventory.0.push(item);
Ok(AddItemResult::NewItem)
Ok((
AddItemResult::NewItem,
self.inventory.0
.last()
.unwrap()
.clone()
))
}
}
}

6
src/ship/packet/builder/message.rs

@ -68,13 +68,13 @@ pub fn create_meseta(area_client: AreaClient, amount: usize) -> CreateItem {
}
}
pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem) -> Result<CreateItem, ShipError> {
let bytes = item.as_client_bytes();
pub fn create_withdrawn_inventory_item(area_client: AreaClient, item: &InventoryItem2) -> Result<CreateItem, ShipError> {
let bytes = item.item.as_client_bytes();
Ok(CreateItem {
client: area_client.local_client.id(),
target: 0,
item_data: bytes[0..12].try_into()?,
item_id: item.item_id().0,
item_id: item.item_id.0,
item_data2: bytes[12..16].try_into()?,
unknown: 0,
})

17
src/ship/packet/handler/direct_message.rs

@ -15,7 +15,7 @@ use libpso::utf8_to_utf16_array;
use crate::ship::packet::builder;
use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem};
use crate::ship::items::state::{ItemState, FloorType, FloorItemDetail};
use crate::ship::items::actions::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, TriggerCreateItem};
use crate::ship::items::actions::{pick_up_item, withdraw_meseta, deposit_meseta, withdraw_item, deposit_item, buy_shop_item, TriggerCreateItem};
const BANK_ACTION_DEPOSIT: u8 = 0;
const BANK_ACTION_WITHDRAW: u8 = 1;
@ -347,7 +347,7 @@ pub async fn buy_item<EG>(id: ClientId,
entity_gateway: &mut EG,
client_location: &ClientLocation,
clients: &mut Clients,
item_manager: &mut ItemManager)
item_state: &mut ItemState)
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
where
EG: EntityGateway
@ -355,7 +355,6 @@ where
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?;
let (item, remove): (&(dyn ShopItem + Send + Sync), bool) = match buy_item.shop_type {
SHOP_OPTION_WEAPON => {
(client.weapon_shop.get(buy_item.shop_index as usize).ok_or(ShipError::ShopError)?, false)
@ -375,16 +374,8 @@ where
}
};
let character_meseta = item_manager.get_character_meseta_mut(&client.character.id)?;
if character_meseta.0 < (item.price() * buy_item.amount as usize) as u32 {
return Err(ShipError::ShopError.into())
}
character_meseta.0 -= (item.price() * buy_item.amount as usize) as u32;
entity_gateway.set_character_meseta(&client.character.id, *character_meseta).await?;
let inventory_item = item_manager.player_buys_item(entity_gateway, &client.character, item, ClientItemId(buy_item.item_id), buy_item.amount as usize).await?;
let create = builder::message::create_withdrawn_inventory_item(area_client, inventory_item)?;
let inventory_item = buy_shop_item(item_state, entity_gateway, &mut client.character, item, ClientItemId(buy_item.item_id), buy_item.amount as u32).await?;
let create = builder::message::create_withdrawn_inventory_item(area_client, &inventory_item)?;
if remove {
match buy_item.shop_type {

13
src/ship/packet/handler/message.rs

@ -395,17 +395,16 @@ where
}
pub async fn player_sells_item<EG> (id: ClientId,
sold_item: &PlayerSoldItem,
entity_gateway: &mut EG,
// client_location: &ClientLocation,
clients: &mut Clients,
item_manager: &mut ItemManager)
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
sold_item: &PlayerSoldItem,
entity_gateway: &mut EG,
clients: &mut Clients,
item_state: &mut ItemState)
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
where
EG: EntityGateway
{
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
item_manager.player_sells_item(entity_gateway, &mut client.character, ClientItemId(sold_item.item_id), sold_item.amount as usize).await?;
//item_manager.player_sells_item(entity_gateway, &mut client.character, ClientItemId(sold_item.item_id), sold_item.amount as usize).await?;
// TODO: send the packet to other clients
Ok(Box::new(None.into_iter()))
}

4
src/ship/ship.rs

@ -523,7 +523,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_state).await?
},
GameMessage::PlayerSoldItem(player_sold_item) => {
handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await?
handler::message::player_sells_item(id, player_sold_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_state).await?
},
_ => {
let cmsg = msg.clone();
@ -562,7 +562,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
handler::direct_message::shop_request(id, shop_request, &block.client_location, &mut self.clients, &block.rooms, &self.level_table, &mut self.shops).await?
},
GameMessage::BuyItem(buy_item) => {
handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await?
handler::direct_message::buy_item(id, buy_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await?
},
GameMessage::TekRequest(tek_request) => {
handler::direct_message::request_tek_item(id, tek_request, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await?

Loading…
Cancel
Save