From f3e75999757ea3e4e1747b9d41cd10cace81614a Mon Sep 17 00:00:00 2001 From: andy Date: Mon, 26 Oct 2020 23:03:51 -0300 Subject: [PATCH] some comments and tests --- src/ship/items/inventory.rs | 42 +++++++ src/ship/items/manager.rs | 5 +- tests/test_character.rs | 2 +- tests/test_item_equip.rs | 218 ++++++++++++++++++++++++++++++++++++ 4 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 tests/test_item_equip.rs diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index 4735d74..763f0a7 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -418,6 +418,48 @@ impl CharacterInventory { }) } + pub fn get_equipped_armor_handle<'a>(&'a mut self) -> Option> { + 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> { + 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> { + 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| { diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 9ee674d..cd777fb 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -46,6 +46,8 @@ pub enum ItemManagerError { ItemIdNotInInventory(ClientItemId), CannotGetMutItem, CannotGetIndividualItem, + InvalidSlot(u8, u8), // slots available, slot attempted + NoArmorEquipped, } @@ -896,6 +898,7 @@ impl ItemManager { Ok(inventory_item) } + // TODO: check if slot exists before putting units into it pub async fn player_equips_item(&mut self, entity_gateway: &mut EG, character: &CharacterEntity, @@ -912,7 +915,7 @@ impl ItemManager { inventory_item.item = ItemDetail::Unit(unit::Unit { unit: u.unit, modifier: u.modifier, - armor_slot: ((equip_slot & 0x7) - 1) % 4, + armor_slot: ((equip_slot & 0x7) - 1) % 4, // or just be lazy and do equip_slot - 9 }); } else { inventory_item.item = ItemDetail::Unit(unit::Unit { diff --git a/tests/test_character.rs b/tests/test_character.rs index 979f123..b05fda4 100644 --- a/tests/test_character.rs +++ b/tests/test_character.rs @@ -9,7 +9,7 @@ mod common; use common::*; #[async_std::test] -async fn test_save_options(ship: &mut ShipServerState, 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; diff --git a/tests/test_item_equip.rs b/tests/test_item_equip.rs new file mode 100644 index 0000000..ebc866e --- /dev/null +++ b/tests/test_item_equip.rs @@ -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); +}