selling items
This commit is contained in:
		
							parent
							
								
									ad7572b726
								
							
						
					
					
						commit
						fad0ccc856
					
				@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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::*;
 | 
			
		||||
@ -1149,7 +1150,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