Merge pull request 'equip_changes' (#241) from equip_changes into master
Reviewed-by: jake <jake@sharnoth.com>
This commit is contained in:
		
						commit
						a50f1d58a4
					
				
							
								
								
									
										110
									
								
								src/bin/main.rs
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								src/bin/main.rs
									
									
									
									
									
								
							| @ -194,6 +194,116 @@ fn main() { | ||||
|                         name: item::BankName("".to_string()), | ||||
|                     } | ||||
|                 }).await; | ||||
|             entity_gateway.create_item( | ||||
|                 NewItemEntity { | ||||
|                     item: ItemDetail::Armor( | ||||
|                         item::armor::Armor { | ||||
|                             armor: item::armor::ArmorType::Frame, | ||||
|                             dfp: 0, | ||||
|                             evp: 0, | ||||
|                             slots: 4, | ||||
|                             modifiers: Vec::new(), | ||||
|                         } | ||||
|                     ), | ||||
|                     location: ItemLocation::Inventory { | ||||
|                         character_id: character.id, | ||||
|                         slot: 5, | ||||
|                         equipped: true, | ||||
|                     } | ||||
|                 } | ||||
|             ).await; | ||||
|             entity_gateway.create_item( | ||||
|                 NewItemEntity { | ||||
|                     item: ItemDetail::Shield( | ||||
|                         item::shield::Shield { | ||||
|                             shield: item::shield::ShieldType::Barrier, | ||||
|                             dfp: 0, | ||||
|                             evp: 0, | ||||
|                         } | ||||
|                     ), | ||||
|                     location: ItemLocation::Inventory { | ||||
|                         character_id: character.id, | ||||
|                         slot: 6, | ||||
|                         equipped: true, | ||||
|                     } | ||||
|                 } | ||||
|             ).await; | ||||
|             entity_gateway.create_item( | ||||
|                 NewItemEntity { | ||||
|                     item: ItemDetail::Unit( | ||||
|                         item::unit::Unit { | ||||
|                             unit: item::unit::UnitType::PriestMind, | ||||
|                             modifier: Some(item::unit::UnitModifier::Minus), | ||||
|                             armor_slot: 0, | ||||
|                         } | ||||
|                     ), | ||||
|                     location: ItemLocation::Inventory { | ||||
|                         character_id: character.id, | ||||
|                         slot: 7, | ||||
|                         equipped: true, | ||||
|                     } | ||||
|                 } | ||||
|             ).await; | ||||
|             entity_gateway.create_item( | ||||
|                 NewItemEntity { | ||||
|                     item: ItemDetail::Unit( | ||||
|                         item::unit::Unit { | ||||
|                             unit: item::unit::UnitType::PriestMind, | ||||
|                             modifier: Some(item::unit::UnitModifier::Minus), | ||||
|                             armor_slot: 1, | ||||
|                         } | ||||
|                     ), | ||||
|                     location: ItemLocation::Inventory { | ||||
|                         character_id: character.id, | ||||
|                         slot: 8, | ||||
|                         equipped: true, | ||||
|                     } | ||||
|                 } | ||||
|             ).await; | ||||
|             entity_gateway.create_item( | ||||
|                 NewItemEntity { | ||||
|                     item: ItemDetail::Unit( | ||||
|                         item::unit::Unit { | ||||
|                             unit: item::unit::UnitType::PriestMind, | ||||
|                             modifier: Some(item::unit::UnitModifier::Minus), | ||||
|                             armor_slot: 2, | ||||
|                         } | ||||
|                     ), | ||||
|                     location: ItemLocation::Inventory { | ||||
|                         character_id: character.id, | ||||
|                         slot: 9, | ||||
|                         equipped: true, | ||||
|                     } | ||||
|                 } | ||||
|             ).await; | ||||
|             entity_gateway.create_item( | ||||
|                 NewItemEntity { | ||||
|                     item: ItemDetail::Unit( | ||||
|                         item::unit::Unit { | ||||
|                             unit: item::unit::UnitType::PriestMind, | ||||
|                             modifier: Some(item::unit::UnitModifier::Minus), | ||||
|                             armor_slot: 3, | ||||
|                         } | ||||
|                     ), | ||||
|                     location: ItemLocation::Inventory { | ||||
|                         character_id: character.id, | ||||
|                         slot: 10, | ||||
|                         equipped: true, | ||||
|                     } | ||||
|                 } | ||||
|             ).await; | ||||
|             entity_gateway.create_item( | ||||
|                 NewItemEntity { | ||||
|                     item: ItemDetail::Mag( | ||||
|                         item::mag::Mag::baby_mag(5) | ||||
|                     ), | ||||
|                     location: ItemLocation::Inventory { | ||||
|                         character_id: character.id, | ||||
|                         slot: 11, | ||||
|                         equipped: true, | ||||
|                     } | ||||
|                 } | ||||
|             ).await; | ||||
|         } | ||||
| 
 | ||||
