diff --git a/src/ship/items/actions.rs b/src/ship/items/actions.rs index 2d7e95c..2b3f815 100644 --- a/src/ship/items/actions.rs +++ b/src/ship/items/actions.rs @@ -484,3 +484,77 @@ where Ok((transaction, result)) }).await } + +fn equip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId, equip_slot: u8) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) + -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +{ + move |(mut item_state, mut transaction), _| { + Box::pin(async move { + let mut inventory = item_state.inventory(&character_id)?; + inventory.equip(&item_id, equip_slot); + transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?; + + Ok(((item_state, transaction), ())) + }) + } +} + +pub async fn equip_item<'a, EG> ( + item_state: &'a mut ItemState, + entity_gateway: &mut EG, + character: &CharacterEntity, + item_id: &ClientItemId, + equip_slot: u8, +) -> 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), result) = ItemStateAction::default() + .act(equip_inventory_item(character.id, *item_id, equip_slot)) + .commit((item_state_proxy, transaction)) + .await?; + item_state_proxy.commit(); + Ok((transaction, result)) + }).await +} + + + +fn unequip_inventory_item(character_id: CharacterEntityId, item_id: ClientItemId) + -> impl for<'a> Fn((ItemStateProxy<'a>, Box), ()) + -> Pin, Box), ()), ItemStateError>> + Send + 'a>> +{ + move |(mut item_state, mut transaction), _| { + Box::pin(async move { + let mut inventory = item_state.inventory(&character_id)?; + inventory.unequip(&item_id); + transaction.gateway().set_character_equips(&character_id, &inventory.as_equipped_entity()).await?; + + Ok(((item_state, transaction), ())) + }) + } +} + +pub async fn unequip_item<'a, EG> ( + item_state: &'a mut ItemState, + entity_gateway: &mut EG, + character: &CharacterEntity, + item_id: &ClientItemId, +) -> 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), result) = ItemStateAction::default() + .act(unequip_inventory_item(character.id, *item_id)) + .commit((item_state_proxy, transaction)) + .await?; + item_state_proxy.commit(); + Ok((transaction, result)) + }).await +} + diff --git a/src/ship/items/state.rs b/src/ship/items/state.rs index aef4692..4905c05 100644 --- a/src/ship/items/state.rs +++ b/src/ship/items/state.rs @@ -630,6 +630,77 @@ impl InventoryState { } } + pub fn add_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { + if self.meseta.0 == 999999 { + return Err(ItemStateError::FullOfMeseta) + } + self.meseta.0 = std::cmp::min(self.meseta.0 + amount, 999999); + Ok(()) + } + + pub fn add_meseta_no_overflow(&mut self, amount: u32) -> Result<(), ItemStateError> { + if self.meseta.0 + amount > 999999 { + return Err(ItemStateError::FullOfMeseta) + } + self.meseta.0 += amount; + Ok(()) + } + + pub fn remove_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { + if amount > self.meseta.0 { + return Err(ItemStateError::InvalidMesetaRemoval(amount)) + } + self.meseta.0 -= amount; + Ok(()) + } + + pub fn equip(&mut self, item_id: &ClientItemId, equip_slot: u8) { + for item in &self.inventory.0 { + if let InventoryItemDetail::Individual(inventory_item) = &item.item { + if item.item_id == *item_id { + match inventory_item.item { + ItemDetail::Weapon(_) => self.equipped.weapon = Some(inventory_item.entity_id), + ItemDetail::Armor(_) => self.equipped.armor = Some(inventory_item.entity_id), + ItemDetail::Shield(_) => self.equipped.shield = Some(inventory_item.entity_id), + ItemDetail::Unit(_) => { + if let Some(unit) = self.equipped.unit.get_mut(equip_slot as usize) { + *unit = Some(inventory_item.entity_id) + } + } + ItemDetail::Mag(_) => self.equipped.mag = Some(inventory_item.entity_id), + _ => {} + } + } + } + } + } + + pub fn unequip(&mut self, item_id: &ClientItemId) { + for item in &self.inventory.0 { + if let InventoryItemDetail::Individual(inventory_item) = &item.item { + if item.item_id == *item_id { + match inventory_item.item { + ItemDetail::Weapon(_) => self.equipped.weapon = None, + ItemDetail::Armor(_) => { + self.equipped.armor = None; + self.equipped.unit = [None; 4]; + } + ItemDetail::Shield(_) => self.equipped.shield = None, + ItemDetail::Unit(_) => { + for unit in self.equipped.unit.iter_mut() { + if *unit == Some(inventory_item.entity_id) { + *unit = None + } + } + } + ItemDetail::Mag(_) => self.equipped.mag = Some(inventory_item.entity_id), + _ => {} + } + } + } + } + } + pub fn as_inventory_entity(&self, _character_id: &CharacterEntityId) -> InventoryEntity { InventoryEntity { items: self.inventory.0.iter() @@ -657,29 +728,10 @@ impl InventoryState { } } - pub fn add_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { - if self.meseta.0 == 999999 { - return Err(ItemStateError::FullOfMeseta) - } - self.meseta.0 = std::cmp::min(self.meseta.0 + amount, 999999); - Ok(()) - } - - pub fn add_meseta_no_overflow(&mut self, amount: u32) -> Result<(), ItemStateError> { - if self.meseta.0 + amount > 999999 { - return Err(ItemStateError::FullOfMeseta) - } - self.meseta.0 += amount; - Ok(()) + pub fn as_equipped_entity(&self) -> EquippedEntity { + self.equipped.clone() } - pub fn remove_meseta(&mut self, amount: u32) -> Result<(), ItemStateError> { - if amount > self.meseta.0 { - return Err(ItemStateError::InvalidMesetaRemoval(amount)) - } - self.meseta.0 -= amount; - Ok(()) - } pub fn as_client_inventory_items(&self) -> [character::InventoryItem; 30] { self.inventory.0.iter() diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 1f0dedf..c558150 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -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}; +use crate::ship::items::actions::{drop_item, drop_partial_item, drop_meseta, equip_item, unequip_item}; pub async fn request_exp(id: ClientId, request_exp: &RequestExp, @@ -341,7 +341,7 @@ pub async fn player_equips_item(id: ClientId, pkt: &PlayerEquipItem, entity_gateway: &mut EG, clients: &Clients, - item_manager: &mut ItemManager) + item_state: &mut ItemState) -> Result + Send>, anyhow::Error> where EG: EntityGateway @@ -353,7 +353,7 @@ where else { 0 }; - item_manager.player_equips_item(entity_gateway, &client.character, ClientItemId(pkt.item_id), equip_slot).await?; + equip_item(item_state, entity_gateway, &client.character, &ClientItemId(pkt.item_id), equip_slot).await?; Ok(Box::new(None.into_iter())) // TODO: tell other players you equipped an item } @@ -361,13 +361,13 @@ pub async fn player_unequips_item(id: ClientId, pkt: &PlayerUnequipItem, entity_gateway: &mut EG, clients: &Clients, - item_manager: &mut ItemManager) + item_state: &mut ItemState) -> Result + Send>, anyhow::Error> 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?; + unequip_item(item_state, entity_gateway, &client.character, &ClientItemId(pkt.item_id)).await?; Ok(Box::new(None.into_iter())) // TODO: tell other players if you unequip an item } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 8b9d369..5316eb5 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -512,10 +512,10 @@ impl ShipServerState { handler::message::player_feed_mag(id, player_feed_mag, &mut self.entity_gateway, &block.client_location, &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, &self.clients, &mut self.item_manager).await? + handler::message::player_equips_item(id, player_equip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::PlayerUnequipItem(player_unequip_item) => { - handler::message::player_unequips_item(id, player_unequip_item, &mut self.entity_gateway, &self.clients, &mut self.item_manager).await? + handler::message::player_unequips_item(id, player_unequip_item, &mut self.entity_gateway, &self.clients, &mut self.item_state).await? }, GameMessage::SortItems(sort_items) => { handler::message::player_sorts_items(id, sort_items, &mut self.entity_gateway, &self.clients, &mut self.item_manager).await?