From 1dc07e216e862ef8690b6dc8e3b5f63896f6d6b4 Mon Sep 17 00:00:00 2001 From: jake Date: Thu, 20 Aug 2020 22:18:31 -0600 Subject: [PATCH 01/17] these should probably only specify the tool used --- src/entity/item/mag.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index 130bd2b..84bfc81 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -1,5 +1,5 @@ use serde::{Serialize, Deserialize}; -use crate::entity::item::ItemEntityId; +use crate::entity::item::tool::ToolType; #[derive(Debug, Copy, Clone)] pub enum ItemParseError { @@ -255,10 +255,10 @@ impl MagType { #[derive(Debug, Clone, PartialEq)] pub enum MagModifier { FeedMag{ - food: ItemEntityId, + food: ToolType, }, - BankMag, - MagCell(ItemEntityId), + BankMag, // when putting a mag in the bank it truncates the values which has applications when raising degenerate mags + MagCell(ToolType), } #[derive(Debug, Copy, Clone, PartialEq)] From 19dd5309cd450f05d5110aee9d4e5eb82b79c309 Mon Sep 17 00:00:00 2001 From: jake Date: Thu, 20 Aug 2020 22:53:34 -0600 Subject: [PATCH 02/17] load mag feeding tables --- Cargo.toml | 1 + src/entity/item/mag.rs | 92 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index da84f18..1537cfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,4 +28,5 @@ derive_more = { version = "0.99.3", features = ["display"]} thiserror = "1.0.15" ages-prs = "0.1" async-trait = "0.1.31" +lazy_static = "1.4.0" diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index 84bfc81..cd3d002 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -1,5 +1,57 @@ +use std::collections::HashMap; use serde::{Serialize, Deserialize}; use crate::entity::item::tool::ToolType; +use std::io::Read; + +#[derive(Debug, Deserialize)] +struct MagStats { + feed_table: u32, +} + +#[derive(Debug, Deserialize)] +struct MagFeedTable { + def: i32, + pow: i32, + dex: i32, + mnd: i32, + iq: i32, + syn: i32, +} + +lazy_static::lazy_static! { + static ref MAG_STATS: HashMap = { + let mut f = std::fs::File::open("data/item_stats/mag_stats.toml").unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mag_stats: HashMap = toml::from_str(&s).unwrap(); + mag_stats.into_iter() + .map(|(name, stats)| { + (name.parse().unwrap(), stats) + }) + .collect::>() + }; + + static ref MAG_FEEDING_TABLES: Vec> = { + let mut f = std::fs::File::open("data/item_stats/mag_feed_table.toml").unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut feed: HashMap>> = toml::from_str(&s).unwrap(); + let feed = feed.remove("feedtable".into()).unwrap(); + feed.into_iter() + .map(|table| { + table.into_iter() + .map(|(tool, stats)| { + (tool.parse().unwrap(), stats) + }) + .collect() + }) + .collect::>>() + }; +} + + #[derive(Debug, Copy, Clone)] pub enum ItemParseError { @@ -389,4 +441,44 @@ impl Mag { Err(ItemParseError::InvalidMagBytes) // TODO: error handling if wrong bytes are given } } + + +#[cfg(test)] +mod test { + use super::*; + use std::io::Read; + + #[test] + fn test_load_mag_stats() { + let mut f = std::fs::File::open("data/item_stats/mag_stats.toml").unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mags: HashMap = toml::from_str(&s).unwrap(); + let _mags = mags.into_iter() + .map(|(name, stats)| { + (name.parse().unwrap(), stats) + }) + .collect::>(); + } + + #[test] + fn test_load_mag_feed_table() { + let mut f = std::fs::File::open("data/item_stats/mag_feed_table.toml").unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let mut feed: HashMap>> = toml::from_str(&s).unwrap(); + let feed = feed.remove("feedtable".into()).unwrap(); + let _feed = feed.into_iter() + .map(|table| { + table.into_iter() + .map(|(tool, stats)| { + (tool.parse().unwrap(), stats) + }) + .collect() + }) + .collect::>>(); + } + } From f583b25176545033bc389cdf84fc74cfbdef4b97 Mon Sep 17 00:00:00 2001 From: jake Date: Thu, 20 Aug 2020 22:59:40 -0600 Subject: [PATCH 03/17] hide mag struct internals --- src/entity/item/mag.rs | 29 ++++++++++++++++++++++------- src/login/character.rs | 14 +------------- src/ship/drops/rare_drop_table.rs | 13 +------------ 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index cd3d002..0669789 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -326,19 +326,34 @@ pub enum PhotonBlast { #[derive(Debug, Clone, PartialEq)] pub struct Mag { pub mag: MagType, - pub def: u16, - pub pow: u16, - pub dex: u16, - pub mnd: u16, + def: u16, + pow: u16, + dex: u16, + mnd: u16, pub synchro: u8, - pub iq: u8, - pub photon_blast: [Option; 3], + iq: u8, + photon_blast: [Option; 3], pub color: u8, - pub modifiers: Vec, + modifiers: Vec, } impl Mag { + pub fn baby_mag(skin: u16) -> Mag { + Mag { + mag: MagType::Mag, + def: 500, + pow: 0, + dex: 0, + mnd: 0, + synchro: 20, + iq: 0, + photon_blast: [None; 3], + color: (skin % 18) as u8, + modifiers: Vec::new(), + } + } + pub fn as_bytes(&self) -> [u8; 16] { let mut result = [0; 16]; result[0..3].copy_from_slice(&self.mag.value()); diff --git a/src/login/character.rs b/src/login/character.rs index cade993..91b38b8 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -226,19 +226,7 @@ async fn new_character(entity_gateway: &mut EG, user: &UserAc entity_gateway.create_item( NewItemEntity { - item: ItemDetail::Mag( - Mag { - mag: MagType::Mag, - def: 500, - pow: 0, - dex: 0, - mnd: 0, - synchro: 20, - iq: 0, - photon_blast: [None; 3], - color: (character.appearance.skin % 18) as u8, - modifiers: Vec::new(), - }), + item: ItemDetail::Mag(Mag::baby_mag(character.appearance.skin)), location: ItemLocation::Inventory { character_id: character.id, slot: 2, diff --git a/src/ship/drops/rare_drop_table.rs b/src/ship/drops/rare_drop_table.rs index dc3dd47..fae0175 100644 --- a/src/ship/drops/rare_drop_table.rs +++ b/src/ship/drops/rare_drop_table.rs @@ -136,18 +136,7 @@ impl RareDropTable { }) }, RareDropItem::Mag(mag) => { - ItemDropType::Mag(Mag { - mag: mag, - def: 500, - pow: 0, - dex: 0, - mnd: 0, - iq: 0, - synchro: 20, - photon_blast: [None; 3], - color: rng.gen_range(0, 18), - modifiers: Vec::new(), - }) + ItemDropType::Mag(Mag::baby_mag(rng.gen_range(0, 18))) } } } From 982f1f5d69f1fe75dc60ffef29000ad0f9a399ec Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 28 Aug 2020 16:15:39 -0600 Subject: [PATCH 04/17] add photon blasts to mag stat data --- data/item_stats/mag_stats.toml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/data/item_stats/mag_stats.toml b/data/item_stats/mag_stats.toml index dae1905..04e93e1 100644 --- a/data/item_stats/mag_stats.toml +++ b/data/item_stats/mag_stats.toml @@ -6,96 +6,124 @@ feed_table = 1 [Mitra] feed_table = 3 +photon_blast = "Pilla" [Surya] feed_table = 3 +photon_blast = "Leilla" [Vayu] feed_table = 4 +photon_blast = "MyllaYoulla" [Varaha] feed_table = 4 +photon_blast = "Leilla" [Kama] feed_table = 4 +photon_blast = "Pilla" [Ushasu] feed_table = 4 +photon_blast = "Leilla" [Apsaras] feed_table = 4 +photon_blast = "Estlla" [Kumara] feed_table = 4 +photon_blast = "Leilla" [Kaitabha] feed_table = 4 +photon_blast = "MyllaYoulla" [Tapas] feed_table = 3 +photon_blast = "MyllaYoulla" [Bhirava] feed_table = 4 +photon_blast = "Pilla" [Kalki] feed_table = 1 +photon_blast = "Estlla" [Rudra] feed_table = 2 +photon_blast = "Leilla" [Marutah] feed_table = 2 +photon_blast = "Pilla" [Yaksa] feed_table = 5 +photon_blast = "Leilla" [Sita] feed_table = 5 +photon_blast = "Pilla" [Garuda] feed_table = 5 +photon_blast = "Pilla" [Nandin] feed_table = 5 +photon_blast = "Estlla" [Ashvinau] feed_table = 2 +photon_blast = "Pilla" [Ribhava] feed_table = 5 [Soma] feed_table = 5 +photon_blast = "Estlla" [Ila] feed_table = 5 +photon_blast = "MyllaYoulla" [Durga] feed_table = 5 +photon_blast = "Estlla" [Vritra] feed_table = 1 +photon_blast = "Golla" [Namuci] feed_table = 2 +photon_blast = "MyllaYoulla" [Sumba] feed_table = 2 +photon_blast = "Leilla" [Naga] feed_table = 6 +photon_blast = "MyllaYoulla" [Pitri] feed_table = 7 [Kabanda] feed_table = 6 +photon_blast = "MyllaYoulla" [Ravana] feed_table = 6 [Marica] feed_table = 6 +photon_blast = "Pilla" [Soniti] feed_table = 7 @@ -105,15 +133,19 @@ feed_table = 7 [Andhaka] feed_table = 6 +photon_blast = "Estlla" [Bana] feed_table = 6 +photon_blast = "Estlla" [Naraka] feed_table = 6 +photon_blast = "Leilla" [Madhu] feed_table = 6 +photon_blast = "MyllaYoulla" [Churel] feed_table = 7 From 3184c79c3c7d7e2511e2fd2e4cb90b0f80f472fc Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 28 Aug 2020 17:32:24 -0600 Subject: [PATCH 05/17] basic mag evolution --- src/entity/character.rs | 4 +- src/entity/item/mag.rs | 586 +++++++++++++++++++++++++++++++++++++++- src/entity/item/tool.rs | 36 +++ src/lib.rs | 2 + 4 files changed, 614 insertions(+), 14 deletions(-) diff --git a/src/entity/character.rs b/src/entity/character.rs index fc87569..4fc6383 100644 --- a/src/entity/character.rs +++ b/src/entity/character.rs @@ -7,7 +7,7 @@ use libpso::character::character::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU}; use crate::entity::item::tech::Technique; use crate::entity::account::UserAccountId; -#[derive(Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum CharacterClass { HUmar, HUnewearl, @@ -64,7 +64,7 @@ impl Into for CharacterClass { } -#[derive(Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)] pub enum SectionID { Viridia, Greenill, diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index 0669789..442bdc2 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -1,21 +1,25 @@ use std::collections::HashMap; use serde::{Serialize, Deserialize}; use crate::entity::item::tool::ToolType; +use crate::entity::character::{CharacterClass, SectionID}; use std::io::Read; +use std::cmp::Ordering::{Less, Greater, Equal}; + #[derive(Debug, Deserialize)] struct MagStats { - feed_table: u32, + feed_table: usize, + photon_blast: Option } #[derive(Debug, Deserialize)] struct MagFeedTable { - def: i32, - pow: i32, - dex: i32, - mnd: i32, - iq: i32, - syn: i32, + def: i16, + pow: i16, + dex: i16, + mnd: i16, + iq: i8, + syn: i8, } lazy_static::lazy_static! { @@ -302,6 +306,144 @@ impl MagType { _ => Err(ItemParseError::InvalidMagType), } } + + pub fn can_evolve(&self) -> bool { + match self { + MagType::Mag => true, + MagType::Varuna => true, + MagType::Mitra => true, + MagType::Surya => true, + MagType::Vayu => true, + MagType::Varaha => true, + MagType::Kama => true, + MagType::Ushasu => true, + MagType::Apsaras => true, + MagType::Kumara => true, + MagType::Kaitabha => true, + MagType::Tapas => true, + MagType::Bhirava => true, + MagType::Kalki => true, + MagType::Rudra => true, + MagType::Marutah => true, + MagType::Yaksa => true, + MagType::Sita => true, + MagType::Garuda => true, + MagType::Nandin => true, + MagType::Ashvinau => true, + MagType::Ribhava => true, + MagType::Soma => true, + MagType::Ila => true, + MagType::Durga => true, + MagType::Vritra => true, + MagType::Namuci => true, + MagType::Sumba => true, + MagType::Naga => true, + MagType::Pitri => true, + MagType::Kabanda => true, + MagType::Ravana => true, + MagType::Marica => true, + MagType::Soniti => true, + MagType::Preta => true, + MagType::Andhaka => true, + MagType::Bana => true, + MagType::Naraka => true, + MagType::Madhu => true, + MagType::Churel => false, + MagType::Robochao => false, + MagType::OpaOpa => false, + MagType::Pian => false, + MagType::Chao => false, + MagType::ChuChu => false, + MagType::KapuKapu => false, + MagType::AngelsWing => false, + MagType::DevilsWing => false, + MagType::Elenor => false, + MagType::MarkIII => false, + MagType::MasterSystem => false, + MagType::Genesis => false, + MagType::SegaSaturn => false, + MagType::Dreamcast => false, + MagType::Hamburger => false, + MagType::PanzersTail => false, + MagType::DevilsTail => false, + MagType::Deva => false, + MagType::Rati => false, + MagType::Savitri => false, + MagType::Rukmin => false, + MagType::Pushan => false, + MagType::Diwari => false, + MagType::Sato => false, + MagType::Bhima => false, + MagType::Nidra => false, + MagType::GeungSi => false, + MagType::Tellusis => false, + MagType::StrikerUnit => false, + MagType::Pioneer => false, + MagType::Puyo => false, + MagType::Moro => false, + MagType::Rappy => false, + MagType::Yahoo => false, + MagType::GaelGiel => false, + MagType::Agastya => false, + } + } +} + + +enum MagAttribute { + //Def, + Pow, + Dex, + Mind, +} + +// one day I hope to be cool enough to figure how to enforce that each magattribute in sequence must be unique +// (to not need the _ in the match) +enum MagAttributeOrdering { + Sequence(MagAttribute, MagAttribute, MagAttribute), + Primary(MagAttribute), + MultiPrimary +} + +impl MagAttributeOrdering { + fn new(pow: u16, dex: u16, mnd: u16) -> MagAttributeOrdering { + let primary = if pow > dex && pow > mnd { + MagAttribute::Pow + } + else if dex > pow && dex > mnd{ + MagAttribute::Dex + } + else if mnd > pow && mnd > dex { + MagAttribute::Mind + } + else { + return MagAttributeOrdering::MultiPrimary + }; + + match primary { + MagAttribute::Pow => { + match dex.cmp(&mnd) { + Greater => MagAttributeOrdering::Sequence(primary, MagAttribute::Dex, MagAttribute::Mind), + Equal => MagAttributeOrdering::Primary(primary), + Less => MagAttributeOrdering::Sequence(primary, MagAttribute::Mind, MagAttribute::Dex), + } + }, + MagAttribute::Dex => { + match pow.cmp(&mnd) { + Greater => MagAttributeOrdering::Sequence(primary, MagAttribute::Pow, MagAttribute::Mind), + Equal => MagAttributeOrdering::Primary(primary), + Less => MagAttributeOrdering::Sequence(primary, MagAttribute::Mind, MagAttribute::Pow), + } + }, + MagAttribute::Mind => { + match pow.cmp(&dex) { + Greater => MagAttributeOrdering::Sequence(primary, MagAttribute::Pow, MagAttribute::Dex), + Equal => MagAttributeOrdering::Primary(primary), + Less => MagAttributeOrdering::Sequence(primary, MagAttribute::Dex, MagAttribute::Pow), + } + }, + } + } } #[derive(Debug, Clone, PartialEq)] @@ -311,9 +453,10 @@ pub enum MagModifier { }, BankMag, // when putting a mag in the bank it truncates the values which has applications when raising degenerate mags MagCell(ToolType), + OwnerChange(CharacterClass, SectionID) } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Deserialize, enum_utils::FromStr)] pub enum PhotonBlast { Farlla, Estlla, @@ -334,7 +477,9 @@ pub struct Mag { iq: u8, photon_blast: [Option; 3], pub color: u8, - modifiers: Vec, + //modifiers: Vec, + class: CharacterClass, + id: SectionID, } @@ -350,7 +495,9 @@ impl Mag { iq: 0, photon_blast: [None; 3], color: (skin % 18) as u8, - modifiers: Vec::new(), + //modifiers: Vec::new(), + class: CharacterClass::HUmar, + id: SectionID::Viridia, } } @@ -422,7 +569,7 @@ impl Mag { } pub fn from_bytes(data: [u8; 16]) -> Result { - let m = MagType::parse_type([data[0], data[1], data[2]]); + let m = MagType::parse_type([data[0], data[1], data[2]]); if m.is_ok() { let mut def = u16::from_le_bytes([data[4], data[5]]); let mut pow = u16::from_le_bytes([data[6], data[7]]); @@ -449,7 +596,9 @@ impl Mag { iq: iq, photon_blast: [None, None, None], // TODO: actually get PBs from bytes color: data[15] % 18, - modifiers: Vec::new(), + //modifiers: Vec::new(), + class: CharacterClass::HUmar, + id: SectionID::Viridia, }) } else { @@ -457,6 +606,382 @@ impl Mag { } } + pub fn def(&self) -> u16 { + self.def/100 + } + + pub fn pow(&self) -> u16 { + self.pow/100 + } + + pub fn dex(&self) -> u16 { + self.dex/100 + } + + pub fn mind(&self) -> u16 { + self.mnd/100 + } + + pub fn level(&self) -> u16 { + self.def() + self.pow() + self.dex() + self.mind() + } + + fn change_mag_type(&mut self, previous_level: u16) { + if !self.mag.can_evolve() { + return + } + + if self.level() >= 10 && previous_level < 10 { + match self.class { + CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => { + self.mag = MagType::Varuna + }, + CharacterClass::RAmar | CharacterClass::RAmarl | CharacterClass::RAcast | CharacterClass::RAcaseal => { + self.mag = MagType::Kalki + }, + CharacterClass::FOmar | CharacterClass::FOmarl | CharacterClass::FOnewm | CharacterClass::FOnewearl => { + self.mag = MagType::Vritra + }, + } + } + + if self.level() >= 35 && previous_level < 35 { + match self.mag { + MagType::Varuna => { + if self.pow > self.dex && self.pow > self.mnd { + self.mag = MagType::Rudra + } + else if self.dex > self.pow && self.dex > self.mnd { + self.mag = MagType::Marutah + } + else if self.mnd > self.pow && self.mnd > self.dex { + self.mag = MagType::Vayu + } + else { + self.mag = MagType::Rudra + } + }, + MagType::Kalki => { + if self.pow > self.dex && self.pow > self.mnd { + self.mag = MagType::Surya + } + else if self.dex > self.pow && self.dex > self.mnd { + self.mag = MagType::Mitra + } + else if self.mnd > self.pow && self.mnd > self.dex { + self.mag = MagType::Tapas + } + else { + self.mag = MagType::Mitra + } + }, + MagType::Vritra => { + if self.pow > self.dex && self.pow > self.mnd { + self.mag = MagType::Sumba + } + else if self.dex > self.pow && self.dex > self.mnd { + self.mag = MagType::Ashvinau + } + else if self.mnd > self.pow && self.mnd > self.dex { + self.mag = MagType::Namuci + } + else { + self.mag = MagType::Namuci + } + }, + _ => unreachable!(), + } + } + + if self.level() >= 50 && self.level() % 5 == 0 { + let mag_attr_ordering = MagAttributeOrdering::new(self.pow, self.dex, self.mnd); + self.mag = match self.id { + SectionID::Viridia | SectionID::Skyly | SectionID::Purplenum | SectionID::Redria | SectionID::Yellowboze => { + match self.class { + CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => { + match mag_attr_ordering { + MagAttributeOrdering::Primary(MagAttribute::Pow) => MagType::Varaha, + MagAttributeOrdering::Primary(MagAttribute::Dex) => MagType::Nandin, + MagAttributeOrdering::Primary(MagAttribute::Mind) => MagType::Kabanda, + MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind) => MagType::Varaha, + MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex) => MagType::Bhirava, + MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind) => MagType::Ila, + MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow) => MagType::Nandin, + MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex) => MagType::Kabanda, + MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow) => MagType::Ushasu, + MagAttributeOrdering::MultiPrimary => { + if self.dex >= self.mnd { + MagType::Varaha + } + else { + MagType::Bhirava + } + }, + _ => unreachable!() + } + }, + CharacterClass::RAmar | CharacterClass::RAmarl | CharacterClass::RAcast | CharacterClass::RAcaseal => { + match mag_attr_ordering { + MagAttributeOrdering::Primary(MagAttribute::Pow) => MagType::Kama, + MagAttributeOrdering::Primary(MagAttribute::Dex) => MagType::Kama, + MagAttributeOrdering::Primary(MagAttribute::Mind) => MagType::Varaha, + MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind) => MagType::Kama, + MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex) => MagType::Bhirava, + MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind) => MagType::Bhirava, + MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow) => MagType::Kama, + MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex) => MagType::Varaha, + MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow) => MagType::Apsaras, + MagAttributeOrdering::MultiPrimary => { + if self.mnd >= self.pow { + MagType::Kama + } + else { + MagType::Bhirava + } + } + _ => unreachable!() + } + }, + CharacterClass::FOmar | CharacterClass::FOmarl | CharacterClass::FOnewm | CharacterClass::FOnewearl => { + match (mag_attr_ordering, self.def() >= 45) { + (MagAttributeOrdering::Primary(MagAttribute::Pow), true) => MagType::Andhaka, + (MagAttributeOrdering::Primary(MagAttribute::Dex), true) => MagType::Bana, + (MagAttributeOrdering::Primary(MagAttribute::Mind), true) => MagType::Bana, + (MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind), true) => MagType::Andhaka, + (MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex), true) => MagType::Andhaka, + (MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind), true) => MagType::Bana, + (MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow), true) => MagType::Bana, + (MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex), true) => MagType::Bana, + (MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow), true) => MagType::Bana, + (MagAttributeOrdering::MultiPrimary, true) => MagType::Bana, + (MagAttributeOrdering::Primary(MagAttribute::Pow), false) => MagType::Naraka, + (MagAttributeOrdering::Primary(MagAttribute::Dex), false) => MagType::Sita, + (MagAttributeOrdering::Primary(MagAttribute::Mind), false) => MagType::Naga, + (MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind), false) => MagType::Naraka, + (MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex), false) => MagType::Ravana, + (MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind), false) => MagType::Ribhava, + (MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow), false) => MagType::Sita, + (MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex), false) => MagType::Naga, + (MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow), false) => MagType::Kabanda, + (MagAttributeOrdering::MultiPrimary, false) => { + if self.pow >= self.dex { + MagType::Naga + } + else { + MagType::Kabanda + } + } + _ => unreachable!() + } + }, + } + }, + SectionID::Greenill | SectionID::Bluefull | SectionID::Pinkal | SectionID::Oran | SectionID::Whitill => { + match self.class { + CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => { + match mag_attr_ordering { + MagAttributeOrdering::Primary(MagAttribute::Pow) => MagType::Kama, + MagAttributeOrdering::Primary(MagAttribute::Dex) => MagType::Yaksa, + MagAttributeOrdering::Primary(MagAttribute::Mind) => MagType::Bana, + MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind) => MagType::Kama, + MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex) => MagType::Apsaras, + MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind) => MagType::Garuda, + MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow) => MagType::Yaksa, + MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex) => MagType::Bana, + MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow) => MagType::Soma, + MagAttributeOrdering::MultiPrimary => { + if self.dex >= self.mnd { + MagType::Kama + } + else { + MagType::Apsaras + } + } + _ => unreachable!() + } + }, + CharacterClass::RAmar | CharacterClass::RAmarl | CharacterClass::RAcast | CharacterClass::RAcaseal => { + match mag_attr_ordering { + MagAttributeOrdering::Primary(MagAttribute::Pow) => MagType::Madhu, + MagAttributeOrdering::Primary(MagAttribute::Dex) => MagType::Varaha, + MagAttributeOrdering::Primary(MagAttribute::Mind) => MagType::Kabanda, + MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind) => MagType::Madhu, + MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex) => MagType::Kaitabha, + MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind) => MagType::Kaitabha, + MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow) => MagType::Varaha, + MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex) => MagType::Kabanda, + MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow) => MagType::Durga, + MagAttributeOrdering::MultiPrimary => { + if self.pow > self.mnd { + MagType::Kaitabha + } + else { + MagType::Varaha + } + } + _ => unreachable!() + } + }, + CharacterClass::FOmar | CharacterClass::FOmarl | CharacterClass::FOnewm | CharacterClass::FOnewearl => { + match (mag_attr_ordering, self.def() >= 45) { + (MagAttributeOrdering::Primary(MagAttribute::Pow), true) => MagType::Andhaka, + (MagAttributeOrdering::Primary(MagAttribute::Dex), true) => MagType::Bana, + (MagAttributeOrdering::Primary(MagAttribute::Mind), true) => MagType::Bana, + (MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind), true) => MagType::Andhaka, + (MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex), true) => MagType::Andhaka, + (MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind), true) => MagType::Bana, + (MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow), true) => MagType::Bana, + (MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex), true) => MagType::Bana, + (MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow), true) => MagType::Bana, + (MagAttributeOrdering::MultiPrimary, true) => MagType::Bana, + (MagAttributeOrdering::Primary(MagAttribute::Pow), false) => MagType::Marica, + (MagAttributeOrdering::Primary(MagAttribute::Dex), false) => MagType::Bhirava, + (MagAttributeOrdering::Primary(MagAttribute::Mind), false) => MagType::Kumara, + (MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Dex, MagAttribute::Mind), false) => MagType::Marica, + (MagAttributeOrdering::Sequence(MagAttribute::Pow, MagAttribute::Mind, MagAttribute::Dex), false) => MagType::Naga, + (MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Pow, MagAttribute::Mind), false) => MagType::Garuda, + (MagAttributeOrdering::Sequence(MagAttribute::Dex, MagAttribute::Mind, MagAttribute::Pow), false) => MagType::Bhirava, + (MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Pow, MagAttribute::Dex), false) => MagType::Kumara, + (MagAttributeOrdering::Sequence(MagAttribute::Mind, MagAttribute::Dex, MagAttribute::Pow), false) => MagType::Ila, + (MagAttributeOrdering::MultiPrimary, false) => { + if self.pow >= self.dex { + MagType::Kumara + } + else { + MagType::Ila + } + } + _ => unreachable!() + } + }, + } + } + }; + } + + if self.level() >= 100 && self.level() % 5 == 0 { + match self.id { + SectionID::Skyly | SectionID::Pinkal | SectionID::Yellowboze => { + if self.def() + self.pow() == self.dex() + self.mind() { + self.mag = match self.class { + CharacterClass::HUmar | CharacterClass::HUcast => { + MagType::Rati + }, + CharacterClass::HUnewearl | CharacterClass::HUcaseal => { + MagType::Savitri + }, + CharacterClass::RAmar | CharacterClass::RAcast => { + MagType::Pushan + }, + CharacterClass::RAmarl | CharacterClass::RAcaseal => { + MagType::Diwari + }, + CharacterClass::FOmar | CharacterClass::FOnewm => { + MagType::Nidra + }, + CharacterClass::FOmarl | CharacterClass::FOnewearl => { + MagType::Bhima + }, + } + } + }, + SectionID::Viridia | SectionID::Bluefull | SectionID::Redria | SectionID::Whitill => { + if self.def() + self.dex() == self.pow() + self.mind() { + self.mag = match self.class { + CharacterClass::HUmar | CharacterClass::HUcast => { + MagType::Deva + }, + CharacterClass::HUnewearl | CharacterClass::HUcaseal => { + MagType::Savitri + }, + CharacterClass::RAmar | CharacterClass::RAcast => { + MagType::Pushan + }, + CharacterClass::RAmarl | CharacterClass::RAcaseal => { + MagType::Rukmin + }, + CharacterClass::FOmar | CharacterClass::FOnewm => { + MagType::Nidra + }, + CharacterClass::FOmarl | CharacterClass::FOnewearl => { + MagType::Sato // best mag + }, + } + } + }, + SectionID::Greenill | SectionID::Purplenum | SectionID::Oran => { + if self.def() + self.mind() == self.pow() + self.dex() { + self.mag = match self.class { + CharacterClass::HUmar | CharacterClass::HUcast => { + MagType::Rati + }, + CharacterClass::HUnewearl | CharacterClass::HUcaseal => { + MagType::Savitri + }, + CharacterClass::RAmar | CharacterClass::RAcast => { + MagType::Pushan + }, + CharacterClass::RAmarl | CharacterClass::RAcaseal => { + MagType::Rukmin + }, + CharacterClass::FOmar | CharacterClass::FOnewm => { + MagType::Nidra + }, + CharacterClass::FOmarl | CharacterClass::FOnewearl => { + MagType::Bhima + }, + } + } + } + } + } + } + + pub fn assign_photon_blast(&mut self) { + MAG_STATS.get(&self.mag).map(|stats| { + stats.photon_blast.map(|photon_blast| { + if !self.photon_blast.contains(&Some(photon_blast)) { + self.photon_blast.iter_mut().find(|k| k.is_none()).map(|pb_slot| { + *pb_slot = Some(photon_blast) + }); + } + }) + }); + } + + pub fn feed(&mut self, tool: ToolType) { + if tool.is_mag_cell() { + //do_mag_cell_thing() + } + let previous_level = self.level(); + MAG_STATS.get(&self.mag).map(|stats| { + MAG_FEEDING_TABLES.get(stats.feed_table).map(|feeding_table| { + feeding_table.get(&tool).map(|feed_stats| { + self.def = std::cmp::max(std::cmp::max((self.def as i16) + feed_stats.def, 0) as u16, self.def()*100); + self.pow = std::cmp::max(std::cmp::max((self.pow as i16) + feed_stats.pow, 0) as u16, self.pow()*100); + self.dex = std::cmp::max(std::cmp::max((self.dex as i16) + feed_stats.dex, 0) as u16, self.dex()*100); + self.mnd = std::cmp::max(std::cmp::max((self.mnd as i16) + feed_stats.mnd, 0) as u16, self.mind()*100); + self.iq = std::cmp::min(((self.iq as i16) + feed_stats.iq as i16) as u8, 200); + self.synchro = std::cmp::min(((self.synchro as i8) + feed_stats.syn) as u8, 120); + }) + }) + }); + //if previous_level != self.level() { + self.change_mag_type(previous_level); + self.assign_photon_blast(); + //} + } + + pub fn change_owner(&mut self, class: CharacterClass, id: SectionID) { + self.class = class; + self.id = id; + } + + pub fn bank(&mut self) { + // what is the truncation logic anyway + } +} + #[cfg(test)] mod test { @@ -496,4 +1021,41 @@ mod test { .collect::>>(); } + #[test] + fn test_raise_a_sato() { + let mut mag = Mag::baby_mag(0); + mag.change_owner(CharacterClass::RAcaseal, SectionID::Whitill); + for _ in 0..137 { + mag.feed(ToolType::Antidote); + } + for _ in 0..75 { + mag.feed(ToolType::Antiparalysis); + } + mag.change_owner(CharacterClass::FOmarl, SectionID::Whitill); + for _ in 0..51 { + mag.feed(ToolType::Antiparalysis); + } + for _ in 0..284 { + mag.feed(ToolType::Dimate); + } + //println!("mag! {:?}", mag); + assert!(mag == Mag { + mag: MagType::Sato, + def: 507, + pow: 5019, + dex: 4505, + mnd: 0, + synchro: 120, + iq: 200, + photon_blast: [Some(PhotonBlast::Estlla), Some(PhotonBlast::Pilla), Some(PhotonBlast::MyllaYoulla)], + color: 0, + class: CharacterClass::FOmarl, + id: SectionID::Whitill, + }); + } + + #[test] + fn test_mag_does_not_level_down() { + } } + diff --git a/src/entity/item/tool.rs b/src/entity/item/tool.rs index de92170..5b95dde 100644 --- a/src/entity/item/tool.rs +++ b/src/entity/item/tool.rs @@ -251,6 +251,42 @@ impl ToolType { } } + pub fn is_mag_cell(&self) -> bool { + match self { + ToolType::CellOfMag502 => true, + ToolType::CellOfMag213 => true, + ToolType::PartsOfRobochao => true, + ToolType::HeartOfOpaOpa => true, + ToolType::HeartOfPian => true, + ToolType::HeartOfChao => true, + ToolType::HeartOfAngel => true, + ToolType::HeartOfDevil => true, + ToolType::KitOfHamburger => true, + ToolType::PanthersSpirit => true, + ToolType::KitOfMark3 => true, + ToolType::KitOfMasterSystem => true, + ToolType::KitOfGenesis => true, + ToolType::KitOfSegaSaturn => true, + ToolType::KitOfDreamcast => true, + ToolType::Tablet => true, + ToolType::DragonScale => true, + ToolType::HeavenStrikerCoat => true, + ToolType::PioneerParts => true, + ToolType::AmitiesMemo => true, + ToolType::HeartOfMorolian => true, + ToolType::RappysBeak => true, + ToolType::YahoosEngine => true, + ToolType::DPhotonCore => true, + ToolType::LibertaKit => true, + ToolType::CellOfMag0503 => true, + ToolType::CellOfMag0504 => true, + ToolType::CellOfMag0505 => true, + ToolType::CellOfMag0506 => true, + ToolType::CellOfMag0507 => true, + _ => false, + } + } + pub fn value(&self) -> [u8; 3] { match self { ToolType::Monomate => [0x03, 0x00, 0x00], diff --git a/src/lib.rs b/src/lib.rs index 309b324..abd1d14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,8 @@ #![feature(maybe_uninit_extra)] #![feature(const_in_array_repeat_expressions)] #![feature(drain_filter)] +#![feature(or_patterns)] + From a68fcb9b10f03f96097979e0b59c1ec0a61ef56d Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 31 Aug 2020 23:44:39 -0600 Subject: [PATCH 06/17] add feed_mag entity_gateway function --- src/entity/gateway/entitygateway.rs | 4 ++++ src/entity/gateway/inmemory.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index c6324e1..e9e0130 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -60,6 +60,10 @@ pub trait EntityGateway: Send + Sync + Clone { unimplemented!(); } + async fn feed_mag(&mut self, _mag_item_id: &ItemEntityId, _tool_item_id: &ItemEntityId) { + unimplemented!(); + } + async fn get_items_by_character(&self, _char: &CharacterEntity) -> Vec { unimplemented!(); } diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index 5959a39..54ad825 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -13,6 +13,7 @@ pub struct InMemoryGateway { user_settings: Arc>>, characters: Arc>>, items: Arc>>, + mag_feedings: Arc>>>, } impl InMemoryGateway { @@ -22,6 +23,7 @@ impl InMemoryGateway { user_settings: Arc::new(Mutex::new(BTreeMap::new())), characters: Arc::new(Mutex::new(BTreeMap::new())), items: Arc::new(Mutex::new(BTreeMap::new())), + mag_feedings: Arc::new(Mutex::new(BTreeMap::new())), } } } @@ -165,6 +167,13 @@ impl EntityGateway for InMemoryGateway { }); } + async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) { + self.mag_feedings.lock().unwrap() + .entry(*mag_item_id) + .or_insert(Vec::new()) + .push(*tool_item_id); + } + async fn get_items_by_character(&self, character: &CharacterEntity) -> Vec { let items = self.items.lock().unwrap(); items @@ -179,6 +188,25 @@ impl EntityGateway for InMemoryGateway { .map(|(_, k)| { k.clone() }) + .map(|mut item| { + item.item = match item.item { + ItemDetail::Mag(mut mag) => { + self.mag_feedings.lock().unwrap().get(&item.id).map(|mag_feedings| { + for mag_feed_id in mag_feedings.iter() { + items.get(&mag_feed_id).map(|mag_feed| { + match mag_feed.item { + ItemDetail::Tool(mag_feed) => mag.feed(mag_feed.tool), + _ => {} + } + }); + } + }); + ItemDetail::Mag(mag) + } + _ => item.item + }; + item + }) .collect() } } From 15b473298160592d858e59e6997fe3255e0a7d2b Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 31 Aug 2020 23:45:40 -0600 Subject: [PATCH 07/17] item helper methods --- src/ship/items/inventory.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index b0cd347..044b6e2 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -3,6 +3,7 @@ use thiserror::Error; use libpso::character::character;//::InventoryItem; use crate::entity::item::{ItemEntityId, ItemDetail, ItemType}; use crate::entity::item::tool::Tool; +use crate::entity::item::mag::Mag; use crate::ship::items::{ClientItemId, BankItem, BankItemHandle}; use crate::ship::items::floor::{IndividualFloorItem, StackedFloorItem}; @@ -20,6 +21,15 @@ pub struct IndividualInventoryItem { pub equipped: bool, } +impl IndividualInventoryItem { + pub fn mag(&mut self) -> Option<&mut Mag> { + match self.item { + ItemDetail::Mag(ref mut mag) => Some(mag), + _ => None + } + } +} + #[derive(Debug, Clone)] pub struct StackedInventoryItem { pub entity_ids: Vec, @@ -178,6 +188,13 @@ impl InventoryItem { } Ok(()) } + + pub fn individual(&mut self) -> Option<&mut IndividualInventoryItem> { + match self { + InventoryItem::Individual(ref mut individual_inventory_item) => Some(individual_inventory_item), + _ => None + } + } } From 2dde4d5716f7420972baab5fe419dfcad16887bd Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 31 Aug 2020 23:46:15 -0600 Subject: [PATCH 08/17] mag feeding --- src/entity/item/mod.rs | 3 +++ src/ship/items/manager.rs | 38 ++++++++++++++++++++++++++++++ src/ship/packet/handler/message.rs | 23 +++++++++++++++++- src/ship/ship.rs | 3 +++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/entity/item/mod.rs b/src/entity/item/mod.rs index b6add91..20bca41 100644 --- a/src/entity/item/mod.rs +++ b/src/entity/item/mod.rs @@ -43,6 +43,9 @@ pub enum ItemLocation { z: f32, }, Consumed, + FedToMag { + mag: ItemEntityId, + } /*Destroyed { // marks an item that has been consumed in some way }, diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 69cd03b..9c3c83b 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -36,6 +36,7 @@ pub enum ItemManagerError { NotEnoughTools(Tool, usize, usize), // have, expected InventoryItemConsumeError(#[from] InventoryItemConsumeError), BankFull, + WrongItemType(ClientItemId), } pub struct ItemManager { @@ -595,4 +596,41 @@ impl ItemManager { Ok(inventory_item.0) } + + pub async fn player_feeds_mag_item(&mut self, + entity_gateway: &mut EG, + character: &CharacterEntity, + mag_id: ClientItemId, + tool_id: ClientItemId) + -> Result<(), ItemManagerError> { + 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() + .ok_or(ItemManagerError::WrongItemType(mag_id))?; + let mag = individual_item + .mag() + .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)) + }; + 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.change_item_location(&entity_id, ItemLocation::FedToMag { + mag: individual_item.entity_id, + }).await; + } + + Ok(()) + } } diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 098f262..09bdd0e 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -326,4 +326,25 @@ EG: EntityGateway } else { Err(ShipError::NotEnoughMeseta(id, client.character.meseta)) } -} \ No newline at end of file +} + + +pub async fn player_feed_mag(id: ClientId, + mag_feed: &PlayerFeedMag, + entity_gateway: &mut EG, + client_location: &ClientLocation, + clients: &Clients, + item_manager: &mut ItemManager) + -> Result + Send>, ShipError> +where + EG: EntityGateway +{ + let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; + item_manager.player_feeds_mag_item(entity_gateway, &client.character, ClientItemId(mag_feed.mag_id), ClientItemId(mag_feed.item_id)).await?; + + let mag_feed = mag_feed.clone(); + Ok(Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() + .map(move |client| { + (client.client, SendShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(mag_feed.clone())))) + }))) +} diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 766dfcb..643d662 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -348,6 +348,9 @@ impl ShipServerState { GameMessage::PlayerUsedMedicalCenter(player_used_medical_center) => { handler::message::player_used_medical_center(id, &player_used_medical_center, &mut self.entity_gateway, &mut self.clients).await }, + GameMessage::PlayerFeedMag(player_feed_mag) => { + handler::message::player_feed_mag(id, &player_feed_mag, &mut self.entity_gateway, &mut self.client_location, &mut self.clients, &mut self.item_manager).await + }, _ => { let cmsg = msg.clone(); Ok(Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter() From 395ce2fbbeb0a44508d0937a4f11564b08e50ff6 Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 31 Aug 2020 23:47:06 -0600 Subject: [PATCH 09/17] mag test --- tests/test_mags.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 tests/test_mags.rs diff --git a/tests/test_mags.rs b/tests/test_mags.rs new file mode 100644 index 0000000..b9bf032 --- /dev/null +++ b/tests/test_mags.rs @@ -0,0 +1,74 @@ +use elseware::common::serverstate::{ClientId, ServerState}; +use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; +use elseware::entity::item; +use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; + +use libpso::packet::ship::*; +use libpso::packet::messages::*; + +#[path = "common.rs"] +mod common; +use common::*; + +#[async_std::test] +async fn test_mag_feed() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::Mag( + item::mag::Mag::baby_mag(0) + ), + location: item::ItemLocation::Inventory { + character_id: char1.id, + slot: 0, + equipped: true, + } + }).await; + for _ in 0..7 { + entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::Tool( + item::tool::Tool { + tool: item::tool::ToolType::Monomate, + } + ), + location: item::ItemLocation::Inventory { + character_id: char1.id, + slot: 1, + equipped: false, + } + }).await; + } + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room(&mut ship, ClientId(1), "room", "").await; + + for _ in 0..7 { + ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerFeedMag(PlayerFeedMag { + client: 0, + target: 0, + mag_id: 0x10000, + item_id: 0x10001, + })))).await.unwrap().for_each(drop); + } + + let p1_items = entity_gateway.get_items_by_character(&char1).await; + let mag = p1_items.get(0).unwrap(); + match &mag.item { + item::ItemDetail::Mag(mag) => { + assert!(mag.level() == 7); + assert!(mag.def() == 5); + assert!(mag.pow() == 2); + assert!(mag.dex() == 0); + assert!(mag.mind() == 0); + } + _ => panic!() + } +} From 50c5699f3413b9f636751187b66d992b2fb81789 Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 2 Sep 2020 22:03:45 -0600 Subject: [PATCH 10/17] handle mags changing owners --- src/entity/gateway/entitygateway.rs | 4 ++ src/entity/gateway/inmemory.rs | 41 ++++++++++++------ src/entity/item/mag.rs | 9 ++-- src/ship/items/inventory.rs | 9 +++- src/ship/items/manager.rs | 5 ++- tests/test_mags.rs | 66 +++++++++++++++++++++++++++++ 6 files changed, 116 insertions(+), 18 deletions(-) diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index e9e0130..168c870 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -64,6 +64,10 @@ pub trait EntityGateway: Send + Sync + Clone { unimplemented!(); } + async fn change_mag_owner(&mut self, _mag_item_id: &ItemEntityId, _character: &CharacterEntity) { + unimplemented!(); + } + async fn get_items_by_character(&self, _char: &CharacterEntity) -> Vec { unimplemented!(); } diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index 54ad825..f263ece 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -13,7 +13,7 @@ pub struct InMemoryGateway { user_settings: Arc>>, characters: Arc>>, items: Arc>>, - mag_feedings: Arc>>>, + mag_modifiers: Arc>>>, } impl InMemoryGateway { @@ -23,7 +23,7 @@ impl InMemoryGateway { user_settings: Arc::new(Mutex::new(BTreeMap::new())), characters: Arc::new(Mutex::new(BTreeMap::new())), items: Arc::new(Mutex::new(BTreeMap::new())), - mag_feedings: Arc::new(Mutex::new(BTreeMap::new())), + mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())), } } } @@ -168,10 +168,19 @@ impl EntityGateway for InMemoryGateway { } async fn feed_mag(&mut self, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) { - self.mag_feedings.lock().unwrap() + self.mag_modifiers.lock().unwrap() .entry(*mag_item_id) .or_insert(Vec::new()) - .push(*tool_item_id); + .push(mag::MagModifier::FeedMag { + food: *tool_item_id + }); + } + + async fn change_mag_owner(&mut self, mag_item_id: &ItemEntityId, character: &CharacterEntity) { + self.mag_modifiers.lock().unwrap() + .entry(*mag_item_id) + .or_insert(Vec::new()) + .push(mag::MagModifier::OwnerChange(character.char_class, character.section_id)); } async fn get_items_by_character(&self, character: &CharacterEntity) -> Vec { @@ -191,14 +200,22 @@ impl EntityGateway for InMemoryGateway { .map(|mut item| { item.item = match item.item { ItemDetail::Mag(mut mag) => { - self.mag_feedings.lock().unwrap().get(&item.id).map(|mag_feedings| { - for mag_feed_id in mag_feedings.iter() { - items.get(&mag_feed_id).map(|mag_feed| { - match mag_feed.item { - ItemDetail::Tool(mag_feed) => mag.feed(mag_feed.tool), - _ => {} - } - }); + self.mag_modifiers.lock().unwrap().get(&item.id).map(|mag_modifiers| { + for mag_modifier in mag_modifiers.iter() { + match mag_modifier { + mag::MagModifier::FeedMag {food} => { + items.get(&food).map(|mag_feed| { + match mag_feed.item { + ItemDetail::Tool(mag_feed) => mag.feed(mag_feed.tool), + _ => {} + } + }); + }, + mag::MagModifier::OwnerChange(class, section_id) => { + mag.change_owner(*class, *section_id) + }, + _ => {} + } } }); ItemDetail::Mag(mag) diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index 442bdc2..55b2f00 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use serde::{Serialize, Deserialize}; use crate::entity::item::tool::ToolType; use crate::entity::character::{CharacterClass, SectionID}; +use crate::entity::item::ItemEntityId; use std::io::Read; use std::cmp::Ordering::{Less, Greater, Equal}; @@ -449,10 +450,10 @@ impl MagAttributeOrdering { #[derive(Debug, Clone, PartialEq)] pub enum MagModifier { FeedMag{ - food: ToolType, + food: ItemEntityId, }, BankMag, // when putting a mag in the bank it truncates the values which has applications when raising degenerate mags - MagCell(ToolType), + MagCell(ItemEntityId), OwnerChange(CharacterClass, SectionID) } @@ -478,8 +479,8 @@ pub struct Mag { photon_blast: [Option; 3], pub color: u8, //modifiers: Vec, - class: CharacterClass, - id: SectionID, + pub class: CharacterClass, + pub id: SectionID, } diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index 044b6e2..024a2ca 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -22,7 +22,14 @@ pub struct IndividualInventoryItem { } impl IndividualInventoryItem { - pub fn mag(&mut self) -> Option<&mut Mag> { + pub fn mag(&self) -> Option<&Mag> { + match self.item { + ItemDetail::Mag(ref mag) => Some(mag), + _ => None + } + } + + pub fn mag_mut(&mut self) -> Option<&mut Mag> { match self.item { ItemDetail::Mag(ref mut mag) => Some(mag), _ => None diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 9c3c83b..276e433 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -261,6 +261,9 @@ impl ItemManager { equipped: false, } ).await; + if let Some(_) = new_inventory_item.mag() { + entity_gateway.change_mag_owner(&new_inventory_item.entity_id, character).await; + } }, None => { return Err(ItemManagerError::CouldNotAddToInventory(item_id)); @@ -615,7 +618,7 @@ impl ItemManager { .individual() .ok_or(ItemManagerError::WrongItemType(mag_id))?; let mag = individual_item - .mag() + .mag_mut() .ok_or(ItemManagerError::WrongItemType(mag_id))?; let consumed_tool_type = match &consumed_tool { diff --git a/tests/test_mags.rs b/tests/test_mags.rs index b9bf032..099455a 100644 --- a/tests/test_mags.rs +++ b/tests/test_mags.rs @@ -2,6 +2,7 @@ use elseware::common::serverstate::{ClientId, ServerState}; use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; use elseware::entity::item; use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket}; +use elseware::entity::character::{CharacterClass, SectionID}; use libpso::packet::ship::*; use libpso::packet::messages::*; @@ -72,3 +73,68 @@ async fn test_mag_feed() { _ => panic!() } } + +#[async_std::test] +async fn test_mag_change_owner() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, mut char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + let (_user2, mut char2) = new_user_character(&mut entity_gateway, "a2", "a").await; + char1.char_class = CharacterClass::RAmarl; + char1.section_id = SectionID::Redria; + entity_gateway.save_character(&char1).await; + char2.char_class = CharacterClass::FOmarl; + char2.section_id = SectionID::Whitill; + entity_gateway.save_character(&char2).await; + + entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::Mag( + item::mag::Mag::baby_mag(0) + ), + location: item::ItemLocation::Inventory { + character_id: char1.id, + slot: 0, + equipped: true, + } + }).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + log_in_char(&mut ship, ClientId(2), "a2", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + join_lobby(&mut ship, ClientId(2)).await; + create_room(&mut ship, ClientId(1), "room", "").await; + join_room(&mut ship, ClientId(2), 0).await; + + ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem { + client: 0, + target: 0, + unknown1: 0, + map_area: 0, + item_id: 0x10000, + x: 0.0, + y: 0.0, + z: 0.0, + })))).await.unwrap().for_each(drop); + + ship.handle(ClientId(2), &RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::PickupItem(PickupItem { + client: 0, + target: 0, + item_id: 0x10000, + map_area: 0, + unknown: [0; 3] + })))).await.unwrap().for_each(drop); + + let p2_items = entity_gateway.get_items_by_character(&char2).await; + let mag = p2_items.get(0).unwrap(); + match &mag.item { + item::ItemDetail::Mag(mag) => { + assert!(mag.class == CharacterClass::FOmarl); + assert!(mag.id == SectionID::Whitill); + }, + _ => panic!() + } +} From c3bf42d3671cbdc3045efb40662fdf519f06e5fb Mon Sep 17 00:00:00 2001 From: jake Date: Wed, 2 Sep 2020 22:31:33 -0600 Subject: [PATCH 11/17] set mag owner on character create --- src/login/character.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/login/character.rs b/src/login/character.rs index 91b38b8..997e46d 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -224,9 +224,11 @@ async fn new_character(entity_gateway: &mut EG, user: &UserAc equipped: true, }}).await; + let mut mag = Mag::baby_mag(character.appearance.skin); + mag.change_owner(character.char_class, character.section_id); entity_gateway.create_item( NewItemEntity { - item: ItemDetail::Mag(Mag::baby_mag(character.appearance.skin)), + item: ItemDetail::Mag(mag), location: ItemLocation::Inventory { character_id: character.id, slot: 2, From 23bc39b5bf5f9dd1c5aaf2d71a4cedb9503ae9cb Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 5 Sep 2020 21:10:12 -0600 Subject: [PATCH 12/17] move tool usage logic into own file --- src/ship/items/mod.rs | 1 + src/ship/items/use_tool.rs | 51 ++++++++++++++++++++++++++++++ src/ship/packet/handler/message.rs | 22 +++++-------- 3 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 src/ship/items/use_tool.rs diff --git a/src/ship/items/mod.rs b/src/ship/items/mod.rs index 08150f2..3268b04 100644 --- a/src/ship/items/mod.rs +++ b/src/ship/items/mod.rs @@ -2,6 +2,7 @@ mod bank; mod floor; mod inventory; mod manager; +pub mod use_tool; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ClientItemId(pub u32); diff --git a/src/ship/items/use_tool.rs b/src/ship/items/use_tool.rs new file mode 100644 index 0000000..59e157b --- /dev/null +++ b/src/ship/items/use_tool.rs @@ -0,0 +1,51 @@ +use crate::entity::gateway::EntityGateway; +use crate::entity::character::CharacterEntity; +use crate::entity::item::ItemDetail; +use crate::entity::item::tool::ToolType; + + + + + + + + + + + +//pub fn use_tool() + +pub async fn power_material(entity_gateway: &mut EG, character: &mut CharacterEntity) { + character.materials.power += 1; + entity_gateway.save_character(character).await; +} + +pub async fn mind_material(entity_gateway: &mut EG, character: &mut CharacterEntity) { + character.materials.mind += 1; + entity_gateway.save_character(character).await; +} + +pub async fn evade_material(entity_gateway: &mut EG, character: &mut CharacterEntity) { + character.materials.evade += 1; + entity_gateway.save_character(character).await; +} + +pub async fn def_material(entity_gateway: &mut EG, character: &mut CharacterEntity) { + character.materials.def += 1; + entity_gateway.save_character(character).await; +} + +pub async fn luck_material(entity_gateway: &mut EG, character: &mut CharacterEntity) { + character.materials.luck += 1; + entity_gateway.save_character(character).await; +} + +pub async fn hp_material(entity_gateway: &mut EG, character: &mut CharacterEntity) { + character.materials.hp += 1; + entity_gateway.save_character(character).await; +} + +pub async fn tp_material(entity_gateway: &mut EG, character: &mut CharacterEntity) { + character.materials.tp += 1; + entity_gateway.save_character(character).await; +} diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 09bdd0e..4f28e0e 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -10,6 +10,7 @@ use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::map::{MapArea}; use crate::ship::items::{ItemManager, ClientItemId}; use crate::ship::packet::builder; +use crate::ship::items::use_tool; pub async fn request_exp(id: ClientId, request_exp: &RequestExp, @@ -274,32 +275,25 @@ where ItemDetail::Tool(t) => { match t.tool { ToolType::PowerMaterial => { - client.character.materials.power += 1; - entity_gateway.save_character(&client.character).await; + use_tool::power_material(entity_gateway, &mut client.character).await; }, ToolType::MindMaterial => { - client.character.materials.mind += 1; - entity_gateway.save_character(&client.character).await; + use_tool::mind_material(entity_gateway, &mut client.character).await; }, ToolType::EvadeMaterial => { - client.character.materials.evade += 1; - entity_gateway.save_character(&client.character).await; + use_tool::evade_material(entity_gateway, &mut client.character).await; }, ToolType::DefMaterial => { - client.character.materials.def += 1; - entity_gateway.save_character(&client.character).await; + use_tool::def_material(entity_gateway, &mut client.character).await; }, ToolType::LuckMaterial => { - client.character.materials.luck += 1; - entity_gateway.save_character(&client.character).await; + use_tool::luck_material(entity_gateway, &mut client.character).await; }, ToolType::HpMaterial => { - client.character.materials.hp += 1; - entity_gateway.save_character(&client.character).await; + use_tool::hp_material(entity_gateway, &mut client.character).await; }, ToolType::TpMaterial => { - client.character.materials.tp += 1; - entity_gateway.save_character(&client.character).await; + use_tool::tp_material(entity_gateway, &mut client.character).await; }, _ => {} } From ebdd4b28dea914e447a0e1c061b3648e8b49738e Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 5 Sep 2020 22:06:39 -0600 Subject: [PATCH 13/17] actually this makes more sense --- src/ship/items/manager.rs | 44 +++++++++++++++++++++++++++++- src/ship/items/use_tool.rs | 7 ++++- src/ship/packet/handler/message.rs | 37 +------------------------ 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 276e433..9537bb4 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -5,7 +5,7 @@ use crate::entity::gateway::EntityGateway; use crate::entity::character::{CharacterEntity, CharacterEntityId}; use crate::entity::item::{ItemDetail, ItemLocation, BankName}; use crate::entity::item::{Meseta, NewItemEntity}; -use crate::entity::item::tool::Tool; +use crate::entity::item::tool::{Tool, ToolType}; use crate::ship::map::MapArea; use crate::ship::ship::ItemDropLocation; use crate::ship::drops::{ItemDrop, ItemDropType}; @@ -14,6 +14,7 @@ use crate::ship::location::{AreaClient, RoomId}; use crate::ship::items::bank::*; use crate::ship::items::floor::*; use crate::ship::items::inventory::*; +use crate::ship::items::use_tool; pub enum TriggerCreateItem { @@ -636,4 +637,45 @@ impl ItemManager { Ok(()) } + + + pub async fn use_item(&mut self, + used_item: ItemDetail, + entity_gateway: &mut EG, + character: &mut CharacterEntity) -> Result<(), ItemManagerError> { + match used_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; + }, + _ => {} + } + } + _ => {} + } + Ok(()) + } } diff --git a/src/ship/items/use_tool.rs b/src/ship/items/use_tool.rs index 59e157b..30a016e 100644 --- a/src/ship/items/use_tool.rs +++ b/src/ship/items/use_tool.rs @@ -1,3 +1,4 @@ +use thiserror::Error; use crate::entity::gateway::EntityGateway; use crate::entity::character::CharacterEntity; use crate::entity::item::ItemDetail; @@ -7,7 +8,11 @@ use crate::entity::item::tool::ToolType; - +#[derive(Error, Debug)] +#[error("")] +pub enum UseItemError { + NoCharacter, +} diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs index 4f28e0e..0307993 100644 --- a/src/ship/packet/handler/message.rs +++ b/src/ship/packet/handler/message.rs @@ -10,7 +10,6 @@ use crate::ship::location::{ClientLocation, ClientLocationError}; use crate::ship::map::{MapArea}; use crate::ship::items::{ItemManager, ClientItemId}; use crate::ship::packet::builder; -use crate::ship::items::use_tool; pub async fn request_exp(id: ClientId, request_exp: &RequestExp, @@ -264,43 +263,9 @@ where EG: EntityGateway { let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let item_used_type = item_manager.player_consumes_tool(entity_gateway, &client.character, ClientItemId(player_use_tool.item_id), 1).await?; - match item_used_type { - 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, &mut client.character).await; - }, - ToolType::MindMaterial => { - use_tool::mind_material(entity_gateway, &mut client.character).await; - }, - ToolType::EvadeMaterial => { - use_tool::evade_material(entity_gateway, &mut client.character).await; - }, - ToolType::DefMaterial => { - use_tool::def_material(entity_gateway, &mut client.character).await; - }, - ToolType::LuckMaterial => { - use_tool::luck_material(entity_gateway, &mut client.character).await; - }, - ToolType::HpMaterial => { - use_tool::hp_material(entity_gateway, &mut client.character).await; - }, - ToolType::TpMaterial => { - use_tool::tp_material(entity_gateway, &mut client.character).await; - }, - _ => {} - } - } - _ => {} - } - + item_manager.use_item(item_used_type, entity_gateway, &mut client.character).await?; Ok(Box::new(None.into_iter())) } From d567c502166c5961b2a8a067fdb733182f2a6bba Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 7 Sep 2020 08:02:12 -0600 Subject: [PATCH 14/17] mag cells --- src/entity/gateway/entitygateway.rs | 4 + src/entity/gateway/inmemory.rs | 16 ++++ src/entity/item/mag.rs | 117 ++++++++++++++++++++++++++++ src/ship/items/inventory.rs | 29 +++++++ src/ship/items/manager.rs | 12 ++- src/ship/items/use_tool.rs | 35 ++++++++- 6 files changed, 208 insertions(+), 5 deletions(-) diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index 168c870..9cf4d4d 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -68,6 +68,10 @@ pub trait EntityGateway: Send + Sync + Clone { unimplemented!(); } + async fn use_mag_cell(&mut self, _mag_item_id: &ItemEntityId, _mag_cell_id: &ItemEntityId) { + unimplemented!(); + } + async fn get_items_by_character(&self, _char: &CharacterEntity) -> Vec { unimplemented!(); } diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index f263ece..5620cb6 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -1,4 +1,5 @@ use std::collections::BTreeMap; +use std::convert::TryInto; use crate::entity::account::*; use crate::entity::character::*; @@ -183,6 +184,13 @@ impl EntityGateway for InMemoryGateway { .push(mag::MagModifier::OwnerChange(character.char_class, character.section_id)); } + async fn use_mag_cell(&mut self, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) { + self.mag_modifiers.lock().unwrap() + .entry(*mag_item_id) + .or_insert(Vec::new()) + .push(mag::MagModifier::MagCell(mag_cell_id.clone())); + } + async fn get_items_by_character(&self, character: &CharacterEntity) -> Vec { let items = self.items.lock().unwrap(); items @@ -214,6 +222,14 @@ impl EntityGateway for InMemoryGateway { mag::MagModifier::OwnerChange(class, section_id) => { mag.change_owner(*class, *section_id) }, + mag::MagModifier::MagCell(mag_cell_id) => { + items.get(&mag_cell_id).map(|mag_cell| { + match mag_cell.item { + ItemDetail::Tool(mag_cell) => mag.apply_mag_cell(mag_cell.tool.try_into().unwrap()), + _ => {} + } + }); + }, _ => {} } } diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index 55b2f00..e9870b3 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -390,6 +390,78 @@ impl MagType { } } +pub enum MagCell { + CellOfMag502, + CellOfMag213, + PartsOfRobochao, + HeartOfOpaOpa, + HeartOfPian, + HeartOfChao, + HeartOfAngel, + HeartOfDevil, + KitOfHamburger, + PanthersSpirit, + KitOfMark3, + KitOfMasterSystem, + KitOfGenesis, + KitOfSegaSaturn, + KitOfDreamcast, + Tablet, + DragonScale, + HeavenStrikerCoat, + PioneerParts, + AmitiesMemo, + HeartOfMorolian, + RappysBeak, + YahoosEngine, + DPhotonCore, + LibertaKit, + CellOfMag0503, + CellOfMag0504, + CellOfMag0505, + CellOfMag0506, + CellOfMag0507, +} + +impl std::convert::TryFrom for MagCell { + type Error = (); + + fn try_from(tool: ToolType) -> Result { + match tool { + ToolType::CellOfMag502 => Ok(MagCell::CellOfMag502), + ToolType::CellOfMag213 => Ok(MagCell::CellOfMag213), + ToolType::PartsOfRobochao => Ok(MagCell::PartsOfRobochao), + ToolType::HeartOfOpaOpa => Ok(MagCell::HeartOfOpaOpa), + ToolType::HeartOfPian => Ok(MagCell::HeartOfPian), + ToolType::HeartOfChao => Ok(MagCell::HeartOfChao), + ToolType::HeartOfAngel => Ok(MagCell::HeartOfAngel), + ToolType::HeartOfDevil => Ok(MagCell::HeartOfDevil), + ToolType::KitOfHamburger => Ok(MagCell::KitOfHamburger), + ToolType::PanthersSpirit => Ok(MagCell::PanthersSpirit), + ToolType::KitOfMark3 => Ok(MagCell::KitOfMark3), + ToolType::KitOfMasterSystem => Ok(MagCell::KitOfMasterSystem), + ToolType::KitOfGenesis => Ok(MagCell::KitOfGenesis), + ToolType::KitOfSegaSaturn => Ok(MagCell::KitOfSegaSaturn), + ToolType::KitOfDreamcast => Ok(MagCell::KitOfDreamcast), + ToolType::Tablet => Ok(MagCell::Tablet), + ToolType::DragonScale => Ok(MagCell::DragonScale), + ToolType::HeavenStrikerCoat => Ok(MagCell::HeavenStrikerCoat), + ToolType::PioneerParts => Ok(MagCell::PioneerParts), + ToolType::AmitiesMemo => Ok(MagCell::AmitiesMemo), + ToolType::HeartOfMorolian => Ok(MagCell::HeartOfMorolian), + ToolType::RappysBeak => Ok(MagCell::RappysBeak), + ToolType::YahoosEngine => Ok(MagCell::YahoosEngine), + ToolType::DPhotonCore => Ok(MagCell::DPhotonCore), + ToolType::LibertaKit => Ok(MagCell::LibertaKit), + ToolType::CellOfMag0503 => Ok(MagCell::CellOfMag0503), + ToolType::CellOfMag0504 => Ok(MagCell::CellOfMag0504), + ToolType::CellOfMag0505 => Ok(MagCell::CellOfMag0505), + ToolType::CellOfMag0506 => Ok(MagCell::CellOfMag0506), + ToolType::CellOfMag0507 => Ok(MagCell::CellOfMag0507), + _ => Err(()), + } + } +} enum MagAttribute { //Def, @@ -981,6 +1053,51 @@ impl Mag { pub fn bank(&mut self) { // what is the truncation logic anyway } + + pub fn apply_mag_cell(&mut self, mag_cell: MagCell) { + self.mag = match mag_cell { + MagCell::CellOfMag502 => { + match self.id { + SectionID::Viridia | SectionID::Skyly | SectionID::Purplenum | SectionID::Redria | SectionID::Yellowboze => { + MagType::Soniti + }, + SectionID::Greenill | SectionID::Bluefull | SectionID::Pinkal | SectionID::Oran | SectionID::Whitill => { + MagType::Pitri + } + } + } + //MagCell::CellOfMag213 => , + MagCell::PartsOfRobochao => MagType::Robochao, + //MagCell::HeartOfOpaOpa => , + //MagCell::HeartOfPian => , + //MagCell::HeartOfChao => , + //MagCell::HeartOfAngel => , + //MagCell::HeartOfDevil => , + //MagCell::KitOfHamburger => , + //MagCell::PanthersSpirit => , + //MagCell::KitOfMark3 => , + //MagCell::KitOfMasterSystem => , + //MagCell::KitOfGenesis => , + //MagCell::KitOfSegaSaturn => , + //MagCell::KitOfDreamcast => , + //MagCell::Tablet => , + //MagCell::DragonScale => , + //MagCell::HeavenStrikerCoat => , + //MagCell::PioneerParts => , + //MagCell::AmitiesMemo => , + //MagCell::HeartOfMorolian => , + //MagCell::RappysBeak => , + //MagCell::YahoosEngine => , + //MagCell::DPhotonCore => , + //MagCell::LibertaKit => , + //MagCell::CellOfMag0503 => , + //MagCell::CellOfMag0504 => , + //MagCell::CellOfMag0505 => , + //MagCell::CellOfMag0506 => , + //MagCell::CellOfMag0507 => , + _ => panic!() + } + } } diff --git a/src/ship/items/inventory.rs b/src/ship/items/inventory.rs index 024a2ca..4cbd57d 100644 --- a/src/ship/items/inventory.rs +++ b/src/ship/items/inventory.rs @@ -74,6 +74,17 @@ pub enum InventoryItemAddToError { } impl InventoryItem { + pub fn entity_ids(&self) -> Vec { + match self { + InventoryItem::Individual(individual_inventory_item) => { + vec![individual_inventory_item.entity_id] + }, + InventoryItem::Stacked(stacked_inventory_item) => { + stacked_inventory_item.entity_ids.clone() + } + } + } + pub fn item_id(&self) -> ClientItemId { match self { InventoryItem::Individual(individual_inventory_item) => { @@ -388,6 +399,24 @@ impl CharacterInventory { }) } + pub fn get_equipped_mag_handle<'a>(&'a mut self) -> Option> { + let (slot, _) = self.items.iter() + .enumerate() + .filter(|(_, item)| { + if let InventoryItem::Individual(individual_inventory_item) = item { + if let ItemDetail::Mag(_) = &individual_inventory_item.item { + return individual_inventory_item.equipped + } + } + false + }) + .nth(0)?; + Some(InventoryItemHandle { + inventory: self, + slot: slot, + }) + } + pub fn get_item_by_id(&self, item_id: ClientItemId) -> Option<&InventoryItem> { self.items.iter() .filter(|item| { diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 9537bb4..025e85f 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -513,7 +513,7 @@ impl ItemManager { character: &CharacterEntity, item_id: ClientItemId, amount: usize) - -> Result { + -> 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)?; @@ -523,7 +523,7 @@ impl ItemManager { ItemLocation::Consumed).await; } - Ok(consumed_item.item()) + Ok(consumed_item) } pub async fn player_deposits_item(&mut self, @@ -640,10 +640,11 @@ impl ItemManager { pub async fn use_item(&mut self, - used_item: ItemDetail, + used_item: ConsumedItem, entity_gateway: &mut EG, character: &mut CharacterEntity) -> Result<(), ItemManagerError> { - match used_item { + 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? //_ => {} @@ -671,6 +672,9 @@ impl ItemManager { ToolType::TpMaterial => { use_tool::tp_material(entity_gateway, character).await; }, + ToolType::CellOfMag502 => { + use_tool::cell_of_mag_502(entity_gateway, &used_item, inventory).await; + }, _ => {} } } diff --git a/src/ship/items/use_tool.rs b/src/ship/items/use_tool.rs index 30a016e..b2812af 100644 --- a/src/ship/items/use_tool.rs +++ b/src/ship/items/use_tool.rs @@ -1,8 +1,10 @@ use thiserror::Error; use crate::entity::gateway::EntityGateway; use crate::entity::character::CharacterEntity; -use crate::entity::item::ItemDetail; +use crate::entity::item::{ItemEntityId, ItemDetail}; use crate::entity::item::tool::ToolType; +use crate::entity::item::mag::MagCell; +use crate::ship::items::{ItemManager, ClientItemId, CharacterInventory, ConsumedItem}; @@ -12,6 +14,8 @@ use crate::entity::item::tool::ToolType; #[error("")] pub enum UseItemError { NoCharacter, + ItemNotEquipped, + InvalidItem, } @@ -54,3 +58,32 @@ pub async fn tp_material(entity_gateway: &mut EG, character: character.materials.tp += 1; entity_gateway.save_character(character).await; } + + + + + +async fn mag_cell(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory, mag_cell_type: MagCell) -> Result<(), UseItemError> { + let mut mag_handle = inventory.get_equipped_mag_handle().ok_or(UseItemError::ItemNotEquipped)?; + let mag_item = mag_handle.item_mut() + .ok_or(UseItemError::InvalidItem)?; + let actual_mag = mag_item + .individual() + .ok_or(UseItemError::InvalidItem)? + .mag_mut() + .ok_or(UseItemError::InvalidItem)?; + actual_mag.apply_mag_cell(mag_cell_type); + for mag_entity_id in mag_item.entity_ids() { + for cell_entity_id in used_cell.entity_ids() { + entity_gateway.use_mag_cell(&mag_entity_id, &cell_entity_id).await; + } + } + + Ok(()) +} + + +pub async fn cell_of_mag_502(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + println!("used a 502!"); + mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag502).await +} From acd4e57d1de66e9d61b95faa323326962d8e5b18 Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 7 Sep 2020 21:14:17 -0600 Subject: [PATCH 15/17] implement rest of mag cells --- src/ship/items/manager.rs | 72 +++++++++++++++++++++++++++- src/ship/items/use_tool.rs | 98 +++++++++++++++++++++++++++++++++++--- tests/test_mags.rs | 70 +++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 7 deletions(-) diff --git a/src/ship/items/manager.rs b/src/ship/items/manager.rs index 025e85f..27ab699 100644 --- a/src/ship/items/manager.rs +++ b/src/ship/items/manager.rs @@ -38,6 +38,7 @@ pub enum ItemManagerError { InventoryItemConsumeError(#[from] InventoryItemConsumeError), BankFull, WrongItemType(ClientItemId), + UseItemError(#[from] use_tool::UseItemError), } pub struct ItemManager { @@ -673,7 +674,76 @@ impl ItemManager { use_tool::tp_material(entity_gateway, character).await; }, ToolType::CellOfMag502 => { - use_tool::cell_of_mag_502(entity_gateway, &used_item, inventory).await; + 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?; }, _ => {} } diff --git a/src/ship/items/use_tool.rs b/src/ship/items/use_tool.rs index b2812af..a3afa10 100644 --- a/src/ship/items/use_tool.rs +++ b/src/ship/items/use_tool.rs @@ -59,10 +59,6 @@ pub async fn tp_material(entity_gateway: &mut EG, character: entity_gateway.save_character(character).await; } - - - - async fn mag_cell(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory, mag_cell_type: MagCell) -> Result<(), UseItemError> { let mut mag_handle = inventory.get_equipped_mag_handle().ok_or(UseItemError::ItemNotEquipped)?; let mag_item = mag_handle.item_mut() @@ -82,8 +78,98 @@ async fn mag_cell(entity_gateway: &mut EG, used_cell: &Consum Ok(()) } - pub async fn cell_of_mag_502(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { - println!("used a 502!"); mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag502).await } + +pub async fn cell_of_mag_213(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::CellOfMag213).await +} + +pub async fn parts_of_robochao(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::PartsOfRobochao).await +} + +pub async fn heart_of_opaopa(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfOpaOpa).await +} + +pub async fn heart_of_pian(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfPian).await +} + +pub async fn heart_of_chao(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfChao).await +} + +pub async fn heart_of_angel(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfAngel).await +} + +pub async fn kit_of_hamburger(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfHamburger).await +} + +pub async fn panthers_spirit(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::PanthersSpirit).await +} + +pub async fn kit_of_mark3(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMark3).await +} + +pub async fn kit_of_master_system(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfMasterSystem).await +} + +pub async fn kit_of_genesis(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfGenesis).await +} + +pub async fn kit_of_sega_saturn(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfSegaSaturn).await +} + +pub async fn kit_of_dreamcast(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::KitOfDreamcast).await +} + +pub async fn tablet(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::Tablet).await +} + +pub async fn dragon_scale(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::DragonScale).await +} + +pub async fn heaven_striker_coat(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::HeavenStrikerCoat).await +} + +pub async fn pioneer_parts(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::PioneerParts).await +} + +pub async fn amities_memo(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::AmitiesMemo).await +} + +pub async fn heart_of_morolian(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::HeartOfMorolian).await +} + +pub async fn rappys_beak(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::RappysBeak).await +} + +pub async fn yahoos_engine(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::YahoosEngine).await +} + +pub async fn d_photon_core(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::DPhotonCore).await +} + +pub async fn liberta_kit(entity_gateway: &mut EG, used_cell: &ConsumedItem, inventory: &mut CharacterInventory) -> Result<(), UseItemError> { + mag_cell(entity_gateway, used_cell, inventory, MagCell::LibertaKit).await +} diff --git a/tests/test_mags.rs b/tests/test_mags.rs index 099455a..aa2e299 100644 --- a/tests/test_mags.rs +++ b/tests/test_mags.rs @@ -138,3 +138,73 @@ async fn test_mag_change_owner() { _ => panic!() } } + + +#[async_std::test] +async fn test_mag_cell() { + let mut entity_gateway = InMemoryGateway::new(); + + let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + let mag = entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::Mag( + item::mag::Mag::baby_mag(0) + ), + location: item::ItemLocation::Inventory { + character_id: char1.id, + slot: 0, + equipped: true, + } + }).await.unwrap(); + + for _ in 0..1000 { + let fed_tool = entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::Tool ( + item::tool::Tool { + tool: item::tool::ToolType::Monomate, + } + ), + location: item::ItemLocation::FedToMag { + mag: mag.id, + } + }).await.unwrap(); + entity_gateway.feed_mag(&mag.id, &fed_tool.id).await; + } + entity_gateway.create_item( + item::NewItemEntity { + item: item::ItemDetail::Tool( + item::tool::Tool { + tool: item::tool::ToolType::CellOfMag502, + } + ), + location: item::ItemLocation::Inventory { + character_id: char1.id, + slot: 1, + equipped: false, + } + }).await; + + let mut ship = ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build(); + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + create_room(&mut ship, ClientId(1), "room", "").await; + + ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerUseItem(PlayerUseItem { + client: 0, + target: 0, + item_id: 0x10001, + })))).await.unwrap().for_each(drop); + + let p1_items = entity_gateway.get_items_by_character(&char1).await; + let mag = p1_items.get(0).unwrap(); + match &mag.item { + item::ItemDetail::Mag(mag) => { + assert!(mag.mag == item::mag::MagType::Soniti); + } + _ => panic!() + } +} From 9e275d23a073657bc9b55a9dcab1a95e2a8d5482 Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 7 Sep 2020 21:23:03 -0600 Subject: [PATCH 16/17] not handling mag cell usage in feeding --- src/entity/item/mag.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index e9870b3..2a7b8a0 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -1023,9 +1023,6 @@ impl Mag { } pub fn feed(&mut self, tool: ToolType) { - if tool.is_mag_cell() { - //do_mag_cell_thing() - } let previous_level = self.level(); MAG_STATS.get(&self.mag).map(|stats| { MAG_FEEDING_TABLES.get(stats.feed_table).map(|feeding_table| { @@ -1156,7 +1153,6 @@ mod test { for _ in 0..284 { mag.feed(ToolType::Dimate); } - //println!("mag! {:?}", mag); assert!(mag == Mag { mag: MagType::Sato, def: 507, From 819ec7bf58580d66abe4274a2266c88a4b164937 Mon Sep 17 00:00:00 2001 From: jake Date: Mon, 7 Sep 2020 21:46:40 -0600 Subject: [PATCH 17/17] actually evolve all the magcell mags --- src/entity/item/mag.rs | 77 +++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/src/entity/item/mag.rs b/src/entity/item/mag.rs index 2a7b8a0..80a95b7 100644 --- a/src/entity/item/mag.rs +++ b/src/entity/item/mag.rs @@ -416,11 +416,6 @@ pub enum MagCell { YahoosEngine, DPhotonCore, LibertaKit, - CellOfMag0503, - CellOfMag0504, - CellOfMag0505, - CellOfMag0506, - CellOfMag0507, } impl std::convert::TryFrom for MagCell { @@ -453,11 +448,6 @@ impl std::convert::TryFrom for MagCell { ToolType::YahoosEngine => Ok(MagCell::YahoosEngine), ToolType::DPhotonCore => Ok(MagCell::DPhotonCore), ToolType::LibertaKit => Ok(MagCell::LibertaKit), - ToolType::CellOfMag0503 => Ok(MagCell::CellOfMag0503), - ToolType::CellOfMag0504 => Ok(MagCell::CellOfMag0504), - ToolType::CellOfMag0505 => Ok(MagCell::CellOfMag0505), - ToolType::CellOfMag0506 => Ok(MagCell::CellOfMag0506), - ToolType::CellOfMag0507 => Ok(MagCell::CellOfMag0507), _ => Err(()), } } @@ -1051,6 +1041,7 @@ impl Mag { // what is the truncation logic anyway } + // TODO: this needs more checks on validity pub fn apply_mag_cell(&mut self, mag_cell: MagCell) { self.mag = match mag_cell { MagCell::CellOfMag502 => { @@ -1063,36 +1054,44 @@ impl Mag { } } } - //MagCell::CellOfMag213 => , + MagCell::CellOfMag213 => { + match self.id { + SectionID::Viridia | SectionID::Skyly | SectionID::Purplenum | SectionID::Redria | SectionID::Yellowboze => { + MagType::Churel + }, + SectionID::Greenill | SectionID::Bluefull | SectionID::Pinkal | SectionID::Oran | SectionID::Whitill => { + MagType::Preta + } + } + }, MagCell::PartsOfRobochao => MagType::Robochao, - //MagCell::HeartOfOpaOpa => , - //MagCell::HeartOfPian => , - //MagCell::HeartOfChao => , - //MagCell::HeartOfAngel => , - //MagCell::HeartOfDevil => , - //MagCell::KitOfHamburger => , - //MagCell::PanthersSpirit => , - //MagCell::KitOfMark3 => , - //MagCell::KitOfMasterSystem => , - //MagCell::KitOfGenesis => , - //MagCell::KitOfSegaSaturn => , - //MagCell::KitOfDreamcast => , - //MagCell::Tablet => , - //MagCell::DragonScale => , - //MagCell::HeavenStrikerCoat => , - //MagCell::PioneerParts => , - //MagCell::AmitiesMemo => , - //MagCell::HeartOfMorolian => , - //MagCell::RappysBeak => , - //MagCell::YahoosEngine => , - //MagCell::DPhotonCore => , - //MagCell::LibertaKit => , - //MagCell::CellOfMag0503 => , - //MagCell::CellOfMag0504 => , - //MagCell::CellOfMag0505 => , - //MagCell::CellOfMag0506 => , - //MagCell::CellOfMag0507 => , - _ => panic!() + MagCell::HeartOfOpaOpa => MagType::OpaOpa, + MagCell::HeartOfPian => MagType::Pian, + MagCell::HeartOfChao => MagType::Chao, + MagCell::HeartOfAngel => MagType::AngelsWing, + MagCell::HeartOfDevil => if self.mag == MagType::DevilsWing { + MagType::DevilsTail + } + else { + MagType::DevilsWing + }, + MagCell::KitOfHamburger => MagType::Hamburger, + MagCell::PanthersSpirit => MagType::PanzersTail, + MagCell::KitOfMark3 => MagType::MarkIII, + MagCell::KitOfMasterSystem => MagType::MasterSystem, + MagCell::KitOfGenesis => MagType::Genesis, + MagCell::KitOfSegaSaturn => MagType::SegaSaturn, + MagCell::KitOfDreamcast => MagType::Dreamcast, + MagCell::Tablet => MagType::GeungSi, + MagCell::DragonScale => MagType::Tellusis, + MagCell::HeavenStrikerCoat => MagType::StrikerUnit, + MagCell::PioneerParts => MagType::Pioneer, + MagCell::AmitiesMemo => MagType::Puyo, + MagCell::HeartOfMorolian => MagType::Moro, + MagCell::RappysBeak => MagType::Rappy, + MagCell::YahoosEngine => MagType::Yahoo, + MagCell::DPhotonCore => MagType::GaelGiel, + MagCell::LibertaKit => MagType::Agastya, } } }