wowlab_engine_domain/dbc/semantics/
ratings.rs1#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5#[non_exhaustive]
6pub enum CombatRating {
7 Crit,
8 Haste,
9 Versatility,
10 Mastery,
11}
12
13bitflags::bitflags! {
14 #[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq)]
17 pub struct CombatRatingMask: i32 {
18 const CRIT = 1 << 10;
19 const HASTE_MELEE = 1 << 14;
20 const VERSATILITY_DAMAGE_DONE = 1 << 16;
21 const VERSATILITY_DAMAGE_TAKEN = 1 << 17;
22 const VERSATILITY_HEALING_DONE = 1 << 18;
23 const VERSATILITY_HEALING_TAKEN = 1 << 19;
24 const MASTERY = 1 << 25;
25 const HASTE_SPELL = 1 << 30;
26
27 const HASTE = Self::HASTE_MELEE.bits()
28 | Self::HASTE_SPELL.bits();
29 const VERSATILITY = Self::VERSATILITY_DAMAGE_DONE.bits()
30 | Self::VERSATILITY_DAMAGE_TAKEN.bits()
31 | Self::VERSATILITY_HEALING_DONE.bits()
32 | Self::VERSATILITY_HEALING_TAKEN.bits();
33 }
34}
35
36impl CombatRatingMask {
37 #[must_use]
38 pub const fn from_dbc(raw: i32) -> Self {
39 Self::from_bits_truncate(raw)
40 }
41
42 #[must_use]
44 pub fn primary_rating(self) -> Option<CombatRating> {
45 [
46 (Self::CRIT, CombatRating::Crit),
47 (Self::HASTE, CombatRating::Haste),
48 (Self::VERSATILITY, CombatRating::Versatility),
49 (Self::MASTERY, CombatRating::Mastery),
50 ]
51 .into_iter()
52 .find_map(|(mask, rating)| self.intersects(mask).then_some(rating))
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use googletest::prelude::*;
59
60 use super::*;
61
62 #[gtest]
63 fn each_bit_resolves_to_its_rating() {
64 expect_that!(
65 CombatRatingMask::from_dbc(1 << 25).primary_rating(),
66 eq(Some(CombatRating::Mastery))
67 );
68 expect_that!(
69 CombatRatingMask::from_dbc(1 << 30).primary_rating(),
70 eq(Some(CombatRating::Haste))
71 );
72 }
73
74 #[gtest]
75 fn crit_wins_when_several_bits_are_set() {
76 let mask = CombatRatingMask::CRIT | CombatRatingMask::HASTE;
77
78 expect_that!(mask.primary_rating(), eq(Some(CombatRating::Crit)));
79 }
80
81 #[gtest]
82 fn unmodelled_bits_resolve_to_none() {
83 expect_that!(
84 CombatRatingMask::from_dbc(1 << 5).primary_rating(),
85 eq(None)
86 );
87 }
88}