Skip to main content

wowlab_parsers/parsers/transform/loot/
item_bonus.rs

1use wowlab_types::data::{
2    ChallengeModeItemBonusOverride, DelvesSeason, Difficulty, ItemBonusListGroup,
3    ItemBonusSequenceSpell, ItemConversionFlat, ItemGroupIlvlScalingEntry, ItemLevelSelector,
4    ItemLevelSelectorQuality, ItemLevelSelectorQualitySet,
5};
6
7use super::shared::difficulty_kind;
8use crate::parsers::dbc::DbcData;
9
10/// 1:1 transform of `ItemBonusListGroup` rows.
11#[must_use]
12pub fn transform_all_item_bonus_list_groups(dbc: &DbcData) -> Vec<ItemBonusListGroup> {
13    dbc.item_bonus_list_group
14        .values()
15        .map(|row| ItemBonusListGroup {
16            id: row.ID,
17            sequence_spell_id: row.SequenceSpellID,
18            player_condition_id: row.PlayerConditionID,
19            item_extended_cost_id: row.ItemExtendedCostID,
20            item_logical_cost_group_id: row.ItemLogicalCostGroupID,
21            item_group_ilvl_scaling_id: row.ItemGroupIlvlScalingID,
22        })
23        .collect()
24}
25
26/// 1:1 transform of `ItemGroupIlvlScalingEntry` rows.
27#[must_use]
28pub fn transform_all_item_group_ilvl_scaling_entries(
29    dbc: &DbcData,
30) -> Vec<ItemGroupIlvlScalingEntry> {
31    dbc.item_group_ilvl_scaling_entry
32        .values()
33        .flatten()
34        .map(|row| ItemGroupIlvlScalingEntry {
35            id: row.ID,
36            currency_type_id: row.CurrencyTypeID,
37            item_id: row.ItemID,
38            cost_scaling: row.CostScaling,
39            flags: row.Flags,
40            player_condition_id: row.PlayerConditionID,
41            conditional_cost_scaling: row.ConditionalCostScaling,
42            item_group_ilvl_scaling_id: row.ItemGroupIlvlScalingID,
43        })
44        .collect()
45}
46
47/// 1:1 transform of `ItemLevelSelector` rows.
48#[must_use]
49pub fn transform_all_item_level_selectors(dbc: &DbcData) -> Vec<ItemLevelSelector> {
50    dbc.item_level_selector
51        .values()
52        .map(|row| ItemLevelSelector {
53            id: row.ID,
54            min_item_level: row.MinItemLevel,
55            item_level_selector_quality_set_id: row.ItemLevelSelectorQualitySetID,
56            azerite_unlock_mapping_set_id: row.AzeriteUnlockMappingSetID,
57        })
58        .collect()
59}
60
61/// 1:1 transform of `ItemLevelSelectorQualitySet` rows.
62#[must_use]
63pub fn transform_all_item_level_selector_quality_sets(
64    dbc: &DbcData,
65) -> Vec<ItemLevelSelectorQualitySet> {
66    dbc.item_level_selector_quality_set
67        .values()
68        .map(|row| ItemLevelSelectorQualitySet {
69            id: row.ID,
70            ilvl_rare: row.IlvlRare,
71            ilvl_epic: row.IlvlEpic,
72        })
73        .collect()
74}
75
76/// 1:1 transform of `ItemLevelSelectorQuality` rows.
77#[must_use]
78pub fn transform_all_item_level_selector_qualities(dbc: &DbcData) -> Vec<ItemLevelSelectorQuality> {
79    dbc.item_level_selector_quality
80        .values()
81        .map(|row| ItemLevelSelectorQuality {
82            id: row.ID,
83            quality_item_bonus_list_id: row.QualityItemBonusListID,
84            quality: row.Quality,
85            parent_ils_quality_set_id: row.ParentILSQualitySetID,
86        })
87        .collect()
88}
89
90/// Walk every `ItemConversion` row, attach embedded child item IDs from `ItemConversionEntry`, and skip parents with no entries.
91#[must_use]
92pub fn transform_all_item_conversions(dbc: &DbcData) -> Vec<ItemConversionFlat> {
93    dbc.item_conversion
94        .values()
95        .filter_map(|row| {
96            let entries = dbc.item_conversion_entry.get(&row.ID)?;
97
98            if entries.is_empty() {
99                return None;
100            }
101
102            let items: Vec<i32> = entries.iter().map(|e| e.ItemID).collect();
103
104            Some(ItemConversionFlat {
105                id: row.ID,
106                item_bonus_tree_id: row.ItemBonusTreeID,
107                item_logical_cost_group_id: row.ItemLogicalCostGroupID,
108                alternate_item_logical_cost_group_id: row.AlternateItemLogicalCostGroupID,
109                player_condition_id: row.PlayerConditionID,
110                items,
111            })
112        })
113        .collect()
114}
115
116/// 1:1 transform of `ChallengeModeItemBonusOverride` rows.
117#[must_use]
118pub fn transform_all_challenge_mode_item_bonus_overrides(
119    dbc: &DbcData,
120) -> Vec<ChallengeModeItemBonusOverride> {
121    dbc.challenge_mode_item_bonus_override
122        .values()
123        .map(|row| ChallengeModeItemBonusOverride {
124            id: row.ID,
125            item_bonus_tree_group_id: row.ItemBonusTreeGroupID,
126            dst_item_bonus_tree_id: row.DstItemBonusTreeID,
127            value: row.Value,
128            required_time_event_passed: row.RequiredTimeEventPassed,
129            required_time_event_not_passed: row.RequiredTimeEventNotPassed,
130            src_item_bonus_tree_id: row.SrcItemBonusTreeID,
131        })
132        .collect()
133}
134
135/// 1:1 transform of `ItemBonusSequenceSpell` rows.
136#[must_use]
137pub fn transform_all_item_bonus_sequence_spells(dbc: &DbcData) -> Vec<ItemBonusSequenceSpell> {
138    dbc.item_bonus_sequence_spell
139        .values()
140        .map(|row| ItemBonusSequenceSpell {
141            id: row.ID,
142            spell_id: row.SpellID,
143            item_id: row.ItemID,
144        })
145        .collect()
146}
147
148/// 1:1 transform of `DelvesSeason` rows.
149#[must_use]
150pub fn transform_all_delves_seasons(dbc: &DbcData) -> Vec<DelvesSeason> {
151    dbc.delves_season
152        .values()
153        .map(|row| DelvesSeason {
154            id: row.ID,
155            faction_id: row.FactionID,
156        })
157        .collect()
158}
159
160/// 1:1 transform of `Difficulty` rows + derived `kind`.
161#[must_use]
162pub fn transform_all_difficulties(dbc: &DbcData) -> Vec<Difficulty> {
163    dbc.difficulty
164        .values()
165        .map(|row| Difficulty {
166            id: row.ID,
167            name: row.Name_lang.clone().unwrap_or_default(),
168            instance_type: row.InstanceType,
169            order_index: row.OrderIndex,
170            min_players: row.MinPlayers,
171            max_players: row.MaxPlayers,
172            flags: row.Flags,
173            item_context: row.ItemContext,
174            kind: difficulty_kind(row.InstanceType),
175        })
176        .collect()
177}
178
179#[cfg(test)]
180mod tests {
181    use googletest::prelude::*;
182    use wowlab_types::data::DifficultyKind;
183
184    use super::*;
185    use crate::parsers::transform::fixtures::{
186        dbc, difficulty_row, item_conversion_entry_row, item_conversion_row,
187    };
188
189    #[gtest]
190    fn transform_all_item_conversions_attaches_and_drops() -> Result<()> {
191        let mut dbc = dbc();
192
193        dbc.item_conversion.insert(1, item_conversion_row(1));
194        dbc.item_conversion.insert(2, item_conversion_row(2));
195        dbc.item_conversion_entry.insert(
196            1,
197            vec![
198                item_conversion_entry_row(10, 1, 100),
199                item_conversion_entry_row(11, 1, 200),
200            ],
201        );
202
203        let out = transform_all_item_conversions(&dbc);
204
205        verify_that!(out.len(), eq(1))?;
206
207        verify_that!(
208            &out,
209            contains(matches_pattern!(ItemConversionFlat {
210                id: eq(&1),
211                items: eq(&vec![100, 200]),
212                ..
213            }))
214        )
215    }
216
217    #[gtest]
218    fn transform_all_difficulties_derives_kind_and_name() -> Result<()> {
219        let mut dbc = dbc();
220
221        dbc.difficulty.insert(2, difficulty_row(2, 2, None));
222
223        let out = transform_all_difficulties(&dbc);
224
225        verify_that!(
226            &out,
227            contains(matches_pattern!(Difficulty {
228                id: eq(&2),
229                kind: eq(&DifficultyKind::Raid),
230                name: eq(""),
231                ..
232            }))
233        )
234    }
235}