From 48abf4533fc1fa5693973760043824bce97069d0 Mon Sep 17 00:00:00 2001 From: andy Date: Tue, 6 Oct 2020 21:35:20 -0300 Subject: [PATCH 01/10] player can (un)equip things now --- src/bin/main.rs | 76 ++++++++++++++++++++++++++++++ src/ship/items/manager.rs | 42 ++++++++++++++++- src/ship/packet/handler/message.rs | 29 ++++++++++++ src/ship/ship.rs | 7 +++ 4 files changed, 153 insertions(+), 1 deletion(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index fe379e0..0ff44be 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -194,6 +194,82 @@ 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::KnightPower, + modifier: Some(item::unit::UnitModifier::Plus), + } + ), + 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::KnightPower, + modifier: Some(item::unit::UnitModifier::PlusPlus), + } + ), + location: ItemLocation::Inventory { + character_id: character.id, + slot: 8, + 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: 9, + equipped: true, + } + } + ).await; } info!("[patch] starting server"); diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 59de10f..e47be8b 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -42,7 +42,9 @@ pub enum ItemManagerError { UseItemError(#[from] use_tool::UseItemError), CouldNotBuyItem, CouldNotAddBoughtItemToInventory, - ItemIdNotInInventory(ClientItemId) + ItemIdNotInInventory(ClientItemId), + CannotGetMutItem, + CannotGetIndividualItem, } @@ -893,4 +895,42 @@ impl ItemManager { }; Ok(inventory_item) } + + pub async fn player_equips_item(&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 inventory_item = inventory_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?.individual().ok_or(ItemManagerError::CannotGetIndividualItem)?; + inventory_item.equipped = true; + entity_gateway.change_item_location(&inventory_item.entity_id, ItemLocation::Inventory{ + character_id: character.id, + slot: character.slot as usize, + equipped: true, + }).await; + + entity_gateway.save_character(character).await; + Ok(()) + } + + pub async fn player_unequips_item(&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 inventory_item = inventory_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?.individual().ok_or(ItemManagerError::CannotGetIndividualItem)?; + inventory_item.equipped = false; + entity_gateway.change_item_location(&inventory_item.entity_id, ItemLocation::Inventory{ + character_id: character.id, + slot: character.slot as usize, + equipped: false, + }).await; + + entity_gateway.save_character(character).await; + Ok(()) + } } diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 0307993..96a4d36 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -307,3 +307,32 @@ where (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone())))) }))) } + +pub async fn player_equips_item(id: ClientId, + pkt: &PlayerEquipItem, + entity_gateway: &mut EG, + clients: &Clients, + item_manager: &mut ItemManager) + -> Result + 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)).await?; + Ok(Box::new(None.into_iter())) +} + +pub async fn player_unequips_item(id: ClientId, + pkt: &PlayerUnequipItem, + entity_gateway: &mut EG, + clients: &Clients, + item_manager: &mut ItemManager) + -> Result + Send>, ShipError> +where + EG: EntityGateway +{ + let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; + item_manager.player_unequips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id)).await?; + Ok(Box::new(None.into_iter())) +} + diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 5d314d5..dc6b6b2 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -393,6 +393,13 @@ impl ShipServerState { 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() From 6c33c7ec9b401ac1fd42ab619ef43c3c0b709853 Mon Sep 17 00:00:00 2001 From: andy Date: Tue, 6 Oct 2020 22:36:02 -0300 Subject: [PATCH 02/10] dont delete items when unequipping --- src/ship/items/inventory.rs | 6 +++++- src/ship/items/manager.rs | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index 0ad1126..1328e80 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -336,7 +336,11 @@ impl<'a> InventoryItemHandle<'a> { })) } } - } + } + + pub fn get_slot(&self) -> usize { + self.slot + } } diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index e47be8b..ffecb3a 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -903,11 +903,12 @@ impl ItemManager { -> 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; entity_gateway.change_item_location(&inventory_item.entity_id, ItemLocation::Inventory{ character_id: character.id, - slot: character.slot as usize, + slot: slot, equipped: true, }).await; @@ -922,11 +923,12 @@ impl ItemManager { -> 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; entity_gateway.change_item_location(&inventory_item.entity_id, ItemLocation::Inventory{ character_id: character.id, - slot: character.slot as usize, + slot: slot, equipped: false, }).await; From be29c83bb9f9f64c4ff32aac3e8f9938ac1bc6f9 Mon Sep 17 00:00:00 2001 From: andy Date: Wed, 14 Oct 2020 20:16:31 -0300 Subject: [PATCH 03/10] check priest mind against dolphin drop --- src/bin/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 0ff44be..8c587a6 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -232,8 +232,8 @@ fn main() { NewItemEntity { item: ItemDetail::Unit( item::unit::Unit { - unit: item::unit::UnitType::KnightPower, - modifier: Some(item::unit::UnitModifier::Plus), + unit: item::unit::UnitType::PriestMind, + modifier: Some(item::unit::UnitModifier::Minus), } ), location: ItemLocation::Inventory { From 555171d11d851e689dd772584346fb08980540d9 Mon Sep 17 00:00:00 2001 From: andy Date: Wed, 21 Oct 2020 00:54:23 -0300 Subject: [PATCH 04/10] server unequips units now. formatting and cleanup unuseds. fix merge conflict --- src/bin/main.rs | 2 +- src/ship/items/inventory.rs | 12 +++++------ src/ship/items/manager.rs | 1 - src/ship/packet/handler/message.rs | 34 ++++++++++++++++++++++++------ 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 8c587a6..292aec2 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -247,7 +247,7 @@ fn main() { NewItemEntity { item: ItemDetail::Unit( item::unit::Unit { - unit: item::unit::UnitType::KnightPower, + unit: item::unit::UnitType::HeavenlyPower, modifier: Some(item::unit::UnitModifier::PlusPlus), } ), diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index 1328e80..4735d74 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -408,13 +408,9 @@ impl CharacterInventory { let (slot, _) = self.items.iter() .enumerate() .filter(|(_, item)| { - if let InventoryItem::Individual(individual_inventory_item) = item { - if let ItemDetail::Mag(_) = &individual_inventory_item.item { - return individual_inventory_item.equipped - } - } + if let InventoryItem::Individual(individual_inventory_item) = item {if let ItemDetail::Mag(_) = &individual_inventory_item.item {return individual_inventory_item.equipped }} false - }) + }) .nth(0)?; Some(InventoryItemHandle { inventory: self, @@ -573,5 +569,9 @@ impl CharacterInventory { pub fn iter(&self) -> impl Iterator { self.items.iter() } + + pub fn items(&self) -> &Vec { + &self.items + } } diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index ffecb3a..2a9a50c 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -678,7 +678,6 @@ impl ItemManager { Ok(()) } - pub async fn use_item(&mut self, used_item: ConsumedItem, entity_gateway: &mut EG, diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 96a4d36..832c06e 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -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(id: ClientId, clients: &mut Clients) -> Result + Send>, ShipError> where -EG: EntityGateway + EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; if client.character.meseta >= 10 { @@ -332,7 +330,29 @@ where EG: EntityGateway { let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - item_manager.player_unequips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id)).await?; - Ok(Box::new(None.into_iter())) -} + let equipped_unit_ids: Vec = { + 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())) +} \ No newline at end of file From 790668f6f7a3ac5d267bafa71271a33ba9d2605e Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 23 Oct 2020 23:09:30 -0300 Subject: [PATCH 05/10] add unit armour slots. equip the unit into the right slot and save correctly --- src/bin/main.rs | 40 ++++++++++++++++++++++-- src/entity/item/unit.rs | 4 ++- src/ship/drops/generic_unit.rs | 2 ++ src/ship/drops/rare_drop_table.rs | 1 + src/ship/items/manager.rs | 50 ++++++++++++++++++++++++++---- src/ship/packet/handler/message.rs | 2 +- src/ship/shops/armor.rs | 1 + 7 files changed, 89 insertions(+), 11 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 292aec2..4d8bed7 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -234,6 +234,7 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), + armour_slot: 0, } ), location: ItemLocation::Inventory { @@ -247,8 +248,9 @@ fn main() { NewItemEntity { item: ItemDetail::Unit( item::unit::Unit { - unit: item::unit::UnitType::HeavenlyPower, - modifier: Some(item::unit::UnitModifier::PlusPlus), + unit: item::unit::UnitType::PriestMind, + modifier: Some(item::unit::UnitModifier::Minus), + armour_slot: 1, } ), location: ItemLocation::Inventory { @@ -258,6 +260,38 @@ fn main() { } } ).await; + entity_gateway.create_item( + NewItemEntity { + item: ItemDetail::Unit( + item::unit::Unit { + unit: item::unit::UnitType::PriestMind, + modifier: Some(item::unit::UnitModifier::Minus), + armour_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), + armour_slot: 3, + } + ), + location: ItemLocation::Inventory { + character_id: character.id, + slot: 10, + equipped: true, + } + } + ).await; entity_gateway.create_item( NewItemEntity { item: ItemDetail::Mag( @@ -265,7 +299,7 @@ fn main() { ), location: ItemLocation::Inventory { character_id: character.id, - slot: 9, + slot: 11, equipped: true, } } diff --git a/src/entity/item/unit.rs b/src/entity/item/unit.rs index aa83bf1..716454e 100644 --- a/src/entity/item/unit.rs +++ b/src/entity/item/unit.rs @@ -335,6 +335,7 @@ pub enum UnitModifier { pub struct Unit { pub unit: UnitType, pub modifier: Option, + pub armour_slot: u8, // 0 - 3 = armour slot 1 - 4 } @@ -361,7 +362,7 @@ impl Unit { }, } } - + result[4] = self.armour_slot; result } @@ -379,6 +380,7 @@ impl Unit { Ok(Unit{ unit: u.unwrap(), modifier: m, + armour_slot: data[4], }) } else { diff --git a/src/ship/drops/generic_unit.rs b/src/ship/drops/generic_unit.rs index 73bc4a6..e071d8d 100644 --- a/src/ship/drops/generic_unit.rs +++ b/src/ship/drops/generic_unit.rs @@ -89,6 +89,7 @@ impl GenericUnitTable { ItemDropType::Unit(Unit { unit: unit_type, modifier: unit_modifier, + armour_slot: 0, }) }) } @@ -116,6 +117,7 @@ mod test { assert!(gut.get_drop(&area, &mut rng) == Some(ItemDropType::Unit(Unit { unit: unit, modifier: umod, + armour_slot: 0, }))); } } diff --git a/src/ship/drops/rare_drop_table.rs b/src/ship/drops/rare_drop_table.rs index fae0175..a464bdf 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/src/ship/drops/rare_drop_table.rs @@ -128,6 +128,7 @@ impl RareDropTable { ItemDropType::Unit(Unit { unit: unit, modifier: None, + armour_slot: 0, }) }, RareDropItem::Tool(tool) => { diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 2a9a50c..e5e095d 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -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}; @@ -898,20 +899,43 @@ impl ItemManager { pub async fn player_equips_item(&mut self, entity_gateway: &mut EG, character: &CharacterEntity, - item_id: ClientItemId) + 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, + armour_slot: ((equip_slot & 0x7) - 1) % 4, + }); + } else { + inventory_item.item = ItemDetail::Unit(unit::Unit { + unit: u.unit, + modifier: u.modifier, + armour_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_character(character).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(()) } @@ -925,13 +949,27 @@ impl ItemManager { 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, + armour_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_character(character).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(()) } } diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 832c06e..cde8059 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -316,7 +316,7 @@ 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)).await?; + item_manager.player_equips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id), pkt.sub_menu).await?; Ok(Box::new(None.into_iter())) } diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index 657b732..3ac3fab 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -89,6 +89,7 @@ impl ShopItem for ArmorShopItem { ItemDetail::Unit(Unit { unit: *unit, modifier: None, + armour_slot: 0, }) }, } From e256423dfa63da0e14e901173ac82cd5a1160c9a Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 23 Oct 2020 23:12:11 -0300 Subject: [PATCH 06/10] remove comments and don't be canadian --- src/bin/main.rs | 8 ++++---- src/entity/item/unit.rs | 6 +++--- src/ship/drops/generic_unit.rs | 4 ++-- src/ship/drops/rare_drop_table.rs | 2 +- src/ship/items/manager.rs | 6 +++--- src/ship/shops/armor.rs | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 4d8bed7..9146fa2 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -234,7 +234,7 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), - armour_slot: 0, + armor_slot: 0, } ), location: ItemLocation::Inventory { @@ -250,7 +250,7 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), - armour_slot: 1, + armor_slot: 1, } ), location: ItemLocation::Inventory { @@ -266,7 +266,7 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), - armour_slot: 2, + armor_slot: 2, } ), location: ItemLocation::Inventory { @@ -282,7 +282,7 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), - armour_slot: 3, + armor_slot: 3, } ), location: ItemLocation::Inventory { diff --git a/src/entity/item/unit.rs b/src/entity/item/unit.rs index 716454e..477c422 100644 --- a/src/entity/item/unit.rs +++ b/src/entity/item/unit.rs @@ -335,7 +335,7 @@ pub enum UnitModifier { pub struct Unit { pub unit: UnitType, pub modifier: Option, - pub armour_slot: u8, // 0 - 3 = armour slot 1 - 4 + pub armor_slot: u8, } @@ -362,7 +362,7 @@ impl Unit { }, } } - result[4] = self.armour_slot; + result[4] = self.armor_slot; result } @@ -380,7 +380,7 @@ impl Unit { Ok(Unit{ unit: u.unwrap(), modifier: m, - armour_slot: data[4], + armor_slot: data[4], }) } else { diff --git a/src/ship/drops/generic_unit.rs b/src/ship/drops/generic_unit.rs index e071d8d..9ba7e65 100644 --- a/src/ship/drops/generic_unit.rs +++ b/src/ship/drops/generic_unit.rs @@ -89,7 +89,7 @@ impl GenericUnitTable { ItemDropType::Unit(Unit { unit: unit_type, modifier: unit_modifier, - armour_slot: 0, + armor_slot: 0, }) }) } @@ -117,7 +117,7 @@ mod test { assert!(gut.get_drop(&area, &mut rng) == Some(ItemDropType::Unit(Unit { unit: unit, modifier: umod, - armour_slot: 0, + armor_slot: 0, }))); } } diff --git a/src/ship/drops/rare_drop_table.rs b/src/ship/drops/rare_drop_table.rs index a464bdf..1056f99 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/src/ship/drops/rare_drop_table.rs @@ -128,7 +128,7 @@ impl RareDropTable { ItemDropType::Unit(Unit { unit: unit, modifier: None, - armour_slot: 0, + armor_slot: 0, }) }, RareDropItem::Tool(tool) => { diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index e5e095d..9ee674d 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -912,13 +912,13 @@ impl ItemManager { inventory_item.item = ItemDetail::Unit(unit::Unit { unit: u.unit, modifier: u.modifier, - armour_slot: ((equip_slot & 0x7) - 1) % 4, + armor_slot: ((equip_slot & 0x7) - 1) % 4, }); } else { inventory_item.item = ItemDetail::Unit(unit::Unit { unit: u.unit, modifier: u.modifier, - armour_slot: 0, + armor_slot: 0, }); } }; @@ -953,7 +953,7 @@ impl ItemManager { inventory_item.item = ItemDetail::Unit(unit::Unit { unit: u.unit, modifier: u.modifier, - armour_slot: 0, + armor_slot: 0, }); }; entity_gateway.change_item_location(&inventory_item.entity_id, ItemLocation::Inventory{ diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index 3ac3fab..17869d9 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -89,7 +89,7 @@ impl ShopItem for ArmorShopItem { ItemDetail::Unit(Unit { unit: *unit, modifier: None, - armour_slot: 0, + armor_slot: 0, }) }, } From f3e75999757ea3e4e1747b9d41cd10cace81614a Mon Sep 17 00:00:00 2001 From: andy Date: Mon, 26 Oct 2020 23:03:51 -0300 Subject: [PATCH 07/10] 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); +} From f3608d99ad9046eaae0d47f66cc67f740669e93b Mon Sep 17 00:00:00 2001 From: andy Date: Mon, 26 Oct 2020 23:39:03 -0300 Subject: [PATCH 08/10] add armor_slot to postgres model for unit --- src/entity/gateway/postgres/models.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/gateway/postgres/models.rs index 7d508d6..ea8fc21 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/gateway/postgres/models.rs @@ -384,6 +384,7 @@ impl Into for PgShield { pub struct PgUnit { unit: unit::UnitType, modifier: Option, + armor_slot: u8, } impl From for PgUnit { @@ -391,6 +392,7 @@ impl From for PgUnit { PgUnit { unit: other.unit, modifier: other.modifier, + armor_slot: other.armor_slot, } } } @@ -400,6 +402,7 @@ impl Into for PgUnit { unit::Unit { unit: self.unit, modifier: self.modifier, + armor_slot: self.armor_slot, } } } From 67e96d33db36e9d0fe0daf157cb5068fa1706202 Mon Sep 17 00:00:00 2001 From: andy Date: Wed, 28 Oct 2020 20:12:42 -0300 Subject: [PATCH 09/10] why did i shuffle this --- src/ship/items/inventory.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index 763f0a7..8094216 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -422,9 +422,13 @@ impl CharacterInventory { 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 }} + 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, From a95bcf35c818a42629ec02abe8b502ec62f75c18 Mon Sep 17 00:00:00 2001 From: andy Date: Wed, 28 Oct 2020 20:15:00 -0300 Subject: [PATCH 10/10] andypls --- src/ship/items/inventory.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index 8094216..b4dcc58 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -408,9 +408,13 @@ impl CharacterInventory { let (slot, _) = self.items.iter() .enumerate() .filter(|(_, item)| { - if let InventoryItem::Individual(individual_inventory_item) = item {if let ItemDetail::Mag(_) = &individual_inventory_item.item {return individual_inventory_item.equipped }} + if let InventoryItem::Individual(individual_inventory_item) = item { + if let ItemDetail::Mag(_) = &individual_inventory_item.item { + return individual_inventory_item.equipped + } + } false - }) + }) .nth(0)?; Some(InventoryItemHandle { inventory: self, @@ -440,9 +444,13 @@ impl CharacterInventory { 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 }} + 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, @@ -454,9 +462,13 @@ impl CharacterInventory { 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 }} + 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,