bare minimum item usage stuff
This commit is contained in:
		
							parent
							
								
									eb23cc2dfd
								
							
						
					
					
						commit
						faf00a904a
					
				| @ -7,7 +7,10 @@ use crate::ship::map::MapArea; | ||||
| use crate::entity::character::{CharacterEntity, CharacterEntityId}; | ||||
| use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction}; | ||||
| use crate::ship::items::state::{ItemState, ItemStateProxy, ItemStateAction, ItemAction, ItemStateError, FloorItem, InventoryItem, AddItemResult, FloorItemDetail, | ||||
|                                 StackedItemDetail, BankItem, BankItemDetail, InventoryItemDetail}; | ||||
|                                 StackedItemDetail, BankItem, BankItemDetail, InventoryItemDetail, IndividualItemDetail}; | ||||
| use crate::ship::items::apply_item::apply_item; | ||||
| use crate::entity::item::ItemDetail; | ||||
| use crate::entity::item::tool::Tool; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @ -597,3 +600,50 @@ where | ||||
|         Ok((transaction, result)) | ||||
|     }).await | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| fn use_consumed_item(character: CharacterEntity) | ||||
|                       -> impl for<'a> Fn((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), InventoryItem) | ||||
|                                          -> Pin<Box<dyn Future<Output=Result<((ItemStateProxy<'a>, Box<dyn EntityGatewayTransaction + 'a>), CharacterEntity), ItemStateError>> + Send + 'a>> | ||||
| { | ||||
|     move |(mut item_state, mut transaction), inventory_item| { | ||||
|         let mut character = character.clone(); | ||||
|         Box::pin(async move { | ||||
|             let mut transaction = inventory_item.with_entity_id(Ok(transaction), |mut transaction: Result<_, ItemStateError>, entity_id| { | ||||
|                 async move { | ||||
|                     if let Ok(transaction) = &mut transaction { | ||||
|                         transaction.gateway().add_item_note(&entity_id, ItemNote::Consumed).await?; | ||||
|                     } | ||||
|                     transaction | ||||
|                 }}).await?; | ||||
| 
 | ||||
|             apply_item(&mut item_state, transaction.gateway(), &mut character, inventory_item).await?; | ||||
| 
 | ||||
|             Ok(((item_state, transaction), character)) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub async fn use_item<'a, EG> ( | ||||
|     item_state: &'a mut ItemState, | ||||
|     entity_gateway: &mut EG, | ||||
|     character: &mut CharacterEntity, | ||||
|     item_id: &ClientItemId, | ||||
|     amount: u32, | ||||
| ) -> Result<(), ItemStateError> | ||||
| where | ||||
|     EG: EntityGateway, | ||||
| { | ||||
|     entity_gateway.with_transaction(|transaction| async move { | ||||
|         let item_state_proxy = ItemStateProxy::new(item_state); | ||||
|         let ((item_state_proxy, transaction), new_character) = ItemStateAction::default() | ||||
|             //.act(consume_inventory_tool(character.id, *item_id, 1))
 | ||||
|             .act(take_item_from_inventory(character.id, *item_id, amount)) | ||||
|             .act(use_consumed_item(character.clone())) | ||||
|             .commit((item_state_proxy, transaction)) | ||||
|             .await?; | ||||
|         item_state_proxy.commit(); | ||||
|         *character = new_character; | ||||
|         Ok((transaction, ())) | ||||
|     }).await | ||||
| } | ||||
|  | ||||
							
								
								
									
										219
									
								
								src/ship/items/apply_item.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								src/ship/items/apply_item.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,219 @@ | ||||
| use thiserror::Error; | ||||
| use crate::entity::gateway::{EntityGateway, GatewayError}; | ||||
| use crate::entity::character::CharacterEntity; | ||||
| use crate::entity::item::mag::MagCell; | ||||
| use crate::entity::item::tool::ToolType; | ||||
| use crate::entity::item::ItemDetail; | ||||
| use crate::ship::items::state::{ItemStateProxy, InventoryState, InventoryItem, InventoryItemDetail}; | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Error, Debug)] | ||||
| pub enum ApplyItemError { | ||||
|     #[error("no character")] | ||||
|     NoCharacter, | ||||
|     #[error("item not equipped")] | ||||
|     ItemNotEquipped, | ||||
|     #[error("invalid item")] | ||||
|     InvalidItem, | ||||
|     #[error("gateway error {0}")] | ||||
|     GatewayError(#[from] GatewayError), | ||||
| } | ||||
| 
 | ||||
| // TODO: make all these functions not-pub
 | ||||
| pub async fn power_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> { | ||||
|     character.materials.power += 1; | ||||
|     entity_gateway.save_character(character).await?; | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub async fn mind_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> { | ||||
|     character.materials.mind += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub async fn evade_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> { | ||||
|     character.materials.evade += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub async fn def_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> { | ||||
|     character.materials.def += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub async fn luck_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> { | ||||
|     character.materials.luck += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub async fn hp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> { | ||||
|     character.materials.hp += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub async fn tp_material<EG: EntityGateway + ?Sized>(entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ApplyItemError> { | ||||
|     character.materials.tp += 1; | ||||
|     entity_gateway.save_character(character).await.unwrap(); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| async fn mag_cell<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory, mag_cell_type: MagCell) -> Result<(), ApplyItemError> { | ||||
|     let mut mag_handle = inventory.get_equipped_mag_handle().ok_or(ApplyItemError::ItemNotEquipped)?; | ||||
|     let mag_item = mag_handle.item_mut() | ||||
|         .ok_or(ApplyItemError::InvalidItem)?; | ||||
|     let actual_mag = mag_item | ||||
|         .individual_mut() | ||||
|         .ok_or(ApplyItemError::InvalidItem)? | ||||
|         .mag_mut() | ||||
|         .ok_or(ApplyItemError::InvalidItem)?; | ||||
|     actual_mag.apply_mag_cell(mag_cell_type); | ||||
|     for mag_entity_id in mag_item.entity_ids() { | ||||
|         for cell_entity_id in used_cell.entity_ids() { | ||||
|             entity_gateway.use_mag_cell(&mag_entity_id, &cell_entity_id).await.unwrap(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub async fn cell_of_mag_502<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag502).await | ||||
| } | ||||
| 
 | ||||
| pub async fn cell_of_mag_213<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag213).await | ||||
| } | ||||
| 
 | ||||
| pub async fn parts_of_robochao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::PartsOfRobochao).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_opaopa<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfOpaOpa).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_pian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfPian).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_chao<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfChao).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_angel<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfAngel).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_hamburger<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfHamburger).await | ||||
| } | ||||
| 
 | ||||
| pub async fn panthers_spirit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::PanthersSpirit).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_mark3<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMark3).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_master_system<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMasterSystem).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_genesis<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfGenesis).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_sega_saturn<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfSegaSaturn).await | ||||
| } | ||||
| 
 | ||||
