use_item_jackolantern #124
| @ -241,6 +241,13 @@ impl InventoryItemEntity { | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn stacked(&self) -> Option<&Vec<ItemEntity>> { | ||||
|         match self { | ||||
|             InventoryItemEntity::Stacked(i) => Some(i), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug, Default)] | ||||
|  | ||||
| @ -1,10 +1,14 @@ | ||||
| // 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 async_std::sync::Arc; | ||||
| use std::future::Future; | ||||
| use std::pin::Pin; | ||||
| use std::iter::IntoIterator; | ||||
| 
 | ||||
| use libpso::packet::{ship::Message, messages::GameMessage}; | ||||
| use crate::ship::map::MapArea; | ||||
| use crate::ship::ship::SendShipPacket; | ||||
| use crate::entity::character::{CharacterEntity, CharacterEntityId}; | ||||
| use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; | ||||
| use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail}; | ||||
| @ -17,6 +21,8 @@ use crate::entity::item::tool::Tool; | ||||
| use crate::entity::item::ItemModifier; | ||||
| use crate::ship::shops::ShopItem; | ||||
| use crate::ship::drops::{ItemDrop, ItemDropType}; | ||||
| use crate::ship::packet::builder; | ||||
| use crate::ship::location::AreaClient; | ||||
| 
 | ||||
| type BoxFuture<T> = Pin<Box<dyn Future<Output=T> + Send>>; | ||||
| 
 | ||||
| @ -462,13 +468,14 @@ where | ||||
| 
 | ||||
| 
 | ||||
