Skip to main content

wowlab_parsers/parsers/scaling/
stats.rs

1use wowlab_types::data::{ItemQuality, ItemScalingData, RandPropPointsFlat, RandPropPointsUse};
2
3const SLOT_GROUP_1: usize = 1;
4const SLOT_GROUP_2: usize = 2;
5const SLOT_GROUP_3: usize = 3;
6
7/// Map `WoW` `inventory_type` to the `RandPropPoints` stat-budget column index (0-4).
8#[must_use]
9pub const fn inventory_type_to_slot_index(inventory_type: i32) -> usize {
10    match inventory_type {
11        3 | 6 | 8 | 10 | 12 => SLOT_GROUP_1,
12        2 | 9 | 11 | 13 | 14 | 16 | 21 | 22 | 23 => SLOT_GROUP_2,
13        15 | 25 | 26 => SLOT_GROUP_3,
14        _ => 0,
15    }
16}
17
18/// Get the stat budget for an item level and quality (`stat_value = stat_alloc * budget * 0.0001`).
19#[must_use]
20pub fn get_stat_budget(
21    scaling_data: &ItemScalingData,
22    item_level: i32,
23    quality: ItemQuality,
24    slot_index: usize,
25) -> Option<f64> {
26    let rpp = scaling_data.rand_prop_points.get(&item_level)?;
27
28    get_stat_budget_from_rpp(rpp, quality, slot_index)
29}
30
31pub(super) fn get_stat_budget_from_rpp(
32    rpp: &RandPropPointsFlat,
33    quality: ItemQuality,
34    slot_index: usize,
35) -> Option<f64> {
36    let bucket = quality.rand_prop_points_bucket(RandPropPointsUse::StatAllocation)?;
37
38    Some(rpp.budget(bucket, slot_index))
39}
40
41/// Return a human-readable name for a raw stat id.
42#[must_use]
43// #t(fn: rust_cyclomatic_complexity) flat lookup table mapping stat IDs to names
44pub const fn get_stat_name(stat_type: i32) -> &'static str {
45    match stat_type {
46        // tidy-alphabetical-start
47        0 => "Mana",
48        1 => "Health",
49        3 => "Agility",
50        32 => "Critical Strike",
51        35 => "Resilience",
52        36 => "Haste",
53        37 => "Expertise",
54        4 => "Strength",
55        40 => "Versatility",
56        45 => "Spell Power",
57        46 => "Health Regen",
58        47 => "Spell Penetration",
59        48 => "Block",
60        49 => "Mastery",
61        5 => "Intellect",
62        50 => "Attack Power",
63        57 => "PvP Power",
64        59 => "Multistrike",
65        6 => "Spirit",
66        61 => "Versatility (bonus)",
67        62 => "Bonus Armor",
68        63 => "Fire Resistance",
69        64 => "Frost Resistance",
70        65 => "Shadow Resistance",
71        66 => "Nature Resistance",
72        67 => "Arcane Resistance",
73        7 => "Stamina",
74        71 => "Agility or Strength or Intellect",
75        72 => "Agility or Strength",
76        73 => "Agility or Intellect",
77        74 => "Strength or Intellect",
78        91 => "Avoidance",
79        92 => "Sturdiness",
80        93 => "Leech",
81        94 => "Speed",
82        95 => "Indestructible",
83        // tidy-alphabetical-end
84        _ => "Unknown",
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use googletest::prelude::*;
91
92    use super::*;
93
94    #[gtest]
95    fn test_stat_names() -> Result<()> {
96        verify_that!(get_stat_name(3), eq("Agility"))?;
97        verify_that!(get_stat_name(4), eq("Strength"))?;
98        verify_that!(get_stat_name(5), eq("Intellect"))?;
99        verify_that!(get_stat_name(7), eq("Stamina"))?;
100        verify_that!(get_stat_name(32), eq("Critical Strike"))?;
101        verify_that!(get_stat_name(36), eq("Haste"))?;
102        verify_that!(get_stat_name(40), eq("Versatility"))?;
103        verify_that!(get_stat_name(49), eq("Mastery"))?;
104
105        Ok(())
106    }
107
108    #[gtest]
109    fn test_inventory_type_to_slot_index_mapping() -> Result<()> {
110        verify_that!(inventory_type_to_slot_index(1), eq(0))?;
111        verify_that!(inventory_type_to_slot_index(5), eq(0))?;
112        verify_that!(inventory_type_to_slot_index(7), eq(0))?;
113        verify_that!(inventory_type_to_slot_index(17), eq(0))?;
114        verify_that!(inventory_type_to_slot_index(20), eq(0))?;
115
116        verify_that!(inventory_type_to_slot_index(3), eq(1))?;
117        verify_that!(inventory_type_to_slot_index(6), eq(1))?;
118        verify_that!(inventory_type_to_slot_index(8), eq(1))?;
119        verify_that!(inventory_type_to_slot_index(10), eq(1))?;
120        verify_that!(inventory_type_to_slot_index(12), eq(1))?;
121
122        verify_that!(inventory_type_to_slot_index(2), eq(2))?;
123        verify_that!(inventory_type_to_slot_index(9), eq(2))?;
124        verify_that!(inventory_type_to_slot_index(11), eq(2))?;
125        verify_that!(inventory_type_to_slot_index(13), eq(2))?;
126        verify_that!(inventory_type_to_slot_index(14), eq(2))?;
127        verify_that!(inventory_type_to_slot_index(16), eq(2))?;
128        verify_that!(inventory_type_to_slot_index(21), eq(2))?;
129        verify_that!(inventory_type_to_slot_index(22), eq(2))?;
130        verify_that!(inventory_type_to_slot_index(23), eq(2))?;
131
132        verify_that!(inventory_type_to_slot_index(15), eq(3))?;
133        verify_that!(inventory_type_to_slot_index(25), eq(3))?;
134        verify_that!(inventory_type_to_slot_index(26), eq(3))?;
135
136        verify_that!(inventory_type_to_slot_index(0), eq(0))?;
137        verify_that!(inventory_type_to_slot_index(99), eq(0))?;
138
139        Ok(())
140    }
141}