From 0f3461b85508ea5207864ccf1c19371bbb3c2a39 Mon Sep 17 00:00:00 2001 From: Jecka Date: Wed, 20 Mar 2024 11:28:47 -0500 Subject: [PATCH] 0.3.96 (#31) * Unfinished skill additions & added methods - Add some functions for summon. - Add a new enum type 'None' for WeaponTypes. * Apply fixes and edits to summon, rearrange and prepare Cargo.toml to 0.3.96 --- Cargo.toml | 6 ++- examples/fetch_summons.rs | 8 +++- examples/guessing_game.rs | 2 +- examples/temp_check_summon.rs | 17 +++++++ src/enums.rs | 5 +++ src/types/mod.rs | 15 +++++++ src/types/students/student.rs | 1 + src/types/summons.rs | 85 +++++++++++++++++++++++++++++++---- 8 files changed, 126 insertions(+), 13 deletions(-) create mode 100644 examples/temp_check_summon.rs diff --git a/Cargo.toml b/Cargo.toml index e4e7094..2532f84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,9 +15,12 @@ tokio = { version = "1", features = [ "parking_lot", "rt-multi-thread", ] } -reqwest = { version = "0.11", features = ["json"] } + +reqwest = { version = "0.12", features = ["json"] } serde = { version = "1", features = ["derive"] } +serde-aux = { version = "4.4.0", default-features = false } + html-escape = "0.2" rand = "0.8" @@ -27,7 +30,6 @@ thiserror = "1.0" strum = "0.26" strum_macros = "0.26" -serde-aux = { version = "4.4.0", default-features = false } # futures = "0.3" # chrono = { version = "0.4", features = ["serde"] } diff --git a/examples/fetch_summons.rs b/examples/fetch_summons.rs index c651eef..b7da2e5 100644 --- a/examples/fetch_summons.rs +++ b/examples/fetch_summons.rs @@ -7,8 +7,12 @@ async fn main() -> anyhow::Result<()> { // Let's iterate over all of them and print out some details... summons.iter().for_each(|summon| { println!( - "{} : {} : ammo cost : {}", - summon.id, summon.name, summon.ammo_cost + "{} : {} : Ammo Cost: {} : Weapon: {}, Armor: {}", + summon.id, + summon.name, + summon.ammo_cost, + summon.weapon_type(), + summon.armor() ) }); Ok(()) diff --git a/examples/guessing_game.rs b/examples/guessing_game.rs index a8abfea..1a7d808 100644 --- a/examples/guessing_game.rs +++ b/examples/guessing_game.rs @@ -1,4 +1,4 @@ -use blue_archive::{types::Student, Language}; +use blue_archive::Language; use rand::Rng; fn read_line_to_buffer(buffer: &mut String) -> Result { diff --git a/examples/temp_check_summon.rs b/examples/temp_check_summon.rs new file mode 100644 index 0000000..ac9f82a --- /dev/null +++ b/examples/temp_check_summon.rs @@ -0,0 +1,17 @@ +use blue_archive::{types::summons::Skill, Language}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + for summon in blue_archive::fetch_all_summons(Language::English).await? { + println!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + println!("Passive Skills for {}", summon.id); + + for skill in summon.skills { + if let Skill::Passive(passive_skill) = skill { + println!("{:#?}", passive_skill.icon()) + } + } + } + + Ok(()) +} diff --git a/src/enums.rs b/src/enums.rs index 3132f62..46a9ff7 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -353,6 +353,8 @@ pub enum Club { * **SG** (Shotgun) * **SMG** (Submachine Gun) * **SR** (Sniper RIfle) + * **Cannon** + * **None** In the case that a weapon type in the data is not present on the wrapper, a [`WeaponType::Unknown(String)`] is returned to represent the unknown weapon type with its name in the `enum`. @@ -383,6 +385,8 @@ pub enum WeaponType { RG, /// **`Cannon`** Cannon, + /// **`None`** + None, /// An **`unknown`** type that contains the inner value. Unknown(String), } @@ -403,6 +407,7 @@ impl WeaponType { Self::SMG => "Submachine Gun", Self::SR => "Sniper Rifle", Self::Cannon => "Cannon", + Self::None => "No Weapon", Self::Unknown(string) => string, } .to_string() diff --git a/src/types/mod.rs b/src/types/mod.rs index 82233fe..26a2c7f 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -282,3 +282,18 @@ pub enum CriticalCheck { #[serde(other)] Unknown, } + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +pub enum RadiusType { + Circle, + Bounce, + Fan, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +#[serde(rename_all = "PascalCase")] +pub struct Radius { + #[serde(alias = "Type")] + kind: RadiusType, + radius: u32, +} diff --git a/src/types/students/student.rs b/src/types/students/student.rs index 83a2c6b..a039f17 100644 --- a/src/types/students/student.rs +++ b/src/types/students/student.rs @@ -274,6 +274,7 @@ pub struct Summon { /// /// There is an issue where Gear in data is represented as `"gear": {}`, therefore this is a mitigation against that. /// If you have a better implementation of handling this, as in allowing for me to represent the data as an `Option`, please send a PR. +/// todo: Could use #[serde(skip_serializing_if = "...")] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] #[serde(untagged)] pub enum GearKind { diff --git a/src/types/summons.rs b/src/types/summons.rs index 7c825d1..b16acc5 100644 --- a/src/types/summons.rs +++ b/src/types/summons.rs @@ -4,9 +4,9 @@ use serde::{Deserialize, Serialize}; use std::str::FromStr; -use crate::{Armor, BulletType}; +use crate::{Armor, BulletType, WeaponType, IMAGE_DATA_URI}; -use super::ID; +use super::{Effect, Radius, ID}; #[derive(Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "PascalCase")] @@ -19,12 +19,12 @@ pub struct Summon { pub kind: String, pub tactic_role: Option, pub star_bonus: Option, - pub bullet_type: String, - pub armor_type: String, + bullet_type: String, + armor_type: String, pub street_battle_adaptation: Option, pub outdoor_battle_adaptation: Option, pub indoor_battle_adaptation: Option, - pub weapon_type: Option, + weapon_type: Option, pub stability_point: u16, pub stability_rate: Option, pub attack_power_1: u16, @@ -41,7 +41,7 @@ pub struct Summon { pub accuracy_point: u16, pub critical_point: u16, pub critical_damage_rate: u32, - pub ammo_count: u8, + pub ammo_count: u32, pub ammo_cost: u8, pub range: u16, pub move_speed: u16, @@ -58,9 +58,78 @@ impl Summon { pub fn armor(&self) -> Armor { Armor::from_str(&self.armor_type).unwrap_or(Armor::Unknown(self.armor_type.clone())) } + + /// Gets the **[`WeaponType`] of the summon. + pub fn weapon_type(&self) -> WeaponType { + match &self.weapon_type { + Some(weapon_type) => WeaponType::from_str(weapon_type) + .unwrap_or(WeaponType::Unknown(weapon_type.clone())), + None => WeaponType::None, + } + } +} + +/// **[`Summon`] specific Skills**. +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "PascalCase", tag = "SkillType")] +pub enum Skill { + #[serde(alias = "autoattack")] + AutoAttack { + effects: Option>, + radius: Option>, + }, + #[serde(alias = "normal")] + Normal(NormalSkill), + #[serde(alias = "passive")] + Passive(PassiveSkill), } -/// **A [`Summon`] specific Skill**. #[derive(Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "PascalCase")] -pub struct Skill {} +pub struct NormalSkill { + pub name: String, + desc: String, + parameters: Vec>, + pub duration: Option, + pub range: Option, + pub radius: Option>, + icon: String, + is_summon_skill: bool, + pub effects: Option>, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct PassiveSkill { + pub name: String, + desc: String, + parameters: Vec>, + pub radius: Option>, + icon: String, + pub is_summon_skill: bool, + pub effects: Option>, +} + +impl NormalSkill { + /** The description of a normal skill. */ + pub fn description(&self) -> String { + html_escape::decode_html_entities(&self.desc).into() + } + + /** Gets the icon of this skill represented in a `URI`. */ + pub fn icon(&self) -> String { + format!("{IMAGE_DATA_URI}/skill/{}.webp", self.icon) + } +} + +impl PassiveSkill { + /** The description of a passive skill. */ + pub fn description(&self) -> String { + html_escape::decode_html_entities(&self.desc).into() + } + + /** Gets the icon of this skill represented in a `URI`. */ + pub fn icon(&self) -> String { + format!("{IMAGE_DATA_URI}/skill/{}.webp", self.icon) + } +}