diff --git a/src/bin/main.rs b/src/bin/main.rs index c2ace7d..8da1334 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -121,7 +121,7 @@ fn main() { Some(item::weapon::WeaponAttribute{attr: item::weapon::Attribute::Dark, value: 30}), None,], tekked: false, - wrapping: Some(item::WrappingPaper::Black_Yellow), + wrapping: Some(item::WrappingPaper::BlackYellow), } ), location: ItemLocation::Inventory { @@ -243,7 +243,8 @@ fn main() { item: ItemDetail::Tool ( item::tool::Tool { tool: item::tool::ToolType::CellOfMag502, - wrapping: None, + // wrapping: None, + wrapping: Some(item::WrappingPaper::PinkYellowGreen), } ), location: item::ItemLocation::Consumed, @@ -292,7 +293,7 @@ fn main() { shield: item::shield::ShieldType::Barrier, dfp: 0, evp: 0, - wrapping: Some(item::WrappingPaper::Yellow), + wrapping: Some(item::WrappingPaper::Green), } ), location: ItemLocation::Inventory { @@ -320,7 +321,8 @@ fn main() { item::unit::Unit { unit: item::unit::UnitType::PriestMind, modifier: Some(item::unit::UnitModifier::Minus), - wrapping: None, + // wrapping: None, + wrapping: Some(item::WrappingPaper::YellowBlue), } ), location: ItemLocation::Inventory { @@ -365,6 +367,56 @@ fn main() { } ).await.unwrap(); + // wrapping monomates doesn't do anything + let item14 = entity_gateway.create_item( + NewItemEntity { + item: ItemDetail::Tool ( + item::tool::Tool { + tool: item::tool::ToolType::Monomate, + // wrapping: None, + wrapping: Some(item::WrappingPaper::Yellow), + } + ), + location: ItemLocation::Inventory { + character_id: character.id, + } + } + ).await.unwrap(); + + /* wrapping techs is no bueno */ + // let item15 = entity_gateway.create_item( + // NewItemEntity { + // item: ItemDetail::TechniqueDisk ( + // item::tech::TechniqueDisk { + // tech: item::tech::Technique::Foie, + // level: 5, + // // wrapping: None, + // wrapping: Some(item::WrappingPaper::Blue), + // } + // ), + // location: ItemLocation::Inventory { + // character_id: character.id, + // } + // } + // ).await.unwrap(); + + let item16 = entity_gateway.create_item( + NewItemEntity { + item: ItemDetail::ESWeapon ( + item::esweapon::ESWeapon { + esweapon: item::esweapon::ESWeaponType::Hammer, + special: Some(item::esweapon::ESWeaponSpecial::Hell), + name: "BAN".to_owned(), + grind: 69u8, + wrapping: Some(item::WrappingPaper::LightBlueOrange), + } + ), + location: ItemLocation::Inventory { + character_id: character.id, + } + } + ).await.unwrap(); + let equipped = item::EquippedEntity { weapon: Some(item2_w.id), armor: Some(item7_a.id), @@ -374,7 +426,7 @@ fn main() { }; entity_gateway.set_character_equips(&character.id, &equipped).await.unwrap(); - let inventory = item::InventoryEntity::new(vec![item0, item1, item2_w, item3, item4, item5_m, item6, item7_a, item8_s, item9_u0, item10_u1, item11_u2, item12_u3, item13]); + let inventory = item::InventoryEntity::new(vec![item0, item1, item2_w, item3, item4, item5_m, item6, item7_a, item8_s, item9_u0, item10_u1, item11_u2, item12_u3, item13, item14, /*item15,*/ item16]); entity_gateway.set_character_inventory(&character.id, &inventory).await.unwrap(); entity_gateway.set_character_bank(&character.id, &item::BankEntity::default(), item::BankName("".into())).await.unwrap(); } diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index c0d3cba..965ddf2 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -85,6 +85,10 @@ pub trait EntityGateway: Send + Sync + Clone { unimplemented!(); } + async fn add_esweapon_modifier(&mut self, _item_id: &ItemEntityId, _modifier: esweapon::ESWeaponModifier) -> Result<(), GatewayError> { + unimplemented!(); + } + async fn add_armor_modifier(&mut self, _item_id: &ItemEntityId, _modifier: armor::ArmorModifier) -> Result<(), GatewayError> { unimplemented!(); } @@ -101,6 +105,13 @@ pub trait EntityGateway: Send + Sync + Clone { unimplemented!(); } + async fn add_tech_modifier(&mut self, _item_id: &ItemEntityId, _modifier: tech::TechModifier) -> Result<(), GatewayError> { + unimplemented!(); + } + + async fn add_tool_modifier(&mut self, _item_id: &ItemEntityId, _modifier: tool::ToolModifier) -> 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 5167ff1..9324221 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -19,9 +19,12 @@ pub struct InMemoryGateway { equips: Arc>>, mag_modifiers: Arc>>>, weapon_modifiers: Arc>>>, + esweapon_modifiers: Arc>>>, armor_modifiers: Arc>>>, shield_modifiers: Arc>>>, unit_modifiers: Arc>>>, + tech_modifiers: Arc>>>, + tool_modifiers: Arc>>>, } impl InMemoryGateway { @@ -36,9 +39,12 @@ 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())), + esweapon_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())), + tech_modifiers: Arc::new(Mutex::new(BTreeMap::new())), + tool_modifiers: Arc::new(Mutex::new(BTreeMap::new())), } } } @@ -58,8 +64,62 @@ impl InMemoryGateway { } ItemDetail::Weapon(weapon) }, + ItemDetail::ESWeapon(mut esweapon) => { + if let Some(esweapon_modifiers) = self.esweapon_modifiers.lock().unwrap().get(&item.id) { + for esweapon_modifier in esweapon_modifiers.iter() { + esweapon.apply_modifier(&esweapon_modifier); + } + } + ItemDetail::ESWeapon(esweapon) + }, + ItemDetail::Armor(mut armor) => { + if let Some(armor_modifiers) = self.armor_modifiers.lock().unwrap().get(&item.id) { + for armor_modifier in armor_modifiers.iter() { + armor.apply_modifier(&armor_modifier); + } + } + ItemDetail::Armor(armor) + }, + ItemDetail::Shield(mut shield) => { + if let Some(shield_modifiers) = self.shield_modifiers.lock().unwrap().get(&item.id) { + for shield_modifier in shield_modifiers.iter() { + shield.apply_modifier(&shield_modifier); + } + } + ItemDetail::Shield(shield) + }, + ItemDetail::Unit(mut unit) => { + if let Some(unit_modifiers) = self.unit_modifiers.lock().unwrap().get(&item.id) { + for unit_modifier in unit_modifiers.iter() { + unit.apply_modifier(&unit_modifier); + } + } + ItemDetail::Unit(unit) + }, + ItemDetail::TechniqueDisk(mut tech) => { + if let Some(tech_modifiers) = self.tech_modifiers.lock().unwrap().get(&item.id) { + for tech_modifier in tech_modifiers.iter() { + tech.apply_modifier(&tech_modifier); + } + } + ItemDetail::TechniqueDisk(tech) + }, + ItemDetail::Tool(mut tool) => { + if let Some(tool_modifiers) = self.tool_modifiers.lock().unwrap().get(&item.id) { + for tool_modifier in tool_modifiers.iter() { + tool.apply_modifier(&tool_modifier); + } + } + ItemDetail::Tool(tool) + }, ItemDetail::Mag(mag) => { - let mut mag = mag::Mag::baby_mag(mag.color as u16); + let mut mag = { + if mag.wrapping.is_some() { + mag::Mag::wrapped_baby_mag(mag.color as u16) + } else { + mag::Mag::baby_mag(mag.color as u16) + } + }; if let Some(mag_modifiers) = self.mag_modifiers.lock().unwrap().get(&item.id) { for mag_modifier in mag_modifiers.iter() { match mag_modifier { @@ -87,12 +147,11 @@ impl InMemoryGateway { } } ItemDetail::Mag(mag) - } - _ => { - item.item - } + }, + // _ => { + // item.item + // } }; - item }) }) @@ -279,6 +338,14 @@ impl EntityGateway for InMemoryGateway { Ok(()) } + async fn add_esweapon_modifier(&mut self, item_id: &ItemEntityId, modifier: esweapon::ESWeaponModifier) -> Result<(), GatewayError> { + self.esweapon_modifiers.lock().unwrap() + .entry(*item_id) + .or_insert(Vec::new()) + .push(modifier); + Ok(()) + } + async fn add_armor_modifier(&mut self, item_id: &ItemEntityId, modifier: armor::ArmorModifier) -> Result<(), GatewayError> { self.armor_modifiers.lock().unwrap() .entry(*item_id) @@ -311,6 +378,22 @@ impl EntityGateway for InMemoryGateway { Ok(()) } + async fn add_tech_modifier(&mut self, item_id: &ItemEntityId, modifier: tech::TechModifier) -> Result<(), GatewayError> { + self.tech_modifiers.lock().unwrap() + .entry(*item_id) + .or_insert(Vec::new()) + .push(modifier); + Ok(()) + } + + async fn add_tool_modifier(&mut self, item_id: &ItemEntityId, modifier: tool::ToolModifier) -> Result<(), GatewayError> { + self.tool_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/migrations/V0001__initial.sql b/src/entity/gateway/postgres/migrations/V0001__initial.sql index b4cd507..11b9eff 100644 --- a/src/entity/gateway/postgres/migrations/V0001__initial.sql +++ b/src/entity/gateway/postgres/migrations/V0001__initial.sql @@ -50,7 +50,7 @@ create table player_character ( prop_y real not null, techs bytea not null, - + config bytea not null, infoboard varchar(172) not null, guildcard varchar(172) not null, @@ -111,6 +111,18 @@ create table unit_modifier ( created_at timestamptz default current_timestamp not null ); +create table tech_modifier ( + tech integer references item (id) not null, + modifier jsonb not null, + created_at timestamptz default current_timestamp not null +); + +create table tool_modifier ( + tool integer references item (id) not null, + modifier jsonb not null, + created_at timestamptz default current_timestamp not null +); + create table esweapon_modifier ( esweapon integer references item (id) not null, modifier jsonb not null, diff --git a/src/entity/gateway/postgres/models.rs b/src/entity/gateway/postgres/models.rs index 8742dcd..04409c2 100644 --- a/src/entity/gateway/postgres/models.rs +++ b/src/entity/gateway/postgres/models.rs @@ -461,6 +461,12 @@ impl Into for PgTool { } } +#[derive(Debug, sqlx::FromRow)] +pub struct PgToolModifier { + pub tool: i32, + pub modifier: sqlx::types::Json, +} + #[derive(Debug, Serialize, Deserialize)] pub struct PgTechDisk { tech: tech::Technique, @@ -488,6 +494,12 @@ impl Into for PgTechDisk { } } +#[derive(Debug, sqlx::FromRow)] +pub struct PgTechModifier { + pub tool: i32, + pub modifier: sqlx::types::Json, +} + #[derive(Debug, Serialize, Deserialize)] pub struct PgMag { mag: mag::MagType, @@ -563,6 +575,13 @@ impl Into for PgESWeapon { } } +#[derive(Debug, sqlx::FromRow)] +pub struct PgESWeaponModifier { + pub esweapon: i32, + pub modifier: sqlx::types::Json, +} + + #[derive(Debug, Serialize, Deserialize)] pub enum PgItemDetail { Weapon(PgWeapon), diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index da0067b..14d4435 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -65,6 +65,23 @@ impl PostgresGateway { ItemDetail::Weapon(weapon) }, + ItemDetail::ESWeapon(mut esweapon) => { + let q = r#"select esweapon, modifier + from esweapon_modifier + where esweapon = $1 + order by created_at"#; + let esweapon_modifiers = sqlx::query_as::<_, PgESWeaponModifier>(q) + .bind(id.0 as i32) + .fetch(&self.pool); + + esweapon_modifiers.for_each(|modifier| { + if let Ok(modifier) = modifier { + esweapon.apply_modifier(&modifier.modifier); + } + }).await; + + ItemDetail::ESWeapon(esweapon) + }, ItemDetail::Mag(mut mag) => { let q = r#"select mag, modifier, item.item -> 'Tool' as feed, item2.item -> 'Tool' as cell from mag_modifier @@ -469,6 +486,14 @@ impl EntityGateway for PostgresGateway { Ok(()) } + async fn add_esweapon_modifier(&mut self, item_id: &ItemEntityId, modifier: esweapon::ESWeaponModifier) -> Result<(), GatewayError> { + sqlx::query("insert into esweapon_modifier (esweapon, modifier) values ($1, $2);") + .bind(item_id.0) + .bind(sqlx::types::Json(modifier)) + .execute(&self.pool).await?; + Ok(()) + } + async fn add_armor_modifier(&mut self, item_id: &ItemEntityId, modifier: armor::ArmorModifier) -> Result<(), GatewayError> { sqlx::query("insert into armor_modifier (armor, modifier) values ($1, $2);") .bind(item_id.0) @@ -501,6 +526,22 @@ impl EntityGateway for PostgresGateway { Ok(()) } + async fn add_tech_modifier(&mut self, item_id: &ItemEntityId, modifier: tech::TechModifier) -> Result<(), GatewayError> { + sqlx::query("insert into tech_modifier (tech, modifier) values ($1, $2);") + .bind(item_id.0) + .bind(sqlx::types::Json(modifier)) + .execute(&self.pool).await?; + Ok(()) + } + + async fn add_tool_modifier(&mut self, item_id: &ItemEntityId, modifier: tool::ToolModifier) -> Result<(), GatewayError> { + sqlx::query("insert into tool_modifier (tool, modifier) values ($1, $2);") + .bind(item_id.0) + .bind(sqlx::types::Json(modifier)) + .execute(&self.pool).await?; + Ok(()) + } + /* async fn get_items_by_character(&self, char_id: &CharacterEntityId) -> Result, GatewayError> { let q = r#"select * from ( diff --git a/src/entity/item/armor.rs b/src/entity/item/armor.rs index 5a15dbc..4024600 100644 --- a/src/entity/item/armor.rs +++ b/src/entity/item/armor.rs @@ -299,7 +299,7 @@ pub enum ArmorModifier { } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct Armor { pub armor: ArmorType, pub dfp: u8, @@ -346,7 +346,7 @@ impl Armor { pub fn apply_modifier(&mut self, modifier: &ArmorModifier) { match modifier { - ArmorModifier::WrapPresent => {self.wrapping = Some(WrappingPaper::White_Pink)}, + ArmorModifier::WrapPresent => {self.wrapping = Some(WrappingPaper::WhitePink)}, ArmorModifier::UnwrapPresent => {self.wrapping = None}, _ => {}, } diff --git a/src/entity/item/esweapon.rs b/src/entity/item/esweapon.rs index 2b71150..26671fd 100644 --- a/src/entity/item/esweapon.rs +++ b/src/entity/item/esweapon.rs @@ -170,6 +170,14 @@ impl ESWeaponSpecial { } } +#[derive(Debug, Serialize, Deserialize)] +pub enum ESWeaponModifier { + WrapPresent { + paper: WrappingPaper, + }, + UnwrapPresent, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ESWeapon { pub esweapon: ESWeaponType, @@ -274,6 +282,14 @@ impl ESWeapon { wrapping: wrapping, } } + + pub fn apply_modifier(&mut self, modifier: &ESWeaponModifier) { + match modifier { + ESWeaponModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, + ESWeaponModifier::UnwrapPresent => {self.wrapping = None}, + _ => {}, + } + } } #[cfg(test)] diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index 3dedef0..a6ba9e4 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -531,7 +531,7 @@ pub enum PhotonBlast { MyllaYoulla, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct Mag { pub mag: MagType, def: u16, @@ -1133,7 +1133,7 @@ impl Mag { pub fn apply_modifier(&mut self, modifier: &MagModifier) { match modifier { - MagModifier::WrapPresent => {self.wrapping = WrappingPaper::from(self.color % 10)}, // prevents mag color from crashing wrapping papers + MagModifier::WrapPresent => {self.wrapping = WrappingPaper::from(self.color % 10)}, // prevents mag color from crashing wrapping papers. client always shows mags in default paper colour ? MagModifier::UnwrapPresent => {self.wrapping = None}, _ => {}, // TODO: other modifiers are already handled elsewhere. do they need to be moved here? } diff --git a/src/entity/item/mod.rs b/src/entity/item/mod.rs index c6bf5ec..0ae6712 100644 --- a/src/entity/item/mod.rs +++ b/src/entity/item/mod.rs @@ -160,33 +160,32 @@ impl ItemDetail { } } - pub fn is_wrapped(self) -> bool { + pub fn is_wrapped(&mut self) -> bool { match self { ItemDetail::Weapon(w) => w.wrapping.is_some(), - // ItemDetail::Armor(a) => a.wrapping.is_some(), - // ItemDetail::Shield(s) => s.wrapping.is_some(), - // ItemDetail::Unit(u) => u.wrapping.is_some(), - // ItemDetail::Tool(t) => t.wrapping.is_some(), - // ItemDetail::TechniqueDisk(d) => d.wrapping.is_some(), - // ItemDetail::Mag(m) => m.wrapping.is_some(), - // ItemDetail::ESWeapon(e) => e.wrapping.is_some(), - _ => false + ItemDetail::Armor(a) => a.wrapping.is_some(), + ItemDetail::Shield(s) => s.wrapping.is_some(), + ItemDetail::Unit(u) => u.wrapping.is_some(), + ItemDetail::Tool(t) => t.wrapping.is_some(), + ItemDetail::TechniqueDisk(d) => d.wrapping.is_some(), + ItemDetail::Mag(m) => m.wrapping.is_some(), + ItemDetail::ESWeapon(e) => e.wrapping.is_some(), + _ => unreachable!(), } } - pub fn unwrap_present(self) -> ItemDetail { + pub fn unwrap_present(&mut self) { match self { - ItemDetail::Weapon(mut w) => w.wrapping = None, - // ItemDetail::Armor(a) => a.wrapping.is_some(), - // ItemDetail::Shield(s) => s.wrapping.is_some(), - // ItemDetail::Unit(u) => u.wrapping.is_some(), - // ItemDetail::Tool(t) => t.wrapping.is_some(), - // ItemDetail::TechniqueDisk(d) => d.wrapping.is_some(), - // ItemDetail::Mag(m) => m.wrapping.is_some(), - // ItemDetail::ESWeapon(e) => e.wrapping.is_some(), - _ => {}, + ItemDetail::Weapon(ref mut w) => w.wrapping = None, + ItemDetail::Armor(ref mut a) => a.wrapping = None, + ItemDetail::Shield(ref mut s) => s.wrapping = None, + ItemDetail::Unit(ref mut u) => u.wrapping = None, + ItemDetail::Tool(ref mut t) => t.wrapping = None, + ItemDetail::TechniqueDisk(ref mut d) => d.wrapping = None, + ItemDetail::Mag(ref mut m) => m.wrapping = None, + ItemDetail::ESWeapon(ref mut e) => e.wrapping = None, + _ => unreachable!(), }; - self } } @@ -229,7 +228,7 @@ impl InventoryItemEntity { _ => self, } } - //pub fn with_individual(&self, func: fn(&ItemEntity) -> T) -> Option { + pub fn with_individual T, T>(&self, func: F) -> Option { match self { InventoryItemEntity::Individual(item) => Some(func(item)), @@ -237,7 +236,6 @@ impl InventoryItemEntity { } } - //pub fn with_stacked(&self, func: fn(&Vec) -> T) -> Option { pub fn with_stacked) -> T, T>(&self, func: F) -> Option { match self { InventoryItemEntity::Stacked(items) => Some(func(items)), @@ -319,7 +317,6 @@ impl BankItemEntity { #[derive(Clone, Debug, Default)] pub struct BankEntity { - //pub items: [Option; 30], pub items: Vec, } @@ -333,12 +330,12 @@ impl BankEntity { #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum WrappingPaper { - White_Pink, // 0 - Yellow_Blue, // 1 - Black_Yellow, // 2 - LightBlue_Orange, // 3 - Pink_YellowGreen, // 4 - Red_Green, // 5 + WhitePink, // 0 + YellowBlue, // 1 + BlackYellow, // 2 + LightBlueOrange, // 3 + PinkYellowGreen, // 4 + RedGreen, // 5 Magenta, // 6 Blue, // 7 Yellow, // 8 @@ -353,12 +350,12 @@ impl WrappingPaper { pub fn from(data: u8) -> Option { match data { - 0 => Some(WrappingPaper::White_Pink), - 1 => Some(WrappingPaper::Yellow_Blue), - 2 => Some(WrappingPaper::Black_Yellow), - 3 => Some(WrappingPaper::LightBlue_Orange), - 4 => Some(WrappingPaper::Pink_YellowGreen), - 5 => Some(WrappingPaper::Red_Green), + 0 => Some(WrappingPaper::WhitePink), + 1 => Some(WrappingPaper::YellowBlue), + 2 => Some(WrappingPaper::BlackYellow), + 3 => Some(WrappingPaper::LightBlueOrange), + 4 => Some(WrappingPaper::PinkYellowGreen), + 5 => Some(WrappingPaper::RedGreen), 6 => Some(WrappingPaper::Magenta), 7 => Some(WrappingPaper::Blue), 8 => Some(WrappingPaper::Yellow), diff --git a/src/entity/item/shield.rs b/src/entity/item/shield.rs index e537428..e8b8d1f 100644 --- a/src/entity/item/shield.rs +++ b/src/entity/item/shield.rs @@ -572,9 +572,8 @@ impl Shield { pub fn apply_modifier(&mut self, modifier: &ShieldModifier) { match modifier { - ShieldModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, + ShieldModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, // TODO: client always shows shields in default paper colour ? ShieldModifier::UnwrapPresent => {self.wrapping = None}, - _ => {}, } } } diff --git a/src/entity/item/tech.rs b/src/entity/item/tech.rs index 91f5296..7abb1b3 100644 --- a/src/entity/item/tech.rs +++ b/src/entity/item/tech.rs @@ -76,6 +76,14 @@ impl Technique { } } +#[derive(Debug, Serialize)] +pub enum TechModifier { + WrapPresent { + paper: WrappingPaper, + }, + UnwrapPresent, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TechniqueDisk { pub tech: Technique, @@ -96,4 +104,11 @@ impl TechniqueDisk { }; result } + + pub fn apply_modifier(&mut self, modifier: &TechModifier) { + match modifier { + TechModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, + TechModifier::UnwrapPresent => {self.wrapping = None}, + } + } } diff --git a/src/entity/item/tool.rs b/src/entity/item/tool.rs index 4079c3c..da4465f 100644 --- a/src/entity/item/tool.rs +++ b/src/entity/item/tool.rs @@ -648,6 +648,13 @@ impl ToolType { } } +#[derive(Debug, Serialize)] +pub enum ToolModifier { + WrapPresent { + paper: WrappingPaper, + }, + UnwrapPresent, +} #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Tool { @@ -696,4 +703,11 @@ impl Tool { pub fn max_stack(&self) -> usize { self.tool.max_stack() } + + pub fn apply_modifier(&mut self, modifier: &ToolModifier) { + match modifier { + ToolModifier::WrapPresent{paper} => {self.wrapping = Some(*paper)}, + ToolModifier::UnwrapPresent => {self.wrapping = None}, + } + } } diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index cc6ce2d..4d5fc1b 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -6,9 +6,11 @@ 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::esweapon::ESWeapon; use crate::entity::item::armor::Armor; // TODO: cleanup uses use crate::entity::item::shield::Shield; use crate::entity::item::unit::Unit; +use crate::entity::item::tech::TechniqueDisk; use crate::ship::items::{ClientItemId, BankItem, BankItemHandle}; use crate::ship::items::floor::{IndividualFloorItem, StackedFloorItem}; @@ -48,10 +50,6 @@ impl IndividualInventoryItem { } } - pub fn is_wrapped(self) -> bool { - self.clone().item.is_wrapped() - } - pub fn weapon_mut(&mut self) -> Option<&mut Weapon> { match self.item { ItemDetail::Weapon(ref mut weapon) => Some(weapon), @@ -59,6 +57,13 @@ impl IndividualInventoryItem { } } + pub fn esweapon_mut(&mut self) -> Option<&mut ESWeapon> { + match self.item { + ItemDetail::ESWeapon(ref mut esweapon) => Some(esweapon), + _ => None + } + } + pub fn armor_mut(&mut self) -> Option<&mut Armor> { match self.item { ItemDetail::Armor(ref mut armor) => Some(armor), @@ -80,6 +85,27 @@ impl IndividualInventoryItem { } } + pub fn tech_mut(&mut self) -> Option<&mut TechniqueDisk> { + match self.item { + ItemDetail::TechniqueDisk(ref mut tech) => Some(tech), + _ => None + } + } + + pub fn tool_mut(&mut self) -> Option<&mut Tool> { + match self.item { + ItemDetail::Tool(ref mut tool) => Some(tool), + _ => None + } + } + + pub fn is_wrapped(&mut self) -> bool { + self.item.is_wrapped() + } + + pub fn unwrap_present(&mut self) { + self.item.unwrap_present(); + } } #[derive(Debug, Clone)] @@ -104,8 +130,11 @@ impl StackedInventoryItem { } pub fn is_wrapped(&self) -> bool { - // TODO: add wrapping to Tool - false + self.tool.wrapping.is_some() + } + + pub fn unwrap_present(&mut self) { + self.tool.wrapping = None; } } @@ -281,26 +310,19 @@ impl InventoryItem { } } - pub fn is_wrapped(self) -> bool { + // TODO: validate if wrapping stacked items & tools are valid in the client. Gallons shop allows users to wrap tools (eg techs) but then the client may not be able to unwrap it afterwards? + pub fn is_wrapped(&mut self) -> bool { match self { InventoryItem::Individual(i) => i.is_wrapped(), InventoryItem::Stacked(s) => s.is_wrapped(), } } - pub fn unwrap_present(self) -> InventoryItem { + pub fn unwrap_present(&mut self) { match self { - InventoryItem::Individual(i) => InventoryItem::Individual(IndividualInventoryItem { - entity_id: i.entity_id, - item_id: i.item_id, - item: i.item.unwrap_present(), - }), - InventoryItem::Stacked(s) => InventoryItem::Stacked(StackedInventoryItem { - entity_ids: s.entity_ids, - item_id: s.item_id, - tool: s.tool, // s.unwrap_present() - }), - } + InventoryItem::Individual(i) => i.unwrap_present(), + InventoryItem::Stacked(s) => s.unwrap_present(), + }; } } diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index ba75443..ac81a48 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -6,11 +6,7 @@ use crate::entity::character::{CharacterEntity, CharacterEntityId, TechLevel}; use crate::entity::item::{ItemDetail, ItemLocation, BankName}; use crate::entity::item::{Meseta, NewItemEntity, ItemEntity, InventoryItemEntity, EquippedEntity, InventoryEntity, BankItemEntity, BankEntity, ItemType}; use crate::entity::item::tool::{Tool, ToolType}; -use crate::entity::item::unit; -use crate::entity::item::weapon; -use crate::entity::item::armor; -use crate::entity::item::shield; -use crate::entity::item::mag; +use crate::entity::item::{unit, weapon, armor, shield, mag, tech, tool, esweapon}; use crate::ship::map::MapArea; use crate::ship::ship::ItemDropLocation; use crate::ship::drops::{ItemDrop, ItemDropType}; @@ -506,7 +502,7 @@ impl ItemManager { 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)?; - + println!("consumed some item"); 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)); @@ -645,164 +641,144 @@ impl ItemManager { 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() { - ItemType::Armor(_) => { - let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.armor_mut().ok_or(ItemManagerError::CannotGetMutItem)?; - if actual_used_item.wrapping.is_some() { - actual_used_item.apply_modifier(&armor::ArmorModifier::UnwrapPresent); - entity_gateway.add_armor_modifier(&used_item.entity_ids()[0], armor::ArmorModifier::UnwrapPresent).await?; - } else { + if used_item.is_wrapped() { + used_item.unwrap_present(); + } else { + match used_item.item_type() { + ItemType::Armor(_) => { + let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.armor_mut().ok_or(ItemManagerError::CannotGetMutItem)?; // combining / unsealing? - } - }, - ItemType::ESWeapon(_) => { - - }, - ItemType::Mag(_) => { - let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.mag_mut().ok_or(ItemManagerError::CannotGetMutItem)?; - if actual_used_item.wrapping.is_some() { - actual_used_item.apply_modifier(&mag::MagModifier::UnwrapPresent); - entity_gateway.add_mag_modifier(&used_item.entity_ids()[0], mag::MagModifier::UnwrapPresent).await?; - } else { + }, + ItemType::ESWeapon(_) => { // TODO: wrap srank weapons + let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.esweapon_mut().ok_or(ItemManagerError::CannotGetMutItem)?; // combining / unsealing? - } - }, - ItemType::Shield(_) => { - let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.shield_mut().ok_or(ItemManagerError::CannotGetMutItem)?; - if actual_used_item.wrapping.is_some() { - actual_used_item.apply_modifier(&shield::ShieldModifier::UnwrapPresent); - entity_gateway.add_shield_modifier(&used_item.entity_ids()[0], shield::ShieldModifier::UnwrapPresent).await?; - } else { + }, + ItemType::Mag(_) => { + let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.mag_mut().ok_or(ItemManagerError::CannotGetMutItem)?; // combining / unsealing? - } - }, - ItemType::TechniqueDisk(_) => { - - }, - ItemType::Tool(_) => { - let consumed_item = used_item.as_consumed_item(); - match &used_item.item_detail() { - 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, &consumed_item, inventory).await?; - }, - ToolType::CellOfMag213 => { - use_tool::cell_of_mag_213(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::PartsOfRobochao => { - use_tool::parts_of_robochao(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::HeartOfOpaOpa => { - use_tool::heart_of_opaopa(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::HeartOfPian => { - use_tool::heart_of_pian(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::HeartOfChao=> { - use_tool::heart_of_chao(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::HeartOfAngel => { - use_tool::heart_of_angel(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::KitOfHamburger => { - use_tool::kit_of_hamburger(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::PanthersSpirit => { - use_tool::panthers_spirit(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::KitOfMark3 => { - use_tool::kit_of_mark3(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::KitOfMasterSystem=> { - use_tool::kit_of_master_system(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::KitOfGenesis => { - use_tool::kit_of_genesis(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::KitOfSegaSaturn => { - use_tool::kit_of_sega_saturn(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::KitOfDreamcast => { - use_tool::kit_of_dreamcast(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::Tablet => { - use_tool::tablet(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::DragonScale => { - use_tool::dragon_scale(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::HeavenStrikerCoat => { - use_tool::heaven_striker_coat(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::PioneerParts => { - use_tool::pioneer_parts(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::AmitiesMemo => { - use_tool::amities_memo(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::HeartOfMorolian => { - use_tool::heart_of_morolian(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::RappysBeak => { - use_tool::rappys_beak(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::YahoosEngine => { - use_tool::yahoos_engine(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::DPhotonCore => { - use_tool::d_photon_core(entity_gateway, &consumed_item, inventory).await?; - }, - ToolType::LibertaKit => { - use_tool::liberta_kit(entity_gateway, &consumed_item, inventory).await?; - }, - _ => {} - } + }, + ItemType::Shield(_) => { + let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.shield_mut().ok_or(ItemManagerError::CannotGetMutItem)?; + // combining / unsealing? + }, + ItemType::TechniqueDisk(_) => { + let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.tech_mut().ok_or(ItemManagerError::CannotGetMutItem)?; + // combining / unsealing? + }, + ItemType::Tool(_) => { + let consumed_item = used_item.as_consumed_item(); + match &used_item.item_detail() { + 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, &consumed_item, inventory).await?; + }, + ToolType::CellOfMag213 => { + use_tool::cell_of_mag_213(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::PartsOfRobochao => { + use_tool::parts_of_robochao(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::HeartOfOpaOpa => { + use_tool::heart_of_opaopa(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::HeartOfPian => { + use_tool::heart_of_pian(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::HeartOfChao=> { + use_tool::heart_of_chao(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::HeartOfAngel => { + use_tool::heart_of_angel(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::KitOfHamburger => { + use_tool::kit_of_hamburger(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::PanthersSpirit => { + use_tool::panthers_spirit(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::KitOfMark3 => { + use_tool::kit_of_mark3(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::KitOfMasterSystem=> { + use_tool::kit_of_master_system(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::KitOfGenesis => { + use_tool::kit_of_genesis(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::KitOfSegaSaturn => { + use_tool::kit_of_sega_saturn(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::KitOfDreamcast => { + use_tool::kit_of_dreamcast(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::Tablet => { + use_tool::tablet(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::DragonScale => { + use_tool::dragon_scale(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::HeavenStrikerCoat => { + use_tool::heaven_striker_coat(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::PioneerParts => { + use_tool::pioneer_parts(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::AmitiesMemo => { + use_tool::amities_memo(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::HeartOfMorolian => { + use_tool::heart_of_morolian(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::RappysBeak => { + use_tool::rappys_beak(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::YahoosEngine => { + use_tool::yahoos_engine(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::DPhotonCore => { + use_tool::d_photon_core(entity_gateway, &consumed_item, inventory).await?; + }, + ToolType::LibertaKit => { + use_tool::liberta_kit(entity_gateway, &consumed_item, inventory).await?; + }, + _ => {} + } + }, + _ => {}, } - _ => {} - } - }, - 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 { + }, + ItemType::Unit(_) => { + let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.unit_mut().ok_or(ItemManagerError::CannotGetMutItem)?; // combining / unsealing? - } - }, - ItemType::Weapon(_) => { - let actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.weapon_mut().ok_or(ItemManagerError::CannotGetMutItem)?; - 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 { + }, + ItemType::Weapon(_) => { + let _actual_used_item = used_item.individual_mut().ok_or(ItemManagerError::CannotGetMutItem)?.weapon_mut().ok_or(ItemManagerError::CannotGetMutItem)?; // combining / unsealing? - } - }, + }, + } } - entity_gateway.set_character_inventory(&character.id, &inventory.as_inventory_entity(&character.id)).await?; Ok(()) } diff --git a/tests/test_item_modifiers.rs b/tests/test_item_modifiers.rs index c890920..796fb9f 100644 --- a/tests/test_item_modifiers.rs +++ b/tests/test_item_modifiers.rs @@ -267,7 +267,7 @@ async fn test_unwrap_mag() { }).unwrap(); } -// TODO: implement wrapping packet (gallons shop quest) +// TODO: implement wrapping packet (message 0xD6) (gallons shop quest) // wrap presents #[async_std::test] async fn test_wrap_weapon() {}