use futures::future::BoxFuture; use crate::ship::items::ClientItemId; use crate::entity::item::Meseta; use crate::ship::ship::SendShipPacket; use crate::ship::map::MapArea; use crate::entity::character::{CharacterEntity, CharacterEntityId}; use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; use crate::entity::item::ItemModifier; use crate::entity::room::RoomEntityId; use crate::ship::items::state::{ItemState, ItemStateProxy, IndividualItemDetail}; use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction}; use crate::ship::items::inventory::InventoryItem; use crate::ship::items::floor::FloorItem; use crate::ship::shops::ShopItem; use crate::ship::trade::TradeItem; use crate::ship::location::AreaClient; use crate::ship::drops::ItemDrop; use crate::ship::monster::MonsterType; use crate::ship::items::actions; pub fn pick_up_item<'a, EG>( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: &'a ClientItemId, ) -> BoxFuture<'a, Result> where EG: EntityGateway + 'static, EG::Transaction<'a>: Clone, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn drop_item<'a, EG>( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: &'a ClientItemId, map_area: MapArea, drop_position: (f32, f32, f32), )-> BoxFuture<'a, Result> where EG: EntityGateway + 'static, EG::Transaction<'a>: Clone, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn drop_partial_item<'a, EG>( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: &'a ClientItemId, map_area: MapArea, drop_position: (f32, f32), amount: u32 ) -> BoxFuture<'a, Result> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn drop_meseta<'a, EG>( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, map_area: MapArea, drop_position: (f32, f32), amount: u32, ) -> BoxFuture<'a, Result> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn withdraw_meseta<'a, EG>( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, amount: u32, ) -> BoxFuture<'a, Result<(), anyhow::Error>> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn deposit_meseta<'a, EG>( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, amount: u32, ) -> BoxFuture<'a, Result<(), anyhow::Error>> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, ())) }) } pub fn withdraw_item<'a, EG>( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: &'a ClientItemId, amount: u32, ) -> BoxFuture<'a, Result> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn deposit_item<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: &'a ClientItemId, amount: u32, ) -> BoxFuture<'a, Result<(), anyhow::Error>> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn equip_item<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: &'a ClientItemId, equip_slot: u8, ) -> BoxFuture<'a, Result<(), anyhow::Error>> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn unequip_item<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: &'a ClientItemId, ) -> BoxFuture<'a, Result<(), anyhow::Error>> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn sort_inventory<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_ids: Vec, ) -> BoxFuture<'a, Result<(), anyhow::Error>> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn use_item<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a mut CharacterEntity, area_client: AreaClient, item_id: &'a ClientItemId, amount: u32, ) -> BoxFuture<'a, Result, anyhow::Error>> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), (pkts, new_character)) = ItemStateAction::default() .act(actions::remove_item_from_inventory(character.id, *item_id, amount)) .act(actions::use_consumed_item(character)) .act(actions::fork( actions::foreach(actions::apply_item_action_packets(character.id, area_client)), actions::apply_item_action_character(character) )) .commit((item_state_proxy, transaction)) .await?; item_state_proxy.commit().await; *character = new_character; Ok((transaction, pkts.into_iter().flatten().collect())) }) } pub fn feed_mag<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, mag_item_id: &'a ClientItemId, tool_item_id: &'a ClientItemId, ) -> BoxFuture<'a, Result<(), anyhow::Error>> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, ())) }) } pub fn buy_shop_item<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, shop_item: &'a (dyn ShopItem + Send + Sync), item_id: ClientItemId, amount: u32, ) -> BoxFuture<'a, Result> where EG: EntityGateway + 'static, { let item_price = shop_item.price() as u32 * amount; entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn sell_item<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: ClientItemId, amount: u32, ) -> BoxFuture<'a, Result> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, result)) }) } pub fn trade_items<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, p1: (&'a AreaClient, &'a CharacterEntity, &'a Vec, Meseta), p2: (&'a AreaClient, &'a CharacterEntity, &'a Vec, Meseta)) -> BoxFuture<'a, Result<(Vec, Vec), anyhow::Error>> where EG: EntityGateway + 'static, { 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(move |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.clone()); 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().await; Ok((transaction, (p1_new_items, p2_new_items))) }) } pub fn take_meseta<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character_id: &'a CharacterEntityId, meseta: Meseta) -> BoxFuture<'a, Result<(), anyhow::Error>> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, ())) }) } pub fn enemy_drops_item<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character_id: CharacterEntityId, room_id: RoomEntityId, monster_type: MonsterType, item_drop: ItemDrop) -> BoxFuture<'a, Result> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default() .act(actions::convert_item_drop_to_floor_item(item_drop)) .act(actions::item_note_enemy_drop(character_id, room_id, monster_type)) .act(actions::add_item_to_local_floor(character_id)) .commit((item_state_proxy, transaction)) .await?; item_state_proxy.commit().await; Ok((transaction, floor_item)) }) } pub fn box_drops_item<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character_id: CharacterEntityId, room_id: RoomEntityId, item_drop: ItemDrop) -> BoxFuture<'a, Result> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default() .act(actions::convert_item_drop_to_floor_item(item_drop)) .act(actions::item_note_box_drop(character_id, room_id)) .act(actions::add_item_to_local_floor(character_id)) .commit((item_state_proxy, transaction)) .await?; item_state_proxy.commit().await; Ok((transaction, floor_item)) }) } pub fn apply_modifier<'a, EG> ( item_state: &'a mut ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: ClientItemId, modifier: ItemModifier) -> BoxFuture<'a, Result> where EG: EntityGateway + 'static, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); 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().await; Ok((transaction, item)) }) } pub fn floor_item_limit_reached<'a, EG> ( item_state: &'a ItemState, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_id: &'a ClientItemId, map_area: MapArea ) -> BoxFuture<'a, Result<(), anyhow::Error>> where EG: EntityGateway + 'static, EG::Transaction<'a>: Clone, { entity_gateway.with_transaction(move |transaction| async move { let item_state_proxy = ItemStateProxy::new(item_state.clone()); let((item_state_proxy, transaction), result) = ItemStateAction::default() .act(actions::take_item_from_floor(character.id, *item_id)) .act(actions::delete_item_from_floor(map_area)) .commit((item_state_proxy, transaction)) .await?; item_state_proxy.commit().await; Ok((transaction, result)) }) }