diff --git a/src/bin/main.rs b/src/bin/main.rs index cb20e41..41e9ad4 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -74,7 +74,7 @@ fn main() { character.meseta = 999999; let character = entity_gateway.create_character(character).await.unwrap(); - for _ in 0..3 { + for _ in 0..3usize { entity_gateway.create_item( item::NewItemEntity { item: item::ItemDetail::Weapon( @@ -94,7 +94,7 @@ fn main() { }).await.unwrap(); } - for _ in 0..8 { + for _ in 0..8usize { entity_gateway.create_item( NewItemEntity { item: ItemDetail::Tool ( @@ -277,6 +277,7 @@ fn main() { dfp: 0, evp: 0, slots: 4, + wrapping: None, } ), location: ItemLocation::Inventory { diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index 261aadc..74d3f5a 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -85,6 +85,18 @@ pub trait EntityGateway: Send + Sync + Clone { unimplemented!(); } + async fn add_armor_modifier(&mut self, _item_id: &ItemEntityId, _modifier: armor::ArmorModifier) -> Result<(), GatewayError> { + unimplemented!(); + } + + async fn add_shield_modifier(&mut self, _item_id: &ItemEntityId, _modifier: shield::ShieldModifier) -> Result<(), GatewayError> { + unimplemented!(); + } + + async fn add_unit_modifier(&mut self, _item_id: &ItemEntityId, _modifier: unit::UnitModifier) -> Result<(), GatewayError> { + unimplemented!(); + } + /* async fn get_items_by_character(&self, _char_id: &CharacterEntityId) -> Result, GatewayError> { diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index cedeaf6..17ab155 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -19,6 +19,9 @@ pub struct InMemoryGateway { equips: Arc>>, mag_modifiers: Arc>>>, weapon_modifiers: Arc>>>, + armor_modifiers: Arc>>>, + shield_modifiers: Arc>>>, + unit_modifiers: Arc>>>, } impl InMemoryGateway { @@ -33,6 +36,9 @@ impl InMemoryGateway { equips: Arc::new(Mutex::new(BTreeMap::new())), mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())), weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())), + armor_modifiers: Arc::new(Mutex::new(BTreeMap::new())), + shield_modifiers: Arc::new(Mutex::new(BTreeMap::new())), + unit_modifiers: Arc::new(Mutex::new(BTreeMap::new())), } } } @@ -273,6 +279,30 @@ impl EntityGateway for InMemoryGateway { Ok(()) } + async fn add_armor_modifier(&mut self, item_id: &ItemEntityId, modifier: armor::ArmorModifier) -> Result<(), GatewayError> { + self.armor_modifiers.lock().unwrap() + .entry(*item_id) + .or_insert(Vec::new()) + .push(modifier); + Ok(()) + } + + async fn add_shield_modifier(&mut self, item_id: &ItemEntityId, modifier: shield::ShieldModifier) -> Result<(), GatewayError> { + self.shield_modifiers.lock().unwrap() + .entry(*item_id) + .or_insert(Vec::new()) + .push(modifier); + Ok(()) + } + + async fn add_unit_modifier(&mut self, item_id: &ItemEntityId, modifier: unit::UnitModifier) -> Result<(), GatewayError> { + self.unit_modifiers.lock().unwrap() + .entry(*item_id) + .or_insert(Vec::new()) + .push(modifier); + Ok(()) + } + async fn get_character_inventory(&mut self, char_id: &CharacterEntityId) -> Result { println!("getting inv"); let inventories = self.inventories.lock().unwrap(); diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/gateway/postgres/models.rs index d6f0c83..e9533c2 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/gateway/postgres/models.rs @@ -335,7 +335,7 @@ pub struct PgArmor { dfp: u8, evp: u8, slots: u8, - // wrapping: Option, // TODO: check if this clobbers slots + wrapping: Option, // TODO: check if this clobbers slots } impl From for PgArmor { @@ -345,7 +345,7 @@ impl From for PgArmor { dfp: other.dfp, evp: other.evp, slots: other.slots, - // wrapping: other.wrapping, + wrapping: other.wrapping, } } } @@ -357,7 +357,7 @@ impl Into for PgArmor { dfp: self.dfp, evp: self.evp, slots: self.slots, - // wrapping: self.wrapping, + wrapping: self.wrapping, } } } diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index 45aee91..f9acf92 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -528,6 +528,7 @@ impl EntityGateway for PostgresGateway { } async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> { + println!("postgres.rs::set_character_inventory - received inventory entity: {:?}", inventory); let inventory = inventory.items.iter() .map(|item| { match item { @@ -540,7 +541,8 @@ impl EntityGateway for PostgresGateway { } }) .collect::>(); - + println!("postgres.rs::set_character_inventory - collected new inventory: {:?}", inventory); + println!("postgres.rs::set_character_inventory - updating pchar: {:?}", char_id.0); sqlx::query("insert into inventory (pchar, items) values ($1, $2) on conflict (pchar) do update set items = $2") .bind(char_id.0) .bind(sqlx::types::Json(inventory)) diff --git a/src/entity/item/armor.rs b/src/entity/item/armor.rs index 9a2d925..7f7bf8b 100644 --- a/src/entity/item/armor.rs +++ b/src/entity/item/armor.rs @@ -293,7 +293,11 @@ impl ArmorType { pub enum ArmorModifier { AddSlot { addslot: ItemEntityId, - } + }, + WrapPresent { + paper: WrappingPaper, + }, + UnwrapPresent, } @@ -303,7 +307,7 @@ pub struct Armor { pub dfp: u8, pub evp: u8, pub slots: u8, - // pub wrapping: Option, // clobbers slots + pub wrapping: Option, } impl Armor { @@ -318,16 +322,32 @@ impl Armor { pub fn from_bytes(data: [u8; 16]) -> Result { let a = ArmorType::parse_type([data[0], data[1], data[2]]); + let w = { + if data[4] & 0x40 == 0x40 { + WrappingPaper::from(0) // always use default wrapping paper to preserve slot info + } else { + None + } + }; if a.is_ok() { Ok(Armor { armor: a.unwrap(), dfp: data[6], evp: data[8], slots: data[5], + wrapping: w, }) } else { Err(ItemParseError::InvalidArmorBytes) // TODO: error handling if wrong bytes are given } } + + pub fn apply_modifier(&mut self, modifier: &ArmorModifier) { + match modifier { + ArmorModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, + ArmorModifier::UnwrapPresent => {self.wrapping = None}, + _ => {}, + } + } } diff --git a/src/entity/item/shield.rs b/src/entity/item/shield.rs index 22ce3d2..e537428 100644 --- a/src/entity/item/shield.rs +++ b/src/entity/item/shield.rs @@ -519,6 +519,13 @@ impl ShieldType { } } +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +pub enum ShieldModifier { + WrapPresent { + paper: WrappingPaper, + }, + UnwrapPresent, +} #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] pub struct Shield { @@ -562,4 +569,12 @@ impl Shield { Err(ItemParseError::InvalidShieldBytes) // TODO: error handling if wrong bytes are given } } + + pub fn apply_modifier(&mut self, modifier: &ShieldModifier) { + match modifier { + ShieldModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, + ShieldModifier::UnwrapPresent => {self.wrapping = None}, + _ => {}, + } + } } diff --git a/src/entity/item/unit.rs b/src/entity/item/unit.rs index 401d1cf..6cf32c1 100644 --- a/src/entity/item/unit.rs +++ b/src/entity/item/unit.rs @@ -330,6 +330,10 @@ pub enum UnitModifier { Plus, Minus, MinusMinus, + WrapPresent { + paper: WrappingPaper, + }, + UnwrapPresent, } #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] @@ -361,6 +365,7 @@ impl Unit { result[6] = 0xFE; result[7] = 0xFF; }, + _ => {}, // handling wrapping here is weird? } } @@ -401,4 +406,12 @@ impl Unit { Err(ItemParseError::InvalidUnitBytes) // TODO: error handling if wrong bytes are given } } + + pub fn apply_modifier(&mut self, modifier: &UnitModifier) { + match modifier { + UnitModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, + UnitModifier::UnwrapPresent => {self.wrapping = None}, + _ => {}, + } + } } diff --git a/src/entity/item/weapon.rs b/src/entity/item/weapon.rs index 45640ae..eeddf4b 100644 --- a/src/entity/item/weapon.rs +++ b/src/entity/item/weapon.rs @@ -1452,6 +1452,10 @@ pub enum WeaponModifier { percent: TekPercentModifier, grind: i32, }, + WrapPresent { + paper: WrappingPaper, + }, + UnwrapPresent, } #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] @@ -1518,6 +1522,8 @@ impl Weapon { self.grind = std::cmp::max(self.grind as i32 + grind, 0) as u8; self.tekked = true; }, + WeaponModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, + WeaponModifier::UnwrapPresent => {self.wrapping = None}, _ => {} } } @@ -1558,7 +1564,6 @@ impl Weapon { if w.is_ok() { let mut s = None; let mut t = true; - let mut p = None; // wrapping paper let g = data[3]; if data[4] & 0x80 == 0x80 { @@ -1566,9 +1571,13 @@ impl Weapon { t = false; } - if data[4] & 0x40 == 0x40 { - p = WrappingPaper::from(data[5]); - } + let p = { + if data[4] & 0x40 == 0x40 { + WrappingPaper::from(data[5]) + } else { + None + } + }; let mut a = [ None, diff --git a/src/login/character.rs b/src/login/character.rs index 9d9969a..91988a0 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -234,6 +234,7 @@ async fn new_character(entity_gateway: &mut EG, user: &UserAc dfp: 0, evp: 0, slots: 0, + wrapping: None, }), location: ItemLocation::Inventory { character_id: character.id, diff --git a/src/ship/drops/generic_armor.rs b/src/ship/drops/generic_armor.rs index 2bf5895..bb9dad6 100644 --- a/src/ship/drops/generic_armor.rs +++ b/src/ship/drops/generic_armor.rs @@ -107,6 +107,7 @@ impl GenericArmorTable { dfp: dfp_modifier as u8, evp: evp_modifier as u8, slots: slots as u8, + wrapping: None, })) } } @@ -126,24 +127,28 @@ mod test { dfp: 0, evp: 0, slots: 1, + wrapping: None, }))); assert!(gat.get_drop(&MapArea::Caves3, &mut rng) == Some(ItemDropType::Armor(Armor { armor: ArmorType::AbsorbArmor, dfp: 1, evp: 1, slots: 1, + wrapping: None, }))); assert!(gat.get_drop(&MapArea::Forest2, &mut rng) == Some(ItemDropType::Armor(Armor { armor: ArmorType::HyperFrame, dfp: 0, evp: 0, slots: 0, + wrapping: None, }))); assert!(gat.get_drop(&MapArea::DarkFalz, &mut rng) == Some(ItemDropType::Armor(Armor { armor: ArmorType::ImperialArmor, dfp: 2, evp: 1, slots: 0, + wrapping: None, }))); } } diff --git a/src/ship/drops/rare_drop_table.rs b/src/ship/drops/rare_drop_table.rs index 450c9ef..7970fd2 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/src/ship/drops/rare_drop_table.rs @@ -114,6 +114,7 @@ impl RareDropTable { dfp: self.armor_stats.dfp_modifier(&armor, rng) as u8, evp: self.armor_stats.evp_modifier(&armor, rng) as u8, slots: self.armor_stats.slots(map_area, rng) as u8, + wrapping: None, }) }, RareDropItem::Shield(shield) => { diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index f70335b..cc6ce2d 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -6,6 +6,9 @@ use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, ItemType, ItemLo use crate::entity::item::tool::Tool; use crate::entity::item::mag::Mag; use crate::entity::item::weapon::Weapon; +use crate::entity::item::armor::Armor; // TODO: cleanup uses +use crate::entity::item::shield::Shield; +use crate::entity::item::unit::Unit; use crate::ship::items::{ClientItemId, BankItem, BankItemHandle}; use crate::ship::items::floor::{IndividualFloorItem, StackedFloorItem}; @@ -55,6 +58,28 @@ impl IndividualInventoryItem { _ => None } } + + pub fn armor_mut(&mut self) -> Option<&mut Armor> { + match self.item { + ItemDetail::Armor(ref mut armor) => Some(armor), + _ => None + } + } + + pub fn shield_mut(&mut self) -> Option<&mut Shield> { + match self.item { + ItemDetail::Shield(ref mut shield) => Some(shield), + _ => None + } + } + + pub fn unit_mut(&mut self) -> Option<&mut Unit> { + match self.item { + ItemDetail::Unit(ref mut unit) => Some(unit), + _ => None + } + } + } #[derive(Debug, Clone)] diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index cbd10f9..b67b048 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -639,9 +639,7 @@ impl ItemManager { entity_gateway: &mut EG, character: &mut CharacterEntity, client_item_id: ClientItemId) -> Result<(), anyhow::Error> { - // println!("manager::use_item(): ClientItemId: {:?}", client_item_id); let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - let mut used_item_handle = inventory.get_item_handle_by_id(client_item_id).ok_or(ItemManagerError::ItemIdNotInInventory(client_item_id))?; let used_item = used_item_handle.item_mut().ok_or(ItemManagerError::CannotGetMutItem)?; match used_item.item_type() { @@ -765,13 +763,25 @@ impl ItemManager { } }, ItemType::Unit(_) => { - + let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.unit_mut().ok_or(ItemManagerError::CannotGetMutItem)?; + if actual_used_item.wrapping.is_some() { + actual_used_item.apply_modifier(&unit::UnitModifier::UnwrapPresent); + entity_gateway.add_unit_modifier(&used_item.entity_ids()[0], unit::UnitModifier::UnwrapPresent).await?; + } else { + // combining / unsealing? + } }, ItemType::Weapon(_) => { let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.weapon_mut().ok_or(ItemManagerError::CannotGetMutItem)?; - actual_used_item.unwrap_present(); + if actual_used_item.wrapping.is_some() { + actual_used_item.apply_modifier(&weapon::WeaponModifier::UnwrapPresent); + entity_gateway.add_weapon_modifier(&used_item.entity_ids()[0], weapon::WeaponModifier::UnwrapPresent).await?; + } else { + // combining / unsealing? + } }, } + entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; Ok(()) } @@ -953,7 +963,6 @@ impl ItemManager { pub fn get_inventory_item_by_id(&mut self, character: &CharacterEntity, item_id: ClientItemId) -> Result<&InventoryItem, anyhow::Error> { let inventory = self.character_inventory.get_mut(&character.id).ok_or(ItemManagerError::NoCharacter(character.id))?; - println!("item_manager.get_inventory_item_by_id() inventory: {:?}", inventory); Ok(inventory.get_item_by_id(item_id).ok_or(ItemManagerError::ItemIdNotInInventory(item_id))?) } } diff --git a/src/ship/shops/armor.rs b/src/ship/shops/armor.rs index feb1705..e4d79a8 100644 --- a/src/ship/shops/armor.rs +++ b/src/ship/shops/armor.rs @@ -71,6 +71,7 @@ impl ShopItem for ArmorShopItem { dfp: 0, evp: 0, slots: *slot as u8, + wrapping: None, }) }, ArmorShopItem::Barrier(barrier) => {