Skip to content

Commit

Permalink
feat: damage types (#20)
Browse files Browse the repository at this point in the history
fix: weapon types not working on melees by adding 2 variants
  • Loading branch information
Mettwasser authored Oct 28, 2024
1 parent 12cda09 commit ea8ddb1
Show file tree
Hide file tree
Showing 7 changed files with 440 additions and 36 deletions.
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,10 @@ log = "0.4.22"
env_logger = "0.11.5"
thiserror = "1.0.63"
moka = { version = "0.12.8", optional = true, features = ["future"] }
strum = { version = "0.26.3", features = ["derive"] }
urlencoding = "2.1.3"
derive_more = { version = "1.0.0", features = ["full"] }
serde_with = "3.11.0"

# TODO: use this lint in V7
# [lints.clippy]
# pedantic = "warn"
118 changes: 118 additions & 0 deletions src/worldstate/models/damage_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use serde::Deserialize;
use serde_with::rust::deserialize_ignore_any;

macro_rules! unordered_pattern {
($a:pat, $b:pat) => {
($a, $b) | ($b, $a)
};
}

#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, derive_more::From, Hash)]
#[serde(untagged)]
pub enum DamageType {
// Physical Damage
Physical(PhysicalDamage),
// Primary Elemental Damage
Elemental(ElementalDamage),
// Secondary Elemental Damage
Combined(CombinedElementalDamage),

#[serde(deserialize_with = "deserialize_ignore_any")]
Other,
}

#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, derive_more::Display, Hash)]
#[serde(rename_all = "lowercase")]
pub enum PhysicalDamage {
Impact,
Puncture,
Slash,
}

#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, derive_more::Display, Hash)]
#[serde(rename_all = "lowercase")]
pub enum ElementalDamage {
Heat,
Cold,
Electricity,
Toxin,
Void,
Tau,
}

impl ElementalDamage {
/// Combines two Primary Elements into their Combined Element.
///
/// Returns [None] if both `a` and `b` are equal.
pub const fn combine(a: Self, b: Self) -> Option<CombinedElementalDamage> {
use CombinedElementalDamage::*;
use ElementalDamage::*;

let combined_element = match (a, b) {
unordered_pattern!(Heat, Cold) => Blast,
unordered_pattern!(Heat, Electricity) => Radiation,
unordered_pattern!(Heat, Toxin) => Gas,
unordered_pattern!(Toxin, Cold) => Viral,
unordered_pattern!(Toxin, Electricity) => Corrosive,
unordered_pattern!(Cold, Electricity) => Magnetic,
_ => return None,
};

Some(combined_element)
}
}

#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, derive_more::Display, Hash)]
#[serde(rename_all = "lowercase")]
pub enum CombinedElementalDamage {
Radiation,
Blast,
Viral,
Corrosive,
Gas,
Magnetic,
}

impl CombinedElementalDamage {
/// Breaks down a combined element into both of its [PrimaryElement]s.
///
/// The order in which they are returned follows classic HCET.
pub const fn break_down(self) -> (ElementalDamage, ElementalDamage) {
use CombinedElementalDamage::*;
use ElementalDamage::*;

match self {
Radiation => (Heat, Electricity),
Blast => (Heat, Cold),
Viral => (Cold, Toxin),
Corrosive => (Electricity, Toxin),
Gas => (Heat, Toxin),
Magnetic => (Cold, Electricity),
}
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_combine() {
let cold = ElementalDamage::Cold;
let electricity = ElementalDamage::Electricity;

let combined: Option<CombinedElementalDamage> = ElementalDamage::combine(cold, electricity);

assert_eq!(combined.unwrap(), CombinedElementalDamage::Magnetic);
}

#[test]
fn test_break_down() {
let corrosive = CombinedElementalDamage::Corrosive;

assert_eq!(
corrosive.break_down(),
(ElementalDamage::Electricity, ElementalDamage::Toxin)
);
}
}
107 changes: 89 additions & 18 deletions src/worldstate/models/faction.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,98 @@
use super::macros::enum_builder;
enum_builder! {
:"A Faction in Warframe"
Faction;
:"Orokin"
use super::damage_type::{
CombinedElementalDamage,
DamageType,
ElementalDamage,
PhysicalDamage,
};

#[derive(Debug, serde::Deserialize, PartialEq, PartialOrd, Clone, Eq, Copy)]
/// A Faction in Warframe
pub enum Faction {
/// Orokin
Orokin,
:"Corrupted"
/// Corrupted
Corrupted,
:"Infested"
/// Infested
#[serde(alias = "Infestation")]
Infested,
:"Infestation"
Infestation,
:"Corpus"
/// Corpus
Corpus,
:"Grineer"
/// Grineer
Grineer,
:"Tenno"
/// Tenno
Tenno,
:"Narmer"
/// Narmer
Narmer,
:"Crossfire"
/// Crossfire, which is Faction-less
Crossfire,
:"Murmur"
Murmur = "The Murmur",
:"ManInTheWall"
ManInTheWall = "Man in the Wall"
/// Murmur
#[serde(rename(deserialize = "The Murmur"))]
Murmur,
/// This is a placeholder faction. For example, it was used during the Jade event
#[serde(rename(deserialize = "Man in the Wall"))]
ManInTheWall,
}

impl crate::ws::VariantDocumentation for Faction {
fn docs(&self) -> &'static str {
match self {
Faction::Orokin => "Orokin",
Faction::Corrupted => "Corrupted",
Faction::Infested => "Infested",
Faction::Corpus => "Corpus",
Faction::Grineer => "Grineer",
Faction::Tenno => "Tenno",
Faction::Narmer => "Narmer",
Faction::Crossfire => "Crossfire, which is Faction-less",
Faction::ManInTheWall => {
"This is a placeholder faction. For example, it was used during"
}
Faction::Murmur => "Murmur",
}
}
}
impl crate::ws::TypeDocumentation for Faction {
fn docs() -> &'static str {
"A Faction in Warframe"
}
}

impl Faction {
pub fn vulnerable_to(self) -> Vec<super::DamageType> {
use CombinedElementalDamage::*;
use DamageType::*;
use ElementalDamage::*;
use Faction::*;
use PhysicalDamage::*;

match self {
Orokin | Corrupted => vec![Physical(Puncture), Combined(Viral)],
Infested => vec![Physical(Slash), Elemental(Heat)],
Corpus => vec![Physical(Puncture), Combined(Magnetic)],
Grineer => vec![Physical(Impact), Combined(Corrosive)],
Narmer => vec![Physical(Slash), Elemental(Toxin)],
Murmur => vec![Elemental(Electricity), Combined(Radiation)],
Tenno => vec![],
Crossfire => vec![],
ManInTheWall => vec![],
}
}

pub fn resistant_to(self) -> Option<DamageType> {
use CombinedElementalDamage::*;
use DamageType::*;
use Faction::*;

match self {
Orokin | Corrupted => Some(Combined(Radiation)),
Narmer => Some(Combined(Magnetic)),
Murmur => Some(Combined(Viral)),
Grineer => None,
Corpus => None,
Infested => None,
Tenno => None,
Crossfire => None,
ManInTheWall => None,
}
}
}
2 changes: 1 addition & 1 deletion src/worldstate/models/items/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub mod warframe;
pub mod weapon;

/// Represents a polarity
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, strum::Display)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, derive_more::Display)]
#[serde(rename_all = "lowercase")]
pub enum Polarity {
/// V (Damage, Powers) - Commonly dropped by Grineer
Expand Down
Loading

0 comments on commit ea8ddb1

Please sign in to comment.