Skip to main content

wowlab_engine_gamedata/game_data/
game_tables.rs

1//! [`ResolvedGameTables`]: `WoW` client `GameTable` rows resolved for a sim run.
2
3use wowlab_types::{
4    data::{
5        CombatRatingsFlat, CombatRatingsMultByIlvlFlat, HpPerStaFlat, RandPropPointsFlat,
6        SpellScalingFlat,
7    },
8    sim::IntMap,
9};
10
11/// `WoW` client `GameTable` rows resolved for a sim run, mirroring [`super::ResolvedCurves`].
12#[derive(Clone, Debug, Default)]
13pub struct ResolvedGameTables {
14    combat_ratings: IntMap<i32, CombatRatingsFlat>,
15    hp_per_sta: IntMap<i32, HpPerStaFlat>,
16    spell_scaling: IntMap<i32, SpellScalingFlat>,
17    combat_ratings_mult_by_ilvl: IntMap<i32, CombatRatingsMultByIlvlFlat>,
18    rand_prop_points: IntMap<i32, RandPropPointsFlat>,
19}
20
21impl ResolvedGameTables {
22    /// Creates an empty game-table collection.
23    #[must_use]
24    pub fn new() -> Self {
25        Self::default()
26    }
27
28    /// Clone the `GameTable` maps out of an [`ItemScalingData`](wowlab_types::data::ItemScalingData) scaling bundle.
29    #[must_use]
30    pub fn from_scaling(scaling: &wowlab_types::data::ItemScalingData) -> Self {
31        Self {
32            combat_ratings: scaling.combat_ratings.clone(),
33            hp_per_sta: scaling.hp_per_sta.clone(),
34            spell_scaling: scaling.spell_scaling.clone(),
35            combat_ratings_mult_by_ilvl: scaling.combat_ratings_mult_by_ilvl.clone(),
36            rand_prop_points: scaling.rand_prop_points.clone(),
37        }
38    }
39
40    #[must_use]
41    pub fn is_empty(&self) -> bool {
42        self.combat_ratings.is_empty()
43            && self.hp_per_sta.is_empty()
44            && self.spell_scaling.is_empty()
45            && self.combat_ratings_mult_by_ilvl.is_empty()
46            && self.rand_prop_points.is_empty()
47    }
48
49    /// Raw `RandPropPoints` row for item-effect scaling at `item_level`.
50    #[must_use]
51    pub fn rand_prop_points_row(&self, item_level: i32) -> Option<&RandPropPointsFlat> {
52        self.rand_prop_points.get(&item_level)
53    }
54
55    /// Raw combat-rating row for `level`; `None` when the level row is absent.
56    #[must_use]
57    pub fn combat_ratings_row(&self, level: u32) -> Option<&CombatRatingsFlat> {
58        self.combat_ratings.get(&i32::try_from(level).ok()?)
59    }
60
61    /// Health granted per point of Stamina at `level`; `None` when the level row is absent.
62    #[must_use]
63    pub fn health_per_stamina(&self, level: u32) -> Option<f64> {
64        self.hp_per_sta
65            .get(&i32::try_from(level).ok()?)
66            .map(|r| r.health)
67    }
68
69    /// The raw `SpellScaling` `GameTable` row for `level`; `None` when the level row is absent.
70    #[must_use]
71    pub fn spell_scaling_row(&self, level: u32) -> Option<&SpellScalingFlat> {
72        self.spell_scaling.get(&i32::try_from(level).ok()?)
73    }
74
75    /// Raw combat-rating multiplier row for `item_level`.
76    #[must_use]
77    pub fn combat_ratings_multiplier_row(
78        &self,
79        item_level: i32,
80    ) -> Option<&CombatRatingsMultByIlvlFlat> {
81        self.combat_ratings_mult_by_ilvl.get(&item_level)
82    }
83}
84
85/// `CombatRatingsMultByIlvl` column selector.
86#[derive(Clone, Copy, Debug, Eq, PartialEq)]
87#[non_exhaustive]
88pub enum RatingMultiplierSlot {
89    Armor,
90    Weapon,
91    Trinket,
92    Jewelry,
93}