|         info!("[patch] starting server"); | ||||
|  | ||||
| @ -384,6 +384,7 @@ impl Into<shield::Shield> for PgShield { | ||||
| pub struct PgUnit { | ||||
|     unit: unit::UnitType, | ||||
|     modifier: Option<unit::UnitModifier>, | ||||
|     armor_slot: u8, | ||||
| } | ||||
| 
 | ||||
| impl From<unit::Unit> for PgUnit { | ||||
| @ -391,6 +392,7 @@ impl From<unit::Unit> for PgUnit { | ||||
|         PgUnit { | ||||
|             unit: other.unit, | ||||
|             modifier: other.modifier, | ||||
|             armor_slot: other.armor_slot, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -400,6 +402,7 @@ impl Into<unit::Unit> for PgUnit { | ||||
|         unit::Unit { | ||||
|             unit: self.unit, | ||||
|             modifier: self.modifier, | ||||
|             armor_slot: self.armor_slot, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -335,6 +335,7 @@ pub enum UnitModifier { | ||||
| pub struct Unit { | ||||
|     pub unit: UnitType, | ||||
|     pub modifier: Option<UnitModifier>, | ||||
|     pub armor_slot: u8, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -361,7 +362,7 @@ impl Unit { | ||||
|                 }, | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         result[4] = self.armor_slot; | ||||
|         result | ||||
|     } | ||||
| 
 | ||||
| @ -379,6 +380,7 @@ impl Unit { | ||||
|             Ok(Unit{ | ||||
|                 unit: u.unwrap(), | ||||
|                 modifier: m, | ||||
|                 armor_slot: data[4], | ||||
|             }) | ||||
|         } | ||||
|         else { | ||||
|  | ||||
| @ -89,6 +89,7 @@ impl GenericUnitTable { | ||||
|             ItemDropType::Unit(Unit { | ||||
|                 unit: unit_type, | ||||
|                 modifier: unit_modifier, | ||||
|                 armor_slot: 0, | ||||
|             }) | ||||
|         }) | ||||
|     } | ||||
| @ -116,6 +117,7 @@ mod test { | ||||
|             assert!(gut.get_drop(&area, &mut rng) == Some(ItemDropType::Unit(Unit { | ||||
|                 unit: unit, | ||||
|                 modifier: umod, | ||||
|                 armor_slot: 0, | ||||
|             }))); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -128,6 +128,7 @@ impl RareDropTable { | ||||
|                 ItemDropType::Unit(Unit { | ||||
|                     unit: unit, | ||||
|                     modifier: None, | ||||
|                     armor_slot: 0, | ||||
|                 }) | ||||
|             }, | ||||
|             RareDropItem::Tool(tool) => { | ||||
|  | ||||
| @ -336,7 +336,11 @@ impl<'a> InventoryItemHandle<'a> { | ||||
|                 })) | ||||
|             } | ||||
|         } | ||||
|     } 
 | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_slot(&self) -> usize { | ||||
|         self.slot | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -418,6 +422,60 @@ impl CharacterInventory { | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_equipped_armor_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> { | ||||
|         let (slot, _) = self.items.iter() | ||||
|             .enumerate() | ||||
|             .filter(|(_, item)| { | ||||
|                 if let InventoryItem::Individual(individual_inventory_item) = item { | ||||
|                     if let ItemDetail::Armor(_) = &individual_inventory_item.item { | ||||
|                         return individual_inventory_item.equipped | ||||
|                     } | ||||
|                 } | ||||
|                 false | ||||
|             }) | ||||
|             .nth(0)?; | ||||
|         Some(InventoryItemHandle { | ||||
|             inventory: self, | ||||
|             slot: slot, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_equipped_shield_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> { | ||||
|         let (slot, _) = self.items.iter() | ||||
|             .enumerate() | ||||
|             .filter(|(_, item)| { | ||||
|                 if let InventoryItem::Individual(individual_inventory_item) = item { | ||||
|                     if let ItemDetail::Shield(_) = &individual_inventory_item.item { | ||||
|                         return individual_inventory_item.equipped | ||||
|                     } | ||||
|                 } | ||||
|                 false | ||||
|             }) | ||||
|             .nth(0)?; | ||||
|         Some(InventoryItemHandle { | ||||
|             inventory: self, | ||||
|             slot: slot, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_equipped_weapon_handle<'a>(&'a mut self) -> Option<InventoryItemHandle<'a>> { | ||||
|         let (slot, _) = self.items.iter() | ||||
|             .enumerate() | ||||
|             .filter(|(_, item)| { | ||||
|                 if let InventoryItem::Individual(individual_inventory_item) = item { | ||||
|                     if let ItemDetail::Weapon(_) = &individual_inventory_item.item { | ||||
|                         return individual_inventory_item.equipped | ||||
|                     } | ||||
|                 } | ||||
|                 false | ||||
|             }) | ||||
|             .nth(0)?; | ||||
|         Some(InventoryItemHandle { | ||||
|             inventory: self, | ||||
|             slot: slot, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&InventoryItem> { | ||||
|         self.items.iter() | ||||
|             .filter(|item| { | ||||
| @ -569,5 +627,9 @@ impl CharacterInventory { | ||||
|     pub fn iter(&self) -> impl Iterator<Item = &InventoryItem> { | ||||
|         self.items.iter() | ||||
|     } | ||||
| 
 | ||||
|     pub fn items(&self) -> &Vec<InventoryItem> { | ||||
|         &self.items | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -4,8 +4,9 @@ use thiserror::Error; | ||||
| use crate::entity::gateway::EntityGateway; | ||||
| use crate::entity::character::{CharacterEntity, CharacterEntityId}; | ||||
| use crate::entity::item::{ItemDetail, ItemLocation, BankName}; | ||||
| use crate::entity::item::{Meseta, NewItemEntity}; | ||||
| use crate::entity::item::{Meseta, NewItemEntity, ItemEntity}; | ||||
| use crate::entity::item::tool::{Tool, ToolType}; | ||||
| use crate::entity::item::unit; | ||||
| use crate::ship::map::MapArea; | ||||
| use crate::ship::ship::ItemDropLocation; | ||||
| use crate::ship::drops::{ItemDrop, ItemDropType}; | ||||
| @ -42,7 +43,11 @@ pub enum ItemManagerError { | ||||
|     UseItemError(#[from] use_tool::UseItemError), | ||||
|     CouldNotBuyItem, | ||||
|     CouldNotAddBoughtItemToInventory, | ||||
|     ItemIdNotInInventory(ClientItemId) | ||||
|     ItemIdNotInInventory(ClientItemId), | ||||
|     CannotGetMutItem, | ||||
|     CannotGetIndividualItem, | ||||
|     InvalidSlot(u8, u8), // slots available, slot attempted
 | ||||
|     NoArmorEquipped, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -676,7 +681,6 @@ impl ItemManager { | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     pub async fn use_item<EG: EntityGateway>(&mut self, | ||||
|                                              used_item: ConsumedItem, | ||||
|                                              entity_gateway: &mut EG, | ||||
| @ -893,4 +897,82 @@ impl ItemManager { | ||||
|         }; | ||||
|         Ok(inventory_item) | ||||
|     } | ||||
| 
 | ||||
|     // TODO: check if slot exists before putting units into it
 | ||||
|     pub async fn player_equips_item<EG: EntityGateway>(&mut self, | ||||
|                                                        entity_gateway: &mut EG, | ||||
|                                                        character: &CharacterEntity, | ||||
|                                                        item_id: ClientItemId, | ||||
|                                                        equip_slot: u8) | ||||
|                                                        -> Result<(), ItemManagerError> { | ||||
|         let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; | ||||
|         let mut inventory_item_handle = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; | ||||
|         let slot = inventory_item_handle.get_slot(); | ||||
|         let inventory_item = inventory_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?.individual().ok_or(ItemManagerError::CannotGetIndividualItem)?; | ||||
|         inventory_item.equipped = true; | ||||
|         if let ItemDetail::Unit(u) = inventory_item.item { | ||||
|             if equip_slot > 0 { | ||||
|                 inventory_item.item = ItemDetail::Unit(unit::Unit { | ||||
|                     unit: u.unit, | ||||
|                     modifier: u.modifier, | ||||
|                     armor_slot: ((equip_slot & 0x7) - 1) % 4, // or just be lazy and do equip_slot - 9
 | ||||
|                 }); | ||||
|             } else { | ||||
|                 inventory_item.item = ItemDetail::Unit(unit::Unit { | ||||
|                     unit: u.unit, | ||||
|                     modifier: u.modifier, | ||||
|                     armor_slot: 0, | ||||
|                 }); | ||||
|             } | ||||
|         }; | ||||
|         entity_gateway.change_item_location(&inventory_item.entity_id, ItemLocation::Inventory{ | ||||
|             character_id: character.id, | ||||
|             slot: slot, | ||||
|             equipped: true, | ||||
|         }).await; | ||||
|         entity_gateway.save_item(&ItemEntity{ | ||||
|             id: inventory_item.entity_id, | ||||
|             location: ItemLocation::Inventory{ | ||||
|                 character_id: character.id, | ||||
|                 slot: slot, | ||||
|                 equipped: true, | ||||
|             }, | ||||
|             item: inventory_item.item.clone(), | ||||
|         }).await; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn player_unequips_item<EG: EntityGateway>(&mut self, | ||||
|                                                        entity_gateway: &mut EG, | ||||
|                                                        character: &CharacterEntity, | ||||
|                                                        item_id: ClientItemId) | ||||
|                                                        -> Result<(), ItemManagerError> { | ||||
|         let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; | ||||
|         let mut inventory_item_handle = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; | ||||
|         let slot = inventory_item_handle.get_slot(); | ||||
|         let inventory_item = inventory_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?.individual().ok_or(ItemManagerError::CannotGetIndividualItem)?; | ||||
|         inventory_item.equipped = false; | ||||
|         if let ItemDetail::Unit(u) = inventory_item.item { | ||||
|             inventory_item.item = ItemDetail::Unit(unit::Unit { | ||||
|                 unit: u.unit, | ||||
|                 modifier: u.modifier, | ||||
|                 armor_slot: 0, | ||||
|             }); | ||||
|         }; | ||||
|         entity_gateway.change_item_location(&inventory_item.entity_id, ItemLocation::Inventory{ | ||||
|             character_id: character.id, | ||||
|             slot: slot, | ||||
|             equipped: false, | ||||
|         }).await; | ||||
|         entity_gateway.save_item(&ItemEntity{ | ||||
|             id: inventory_item.entity_id, | ||||
|             location: ItemLocation::Inventory{ | ||||
|                 character_id: character.id, | ||||
|                 slot: slot, | ||||
|                 equipped: false, | ||||
|             }, | ||||
|             item: inventory_item.item.clone(), | ||||
|         }).await; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,13 +1,11 @@ | ||||
| use libpso::packet::ship::*; | ||||
| use libpso::packet::messages::*; | ||||
| use crate::entity::gateway::EntityGateway; | ||||
| use crate::entity::item::ItemDetail; | ||||
| use crate::entity::item::tool::ToolType; | ||||
| use crate::entity::item::{ItemType}; | ||||
| use crate::common::serverstate::ClientId; | ||||
| use crate::common::leveltable::CharacterLevelTable; | ||||
| use crate::ship::ship::{SendShipPacket, ShipError, Rooms, Clients, ItemDropLocation}; | ||||
| use crate::ship::location::{ClientLocation, ClientLocationError}; | ||||
| use crate::ship::map::{MapArea}; | ||||
| use crate::ship::items::{ItemManager, ClientItemId}; | ||||
| use crate::ship::packet::builder; | ||||
| 
 | ||||
| @ -275,7 +273,7 @@ pub async fn player_used_medical_center<EG>(id: ClientId, | ||||
|                                             clients: &mut Clients) | ||||
|                                             -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> | ||||
| where | ||||
| EG: EntityGateway | ||||
|     EG: EntityGateway | ||||
| { | ||||
|     let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; | ||||
|     if client.character.meseta >= 10 { | ||||
| @ -307,3 +305,54 @@ where | ||||
|                         (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone())))) | ||||
|                     }))) | ||||
| } | ||||
| 
 | ||||
| pub async fn player_equips_item<EG>(id: ClientId, | ||||
|                                     pkt: &PlayerEquipItem, | ||||
|                                     entity_gateway: &mut EG, | ||||
|                                     clients: &Clients, | ||||
|                                     item_manager: &mut ItemManager) | ||||
|                                     -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> | ||||
| where | ||||
|     EG: EntityGateway | ||||
| { | ||||
|     let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; | ||||
|     item_manager.player_equips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id), pkt.sub_menu).await?; | ||||
|     Ok(Box::new(None.into_iter())) | ||||
| } | ||||
| 
 | ||||
| pub async fn player_unequips_item<EG>(id: ClientId, | ||||
|                                     pkt: &PlayerUnequipItem, | ||||
|                                     entity_gateway: &mut EG, | ||||
|                                     clients: &Clients, | ||||
|                                     item_manager: &mut ItemManager) | ||||
|                                     -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> | ||||
| where | ||||
|     EG: EntityGateway | ||||
| { | ||||
|     let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; | ||||
|     let equipped_unit_ids: Vec<ClientItemId> = { | ||||
|         item_manager.player_unequips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id)).await?; | ||||
|         let inventory = item_manager.get_character_inventory(&client.character).unwrap(); | ||||
|         let ue_item = inventory.get_item_by_id(ClientItemId(pkt.item_id)).ok_or(ShipError::ItemError)?; | ||||
|         if let ItemType::Armor(_) = ue_item.item_type() { | ||||
|             inventory.items() | ||||
|             .iter() | ||||
|             .filter(|inv_item| { | ||||
|                 if let ItemType::Unit(_) = inv_item.item_type() { | ||||
|                     return inv_item.equipped() | ||||
|                 } | ||||
|                     false | ||||
|                 }) | ||||
|             .map(|u| u.item_id()) | ||||
|             .collect() | ||||
|         } else { | ||||
|             Vec::new() | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     for unit_id in equipped_unit_ids { | ||||
|         item_manager.player_unequips_item(entity_gateway, &client.character, unit_id).await; | ||||
|     } | ||||
| 
 | ||||
|     Ok(Box::new(None.into_iter())) | ||||
| } | ||||
| @ -393,6 +393,13 @@ impl<EG: EntityGateway> ShipServerState<EG> { | ||||
|             GameMessage::PlayerFeedMag(player_feed_mag) => { | ||||
|                 handler::message::player_feed_mag(id, &player_feed_mag, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await | ||||
|             }, | ||||
|             GameMessage::PlayerEquipItem(player_equip_item) => { | ||||
|                 handler::message::player_equips_item(id, &player_equip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await | ||||
|             }, | ||||
|             GameMessage::PlayerUnequipItem(player_unequip_item) => { | ||||
|                 handler::message::player_unequips_item(id, &player_unequip_item, &mut self.entity_gateway, &mut self.clients, &mut self.item_manager).await | ||||
|             }, | ||||
| 
 | ||||
|             _ => { | ||||
|                 let cmsg = msg.clone(); | ||||
|                 Ok(Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter() | ||||
|  | ||||
| @ -89,6 +89,7 @@ impl ShopItem for ArmorShopItem { | ||||
|                 ItemDetail::Unit(Unit { | ||||
|                     unit: *unit, | ||||
|                     modifier: None, | ||||
|                     armor_slot: 0, | ||||
|                 }) | ||||
|             }, | ||||
|         } | ||||
|  | ||||
| @ -9,7 +9,7 @@ mod common; | ||||
| use common::*; | ||||
| 
 | ||||
| #[async_std::test] | ||||
| async fn test_save_options<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id: ClientId, options: u32) { | ||||
| async fn test_save_options() { | ||||
|     let mut entity_gateway = InMemoryGateway::new(); | ||||
| 
 | ||||
|     let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; | ||||
|  | ||||
							
								
								
									
										218
									
								
								tests/test_item_equip.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								tests/test_item_equip.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,218 @@ | ||||
| use elseware::common::serverstate::{ClientId, ServerState}; | ||||
| use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; | ||||
| use elseware::ship::ship::{ShipServerState, RecvShipPacket}; | ||||
| use elseware::entity::item; | ||||
| 
 | ||||
| use libpso::packet::ship::*; | ||||
| use libpso::packet::messages::*; | ||||
| 
 | ||||
| #[path = "common.rs"] | ||||
| mod common; | ||||
| use common::*; | ||||
| 
 | ||||
| #[async_std::test] | ||||
| async fn test_equip_unit_from_equip_menu() { | ||||
|     let mut entity_gateway = InMemoryGateway::new(); | ||||
| 
 | ||||
|     let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; | ||||
| 
 | ||||
|     entity_gateway.create_item( | ||||
|         item::NewItemEntity { | ||||
|             item: item::ItemDetail::Armor( | ||||
|                 item::armor::Armor{ | ||||
|                     armor: item::armor::ArmorType::Frame, | ||||
|                     dfp: 0, | ||||
|                     evp: 0, | ||||
|                     slots: 4, | ||||
|                     modifiers: Vec::new(), | ||||
|                 }), | ||||
|             location: item::ItemLocation::Inventory { | ||||
|                 character_id: char1.id, | ||||
|                 slot: 0, | ||||
|                 equipped: true, | ||||
|             } | ||||
|         }).await; | ||||
| 
 | ||||
|     entity_gateway.create_item( | ||||
|         item::NewItemEntity { | ||||
|             item: item::ItemDetail::Unit( | ||||
|                 item::unit::Unit{ | ||||
|                     unit: item::unit::UnitType::KnightPower, | ||||
|                     modifier: None, | ||||
|                     armor_slot: 0, | ||||
|                 }), | ||||
|             location: item::ItemLocation::Inventory { | ||||
|                 character_id: char1.id, | ||||
|                 slot: 1, | ||||
|                 equipped: false, | ||||
|             } | ||||
|         }).await.unwrap(); | ||||
| 
 | ||||
|     entity_gateway.create_item( | ||||
|         item::NewItemEntity { | ||||
|             item: item::ItemDetail::Unit( | ||||
|                 item::unit::Unit{ | ||||
|                     unit: item::unit::UnitType::KnightPower, | ||||
|                     modifier: Some(item::unit::UnitModifier::Plus), | ||||
|                     armor_slot: 0, | ||||
|                 }), | ||||
|             location: item::ItemLocation::Inventory { | ||||
|                 character_id: char1.id, | ||||
|                 slot: 2, | ||||
|                 equipped: false, | ||||
|             } | ||||
|         }).await.unwrap(); | ||||
| 
 | ||||
|     let mut ship = 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::PlayerEquipItem(PlayerEquipItem { | ||||
|         client: 0, | ||||
|         target: 0, | ||||
|         item_id: 0x10001, | ||||
|         sub_menu: 9, | ||||
|         unknown1: 0, | ||||
|     })))).await.unwrap().for_each(drop); | ||||
| 
 | ||||
|     // case when someone tries to send invalid submenu? submenu is 9-12 in normal gameplay
 | ||||
|     ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerEquipItem(PlayerEquipItem { | ||||
|         client: 0, | ||||
|         target: 0, | ||||
|         item_id: 0x10002, | ||||
|         sub_menu: 14, | ||||
|         unknown1: 0, | ||||
|     })))).await.unwrap().for_each(drop); | ||||
| 
 | ||||
|     let items = entity_gateway.get_items_by_character(&char1).await; | ||||
|     let (unit1, unit2) = (&items[1], &items[2]); | ||||
| 
 | ||||
|     let unit1_equipped = match unit1.location { | ||||
|         item::ItemLocation::Inventory{equipped, ..} => equipped, | ||||
|         _ => false, | ||||
|     }; | ||||
| 
 | ||||
|     let unit2_equipped = match unit2.location { | ||||
|         item::ItemLocation::Inventory{equipped, ..} => equipped, | ||||
|         _ => false, | ||||
|     }; | ||||
| 
 | ||||
|     assert!({ | ||||
|         match unit1.item { | ||||
|             item::ItemDetail::Unit(u) => { | ||||
|                 if u.armor_slot == 0 && unit1_equipped { | ||||
|                     true | ||||
|                 } else { | ||||
|                     false | ||||
|                 } | ||||
|             }, | ||||
|             _ => false, | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     assert!({ | ||||
|         match unit2.item { | ||||
|             item::ItemDetail::Unit(u) => { | ||||
|                 if u.armor_slot == 1 && unit2_equipped { | ||||
|                     true | ||||
|                 } else { | ||||
|                     false | ||||
|                 } | ||||
|             }, | ||||
|             _ => false, | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| #[async_std::test] | ||||
| async fn test_unequip_armor_with_units() { | ||||
|     let mut entity_gateway = InMemoryGateway::new(); | ||||
| 
 | ||||
|     let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; | ||||
| 
 | ||||
|     entity_gateway.create_item( | ||||
|         item::NewItemEntity { | ||||
|             item: item::ItemDetail::Armor( | ||||
|                 item::armor::Armor{ | ||||
|                     armor: item::armor::ArmorType::Frame, | ||||
|                     dfp: 0, | ||||
|                     evp: 0, | ||||
|                     slots: 4, | ||||
|                     modifiers: Vec::new(), | ||||
|                 }), | ||||
|             location: item::ItemLocation::Inventory { | ||||
|                 character_id: char1.id, | ||||
|                 slot: 0, | ||||
|                 equipped: true, | ||||
|             } | ||||
|         }).await; | ||||
| 
 | ||||
|     entity_gateway.create_item( | ||||
|         item::NewItemEntity { | ||||
|             item: item::ItemDetail::Unit( | ||||
|                 item::unit::Unit{ | ||||
|                     unit: item::unit::UnitType::KnightPower, | ||||
|                     modifier: None, | ||||
|                     armor_slot: 0, | ||||
|                 }), | ||||
|             location: item::ItemLocation::Inventory { | ||||
|                 character_id: char1.id, | ||||
|                 slot: 1, | ||||
|                 equipped: true, | ||||
|             } | ||||
|         }).await.unwrap(); | ||||
| 
 | ||||
|     entity_gateway.create_item( | ||||
|         item::NewItemEntity { | ||||
|             item: item::ItemDetail::Unit( | ||||
|                 item::unit::Unit{ | ||||
|                     unit: item::unit::UnitType::KnightPower, | ||||
|                     modifier: Some(item::unit::UnitModifier::Plus), | ||||
|                     armor_slot: 1, | ||||
|                 }), | ||||
|             location: item::ItemLocation::Inventory { | ||||
|                 character_id: char1.id, | ||||
|                 slot: 2, | ||||
|                 equipped: true, | ||||
|             } | ||||
|         }).await.unwrap(); | ||||
| 
 | ||||
|     let mut ship = 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::PlayerUnequipItem(PlayerUnequipItem { | ||||
|         client: 0, | ||||
|         target: 0, | ||||
|         item_id: 0x10000, | ||||
|         unknown1: 0, | ||||
|     })))).await.unwrap().for_each(drop); | ||||
| 
 | ||||
|     let items = entity_gateway.get_items_by_character(&char1).await; | ||||
|     let (armor, unit1, unit2) = (&items[0], &items[1], &items[2]); | ||||
| 
 | ||||
|     let armor_equipped = match armor.location { | ||||
|         item::ItemLocation::Inventory{equipped, ..} => equipped, | ||||
|         _ => true, | ||||
|     }; | ||||
|     
 | ||||
|     let unit1_equipped = match unit1.location { | ||||
|         item::ItemLocation::Inventory{equipped, ..} => equipped, | ||||
|         _ => true, | ||||
|     }; | ||||
| 
 | ||||
|     let unit2_equipped = match unit2.location { | ||||
|         item::ItemLocation::Inventory{equipped, ..} => equipped, | ||||
|         _ => true, | ||||
|     }; | ||||
| 
 | ||||
|     assert!(armor_equipped == false); | ||||
|     assert!(unit1_equipped == false); | ||||
|     assert!(unit2_equipped == false); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user