selling items
This commit is contained in:
		
							parent
							
								
									eb9fdb485b
								
							
						
					
					
						commit
						6bacdd4fe3
					
				| @ -787,3 +787,48 @@ where | ||||
|         Ok((transaction, result)) | ||||
|     }).await | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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>> | ||||
| { | ||||
|     move |(mut item_state, mut transaction), inventory_item| { | ||||
|         Box::pin(async move { | ||||
|             let mut inventory = item_state.inventory(&character_id)?; | ||||
|             let price = inventory_item.item.sell_price()?; | ||||
|             inventory.add_meseta_no_overflow(price)?; | ||||
| 
 | ||||
|             let mut transaction = inventory_item.with_entity_id(transaction, |mut transaction, entity_id| { | ||||
|                 async move { | ||||
|                     transaction.gateway().add_item_note(&entity_id, ItemNote::SoldToShop).await?; | ||||
|                     Ok(transaction) | ||||
|                 }}).await?; | ||||
|             transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?; | ||||
|             item_state.set_inventory(inventory); | ||||
|             Ok(((item_state, transaction), inventory_item)) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| } | ||||
|  | ||||
| @ -9,9 +9,10 @@ use crate::ship::map::MapArea; | ||||
| use crate::ship::location::{AreaClient, RoomId}; | ||||
| use crate::entity::character::{CharacterEntity, CharacterEntityId}; | ||||
| use crate::entity::gateway::{EntityGateway, GatewayError}; | ||||
| use crate::entity::item::tool::Tool; | ||||
| use crate::entity::item::tool::{Tool, ToolType}; | ||||
| use crate::entity::item::mag::Mag; | ||||
| use crate::ship::drops::ItemDrop; | ||||
| use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem}; | ||||
| 
 | ||||
| // TODO: Commit trait that ItemStateProxy and EntityTransaction implement that .commit requires and acts on upon everything succeeding (like 3 less lines of code!)
 | ||||
| 
 | ||||
| @ -65,6 +66,9 @@ pub enum ItemStateError { | ||||
| 
 | ||||
|     #[error("item is not mag food {0}")] | ||||
|     NotMagFood(ClientItemId), | ||||
| 
 | ||||
|     #[error("item is not sellable")] | ||||
|     ItemNotSellable, | ||||
| } | ||||
| 
 | ||||
| pub enum FloorType { | ||||
| @ -299,6 +303,64 @@ impl InventoryItemDetail { | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 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) | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ use crate::ship::location::{ClientLocation, ClientLocationError}; | ||||
| use crate::ship::items::{ItemManager, 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}; | ||||
| use crate::ship::items::actions::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item, feed_mag, sell_item}; | ||||
| 
 | ||||
| pub async fn request_exp<EG: EntityGateway>(id: ClientId, | ||||
|                                             request_exp: &RequestExp, | ||||
| @ -404,7 +404,7 @@ 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?;
 | ||||
|     sell_item(item_state, entity_gateway, &client.character, ClientItemId(sold_item.item_id), sold_item.amount as u32).await?; | ||||
|     // TODO: send the packet to other clients
 | ||||
|     Ok(Box::new(None.into_iter())) | ||||
| } | ||||
|  | ||||
| @ -4,6 +4,7 @@ use elseware::entity::item; | ||||
| use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; | ||||
| use elseware::ship::room::Difficulty; | ||||
| use elseware::ship::items::manager::ItemManagerError; | ||||
| use elseware::ship::items::state::ItemStateError; | ||||
| 
 | ||||
| use libpso::packet::ship::*; | ||||
| use libpso::packet::messages::*; | ||||
| @ -1142,7 +1143,7 @@ async fn test_player_cant_sell_if_meseta_would_go_over_max() { | ||||
|         item_id: 0x10000, | ||||
|         amount: 1, | ||||
|     })))).await.err().unwrap(); | ||||
|     assert!(matches!(ack.downcast::<ItemManagerError>().unwrap(), ItemManagerError::WalletFull)); | ||||
|     assert!(matches!(ack.downcast::<ItemStateError>().unwrap(), ItemStateError::FullOfMeseta)); | ||||
| 
 | ||||
|     let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap(); | ||||
|     assert_eq!(c1_meseta.0, 999995); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user