From 250be01fab18199f63db8b3aa966f054545ce59d Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 14 Nov 2023 00:06:05 -0700 Subject: [PATCH] another dead file --- src/items/src/manager.rs | 1380 -------------------------------------- 1 file changed, 1380 deletions(-) delete mode 100644 src/items/src/manager.rs diff --git a/src/items/src/manager.rs b/src/items/src/manager.rs deleted file mode 100644 index d368ec6..0000000 --- a/src/items/src/manager.rs +++ /dev/null @@ -1,1380 +0,0 @@ -use crate::ClientItemId; -use std::collections::HashMap; -use std::cmp::Ordering; -use std::cell::RefCell; -use thiserror::Error; -use crate::entity::gateway::{EntityGateway, GatewayError}; -use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel}; -use crate::entity::item::{ItemDetail, ItemNote, BankName}; -use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, BankItemEntity}; -use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::weapon; -use maps::area::MapArea; -use crate::ship::ship::ItemDropLocation; -use crate::ship::trade::TradeItem; -use drops::{ItemDrop, ItemDropType}; -use location::{AreaClient, RoomId}; -use shops::ShopItem; -use crate::ship::packet::handler::trade::{TradeError, OTHER_MESETA_ITEM_ID}; - -use crate::bank::*; -use crate::floor::*; -use crate::inventory::*; -use crate::transaction::{ItemTransaction, ItemAction, TransactionError, TransactionCommitError}; - -#[derive(PartialEq, Eq)] -pub enum FloorType { - Local, - Shared, -} - -pub enum TriggerCreateItem { - Yes, - No -} - -#[derive(Error, Debug)] -#[error("itemmanager")] -pub enum ItemManagerError { - #[error("gateway")] - EntityGatewayError, - #[error("no such item id {0}")] - NoSuchItemId(ClientItemId), - NoCharacter(CharacterEntityId), - NoRoom(RoomId), - CouldNotAddToInventory(ClientItemId), - //ItemBelongsToOtherPlayer, - #[error("shrug")] - Idunnoman, - CouldNotSplitItem(ClientItemId), - #[error("could not drop meseta")] - CouldNotDropMeseta, - InvalidBankName(BankName), - #[error("not enough tools")] - NotEnoughTools(Tool, usize, usize), // have, expected - InventoryItemConsumeError(#[from] InventoryItemConsumeError), - #[error("bank full")] - BankFull, - WrongItemType(ClientItemId), - UseItemError(#[from] use_tool::UseItemError), - #[error("could not buy item")] - CouldNotBuyItem, - #[error("could not add bought item to inventory")] - CouldNotAddBoughtItemToInventory, - ItemIdNotInInventory(ClientItemId), - #[error("cannot get mut item")] - CannotGetMutItem, - #[error("cannot get individual item")] - CannotGetIndividualItem, - InvalidSlot(u8, u8), // slots available, slot attempted - #[error("no armor equipped")] - NoArmorEquipped, - GatewayError(#[from] GatewayError), - #[error("stacked item")] - StackedItemError(Vec), - #[error("item not sellable")] - ItemNotSellable(InventoryItem), - #[error("wallet full")] - WalletFull, - #[error("invalid sale")] - InvalidSale, - ItemTransactionAction(Box), - #[error("invalid trade")] - InvalidTrade, -} - -impl std::convert::From> for ItemManagerError -where - E: std::fmt::Debug + std::marker::Send + std::marker::Sync + std::error::Error + 'static, -{ - fn from(other: TransactionError) -> ItemManagerError { - match other { - TransactionError::Action(err) => { - ItemManagerError::ItemTransactionAction(Box::new(err)) - }, - TransactionError::Commit(err) => { - match err { - TransactionCommitError::Gateway(gw) => { - ItemManagerError::GatewayError(gw) - }, - TransactionCommitError::ItemManager(im) => { - im - } - } - } - } - } -} - - -pub struct ItemManager { - pub(super) id_counter: u32, - - pub(self) character_inventory: HashMap, - pub(self) character_meseta: HashMap, - pub(self) bank_meseta: HashMap, - //character_bank: HashMap>, - pub(self) character_bank: HashMap, - pub(self) character_floor: HashMap, - - pub(self) character_room: HashMap, - pub(self) room_floor: HashMap, - pub(self) room_item_id_counter: RefCell ClientItemId + Send>>>, -} - -impl Default for ItemManager { - fn default() -> ItemManager { - ItemManager { - id_counter: 0, - character_inventory: HashMap::new(), - character_meseta: HashMap::new(), - bank_meseta: HashMap::new(), - character_bank: HashMap::new(), - character_floor: HashMap::new(), - character_room: HashMap::new(), - room_floor: HashMap::new(), - room_item_id_counter: RefCell::new(HashMap::new()), - } - } -} - -impl ItemManager { - pub fn next_global_item_id(&mut self) -> ClientItemId { - self.id_counter += 1; - ClientItemId(self.id_counter) - } - - pub async fn load_character(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), anyhow::Error> { - let inventory = entity_gateway.get_character_inventory(&character.id).await?; - let bank = entity_gateway.get_character_bank(&character.id, &BankName("".into())).await?; - let equipped = entity_gateway.get_character_equips(&character.id).await?; - - let inventory_items = inventory.items.into_iter() - .map(|item| -> Result { - Ok(match item { - InventoryItemEntity::Individual(item) => { - InventoryItem::Individual(IndividualInventoryItem { - entity_id: item.id, - item_id: self.next_global_item_id(), - item: item.item, - }) - }, - InventoryItemEntity::Stacked(items) => { - InventoryItem::Stacked(StackedInventoryItem { - entity_ids: items.iter().map(|i| i.id).collect(), - item_id: self.next_global_item_id(), - tool: items.get(0) - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - .item - .clone() - .as_tool() - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - }) - }, - }) - }) - .collect::, _>>()?; - let character_inventory = CharacterInventory::new(inventory_items, &equipped); - - let bank_items = bank.items.into_iter() - .map(|item| -> Result { - Ok(match item { - BankItemEntity::Individual(item) => { - BankItem::Individual(IndividualBankItem { - entity_id: item.id, - item_id: self.next_global_item_id(), - item: item.item, - }) - }, - BankItemEntity::Stacked(items) => { - BankItem::Stacked(StackedBankItem { - entity_ids: items.iter().map(|i| i.id).collect(), - item_id: self.next_global_item_id(), - tool: items.get(0) - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - .item - .clone() - .as_tool() - .ok_or_else(|| ItemManagerError::StackedItemError(items.clone()))? - }) - }, - }) - }) - .collect::, _>>()?; - let character_bank = CharacterBank::new(bank_items); - - let character_meseta = entity_gateway.get_character_meseta(&character.id).await?; - let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &BankName("".into())).await?; - - self.character_inventory.insert(character.id, character_inventory); - self.character_bank.insert(character.id, character_bank); - self.character_meseta.insert(character.id, character_meseta); - self.bank_meseta.insert(character.id, bank_meseta); - Ok(()) - } - - pub fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) { - let base_inventory_id = ((area_client.local_client.id() as u32) << 21) | 0x10000; - let inventory = self.character_inventory.get_mut(&character.id).unwrap(); - inventory.initialize_item_ids(base_inventory_id); - let base_bank_id = ((area_client.local_client.id() as u32) << 21) | 0x20000; - let default_bank = self.character_bank.get_mut(&character.id); - if let Some(default_bank ) = default_bank { - default_bank.initialize_item_ids(base_bank_id); - } - self.character_room.insert(character.id, room_id); - self.character_floor.insert(character.id, RoomFloorItems::default()); - self.room_floor.entry(room_id).or_insert_with(RoomFloorItems::default); - - let mut inc = 0x00810000; - self.room_item_id_counter.borrow_mut().entry(room_id).or_insert_with(|| Box::new(move || { - inc += 1; - ClientItemId(inc) - })); - } - - pub fn get_character_inventory(&self, character: &CharacterEntity) -> Result<&CharacterInventory, anyhow::Error> { - Ok(self.character_inventory.get(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?) - } - - pub fn get_character_inventory_mut<'a>(&'a mut self, character: &CharacterEntity) -> Result<&'a mut CharacterInventory, anyhow::Error> { - Ok(self.character_inventory.get_mut(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?) - } - - pub fn get_character_bank(&self, character: &CharacterEntity) -> Result<&CharacterBank, anyhow::Error> { - self.character_bank - .get(&character.id) - .ok_or_else(|| ItemManagerError::NoCharacter(character.id).into()) - } - - pub fn get_character_meseta(&self, character_id: &CharacterEntityId) -> Result<&Meseta, ItemManagerError> { - self.character_meseta.get(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_character_meseta_mut<'a>(&'a mut self, character_id: &CharacterEntityId) -> Result<&'a mut Meseta, ItemManagerError> { - self.character_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_bank_meseta(&self, character_id: &CharacterEntityId) -> Result<&Meseta, ItemManagerError> { - self.bank_meseta.get(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_bank_meseta_mut<'a>(&'a mut self, character_id: &CharacterEntityId) -> Result<&'a mut Meseta, ItemManagerError> { - self.bank_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id)) - } - - pub fn get_character_and_bank_meseta_mut<'a>(&'a mut self, character_id: &CharacterEntityId) -> Result<(&'a mut Meseta, &'a mut Meseta), ItemManagerError> { - Ok(( - self.character_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id))?, - self.bank_meseta.get_mut(character_id) - .ok_or(ItemManagerError::NoCharacter(*character_id))? - )) - } - - pub fn remove_character_from_room(&mut self, character: &CharacterEntity) { - self.character_inventory.remove(&character.id); - self.character_floor.remove(&character.id); - if let Some(room) = self.character_room.remove(&character.id).as_ref() { - if self.character_room.iter().any(|(_, r)| r == room) { - self.room_floor.remove(room); - } - } - } - - pub fn get_floor_item_by_id(&self, character: &CharacterEntity, item_id: ClientItemId) -> Result<(&FloorItem, FloorType), anyhow::Error> { - let local_floor = self.character_floor.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = self.room_floor.get(room).ok_or(ItemManagerError::NoCharacter(character.id))?; - - local_floor.get_item_by_id(item_id).map(|item| (item, FloorType::Local)) - .or_else(|| { - shared_floor.get_item_by_id(item_id).map(|item| (item, FloorType::Shared)) - }) - .ok_or_else(|| ItemManagerError::NoSuchItemId(item_id).into()) - } - - pub async fn character_picks_up_item(&mut self, entity_gateway: &mut EG, character: &mut CharacterEntity, item_id: ClientItemId) - -> Result { - let it = ItemTransaction::new(self, (character, item_id)) - .act(|it, (character, item_id)| -> Result<_, ItemManagerError> { - let local_floor = it.manager.character_floor.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let inventory = it.manager.character_inventory.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room_id = it.manager.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = it.manager.room_floor.get(room_id).ok_or(ItemManagerError::NoRoom(*room_id))?; - - let floor_item = match local_floor.get_item_by_id(*item_id) { - Some(floor_item) => { - it.action(Box::new(RemoveFromLocalFloor { - character_id: character.id, - item_id: *item_id - })); - floor_item - }, - None => { - match shared_floor.get_item_by_id(*item_id) { - Some(floor_item) => { - it.action(Box::new(RemoveFromSharedFloor { - room_id: *room_id, - item_id: *item_id - })); - floor_item - }, - None => { - return Err(ItemManagerError::NoSuchItemId(*item_id)) - } - } - } - }; - - let create_trigger = match floor_item { - FloorItem::Individual(individual_floor_item) => { - if inventory.space_for_individual_item() { - it.action(Box::new(AddIndividualFloorItemToInventory { - character: (**character).clone(), - item: individual_floor_item.clone() - })) - } - else { - return Err(ItemManagerError::CouldNotAddToInventory(*item_id)); - } - TriggerCreateItem::Yes - }, - FloorItem::Stacked(stacked_floor_item) => { - match inventory.space_for_stacked_item(&stacked_floor_item.tool, stacked_floor_item.entity_ids.len()) { - SpaceForStack::Yes(YesThereIsSpace::NewStack) => { - it.action(Box::new(AddStackedFloorItemToInventory { - character_id: character.id, - item: stacked_floor_item.clone() - })); - TriggerCreateItem::Yes - }, - SpaceForStack::Yes(YesThereIsSpace::ExistingStack) => { - it.action(Box::new(AddStackedFloorItemToInventory { - character_id: character.id, - item: stacked_floor_item.clone() - })); - TriggerCreateItem::No - }, - SpaceForStack::No(_) => { - return Err(ItemManagerError::CouldNotAddToInventory(*item_id)); - }, - } - }, - FloorItem::Meseta(meseta_floor_item) => { - let character_meseta = it.manager.character_meseta.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - if character_meseta.0 >= 999999 { - return Err(ItemManagerError::CouldNotAddToInventory(*item_id)); - } - it.action(Box::new(AddMesetaFloorItemToInventory { - character_id: character.id, - item: meseta_floor_item.clone() - })); - - TriggerCreateItem::No - }, - }; - Ok(create_trigger) - }); - it.commit(self, entity_gateway) - .await - .map_err(|err| err.into()) - } - - pub async fn enemy_drop_item_on_local_floor<'a, EG: EntityGateway>(&'a mut self, entity_gateway: &'a mut EG, character: &'a CharacterEntity, item_drop: ItemDrop) -> Result<&'a FloorItem, anyhow::Error> { - let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - enum ItemOrMeseta { - Individual(ItemDetail), - Stacked(Tool), - Meseta(Meseta) - } - - let item = match item_drop.item { - ItemDropType::Weapon(w) => ItemOrMeseta::Individual(ItemDetail::Weapon(w)), - ItemDropType::Armor(w) => ItemOrMeseta::Individual(ItemDetail::Armor(w)), - ItemDropType::Shield(w) => ItemOrMeseta::Individual(ItemDetail::Shield(w)), - ItemDropType::Unit(w) => ItemOrMeseta::Individual(ItemDetail::Unit(w)), - ItemDropType::TechniqueDisk(w) => ItemOrMeseta::Individual(ItemDetail::TechniqueDisk(w)), - ItemDropType::Mag(w) => ItemOrMeseta::Individual(ItemDetail::Mag(w)), - //ItemDropType::IndividualTool(t) => ItemOrMeseta::Individual(ItemDetail::Tool(t)), - //ItemDropType::StackedTool(t, _) => ItemOrMeseta::Stacked(t), - ItemDropType::Tool(t) if t.tool.is_stackable() => ItemOrMeseta::Stacked(t), - ItemDropType::Tool(t) if !t.tool.is_stackable() => ItemOrMeseta::Individual(ItemDetail::Tool(t)), - ItemDropType::Meseta(m) => ItemOrMeseta::Meseta(Meseta(m)), - _ => unreachable!() // rust isnt smart enough to see that the conditional on tool catches everything - }; - - let item_id = self.room_item_id_counter.borrow_mut().get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); - let floor_item = match item { - ItemOrMeseta::Individual(item_detail) => { - let entity = entity_gateway.create_item(NewItemEntity { - item: item_detail.clone(), - }).await?; - entity_gateway.add_item_note(&entity.id, ItemNote::EnemyDrop { - character_id: character.id, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }).await?; - FloorItem::Individual(IndividualFloorItem { - entity_id: entity.id, - item_id, - item: item_detail, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }) - }, - ItemOrMeseta::Stacked(tool) => { - let entity = entity_gateway.create_item(NewItemEntity { - item: ItemDetail::Tool(tool), - }).await?; - entity_gateway.add_item_note(&entity.id, ItemNote::EnemyDrop { - character_id: character.id, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }).await?; - FloorItem::Stacked(StackedFloorItem { - entity_ids: vec![entity.id], - item_id, - tool, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }) - }, - ItemOrMeseta::Meseta(meseta) => { - FloorItem::Meseta(MesetaFloorItem { - item_id, - meseta, - map_area: item_drop.map_area, - x: item_drop.x, - y: item_drop.y, - z: item_drop.z, - }) - }, - }; - - self.character_floor.entry(character.id).or_insert_with(RoomFloorItems::default).add_item(floor_item); - // TODO: make these real errors - self.character_floor.get(&character.id).ok_or(ItemManagerError::Idunnoman)?.get_item_by_id(item_id).ok_or_else(|| ItemManagerError::Idunnoman.into()) - } - - pub async fn player_drop_item_on_shared_floor(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - //inventory_item: InventoryItem, - item_id: ClientItemId, - item_drop_location: (MapArea, f32, f32, f32)) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let dropped_inventory_item = inventory.take_item_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - - match dropped_inventory_item { - InventoryItem::Individual(individual_inventory_item) => { - let individual_floor_item = shared_floor.drop_individual_inventory_item(individual_inventory_item, item_drop_location); - entity_gateway.add_item_note( - &individual_floor_item.entity_id, - ItemNote::PlayerDrop { - character_id: character.id, - map_area: item_drop_location.0, - x: item_drop_location.1, - y: item_drop_location.2, - z: item_drop_location.3, - } - ).await?; - }, - InventoryItem::Stacked(stacked_inventory_item) => { - let stacked_floor_item = shared_floor.drop_stacked_inventory_item(stacked_inventory_item, item_drop_location); - for entity_id in &stacked_floor_item.entity_ids { - entity_gateway.add_item_note( - entity_id, - ItemNote::PlayerDrop { - character_id: character.id, - map_area: item_drop_location.0, - x: item_drop_location.1, - y: item_drop_location.2, - z: item_drop_location.3, - } - ).await?; - } - }, - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn player_drops_meseta_on_shared_floor(&mut self, - entity_gateway: &mut EG, - character: &mut CharacterEntity, - drop_location: ItemDropLocation, - amount: u32) - -> Result { - let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let character_meseta = self.character_meseta.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - if character_meseta.0 < amount { - return Err(ItemManagerError::CouldNotDropMeseta.into()) - } - character_meseta.0 -= amount; - entity_gateway.set_character_meseta(&character.id, *character_meseta).await?; - - let item_id = self.room_item_id_counter.borrow_mut().get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); - let floor_item = FloorItem::Meseta(MesetaFloorItem { - item_id, - meseta: Meseta(amount), - map_area: drop_location.map_area, - x: drop_location.x, - y: 0.0, - z: drop_location.z, - }); - - shared_floor.add_item(floor_item.clone()); - Ok(floor_item) - } - - pub async fn player_drops_partial_stack_on_shared_floor<'a, EG: EntityGateway>(&'a mut self, - entity_gateway: &'a mut EG, - character: &'a CharacterEntity, - //inventory_item: InventoryItem, - item_id: ClientItemId, - drop_location: ItemDropLocation, - amount: usize) - -> Result<&'a StackedFloorItem, anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let room_id = self.character_room.get(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let shared_floor = self.room_floor.get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_to_split = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - - let new_item_id = self.room_item_id_counter.borrow_mut().get_mut(room_id).ok_or(ItemManagerError::NoCharacter(character.id))?(); - let stacked_floor_item = shared_floor.drop_partial_stacked_inventory_item(item_to_split, amount, new_item_id, (drop_location.map_area, drop_location.x, 0.0, drop_location.z)) - .ok_or(ItemManagerError::CouldNotSplitItem(item_id))?; - - for entity_id in &stacked_floor_item.entity_ids { - entity_gateway.add_item_note( - entity_id, - ItemNote::PlayerDrop { - character_id: character.id, - map_area: drop_location.map_area, - x: drop_location.x, - y: 0.0, - z: drop_location.z, - } - ).await?; - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(stacked_floor_item) - } - - pub async fn player_consumes_tool(&mut self, - entity_gateway: &mut EG, - character: &mut CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let used_item = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let consumed_item = used_item.consume(amount)?; - - if let ItemDetail::TechniqueDisk(tech_disk) = consumed_item.item() { - // TODO: validate tech level in packet is in bounds [1..30] - character.techs.set_tech(tech_disk.tech, TechLevel(tech_disk.level as u8)); - entity_gateway.save_character(character).await?; - }; - - for entity_id in consumed_item.entity_ids() { - entity_gateway.add_item_note(&entity_id, - ItemNote::Consumed).await?; - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(consumed_item) - } - - pub async fn player_deposits_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let bank = self.character_bank - .get_mut(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_to_deposit = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let _bank_item = bank.deposit_item(item_to_deposit, amount).ok_or(ItemManagerError::Idunnoman)?; - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - entity_gateway.set_character_bank(&character.id, &bank.as_bank_entity(&character.id, &BankName("".into())), &BankName("".into())).await?; - Ok(()) - } - - pub async fn player_withdraws_item<'a, EG: EntityGateway>(&'a mut self, - entity_gateway: &'a mut EG, - character: &'a CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result<&'a InventoryItem, anyhow::Error> { - - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let bank = self.character_bank - .get_mut(&character.id) - .ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_to_withdraw = bank.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let inventory_item_slot = { - let inventory_item = inventory.withdraw_item(item_to_withdraw, amount).ok_or(ItemManagerError::Idunnoman)?; - inventory_item.1 - }; - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - entity_gateway.set_character_bank(&character.id, &bank.as_bank_entity(&character.id, &BankName("".into())), &BankName("".into())).await?; - inventory.slot(inventory_item_slot).ok_or_else(|| ItemManagerError::Idunnoman.into()) - } - - pub async fn player_feeds_mag_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - mag_id: ClientItemId, - tool_id: ClientItemId) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let consumed_tool = { - let item_to_feed = inventory.get_item_handle_by_id(tool_id).ok_or(ItemManagerError::NoSuchItemId(tool_id))?; - item_to_feed.consume(1)? - }; - let mut mag_handle = inventory.get_item_handle_by_id(mag_id).ok_or(ItemManagerError::NoSuchItemId(mag_id))?; - - let individual_item = mag_handle.item_mut() - .ok_or(ItemManagerError::NoSuchItemId(mag_id))? - .individual_mut() - .ok_or(ItemManagerError::WrongItemType(mag_id))?; - let mag = individual_item - .mag_mut() - .ok_or(ItemManagerError::WrongItemType(mag_id))?; - - let consumed_tool_type = match &consumed_tool { - ConsumedItem::Stacked(stacked_consumed_item) => stacked_consumed_item.tool.tool, - _ => return Err(ItemManagerError::WrongItemType(tool_id).into()) - }; - mag.feed(consumed_tool_type); - - for entity_id in consumed_tool.entity_ids() { - entity_gateway.feed_mag(&individual_item.entity_id, &entity_id).await?; - entity_gateway.add_item_note(&entity_id, ItemNote::FedToMag { - mag: individual_item.entity_id, - }).await?; - } - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn use_item(&mut self, - used_item: ConsumedItem, - entity_gateway: &mut EG, - character: &mut CharacterEntity) -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - match &used_item.item() { - ItemDetail::Weapon(_w) => { - // something like when items are used to combine/transform them? - //_ => {} - }, - ItemDetail::Tool(t) => { - match t.tool { - ToolType::PowerMaterial => { - use_tool::power_material(entity_gateway, character).await; - }, - ToolType::MindMaterial => { - use_tool::mind_material(entity_gateway, character).await; - }, - ToolType::EvadeMaterial => { - use_tool::evade_material(entity_gateway, character).await; - }, - ToolType::DefMaterial => { - use_tool::def_material(entity_gateway, character).await; - }, - ToolType::LuckMaterial => { - use_tool::luck_material(entity_gateway, character).await; - }, - ToolType::HpMaterial => { - use_tool::hp_material(entity_gateway, character).await; - }, - ToolType::TpMaterial => { - use_tool::tp_material(entity_gateway, character).await; - }, - ToolType::CellOfMag502 => { - use_tool::cell_of_mag_502(entity_gateway, &used_item, inventory).await?; - }, - ToolType::CellOfMag213 => { - use_tool::cell_of_mag_213(entity_gateway, &used_item, inventory).await?; - }, - ToolType::PartsOfRobochao => { - use_tool::parts_of_robochao(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfOpaOpa => { - use_tool::heart_of_opaopa(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfPian => { - use_tool::heart_of_pian(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfChao=> { - use_tool::heart_of_chao(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfAngel => { - use_tool::heart_of_angel(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfHamburger => { - use_tool::kit_of_hamburger(entity_gateway, &used_item, inventory).await?; - }, - ToolType::PanthersSpirit => { - use_tool::panthers_spirit(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfMark3 => { - use_tool::kit_of_mark3(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfMasterSystem=> { - use_tool::kit_of_master_system(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfGenesis => { - use_tool::kit_of_genesis(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfSegaSaturn => { - use_tool::kit_of_sega_saturn(entity_gateway, &used_item, inventory).await?; - }, - ToolType::KitOfDreamcast => { - use_tool::kit_of_dreamcast(entity_gateway, &used_item, inventory).await?; - }, - ToolType::Tablet => { - use_tool::tablet(entity_gateway, &used_item, inventory).await?; - }, - ToolType::DragonScale => { - use_tool::dragon_scale(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeavenStrikerCoat => { - use_tool::heaven_striker_coat(entity_gateway, &used_item, inventory).await?; - }, - ToolType::PioneerParts => { - use_tool::pioneer_parts(entity_gateway, &used_item, inventory).await?; - }, - ToolType::AmitiesMemo => { - use_tool::amities_memo(entity_gateway, &used_item, inventory).await?; - }, - ToolType::HeartOfMorolian => { - use_tool::heart_of_morolian(entity_gateway, &used_item, inventory).await?; - }, - ToolType::RappysBeak => { - use_tool::rappys_beak(entity_gateway, &used_item, inventory).await?; - }, - ToolType::YahoosEngine => { - use_tool::yahoos_engine(entity_gateway, &used_item, inventory).await?; - }, - ToolType::DPhotonCore => { - use_tool::d_photon_core(entity_gateway, &used_item, inventory).await?; - }, - ToolType::LibertaKit => { - use_tool::liberta_kit(entity_gateway, &used_item, inventory).await?; - }, - _ => {} - } - } - _ => {} - } - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn player_buys_item<'a, EG: EntityGateway>(&'a mut self, - entity_gateway: &'a mut EG, - character: &'a CharacterEntity, - shop_item: &'a (dyn ShopItem + Send + Sync), - item_id: ClientItemId, - amount: usize) - -> Result<&'a InventoryItem, anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item_detail = shop_item.as_item(); - let inventory_item = match item_detail { - ItemDetail::Tool(tool) => { - if tool.is_stackable() { - let mut item_entities = Vec::new(); - for _ in 0..amount { - let item_entity = entity_gateway.create_item(NewItemEntity { - item: ItemDetail::Tool(tool), - }).await?; - entity_gateway.add_item_note(&item_entity.id, ItemNote::BoughtAtShop { - character_id: character.id, - }).await?; - item_entities.push(item_entity); - } - let floor_item = StackedFloorItem { - entity_ids: item_entities.into_iter().map(|i| i.id).collect(), - item_id, - tool, - // TODO: this is gonna choke if I ever require the item being near the player for pickup - map_area: MapArea::Pioneer2Ep1, - x: 0.0, - y: 0.0, - z: 0.0, - }; - let item_id = { - let (picked_up_item, _slot) = inventory.pick_up_stacked_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; - picked_up_item.item_id - }; - inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? - } - else { - let item_entity = entity_gateway.create_item(NewItemEntity { - item: ItemDetail::Tool(tool), - }).await?; - entity_gateway.add_item_note(&item_entity.id, ItemNote::BoughtAtShop { - character_id: character.id, - }).await?; - - let floor_item = IndividualFloorItem { - entity_id: item_entity.id, - item_id, - item: ItemDetail::Tool(tool), - // TODO: this is gonna choke if I ever require the item being near the player for pickup - map_area: MapArea::Pioneer2Ep1, - x: 0.0, - y: 0.0, - z: 0.0, - }; - let item_id = { - let (picked_up_item, _slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; - picked_up_item.item_id - }; - inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? - } - }, - item_detail => { - let item_entity = entity_gateway.create_item(NewItemEntity { - item: item_detail.clone(), - }).await?; - entity_gateway.add_item_note(&item_entity.id, ItemNote::BoughtAtShop { - character_id: character.id, - }).await?; - let floor_item = IndividualFloorItem { - entity_id: item_entity.id, - item_id, - item: item_detail, - // TODO: this is gonna choke if I ever require the item being near the player for pickup - map_area: MapArea::Pioneer2Ep1, - x: 0.0, - y: 0.0, - z: 0.0, - }; - let item_id = { - let (picked_up_item, _slot) = inventory.pick_up_individual_floor_item(&floor_item).ok_or(ItemManagerError::CouldNotAddBoughtItemToInventory)?; - picked_up_item.item_id - }; - inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))? - }, - }; - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(inventory_item) - } - - pub async fn player_sells_item(&mut self, - entity_gateway: &mut EG, - character: &mut CharacterEntity, - item_id: ClientItemId, - amount: usize) - -> Result<(), anyhow::Error> { - let character_meseta = self.get_character_meseta(&character.id)?.0; - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let sold_item_handle = inventory.get_item_handle_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - if let Some(item_sold) = sold_item_handle.item() { - let unit_price = item_sold.get_sell_price()?; { - let total_sale = unit_price * amount as u32; - if character_meseta + total_sale <= 999999 { - match item_sold { - InventoryItem::Individual(i) => { - entity_gateway.add_item_note(&i.entity_id, ItemNote::SoldToShop).await?; - inventory.remove_by_id(item_id).ok_or(ItemManagerError::NoSuchItemId(item_id))?; - }, - InventoryItem::Stacked(s) => { - match amount.cmp(&s.count()) { - Ordering::Less | Ordering::Equal => { - sold_item_handle.consume(amount)?; - }, - Ordering::Greater => return Err(ItemManagerError::InvalidSale.into()), - }; - }, - } - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - let character_meseta = self.get_character_meseta_mut(&character.id)?; - character_meseta.0 += total_sale; - entity_gateway.set_character_meseta(&character.id, *character_meseta).await?; - } - else { - return Err(ItemManagerError::WalletFull.into()) - } - } - } else { - return Err(ItemManagerError::ItemIdNotInInventory(item_id).into()) - } - Ok(()) - } - - // TODO: check if slot exists before putting units into it - pub async fn player_equips_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId, - equip_slot: u8) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - inventory.equip(&item_id, equip_slot); - entity_gateway.set_character_equips(&character.id, &inventory.as_equipped_entity()).await?; - Ok(()) - } - - pub async fn player_unequips_item(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - inventory.unequip(&item_id); - entity_gateway.set_character_equips(&character.id, &inventory.as_equipped_entity()).await?; - Ok(()) - } - - pub async fn player_sorts_items(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_ids: [u32; 30]) - -> Result<(), anyhow::Error> { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let sorted_inventory_items: Vec = item_ids.iter() - .filter(|&client_item_id| *client_item_id < 0xFFFFFFFF) - .map(|&client_item_id| inventory.get_item_by_id(ClientItemId(client_item_id))) - .filter(|&x| x.is_some()) - .map(|x| x.cloned().unwrap()) - .collect(); - - inventory.set_items(sorted_inventory_items); - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - Ok(()) - } - - pub async fn replace_item_with_tekked(&mut self, - entity_gateway: &mut EG, - character: &CharacterEntity, - item_id: ClientItemId, - tek: weapon::WeaponModifier) - -> Result { - let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - - let item = inventory.remove_by_id(item_id) - .ok_or(ItemManagerError::NoSuchItemId(item_id))?; - let individual = item - .individual() - .ok_or(ItemManagerError::WrongItemType(item_id))?; - - let entity_id = individual.entity_id; - let mut weapon = *individual - .weapon() - .ok_or(ItemManagerError::WrongItemType(item_id))?; - - weapon.apply_modifier(&tek); - entity_gateway.add_weapon_modifier(&entity_id, tek).await?; - - inventory.add_item(InventoryItem::Individual(IndividualInventoryItem { - entity_id, - item_id, - item: ItemDetail::Weapon(weapon), - })); - - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; - - Ok(weapon) - } - - pub async fn trade_items(&mut self, - entity_gateway: &mut EG, - room_id: RoomId, - p1: (&AreaClient, &CharacterEntity, &Vec, usize), - p2: (&AreaClient, &CharacterEntity, &Vec, usize)) - -> Result, anyhow::Error> { - let it = ItemTransaction::new(self, (p1, p2, room_id)) - .act(|it, (p1, p2, room_id)| -> Result<_, anyhow::Error> { - let p1_inventory = it.manager.get_character_inventory(p1.1)?; - let p2_inventory = it.manager.get_character_inventory(p2.1)?; - - [(p2_inventory, p1_inventory, p2.2, p1.2), (p1_inventory, p2_inventory, p1.2, p2.2)].iter() - .map(|(src_inventory, dest_inventory, trade_recv, trade_send)| { - let item_slots_lost_to_trade = trade_send - .iter() - .fold(0, |acc, item| { - match item { - TradeItem::Individual(..) => { - acc + 1 - }, - TradeItem::Stacked(item_id, amount) => { - let stacked_inventory_item = try { - src_inventory - .get_item_by_id(*item_id)? - .stacked() - }; - if let Some(Some(item)) = stacked_inventory_item { - if item.count() == *amount { - acc + 1 - } - else { - acc - } - } - else { - acc - } - } - } - }); - trade_recv - .iter() - .try_fold(dest_inventory.count(), |acc, item| { - match item { - TradeItem::Individual(..) => { - if acc >= (30 + item_slots_lost_to_trade) { - Err(TradeError::NoInventorySpace) - } - else { - Ok(acc + 1) - } - }, - TradeItem::Stacked(item_id, amount) => { - let stacked_inventory_item = src_inventory - .get_item_by_id(*item_id) - .ok_or(TradeError::InvalidItemId(*item_id))? - .stacked() - .ok_or(TradeError::InvalidItemId(*item_id))?; - match dest_inventory.space_for_stacked_item(&stacked_inventory_item.tool, *amount) { - SpaceForStack::Yes(YesThereIsSpace::ExistingStack) => { - Ok(acc) - }, - SpaceForStack::Yes(YesThereIsSpace::NewStack) => { - Ok(acc + 1) - }, - SpaceForStack::No(NoThereIsNotSpace::FullStack) => { - Err(TradeError::NoStackSpace) - }, - SpaceForStack::No(NoThereIsNotSpace::FullInventory) => { - if acc >= (30 + item_slots_lost_to_trade) { - Err(TradeError::NoInventorySpace) - } - else { - Ok(acc + 1) - } - }, - } - } - } - }) - }) - .collect::, _>>()?; - - let trade_items = [(p1, p2, p1_inventory), (p2, p1, p2_inventory)] - .map(|(src_client, dest_client, src_inventory)| { - src_client.2.iter() - .map(|item| -> Option<(Option, Box>)> { - match item { - TradeItem::Individual(item_id) => { - let item = src_inventory.get_item_by_id(*item_id)?.individual()?; - let new_item_id = it.manager.room_item_id_counter.borrow_mut().get_mut(room_id)?(); - Some(( - Some(ItemToTrade { - add_to: *dest_client.0, - remove_from: *src_client.0, - current_item_id: *item_id, - new_item_id, - item_detail: ItemToTradeDetail::Individual(item.item.clone()) - }), - Box::new(TradeIndividualItem { - src_character_id: src_client.1.id, - dest_character_id: dest_client.1.id, - current_item_id: *item_id, - new_item_id, - }), - )) - }, - TradeItem::Stacked(item_id, amount) => { - let item = src_inventory.get_item_by_id(*item_id)?.stacked()?; - if item.count() < *amount { - None - } - else { - let new_item_id = it.manager.room_item_id_counter.borrow_mut().get_mut(room_id)?(); - Some(( - Some(ItemToTrade { - add_to: *dest_client.0, - remove_from: *src_client.0, - current_item_id: *item_id, - new_item_id, - item_detail: ItemToTradeDetail::Stacked(item.tool, *amount) - }), - Box::new(TradeStackedItem { - src_character_id: src_client.1.id, - dest_character_id: dest_client.1.id, - //item_ids: item.entity_ids.iter().cloned().take(*amount).collect(), - current_item_id: *item_id, - new_item_id, - amount: *amount, - }), - )) - } - } - } - }) - .chain( - if src_client.3 > 0 { - Box::new(std::iter::once(Some( - (Some(ItemToTrade { - add_to: *dest_client.0, - remove_from: *src_client.0, - current_item_id: OTHER_MESETA_ITEM_ID, - new_item_id: OTHER_MESETA_ITEM_ID, - item_detail: ItemToTradeDetail::Meseta(src_client.3) - }), - Box::new(TradeMeseta { - src_character_id: src_client.1.id, - dest_character_id: dest_client.1.id, - amount: src_client.3, - }) as Box>)))) as Box> - } - else { - Box::new(std::iter::empty()) as Box> - }) - .collect::>>() - }); - - - if let [Some(p1_trades), Some(p2_trades)] = trade_items { - let (p1_item_trades, p1_item_actions): (Vec<_>, Vec<_>) = p1_trades.into_iter().unzip(); - let (p2_item_trades, p2_item_actions): (Vec<_>, Vec<_>) = p2_trades.into_iter().unzip(); - - let item_trades = p1_item_trades.into_iter().flatten().chain(p2_item_trades.into_iter().flatten()); - let item_actions = p1_item_actions.into_iter().chain(p2_item_actions.into_iter()); - - for action in item_actions { - it.action(action); - } - - Ok(item_trades.collect()) - } - else { - Err(ItemManagerError::InvalidTrade.into()) - } - - }); - it.commit(self, entity_gateway) - .await - .map_err(|err| err.into()) - } -} - -#[derive(Debug)] -pub enum ItemToTradeDetail { - Individual(ItemDetail), - Stacked(Tool, usize), - Meseta(usize), -} - -#[derive(Debug)] -pub struct ItemToTrade { - pub add_to: AreaClient, - pub remove_from: AreaClient, - pub current_item_id: ClientItemId, - pub new_item_id: ClientItemId, - pub item_detail: ItemToTradeDetail, -} - - -#[derive(Debug)] -struct RemoveFromLocalFloor { - character_id: CharacterEntityId, - item_id: ClientItemId, -} - -#[async_trait::async_trait] -impl ItemAction for RemoveFromLocalFloor { - async fn commit(&self, item_manager: &mut ItemManager, _entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let local_floor = item_manager.character_floor.get_mut(&self.character_id).ok_or(ItemManagerError::NoCharacter(self.character_id))?; - local_floor.remove_item(&self.item_id); - Ok(()) - } -} - - -#[derive(Debug)] -struct RemoveFromSharedFloor { - room_id: RoomId, - item_id: ClientItemId, -} - -#[async_trait::async_trait] -impl ItemAction for RemoveFromSharedFloor { - async fn commit(&self, item_manager: &mut ItemManager, _entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let shared_floor = item_manager.room_floor.get_mut(&self.room_id).ok_or(ItemManagerError::NoRoom(self.room_id))?; - shared_floor.remove_item(&self.item_id); - Ok(()) - } -} - - -#[derive(Debug)] -struct AddIndividualFloorItemToInventory{ - character: CharacterEntity, - item: IndividualFloorItem, -} - -#[async_trait::async_trait] -impl ItemAction for AddIndividualFloorItemToInventory { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let inventory = item_manager.character_inventory.get_mut(&self.character.id).ok_or(ItemManagerError::NoCharacter(self.character.id))?; - let inv_item = inventory.add_individual_floor_item(&self.item); - - entity_gateway.add_item_note( - &self.item.entity_id, - ItemNote::Pickup { - character_id: self.character.id, - } - ).await?; - - if inv_item.mag().is_some() { - entity_gateway.change_mag_owner(&self.item.entity_id, &self.character).await?; - } - - entity_gateway.set_character_inventory(&self.character.id, &inventory.as_inventory_entity(&self.character.id)).await?; - Ok(()) - } -} - - -#[derive(Debug)] -struct AddStackedFloorItemToInventory{ - character_id: CharacterEntityId, - item: StackedFloorItem, -} - -#[async_trait::async_trait] -impl ItemAction for AddStackedFloorItemToInventory { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let inventory = item_manager.character_inventory.get_mut(&self.character_id).ok_or(ItemManagerError::NoCharacter(self.character_id))?; - inventory.add_stacked_floor_item(&self.item); - - entity_gateway.set_character_inventory(&self.character_id, &inventory.as_inventory_entity(&self.character_id)).await?; - Ok(()) - } -} - - -#[derive(Debug)] -struct AddMesetaFloorItemToInventory{ - character_id: CharacterEntityId, - item: MesetaFloorItem, -} - -#[async_trait::async_trait] -impl ItemAction for AddMesetaFloorItemToInventory { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let character_meseta = item_manager.character_meseta.get_mut(&self.character_id).ok_or(ItemManagerError::NoCharacter(self.character_id))?; - character_meseta.0 = std::cmp::min(character_meseta.0 + self.item.meseta.0, 999999); - entity_gateway.set_character_meseta(&self.character_id, *character_meseta).await?; - Ok(()) - } -} - - -#[derive(Debug)] -struct TradeIndividualItem { - src_character_id: CharacterEntityId, - dest_character_id: CharacterEntityId, - current_item_id: ClientItemId, - new_item_id: ClientItemId, -} - -#[async_trait::async_trait] -impl ItemAction for TradeIndividualItem { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let src_inventory = item_manager.character_inventory.get_mut(&self.src_character_id).ok_or(ItemManagerError::NoCharacter(self.src_character_id))?; - let inventory_item = src_inventory.take_item_by_id(self.current_item_id).ok_or(ItemManagerError::NoSuchItemId(self.current_item_id))?; - entity_gateway.set_character_inventory(&self.src_character_id, &src_inventory.as_inventory_entity(&self.src_character_id)).await?; - - let dest_inventory = item_manager.character_inventory.get_mut(&self.dest_character_id).ok_or(ItemManagerError::NoCharacter(self.dest_character_id))?; - dest_inventory.add_item_with_new_item_id(inventory_item, self.new_item_id); - entity_gateway.set_character_inventory(&self.dest_character_id, &dest_inventory.as_inventory_entity(&self.dest_character_id)).await?; - - Ok(()) - } -} - -#[derive(Debug)] -struct TradeStackedItem { - src_character_id: CharacterEntityId, - dest_character_id: CharacterEntityId, - current_item_id: ClientItemId, - new_item_id: ClientItemId, - amount: usize, -} - -#[async_trait::async_trait] -impl ItemAction for TradeStackedItem { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - let src_inventory = item_manager.character_inventory.get_mut(&self.src_character_id).ok_or(ItemManagerError::NoCharacter(self.src_character_id))?; - let inventory_item = src_inventory.take_stacked_item_by_id(self.current_item_id, self.amount).ok_or(ItemManagerError::NoSuchItemId(self.current_item_id))?; - entity_gateway.set_character_inventory(&self.src_character_id, &src_inventory.as_inventory_entity(&self.src_character_id)).await?; - - let dest_inventory = item_manager.character_inventory.get_mut(&self.dest_character_id).ok_or(ItemManagerError::NoCharacter(self.dest_character_id))?; - dest_inventory.add_item_with_new_item_id(InventoryItem::Stacked(inventory_item), self.new_item_id); - entity_gateway.set_character_inventory(&self.dest_character_id, &dest_inventory.as_inventory_entity(&self.dest_character_id)).await?; - - Ok(()) - } -} - -#[derive(Debug)] -struct TradeMeseta { - src_character_id: CharacterEntityId, - dest_character_id: CharacterEntityId, - amount: usize, -} - -#[async_trait::async_trait] -impl ItemAction for TradeMeseta { - async fn commit(&self, item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> { - { - let src_meseta = item_manager.get_character_meseta_mut(&self.src_character_id)?; - src_meseta.0 -= self.amount as u32; - entity_gateway.set_character_meseta(&self.src_character_id, *src_meseta).await?; - } - { - let dest_meseta = item_manager.get_character_meseta_mut(&self.dest_character_id)?; - dest_meseta.0 += self.amount as u32; - entity_gateway.set_character_meseta(&self.dest_character_id, *dest_meseta).await?; - } - Ok(()) - } -}