Skip to main content

wowlab_types/types/combat/
damage.rs

1#[derive(
2    Clone,
3    Copy,
4    Debug,
5    Default,
6    Eq,
7    Hash,
8    PartialEq,
9    num_enum::IntoPrimitive,
10    num_enum::TryFromPrimitive,
11    serde::Deserialize,
12    serde::Serialize,
13    strum::Display,
14    strum::EnumCount,
15    strum::EnumIter,
16    strum::EnumString,
17)]
18#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
19#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
20#[repr(u8)]
21// #t(rust_non_exhaustive_on_public) WoW damage schools are game-defined
22pub enum DamageSchool {
23    #[default]
24    Physical = 0,
25    Holy = 1,
26    Fire = 2,
27    Nature = 3,
28    Frost = 4,
29    Shadow = 5,
30    Arcane = 6,
31    Chaos = 7,
32}
33
34impl DamageSchool {
35    pub const COUNT: usize = <Self as strum::EnumCount>::COUNT;
36
37    #[must_use]
38    pub const fn is_physical(self) -> bool {
39        matches!(self, Self::Physical)
40    }
41
42    #[must_use]
43    pub const fn is_magic(self) -> bool {
44        !self.is_physical()
45    }
46}
47
48#[derive(
49    Clone,
50    Copy,
51    Debug,
52    Default,
53    Eq,
54    Hash,
55    PartialEq,
56    num_enum::IntoPrimitive,
57    num_enum::TryFromPrimitive,
58    serde::Deserialize,
59    serde::Serialize,
60    strum::Display,
61    strum::EnumCount,
62    strum::EnumIter,
63    strum::EnumString,
64)]
65#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
66#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
67#[repr(u8)]
68// #t(rust_non_exhaustive_on_public) WoW hit outcomes are game-defined
69pub enum HitResult {
70    #[default]
71    Hit = 0,
72    Crit = 1,
73    Miss = 2,
74    Dodge = 3,
75    Parry = 4,
76    Glance = 5,
77    Block = 6,
78    CritBlock = 7,
79}
80
81impl HitResult {
82    #[must_use]
83    pub const fn is_hit(self) -> bool {
84        matches!(
85            self,
86            Self::Hit | Self::Crit | Self::Glance | Self::Block | Self::CritBlock
87        )
88    }
89
90    #[must_use]
91    pub const fn is_crit(self) -> bool {
92        matches!(self, Self::Crit)
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use googletest::prelude::*;
99    use rstest::rstest;
100
101    use super::*;
102
103    #[gtest]
104    #[rstest]
105    #[case::physical(DamageSchool::Physical, true, false)]
106    #[case::fire(DamageSchool::Fire, false, true)]
107    #[case::holy(DamageSchool::Holy, false, true)]
108    #[case::shadow(DamageSchool::Shadow, false, true)]
109    #[case::chaos(DamageSchool::Chaos, false, true)]
110    fn damage_school_physical_magic(
111        #[case] school: DamageSchool,
112        #[case] is_physical: bool,
113        #[case] is_magic: bool,
114    ) -> Result<()> {
115        verify_that!(school.is_physical(), eq(is_physical))?;
116
117        verify_that!(school.is_magic(), eq(is_magic))
118    }
119
120    #[gtest]
121    #[rstest]
122    #[case::physical(0, DamageSchool::Physical)]
123    #[case::chaos(7, DamageSchool::Chaos)]
124    fn damage_school_try_from_ok(#[case] raw: u8, #[case] expected: DamageSchool) -> Result<()> {
125        verify_that!(DamageSchool::try_from(raw).ok(), some(eq(expected)))
126    }
127
128    #[gtest]
129    fn damage_school_try_from_out_of_range() -> Result<()> {
130        verify_that!(DamageSchool::try_from(8u8).ok(), none())
131    }
132
133    #[gtest]
134    #[rstest]
135    #[case::hit(HitResult::Hit, true, false)]
136    #[case::crit(HitResult::Crit, true, true)]
137    #[case::miss(HitResult::Miss, false, false)]
138    #[case::dodge(HitResult::Dodge, false, false)]
139    #[case::parry(HitResult::Parry, false, false)]
140    #[case::glance(HitResult::Glance, true, false)]
141    #[case::block(HitResult::Block, true, false)]
142    #[case::critical_block(HitResult::CritBlock, true, false)]
143    fn hit_result_predicates(
144        #[case] result: HitResult,
145        #[case] is_hit: bool,
146        #[case] is_crit: bool,
147    ) -> Result<()> {
148        verify_that!(result.is_hit(), eq(is_hit))?;
149
150        verify_that!(result.is_crit(), eq(is_crit))
151    }
152}