| pub(super) fn use_consumed_item<EG, TR>( | ||||
|     character: CharacterEntity, | ||||
|     character: &CharacterEntity, | ||||
| ) -> impl Fn((ItemStateProxy, TR), InventoryItem) | ||||
|              -> BoxFuture<Result<((ItemStateProxy, TR), Vec<ApplyItemAction>), ItemStateError>> | ||||
| where | ||||
|     EG: EntityGateway + Clone + 'static, | ||||
|     TR: EntityGatewayTransaction<ParentGateway = EG> + 'static, | ||||
| { | ||||
|     let character = character.clone(); | ||||
|     move |(mut item_state, transaction), inventory_item| { | ||||
|         let mut character = character.clone(); | ||||
|         Box::pin(async move { | ||||
| @ -690,22 +697,22 @@ where | ||||
| 
 | ||||
| 
 | ||||
| #[async_recursion::async_recursion] | ||||
| async fn foreach_inner<'a, EG, TR, O, T, F>( | ||||
| async fn foreach_inner<'a, EG, TR, O, T, F, I>( | ||||
|     state: (ItemStateProxy, TR), | ||||
|     mut input: Vec<T>, | ||||
|     func: F, | ||||
|     mut input: I, | ||||
|     func: Arc<F>, | ||||
| ) -> Result<((ItemStateProxy, TR), Vec<O>), ItemStateError> | ||||
| where | ||||
|     'a: 'async_recursion, | ||||
|     EG: EntityGateway, | ||||
|     TR: EntityGatewayTransaction<ParentGateway = EG> + 'static, | ||||
|     O: Send, | ||||
|     T: Clone + Send, | ||||
|     T: Send, | ||||
|     F: Fn((ItemStateProxy, TR), T) | ||||
|                    -> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync, | ||||
|     F: Clone, | ||||
|     I: Iterator<Item = T> + Send + Sync + 'static, | ||||
| { | ||||
|     let item = match input.pop() { | ||||
|     let item = match input.next() { | ||||
|         Some(item) => item, | ||||
|         None => return Ok((state, Vec::new())) | ||||
|     }; | ||||
| @ -718,9 +725,9 @@ where | ||||
|     Ok((state, output)) | ||||
| } | ||||
| 
 | ||||
| pub(super) fn foreach<EG, TR, O, T, F>( | ||||
| pub(super) fn foreach<EG, TR, O, T, F, I>( | ||||
|     func: F | ||||
| ) -> impl Fn((ItemStateProxy, TR), Vec<T>) | ||||
| ) -> impl Fn((ItemStateProxy, TR), I) | ||||
|                      -> BoxFuture<Result<((ItemStateProxy, TR), Vec<O>), ItemStateError>> | ||||
| where | ||||
|     EG: EntityGateway, | ||||
| @ -729,11 +736,14 @@ where | ||||
|     T: Send + Clone +  'static + std::fmt::Debug, | ||||
|     F: Fn((ItemStateProxy, TR), T) | ||||
|           -> BoxFuture<Result<((ItemStateProxy, TR), O), ItemStateError>> + Send + Sync + 'static, | ||||
|     F: Clone, | ||||
|     T: Clone + Send + Sync, | ||||
|     T: Send + Sync, | ||||
|     I: IntoIterator<Item = T> + Send + Sync + 'static, | ||||
|     I::IntoIter: Send + Sync, | ||||
| { | ||||
|     let func = Arc::new(func); | ||||
|     move |(item_state, transaction), items| { | ||||
|         let func = func.clone(); | ||||
|         let items = items.into_iter(); | ||||
|         Box::pin(async move { | ||||
|             let (state, result) = foreach_inner((item_state, transaction), items, func).await?; | ||||
|             Ok((state, result)) | ||||
| @ -758,6 +768,35 @@ where | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(super) fn fork<EG, TR, F1, F2, T, O1, O2>( | ||||
|     func1: F1, | ||||
|     func2: F2, | ||||
| ) -> impl Fn((ItemStateProxy, TR), T) | ||||
|              -> BoxFuture<Result<((ItemStateProxy, TR), (O1, O2)), ItemStateError>> | ||||
| where | ||||
|     EG: EntityGateway, | ||||
|     TR: EntityGatewayTransaction<ParentGateway = EG> + 'static, | ||||
|     F1: Fn((ItemStateProxy, TR), T) -> BoxFuture<Result<((ItemStateProxy, TR), O1), ItemStateError>> + Send + Sync + 'static, | ||||
|     F2: Fn((ItemStateProxy, TR), T) -> BoxFuture<Result<((ItemStateProxy, TR), O2), ItemStateError>> + Send + Sync + 'static, | ||||
|     T: Send + Sync + Clone + 'static, | ||||
|     O1: Send, | ||||
|     O2: Send, | ||||
| { | ||||
|     let func1 = Arc::new(func1); | ||||
|     let func2 = Arc::new(func2); | ||||
|     move |(item_state, transaction), input| { | ||||
|         let input = input.clone(); | ||||
|         let func1 = func1.clone(); | ||||
|         let func2 = func2.clone(); | ||||
|         Box::pin(async move { | ||||
|             let ((item_state, transaction), result1) = func1((item_state, transaction), input.clone()).await?; | ||||
|             let ((item_state, transaction), result2) = func2((item_state, transaction), input).await?; | ||||
| 
 | ||||
|             Ok(((item_state, transaction), (result1, result2))) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(super) fn add_item_to_inventory<EG, TR>( | ||||
|     character: CharacterEntity, | ||||
| ) -> impl Fn((ItemStateProxy, TR), InventoryItem) | ||||
| @ -994,3 +1033,86 @@ where | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub(super) fn apply_item_action_packets<EG, TR>( | ||||
|     character_id: CharacterEntityId, | ||||
|     area_client: AreaClient, | ||||
| ) -> impl Fn((ItemStateProxy, TR), ApplyItemAction) | ||||
|              -> BoxFuture<Result<((ItemStateProxy, TR), Vec<SendShipPacket>), ItemStateError>> | ||||
| where | ||||
|     EG: EntityGateway, | ||||
|     TR: EntityGatewayTransaction<ParentGateway = EG> + 'static, | ||||
| { | ||||
|     move |(mut item_state, mut transaction), apply_item_action| { | ||||
|         Box::pin(async move { | ||||
|             let pkts = if let ApplyItemAction::CreateItem(item_detail) = apply_item_action { | ||||
|                 let new_item = transaction.gateway().create_item(NewItemEntity { | ||||
|                     item: item_detail.clone(), | ||||
|                 }).await?; | ||||
| 
 | ||||
|                 let item_id = item_state.new_item_id().await?; | ||||
| 
 | ||||
|                 let (inventory_item_detail, create_item) = if item_detail.is_stackable() { | ||||
|                     let tool = item_detail.as_tool().ok_or_else(|| ItemStateError::NotATool(ClientItemId(0xFFFFFFFF)))?; | ||||
| 
 | ||||
|                     let create_item = builder::message::create_stacked_item(area_client, item_id, &tool, 1).map_err(|_err| ItemStateError::Dummy)?; | ||||
|                     let item_detail = StackedItemDetail { | ||||
|                         entity_ids: vec![new_item.id], | ||||
|                         tool | ||||
|                     }; | ||||
|                     (InventoryItemDetail::Stacked(item_detail), create_item) | ||||
|                 } | ||||
|                 else { | ||||
|                     let item_detail = IndividualItemDetail { | ||||
|                         entity_id: new_item.id, | ||||
|                         item: item_detail, | ||||
|                     }; | ||||
|                     let create_item = builder::message::create_individual_item(area_client, item_id, &item_detail).map_err(|_err| ItemStateError::Dummy)?; | ||||
|                     (InventoryItemDetail::Individual(item_detail), create_item) | ||||
|                 }; | ||||
| 
 | ||||
|                 let inventory_item = InventoryItem { | ||||
|                     item_id, | ||||
|                     item: inventory_item_detail, | ||||
|                 }; | ||||
| 
 | ||||
|                 let mut inventory = item_state.inventory(&character_id).await?; | ||||
|                 inventory.add_item(inventory_item)?; | ||||
|                 transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?; | ||||
|                 item_state.set_inventory(inventory).await; | ||||
| 
 | ||||
|                 vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))] | ||||
|             } | ||||
|             else { | ||||
|                 Vec::new() | ||||
|             }; | ||||
| 
 | ||||
|             Ok(((item_state, transaction), pkts)) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(super) fn apply_item_action_character<EG, TR>( | ||||
|     character: &CharacterEntity | ||||
| ) -> impl Fn((ItemStateProxy, TR), Vec<ApplyItemAction>) | ||||
|              -> BoxFuture<Result<((ItemStateProxy, TR), CharacterEntity), ItemStateError>> | ||||
| where | ||||
|     EG: EntityGateway, | ||||
|     TR: EntityGatewayTransaction<ParentGateway = EG> + 'static, | ||||
| { | ||||
|     let character = character.clone(); | ||||
|     move |(item_state, transaction), apply_item_actions| { | ||||
|         let mut character = character.clone(); | ||||
|         Box::pin(async move { | ||||
|             for action in apply_item_actions { | ||||
|                 match action { | ||||
|                     ApplyItemAction::UpdateCharacter(new_character) => character = *new_character, | ||||
|                     _ => {} | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             Ok(((item_state, transaction), character)) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -2,10 +2,12 @@ use std::convert::TryInto; | ||||
| use futures::future::{join_all, BoxFuture, LocalBoxFuture}; | ||||
| use futures::stream::{FuturesOrdered, StreamExt}; | ||||
| use thiserror::Error; | ||||
| use rand::{Rng, SeedableRng}; | ||||
| use rand::distributions::{WeightedIndex, Distribution}; | ||||
| use crate::entity::gateway::{EntityGateway, GatewayError}; | ||||
| use crate::entity::character::CharacterEntity; | ||||
| use crate::entity::item::mag::{MagCell, MagCellError}; | ||||
| use crate::entity::item::tool::ToolType; | ||||
| use crate::entity::item::mag::{MagType, MagCell, MagCellError}; | ||||
| use crate::entity::item::tool::{Tool, ToolType}; | ||||
| use crate::entity::item::{ItemDetail, ItemEntityId}; | ||||
| use crate::ship::items::state::{ItemStateProxy, ItemStateError}; | ||||
| use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail}; | ||||
| @ -29,9 +31,12 @@ pub enum ApplyItemError { | ||||
|     MagCellError(#[from] MagCellError), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum ApplyItemAction { | ||||
|     UpdateCharacter(CharacterEntity), | ||||
|     CreateItem(()), | ||||
|     UpdateCharacter(Box<CharacterEntity>), | ||||
|     CreateItem(ItemDetail), | ||||
|     //TransformItem,
 | ||||
|     //RemoveItem,
 | ||||
| } | ||||
| 
 | ||||
| impl From<ItemStateError> for ApplyItemError { | ||||
| @ -43,43 +48,43 @@ impl From<ItemStateError> for ApplyItemError { | ||||
| async fn power_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { | ||||
|     character.materials.power += 1; | ||||
|     entity_gateway.save_character(character).await?; | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) | ||||
| } | ||||
| 
 | ||||
| async fn mind_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { | ||||
|     character.materials.mind += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) | ||||
| } | ||||
| 
 | ||||
| async fn evade_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { | ||||
|     character.materials.evade += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) | ||||
| } | ||||
| 
 | ||||
| async fn def_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { | ||||
|     character.materials.def += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) | ||||
| } | ||||
| 
 | ||||
| async fn luck_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { | ||||
|     character.materials.luck += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) | ||||
| } | ||||
| 
 | ||||
| async fn hp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { | ||||
|     character.materials.hp += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) | ||||
| } | ||||
| 
 | ||||
| async fn tp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<Vec<ApplyItemAction>, ApplyItemError> { | ||||
|     character.materials.tp += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(character.clone())]) | ||||
|     Ok(vec![ApplyItemAction::UpdateCharacter(Box::new(character.clone()))]) | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| @ -224,13 +229,23 @@ pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| async fn jack_o_lantern<'a, EG>(item_state: &mut ItemStateProxy, | ||||
|                                 entity_gateway: &mut EG | ||||
| ) -> Result<Vec<ApplyItemAction>, ApplyItemError> | ||||
| where | ||||
|     EG: EntityGateway + ?Sized, | ||||
| 
 | ||||
| fn jack_o_lantern() -> Result<Vec<ApplyItemAction>, ApplyItemError> | ||||
| { | ||||
|     Ok(Vec::new()) | ||||
|     let mag_rate = WeightedIndex::new(&[13, 13, 13, 13, 12, 12, 12, 12]).unwrap(); | ||||
|     let mag_type = match mag_rate.sample(&mut rand_chacha::ChaChaRng::from_entropy()) { | ||||
|         0 => ToolType::CellOfMag502, | ||||
|         1 => ToolType::CellOfMag213, | ||||
|         2 => ToolType::HeartOfChuChu, | ||||
|         3 => ToolType::HeartOfKapuKapu, | ||||
|         4 => ToolType::PartsOfRobochao, | ||||
|         5 => ToolType::HeartOfOpaOpa, | ||||
|         6 => ToolType::HeartOfPian, | ||||
|         7 => ToolType::HeartOfChao, | ||||
|         _ => unreachable!(), | ||||
|     }; | ||||
| 
 | ||||
|     Ok(vec![ApplyItemAction::CreateItem(ItemDetail::Tool(Tool {tool: mag_type}))]) | ||||
| } | ||||
| 
 | ||||
| async fn apply_tool<'a, EG>(item_state: &mut ItemStateProxy, | ||||
| @ -283,7 +298,7 @@ where | ||||
|             | ToolType::LibertaKit => { | ||||
|                 mag_cell(item_state, entity_gateway, character, entity_id, tool.try_into()?).await | ||||
|             } | ||||
|         ToolType::JackOLantern => jack_o_lantern(item_state, entity_gateway).await, | ||||
|         ToolType::JackOLantern => jack_o_lantern(), | ||||
|         // TODO: rest of these
 | ||||
|         _ => Err(ApplyItemError::InvalidItem) | ||||
|     } | ||||
|  | ||||
| @ -179,7 +179,7 @@ pub enum InventoryError { | ||||
|     MesetaFull, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct InventoryState { | ||||
|     pub character_id: CharacterEntityId, | ||||
|     pub item_id_counter: u32, | ||||
|  | ||||
| @ -124,7 +124,7 @@ pub enum AddItemResult { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct ItemState { | ||||
|     character_inventory: Arc<RwLock<HashMap<CharacterEntityId, RwLock<InventoryState>>>>, | ||||
|     character_bank: Arc<RwLock<HashMap<CharacterEntityId, RwLock<BankState>>>>, | ||||
|  | ||||
| @ -272,22 +272,28 @@ pub async fn use_item<'a, EG> ( | ||||
|     item_state: &'a mut ItemState, | ||||
|     entity_gateway: &mut EG, | ||||
|     character: &mut CharacterEntity, | ||||
|     area_client: AreaClient, | ||||
|     item_id: &ClientItemId, | ||||
|     amount: u32, | ||||
| ) -> Result<(), ItemStateError> | ||||
| ) -> Result<Vec<SendShipPacket>, ItemStateError> | ||||
| where | ||||
|     EG: EntityGateway + 'static, | ||||
| { | ||||
|     entity_gateway.with_transaction(|transaction| async move { | ||||
|         let item_state_proxy = ItemStateProxy::new(item_state.clone()); | ||||
|         let ((item_state_proxy, transaction), apply_item_actions) = ItemStateAction::default() | ||||
|         let ((item_state_proxy, transaction), (pkts, new_character)) = ItemStateAction::default() | ||||
|             .act(actions::take_item_from_inventory(character.id, *item_id, amount)) | ||||
|             .act(actions::use_consumed_item(character.clone())) | ||||
|             .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, ())) | ||||
|         Ok((transaction, pkts.into_iter().flatten().collect())) | ||||
|     }).await | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -330,20 +330,32 @@ where | ||||
| pub async fn player_uses_item<EG>(id: ClientId, | ||||
|                                   player_use_tool: PlayerUseItem, | ||||
|                                   entity_gateway: &mut EG, | ||||
|                                   _client_location: &ClientLocation, | ||||
|                                   client_location: &ClientLocation, | ||||
|                                   clients: &Clients, | ||||
|                                   item_state: &mut ItemState) | ||||
|                                   -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> | ||||
| where | ||||
|     EG: EntityGateway + Clone + 'static, | ||||
| { | ||||
|     clients.with_mut(id, |client| { | ||||
|     let neighbors = client_location.get_all_clients_by_client(id).await?.into_iter(); | ||||
|     let area_client = client_location.get_local_client(id).await?; | ||||
| 
 | ||||
|     Ok(clients.with_mut(id, |client| { | ||||
|         let mut entity_gateway = entity_gateway.clone(); | ||||
|         let mut item_state = item_state.clone(); | ||||
|         Box::pin(async move { | ||||
|             use_item(&mut item_state, &mut entity_gateway, &mut client.character, &ClientItemId(player_use_tool.item_id), 1).await | ||||
|         })}).await??; | ||||
|     Ok(Vec::new()) | ||||
|             use_item(&mut item_state, &mut entity_gateway, &mut client.character, area_client, &ClientItemId(player_use_tool.item_id), 1).await | ||||
|         })}).await?? | ||||
|        .into_iter() | ||||
|        .flat_map(move |pkt| { | ||||
|            let player_use_tool = player_use_tool.clone(); | ||||
|            neighbors.clone().map(move |client| { | ||||
|                vec![(client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerUseItem(player_use_tool.clone())))), (client.client, pkt.clone())] | ||||
|            }) | ||||
|        }) | ||||
|        .flatten() | ||||
|        .collect::<Vec<_>>() | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| pub async fn player_used_medical_center<EG>(id: ClientId, | ||||
|  | ||||
| @ -251,6 +251,59 @@ async fn test_use_materials() { | ||||
|     assert!(char.materials.luck == 2); | ||||
| } | ||||
| 
 | ||||
| #[async_std::test] | ||||
| async fn test_jackolantern() { | ||||
|     let mut entity_gateway = InMemoryGateway::default(); | ||||
|     let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; | ||||
| 
 | ||||
|     let p1_inv = vec![ | ||||
|         item::InventoryItemEntity::Stacked( | ||||
|             vec![ | ||||
|                 entity_gateway.create_item( | ||||
|                     item::NewItemEntity { | ||||
|                         item: item::ItemDetail::Tool( | ||||
|                             item::tool::Tool { | ||||
|                                 tool: item::tool::ToolType::JackOLantern, | ||||
|                             } | ||||
|                         ), | ||||
|                     }).await.unwrap(), | ||||
|                 entity_gateway.create_item(item::NewItemEntity { | ||||
|                     item: item::ItemDetail::Tool( | ||||
|                         item::tool::Tool { | ||||
|                             tool: item::tool::ToolType::JackOLantern, | ||||
|                         } | ||||
|                     ), | ||||
|                 }).await.unwrap(), | ||||
|             ])]; | ||||
|     entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap(); | ||||
| 
 | ||||
|     let mut ship = Box::new(ShipServerState::builder() | ||||
|         .gateway(entity_gateway.clone()) | ||||
|         .build()); | ||||
|     log_in_char(&mut ship, ClientId(1), "a1", "a").await; | ||||
|     join_lobby(&mut ship, ClientId(1)).await; | ||||
|     create_room(&mut ship, ClientId(1), "room", "").await; | ||||
| 
 | ||||
|     ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { | ||||
|         client: 0, | ||||
|         target: 0, | ||||
|         item_id: 0x10000, | ||||
|     })))).await.unwrap(); | ||||
| 
 | ||||
|     ship.handle(ClientId(1), RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { | ||||
|         client: 0, | ||||
|         target: 0, | ||||
|         item_id: 0x10000, | ||||
|     })))).await.unwrap(); | ||||
| 
 | ||||
|     let inventory_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap(); | ||||
|     for item in inventory_items.items { | ||||
|         for sitem in item.stacked().unwrap() { | ||||
|             assert!(sitem.item.clone().as_tool().unwrap().tool.is_mag_cell()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // TODO: tests for ALL ITEMS WOW
 | ||||
| 
 | ||||
| /* | ||||
|  | ||||
| @ -1792,7 +1792,7 @@ async fn test_trade_multiple_individual() { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 1, | ||||
|             item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
 | ||||
|             item_id: 0x810003, | ||||
|             item_id: 0x810004, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -1801,7 +1801,7 @@ async fn test_trade_multiple_individual() { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 1, | ||||
|             item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
 | ||||
|             item_id: 0x810003, | ||||
|             item_id: 0x810004, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -1810,7 +1810,7 @@ async fn test_trade_multiple_individual() { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 1, | ||||
|             item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
 | ||||
|             item_id: 0x810004, | ||||
|             item_id: 0x810003, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -1819,7 +1819,7 @@ async fn test_trade_multiple_individual() { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 1, | ||||
|             item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
 | ||||
|             item_id: 0x810004, | ||||
|             item_id: 0x810003, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -1828,7 +1828,7 @@ async fn test_trade_multiple_individual() { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 0, | ||||
|             item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
 | ||||
|             item_id: 0x810001, | ||||
|             item_id: 0x810002, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -1837,7 +1837,7 @@ async fn test_trade_multiple_individual() { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 0, | ||||
|             item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
 | ||||
|             item_id: 0x810001, | ||||
|             item_id: 0x810002, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -1846,7 +1846,7 @@ async fn test_trade_multiple_individual() { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 0, | ||||
|             item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
 | ||||
|             item_id: 0x810002, | ||||
|             item_id: 0x810001, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -1855,7 +1855,7 @@ async fn test_trade_multiple_individual() { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 0, | ||||
|             item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
 | ||||
|             item_id: 0x810002, | ||||
|             item_id: 0x810001, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -2063,7 +2063,7 @@ async fn test_trade_multiple_stacked() { | ||||
|     assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 1, | ||||
|             item_id: 0x810003, | ||||
|             item_id: 0x810004, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -2071,7 +2071,7 @@ async fn test_trade_multiple_stacked() { | ||||
|     assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 1, | ||||
|             item_id: 0x810003, | ||||
|             item_id: 0x810004, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -2079,7 +2079,7 @@ async fn test_trade_multiple_stacked() { | ||||
|     assert!(matches!(ack[6], (ClientId(1), SendShipPacket::Message(Message { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 1, | ||||
|             item_id: 0x810004, | ||||
|             item_id: 0x810003, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -2087,7 +2087,7 @@ async fn test_trade_multiple_stacked() { | ||||
|     assert!(matches!(ack[7], (ClientId(2), SendShipPacket::Message(Message { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 1, | ||||
|             item_id: 0x810004, | ||||
|             item_id: 0x810003, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -2095,7 +2095,7 @@ async fn test_trade_multiple_stacked() { | ||||
|     assert!(matches!(ack[8], (ClientId(1), SendShipPacket::Message(Message { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 0, | ||||
|             item_id: 0x810001, | ||||
|             item_id: 0x810002, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -2103,7 +2103,7 @@ async fn test_trade_multiple_stacked() { | ||||
|     assert!(matches!(ack[9], (ClientId(2), SendShipPacket::Message(Message { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 0, | ||||
|             item_id: 0x810001, | ||||
|             item_id: 0x810002, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -2111,7 +2111,7 @@ async fn test_trade_multiple_stacked() { | ||||
|     assert!(matches!(ack[10], (ClientId(1), SendShipPacket::Message(Message { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 0, | ||||
|             item_id: 0x810002, | ||||
|             item_id: 0x810001, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
| @ -2119,7 +2119,7 @@ async fn test_trade_multiple_stacked() { | ||||
|     assert!(matches!(ack[11], (ClientId(2), SendShipPacket::Message(Message { | ||||
|         msg: GameMessage::CreateItem(CreateItem { | ||||
|             client: 0, | ||||
|             item_id: 0x810002, | ||||
|             item_id: 0x810001, | ||||
|             .. | ||||
|         }), | ||||
|         .. | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user