| pub async fn kit_of_dreamcast<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfDreamcast).await | ||||
| } | ||||
| 
 | ||||
| pub async fn tablet<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::Tablet).await | ||||
| } | ||||
| 
 | ||||
| pub async fn dragon_scale<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::DragonScale).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heaven_striker_coat<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeavenStrikerCoat).await | ||||
| } | ||||
| 
 | ||||
| pub async fn pioneer_parts<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::PioneerParts).await | ||||
| } | ||||
| 
 | ||||
| pub async fn amities_memo<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::AmitiesMemo).await | ||||
| } | ||||
| 
 | ||||
| pub async fn heart_of_morolian<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfMorolian).await | ||||
| } | ||||
| 
 | ||||
| pub async fn rappys_beak<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::RappysBeak).await | ||||
| } | ||||
| 
 | ||||
| pub async fn yahoos_engine<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::YahoosEngine).await | ||||
| } | ||||
| 
 | ||||
| pub async fn d_photon_core<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::DPhotonCore).await | ||||
| } | ||||
| 
 | ||||
| pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), ApplyItemError> { | ||||
|     mag_cell(entity_gateway, used_cell, inventory, MagCell::LibertaKit).await | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| async fn apply_tool<'a, EG: EntityGateway + ?Sized>(item_state: &mut ItemStateProxy<'a>, entity_gateway: &mut EG, character: &mut CharacterEntity, tool: ToolType) -> Result<(), ApplyItemError> { | ||||
|     match tool { | ||||
|         ToolType::PowerMaterial => power_material(entity_gateway, character).await, | ||||
|         ToolType::MindMaterial => mind_material(entity_gateway, character).await, | ||||
|         ToolType::EvadeMaterial => evade_material(entity_gateway, character).await, | ||||
|         ToolType::DefMaterial => def_material(entity_gateway, character).await, | ||||
|         ToolType::LuckMaterial => luck_material(entity_gateway, character).await, | ||||
|         ToolType::HpMaterial => hp_material(entity_gateway, character).await, | ||||
|         ToolType::TpMaterial => tp_material(entity_gateway, character).await, | ||||
|         ToolType::Monomate => Ok(()), | ||||
|         ToolType::Dimate => Ok(()), | ||||
|         ToolType::Trimate => Ok(()), | ||||
|         ToolType::Monofluid => Ok(()), | ||||
|         ToolType::Difluid => Ok(()), | ||||
|         ToolType::Trifluid => Ok(()), | ||||
|         ToolType::HuntersReport => Ok(()), | ||||
|         // TODO: rest of these
 | ||||
|         _ => Err(ApplyItemError::InvalidItem) | ||||
|     } | ||||
|     
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub async fn apply_item<'a, EG: EntityGateway + ?Sized>(item_state: &mut ItemStateProxy<'a>, entity_gateway: &mut EG, character: &mut CharacterEntity, item: InventoryItem) -> Result<(), ApplyItemError> { | ||||
|     let item_detail = match item.item { | ||||
|         InventoryItemDetail::Individual(individual_item) => { | ||||
|             individual_item.item | ||||
|         }, | ||||
|         InventoryItemDetail::Stacked(stacked_item) => { | ||||
|             ItemDetail::Tool(stacked_item.tool) | ||||
|         }, | ||||
|     }; | ||||
| 
 | ||||
|     match item_detail { | ||||
|         ItemDetail::Tool(tool) => apply_tool(item_state, entity_gateway, character, tool.tool).await, | ||||
|         _ => Err(ApplyItemError::InvalidItem) | ||||
|     } | ||||
| } | ||||
| @ -6,6 +6,7 @@ pub mod transaction; | ||||
| pub mod use_tool; | ||||
| pub mod state; | ||||
| pub mod actions; | ||||
| pub mod apply_item; | ||||
| use serde::{Serialize, Deserialize}; | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, derive_more::Display)] | ||||
|  | ||||
| @ -24,6 +24,9 @@ pub enum ItemStateError { | ||||
|     #[error("floor item {0} not found")] | ||||
|     NoFloorItem(ClientItemId), | ||||
| 
 | ||||
|     #[error("expected {0} to be a tool")] | ||||
|     NotATool(ClientItemId), | ||||
| 
 | ||||
|     #[error("bank item {0} not found")] | ||||
|     NoBankItem(ClientItemId), | ||||
| 
 | ||||
| @ -50,6 +53,9 @@ pub enum ItemStateError { | ||||
| 
 | ||||
|     #[error("stacked item")] | ||||
|     StackedItemError(Vec<ItemEntity>), | ||||
| 
 | ||||
|     #[error("apply item {0}")] | ||||
|     ApplyItemError(#[from] crate::ship::items::apply_item::ApplyItemError), | ||||
| } | ||||
| 
 | ||||
| pub enum FloorType { | ||||
|  | ||||
| @ -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 crate::ship::items::actions::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item, sort_inventory, use_item}; | ||||
| 
 | ||||
| pub async fn request_exp<EG: EntityGateway>(id: ClientId, | ||||
|                                             request_exp: &RequestExp, | ||||
| @ -278,20 +278,18 @@ where | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub async fn use_item<EG>(id: ClientId, | ||||
| pub async fn player_uses_item<EG>(id: ClientId, | ||||
|                           player_use_tool: &PlayerUseItem, | ||||
|                           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 | ||||
| { | ||||
|     let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; | ||||
|     let item_used_type = item_manager.player_consumes_tool(entity_gateway, &mut client.character, ClientItemId(player_use_tool.item_id), 1).await?; | ||||
| 
 | ||||
|     item_manager.use_item(item_used_type, entity_gateway, &mut client.character).await?; | ||||
|     use_item(item_state, entity_gateway, &mut client.character, &ClientItemId(player_use_tool.item_id), 1).await?; | ||||
|     Ok(Box::new(None.into_iter())) // TODO: should probably tell other players we used an item
 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -502,7 +502,7 @@ impl<EG: EntityGateway> ShipServerState<EG> { | ||||
|             }, | ||||
|             GameMessage::PlayerUseItem(player_use_item) => { | ||||
|                 let block = self.blocks.with_client(id, &self.clients)?; | ||||
|                 handler::message::use_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager).await? | ||||
|                 handler::message::player_uses_item(id, player_use_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_state).await? | ||||
|             }, | ||||
|             GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => { | ||||
|                 handler::message::player_used_medical_center(id, player_used_medical_center, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await? | ||||
|  | ||||
| @ -164,7 +164,7 @@ async fn test_use_nonstackable_tool() { | ||||
|         item::NewItemEntity { | ||||
|             item: item::ItemDetail::Tool( | ||||
|                 item::tool::Tool { | ||||
|                     tool: item::tool::ToolType::MagicStoneIritista, | ||||
|                     tool: item::tool::ToolType::HuntersReport, | ||||
|                 } | ||||
|             ), | ||||
|         }).await.unwrap()); | ||||
| @ -251,6 +251,9 @@ async fn test_use_materials() { | ||||
|     assert!(char.materials.luck == 2); | ||||
| } | ||||
| 
 | ||||
| // TODO: tests for ALL ITEMS WOW
 | ||||
| 
 | ||||
| /* | ||||
| #[async_std::test] | ||||
| pub async fn test_learn_new_tech() {} | ||||
| 
 | ||||
| @ -268,3 +271,4 @@ pub async fn test_char_cannot_learn_high_level_tech() {} | ||||
| 
 | ||||
| #[async_std::test] | ||||
| pub async fn test_android_cannot_learn_tech() {} | ||||
| */ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user