1use wowlab_types::data::{
2 ContentTuningFlat, ContentTuningXDifficultyFlat, ContentTuningXExpectedFlat,
3 CreatureDifficultyFlat, CreatureFlat,
4};
5
6use crate::parsers::dbc::DbcData;
7
8#[must_use]
10pub fn transform_all_creatures(dbc: &DbcData) -> Vec<CreatureFlat> {
11 dbc.creature
12 .values()
13 .map(|row| CreatureFlat {
14 id: row.ID,
15 name: row.Name_lang.clone().unwrap_or_default(),
16 classification: row.Classification,
17 creature_type: row.CreatureType,
18 creature_family: row.CreatureFamily,
19 })
20 .collect()
21}
22
23#[must_use]
25pub fn transform_all_creature_difficulties(dbc: &DbcData) -> Vec<CreatureDifficultyFlat> {
26 dbc.creature_difficulty
27 .values()
28 .flatten()
29 .map(|row| CreatureDifficultyFlat {
30 id: row.ID,
31 creature_id: row.CreatureID,
32 content_tuning_id: row.ContentTuningID,
33 faction_template_id: row.FactionTemplateID,
34 field_9_0_1_35522_003_min: row.Field_9_0_1_35522_003Min,
35 field_9_0_1_35522_003_max: row.Field_9_0_1_35522_003Max,
36 flags_0: row.Flags_0,
37 flags_1: row.Flags_1,
38 flags_2: row.Flags_2,
39 flags_3: row.Flags_3,
40 flags_4: row.Flags_4,
41 flags_5: row.Flags_5,
42 flags_6: row.Flags_6,
43 flags_7: row.Flags_7,
44 flags_8: row.Flags_8,
45 })
46 .collect()
47}
48
49#[must_use]
51pub fn transform_all_content_tunings(dbc: &DbcData) -> Vec<ContentTuningFlat> {
52 dbc.content_tuning
53 .values()
54 .map(|row| ContentTuningFlat {
55 id: row.ID,
56 flags: row.Flags,
57 expansion_id: row.ExpansionID,
58 hp_scaling_curve_id: row.HPScalingCurveID,
59 dmg_scaling_curve_id: row.DMGScalingCurveID,
60 hp_primary_stat_scaling_curve_id: row.HPPrimaryStatScalingCurveID,
61 dmg_primary_stat_scaling_curve_id: row.DMGPrimaryStatScalingCurveID,
62 primary_stat_scaling_mod_player_data_element_character_id: row
63 .PrimaryStatScalingModPlayerDataElementCharacterID,
64 primary_stat_scaling_mod_player_data_element_character_multiplier: row
65 .PrimaryStatScalingModPlayerDataElementCharacterMultiplier,
66 min_level_squish: row.MinLevelSquish,
67 max_level_squish: row.MaxLevelSquish,
68 min_level_scaling_offset: row.MinLevelScalingOffset,
69 max_level_scaling_offset: row.MaxLevelScalingOffset,
70 allowed_min_offset: row.AllowedMinOffset,
71 allowed_max_offset: row.AllowedMaxOffset,
72 lfg_min_level: row.LfgMinLevel,
73 lfg_max_level: row.LfgMaxLevel,
74 ilevel: row.ILevel,
75 xp_mult_quest: row.XpMultQuest,
76 })
77 .collect()
78}
79
80#[must_use]
82pub fn transform_all_content_tuning_x_difficulty(
83 dbc: &DbcData,
84) -> Vec<ContentTuningXDifficultyFlat> {
85 dbc.content_tuning_x_difficulty
86 .values()
87 .flatten()
88 .map(|row| ContentTuningXDifficultyFlat {
89 id: row.ID,
90 content_tuning_id: row.ContentTuningID,
91 difficulty_id: row.DifficultyID,
92 })
93 .collect()
94}
95
96#[must_use]
98pub fn transform_all_content_tuning_x_expected(dbc: &DbcData) -> Vec<ContentTuningXExpectedFlat> {
99 dbc.content_tuning_x_expected
100 .values()
101 .flatten()
102 .map(|row| ContentTuningXExpectedFlat {
103 id: row.ID,
104 content_tuning_id: row.ContentTuningID,
105 expected_stat_mod_id: row.ExpectedStatModID,
106 min_mythic_plus_season_id: row.MinMythicPlusSeasonID,
107 max_mythic_plus_season_id: row.MaxMythicPlusSeasonID,
108 })
109 .collect()
110}
111
112#[cfg(test)]
113mod creature_tests {
114 use googletest::prelude::*;
115
116 use super::*;
117 use crate::parsers::{
118 dbc::rows::{CreatureDifficultyRow, CreatureRow},
119 transform::fixtures::dbc,
120 };
121
122 const fn creature_difficulty_row(
123 id: i32,
124 creature_id: i32,
125 content_tuning_id: i32,
126 ) -> CreatureDifficultyRow {
127 CreatureDifficultyRow {
128 ID: id,
129 Field_9_0_1_35522_003Min: 0,
130 Field_9_0_1_35522_003Max: 0,
131 FactionTemplateID: 16,
132 ContentTuningID: content_tuning_id,
133 Flags_0: 268_959_756,
134 Flags_1: 0,
135 Flags_2: 0,
136 Flags_3: 0,
137 Flags_4: 16_777_216,
138 Flags_5: 0,
139 Flags_6: 0,
140 Flags_7: 0,
141 Flags_8: 0,
142 CreatureID: creature_id,
143 }
144 }
145
146 #[gtest]
147 fn creatures_map_identity_and_classification() -> Result<()> {
148 let mut dbc = dbc();
149
150 dbc.creature.insert(
151 220_586,
152 CreatureRow {
153 ID: 220_586,
154 Name_lang: Some("Queen Ansurek".to_string()),
155 Classification: 1,
156 CreatureType: 7,
157 CreatureFamily: 0,
158 },
159 );
160 dbc.creature.insert(
161 3,
162 CreatureRow {
163 ID: 3,
164 Name_lang: None,
165 Classification: 0,
166 CreatureType: 6,
167 CreatureFamily: 0,
168 },
169 );
170
171 let result = transform_all_creatures(&dbc);
172
173 verify_that!(result, len(eq(2)))?;
174 verify_that!(
175 result,
176 contains(matches_pattern!(CreatureFlat {
177 id: eq(&220_586),
178 name: eq("Queen Ansurek"),
179 classification: eq(&1),
180 creature_type: eq(&7),
181 creature_family: eq(&0),
182 }))
183 )?;
184
185 verify_that!(
186 result,
187 contains(matches_pattern!(CreatureFlat {
188 id: eq(&3),
189 name: eq(""),
190 ..
191 }))
192 )
193 }
194
195 #[gtest]
196 fn creature_difficulties_flatten_grouped_rows() -> Result<()> {
197 let mut dbc = dbc();
198
199 dbc.creature_difficulty.insert(
200 220_586,
201 vec![creature_difficulty_row(270_199, 220_586, 719)],
202 );
203 dbc.creature_difficulty.insert(
204 3,
205 vec![
206 creature_difficulty_row(2, 3, 13),
207 creature_difficulty_row(4, 3, 14),
208 ],
209 );
210
211 let result = transform_all_creature_difficulties(&dbc);
212
213 verify_that!(result, len(eq(3)))?;
214
215 verify_that!(
216 result,
217 contains(matches_pattern!(CreatureDifficultyFlat {
218 id: eq(&270_199),
219 creature_id: eq(&220_586),
220 content_tuning_id: eq(&719),
221 faction_template_id: eq(&16),
222 flags_0: eq(&268_959_756),
223 flags_4: eq(&16_777_216),
224 ..
225 }))
226 )
227 }
228}
229
230#[cfg(test)]
231mod content_tuning_tests {
232 use googletest::prelude::*;
233
234 use super::*;
235 use crate::parsers::{
236 dbc::rows::{ContentTuningRow, ContentTuningXDifficultyRow, ContentTuningXExpectedRow},
237 transform::fixtures::dbc,
238 };
239
240 #[gtest]
241 fn content_tunings_map_all_scaling_fields() -> Result<()> {
242 let mut dbc = dbc();
243
244 dbc.content_tuning.insert(
245 719,
246 ContentTuningRow {
247 ID: 719,
248 Flags: 32,
249 ExpansionID: 7,
250 HPScalingCurveID: 0,
251 DMGScalingCurveID: 0,
252 HPPrimaryStatScalingCurveID: 0,
253 DMGPrimaryStatScalingCurveID: 0,
254 PrimaryStatScalingModPlayerDataElementCharacterID: 0,
255 PrimaryStatScalingModPlayerDataElementCharacterMultiplier: 0.0,
256 MinLevelSquish: 50,
257 MaxLevelSquish: 50,
258 MinLevelScalingOffset: 0,
259 MaxLevelScalingOffset: 0,
260 AllowedMinOffset: 0,
261 AllowedMaxOffset: 0,
262 LfgMinLevel: 0,
263 LfgMaxLevel: 0,
264 ILevel: 0,
265 XpMultQuest: 1.0,
266 },
267 );
268
269 let result = transform_all_content_tunings(&dbc);
270
271 verify_that!(
272 result,
273 elements_are![matches_pattern!(ContentTuningFlat {
274 id: eq(&719),
275 flags: eq(&32),
276 expansion_id: eq(&7),
277 hp_scaling_curve_id: eq(&0),
278 dmg_scaling_curve_id: eq(&0),
279 min_level_squish: eq(&50),
280 max_level_squish: eq(&50),
281 ..
282 })]
283 )?;
284
285 verify_that!(f64::from(result[0].xp_mult_quest), near(1.0, 1e-6))
286 }
287
288 #[gtest]
289 fn content_tuning_x_difficulty_flattens_mapping() -> Result<()> {
290 let mut dbc = dbc();
291
292 dbc.content_tuning_x_difficulty.insert(
293 719,
294 vec![ContentTuningXDifficultyRow {
295 ID: 4135,
296 DifficultyID: 14,
297 ContentTuningID: 719,
298 }],
299 );
300
301 let result = transform_all_content_tuning_x_difficulty(&dbc);
302
303 verify_that!(
304 result,
305 elements_are![matches_pattern!(ContentTuningXDifficultyFlat {
306 id: eq(&4135),
307 content_tuning_id: eq(&719),
308 difficulty_id: eq(&14),
309 })]
310 )
311 }
312
313 #[gtest]
314 fn content_tuning_x_expected_keeps_season_bounds() -> Result<()> {
315 let mut dbc = dbc();
316
317 dbc.content_tuning_x_expected.insert(
318 1279,
319 vec![
320 ContentTuningXExpectedRow {
321 ID: 3032,
322 ExpectedStatModID: 391,
323 MinMythicPlusSeasonID: 117,
324 MaxMythicPlusSeasonID: 0,
325 ContentTuningID: 1279,
326 },
327 ContentTuningXExpectedRow {
328 ID: 449,
329 ExpectedStatModID: 14,
330 MinMythicPlusSeasonID: 0,
331 MaxMythicPlusSeasonID: 100,
332 ContentTuningID: 1279,
333 },
334 ],
335 );
336
337 let result = transform_all_content_tuning_x_expected(&dbc);
338
339 verify_that!(result, len(eq(2)))?;
340 verify_that!(
341 result,
342 contains(matches_pattern!(ContentTuningXExpectedFlat {
343 id: eq(&3032),
344 content_tuning_id: eq(&1279),
345 expected_stat_mod_id: eq(&391),
346 min_mythic_plus_season_id: eq(&117),
347 max_mythic_plus_season_id: eq(&0),
348 }))
349 )?;
350
351 verify_that!(
352 result,
353 contains(matches_pattern!(ContentTuningXExpectedFlat {
354 id: eq(&449),
355 min_mythic_plus_season_id: eq(&0),
356 max_mythic_plus_season_id: eq(&100),
357 ..
358 }))
359 )
360 }
361}