wow_dbc/wrath_tables/
spell.rs

1use crate::{
2    DbcTable, ExtendedLocalizedString, Indexable,
3};
4use crate::header::{
5    DbcHeader, HEADER_SIZE, parse_header,
6};
7use crate::wrath_tables::area_group::AreaGroupKey;
8use crate::wrath_tables::faction::FactionKey;
9use crate::wrath_tables::power_display::PowerDisplayKey;
10use crate::wrath_tables::spell_cast_times::SpellCastTimesKey;
11use crate::wrath_tables::spell_category::SpellCategoryKey;
12use crate::wrath_tables::spell_description_variables::SpellDescriptionVariablesKey;
13use crate::wrath_tables::spell_dispel_type::SpellDispelTypeKey;
14use crate::wrath_tables::spell_duration::SpellDurationKey;
15use crate::wrath_tables::spell_focus_object::SpellFocusObjectKey;
16use crate::wrath_tables::spell_icon::SpellIconKey;
17use crate::wrath_tables::spell_mechanic::SpellMechanicKey;
18use crate::wrath_tables::spell_missile::SpellMissileKey;
19use crate::wrath_tables::spell_rune_cost::SpellRuneCostKey;
20use std::io::Write;
21use wow_world_base::wrath::AuraMod;
22
23#[derive(Debug, Clone, PartialEq, PartialOrd)]
24pub struct Spell {
25    pub rows: Vec<SpellRow>,
26}
27
28impl DbcTable for Spell {
29    type Row = SpellRow;
30
31    const FILENAME: &'static str = "Spell.dbc";
32
33    fn rows(&self) -> &[Self::Row] { &self.rows }
34    fn rows_mut(&mut self) -> &mut [Self::Row] { &mut self.rows }
35
36    fn read(b: &mut impl std::io::Read) -> Result<Self, crate::DbcError> {
37        let mut header = [0_u8; HEADER_SIZE];
38        b.read_exact(&mut header)?;
39        let header = parse_header(&header)?;
40
41        if header.record_size != 936 {
42            return Err(crate::DbcError::InvalidHeader(
43                crate::InvalidHeaderError::RecordSize {
44                    expected: 936,
45                    actual: header.record_size,
46                },
47            ));
48        }
49
50        if header.field_count != 234 {
51            return Err(crate::DbcError::InvalidHeader(
52                crate::InvalidHeaderError::FieldCount {
53                    expected: 234,
54                    actual: header.field_count,
55                },
56            ));
57        }
58
59        let mut r = vec![0_u8; (header.record_count * header.record_size) as usize];
60        b.read_exact(&mut r)?;
61        let mut string_block = vec![0_u8; header.string_block_size as usize];
62        b.read_exact(&mut string_block)?;
63
64        let mut rows = Vec::with_capacity(header.record_count as usize);
65
66        for mut chunk in r.chunks(header.record_size as usize) {
67            let chunk = &mut chunk;
68
69            // id: primary_key (Spell) int32
70            let id = SpellKey::new(crate::util::read_i32_le(chunk)?);
71
72            // category: foreign_key (SpellCategory) int32
73            let category = SpellCategoryKey::new(crate::util::read_i32_le(chunk)?.into());
74
75            // dispel_type: foreign_key (SpellDispelType) int32
76            let dispel_type = SpellDispelTypeKey::new(crate::util::read_i32_le(chunk)?.into());
77
78            // mechanic: foreign_key (SpellMechanic) int32
79            let mechanic = SpellMechanicKey::new(crate::util::read_i32_le(chunk)?.into());
80
81            // attributes: int32
82            let attributes = crate::util::read_i32_le(chunk)?;
83
84            // attributes_ex: int32
85            let attributes_ex = crate::util::read_i32_le(chunk)?;
86
87            // attributes_ex_b: int32
88            let attributes_ex_b = crate::util::read_i32_le(chunk)?;
89
90            // attributes_ex_c: int32
91            let attributes_ex_c = crate::util::read_i32_le(chunk)?;
92
93            // attributes_ex_d: int32
94            let attributes_ex_d = crate::util::read_i32_le(chunk)?;
95
96            // attributes_ex_e: int32
97            let attributes_ex_e = crate::util::read_i32_le(chunk)?;
98
99            // attributes_ex_f: int32
100            let attributes_ex_f = crate::util::read_i32_le(chunk)?;
101
102            // attributes_ex_g: int32
103            let attributes_ex_g = crate::util::read_i32_le(chunk)?;
104
105            // shapeshift_mask: int32[2]
106            let shapeshift_mask = crate::util::read_array_i32::<2>(chunk)?;
107
108            // shapeshift_exclude: int32[2]
109            let shapeshift_exclude = crate::util::read_array_i32::<2>(chunk)?;
110
111            // targets: int32
112            let targets = crate::util::read_i32_le(chunk)?;
113
114            // target_creature_type: int32
115            let target_creature_type = crate::util::read_i32_le(chunk)?;
116
117            // requires_spell_focus: foreign_key (SpellFocusObject) int32
118            let requires_spell_focus = SpellFocusObjectKey::new(crate::util::read_i32_le(chunk)?.into());
119
120            // facing_caster_flags: int32
121            let facing_caster_flags = crate::util::read_i32_le(chunk)?;
122
123            // caster_aura_state: int32
124            let caster_aura_state = crate::util::read_i32_le(chunk)?;
125
126            // target_aura_state: int32
127            let target_aura_state = crate::util::read_i32_le(chunk)?;
128
129            // exclude_caster_aura_state: int32
130            let exclude_caster_aura_state = crate::util::read_i32_le(chunk)?;
131
132            // exclude_target_aura_state: int32
133            let exclude_target_aura_state = crate::util::read_i32_le(chunk)?;
134
135            // caster_aura_spell: int32
136            let caster_aura_spell = crate::util::read_i32_le(chunk)?;
137
138            // target_aura_spell: int32
139            let target_aura_spell = crate::util::read_i32_le(chunk)?;
140
141            // exclude_caster_aura_spell: int32
142            let exclude_caster_aura_spell = crate::util::read_i32_le(chunk)?;
143
144            // exclude_target_aura_spell: int32
145            let exclude_target_aura_spell = crate::util::read_i32_le(chunk)?;
146
147            // casting_time_index: foreign_key (SpellCastTimes) int32
148            let casting_time_index = SpellCastTimesKey::new(crate::util::read_i32_le(chunk)?.into());
149
150            // recovery_time: int32
151            let recovery_time = crate::util::read_i32_le(chunk)?;
152
153            // category_recovery_time: int32
154            let category_recovery_time = crate::util::read_i32_le(chunk)?;
155
156            // interrupt_flags: int32
157            let interrupt_flags = crate::util::read_i32_le(chunk)?;
158
159            // aura_interrupt_flags: int32
160            let aura_interrupt_flags = crate::util::read_i32_le(chunk)?;
161
162            // channel_interrupt_flags: int32
163            let channel_interrupt_flags = crate::util::read_i32_le(chunk)?;
164
165            // proc_type_mask: int32
166            let proc_type_mask = crate::util::read_i32_le(chunk)?;
167
168            // proc_chance: int32
169            let proc_chance = crate::util::read_i32_le(chunk)?;
170
171            // proc_charges: int32
172            let proc_charges = crate::util::read_i32_le(chunk)?;
173
174            // max_level: int32
175            let max_level = crate::util::read_i32_le(chunk)?;
176
177            // base_level: int32
178            let base_level = crate::util::read_i32_le(chunk)?;
179
180            // spell_level: int32
181            let spell_level = crate::util::read_i32_le(chunk)?;
182
183            // duration_index: foreign_key (SpellDuration) int32
184            let duration_index = SpellDurationKey::new(crate::util::read_i32_le(chunk)?.into());
185
186            // power_type: int32
187            let power_type = crate::util::read_i32_le(chunk)?;
188
189            // mana_cost: int32
190            let mana_cost = crate::util::read_i32_le(chunk)?;
191
192            // mana_cost_per_level: int32
193            let mana_cost_per_level = crate::util::read_i32_le(chunk)?;
194
195            // mana_per_second: int32
196            let mana_per_second = crate::util::read_i32_le(chunk)?;
197
198            // mana_per_second_per_level: int32
199            let mana_per_second_per_level = crate::util::read_i32_le(chunk)?;
200
201            // range_index: int32
202            let range_index = crate::util::read_i32_le(chunk)?;
203
204            // speed: float
205            let speed = crate::util::read_f32_le(chunk)?;
206
207            // modal_next_spell: int32
208            let modal_next_spell = crate::util::read_i32_le(chunk)?;
209
210            // cumulative_aura: int32
211            let cumulative_aura = crate::util::read_i32_le(chunk)?;
212
213            // totem: int32[2]
214            let totem = crate::util::read_array_i32::<2>(chunk)?;
215
216            // reagent: int32[8]
217            let reagent = crate::util::read_array_i32::<8>(chunk)?;
218
219            // reagent_count: int32[8]
220            let reagent_count = crate::util::read_array_i32::<8>(chunk)?;
221
222            // equipped_item_class: int32
223            let equipped_item_class = crate::util::read_i32_le(chunk)?;
224
225            // equipped_item_subclass: int32
226            let equipped_item_subclass = crate::util::read_i32_le(chunk)?;
227
228            // equipped_item_inv_types: int32
229            let equipped_item_inv_types = crate::util::read_i32_le(chunk)?;
230
231            // effect: int32[3]
232            let effect = crate::util::read_array_i32::<3>(chunk)?;
233
234            // effect_die_sides: int32[3]
235            let effect_die_sides = crate::util::read_array_i32::<3>(chunk)?;
236
237            // effect_real_points_per_level: float[3]
238            let effect_real_points_per_level = crate::util::read_array_f32::<3>(chunk)?;
239
240            // effect_base_points: int32[3]
241            let effect_base_points = crate::util::read_array_i32::<3>(chunk)?;
242
243            // effect_mechanic: int32[3]
244            let effect_mechanic = crate::util::read_array_i32::<3>(chunk)?;
245
246            // implicit_target_a: int32[3]
247            let implicit_target_a = crate::util::read_array_i32::<3>(chunk)?;
248
249            // implicit_target_b: int32[3]
250            let implicit_target_b = crate::util::read_array_i32::<3>(chunk)?;
251
252            // effect_radius_index: int32[3]
253            let effect_radius_index = crate::util::read_array_i32::<3>(chunk)?;
254
255            // effect_aura: AuraMod[3]
256            let effect_aura = {
257                let mut arr = [AuraMod::default(); 3];
258                for i in arr.iter_mut() {
259                    *i = crate::util::read_i32_le(chunk)?.try_into()?;
260                }
261
262                arr
263            };
264
265            // effect_aura_period: int32[3]
266            let effect_aura_period = crate::util::read_array_i32::<3>(chunk)?;
267
268            // effect_amplitude: float[3]
269            let effect_amplitude = crate::util::read_array_f32::<3>(chunk)?;
270
271            // effect_chain_targets: int32[3]
272            let effect_chain_targets = crate::util::read_array_i32::<3>(chunk)?;
273
274            // effect_item_type: int32[3]
275            let effect_item_type = crate::util::read_array_i32::<3>(chunk)?;
276
277            // effect_misc_value: int32[3]
278            let effect_misc_value = crate::util::read_array_i32::<3>(chunk)?;
279
280            // effect_misc_value_b: int32[3]
281            let effect_misc_value_b = crate::util::read_array_i32::<3>(chunk)?;
282
283            // effect_trigger_spell: int32[3]
284            let effect_trigger_spell = crate::util::read_array_i32::<3>(chunk)?;
285
286            // effect_points_per_combo: float[3]
287            let effect_points_per_combo = crate::util::read_array_f32::<3>(chunk)?;
288
289            // effect_spell_class_mask_a: int32[3]
290            let effect_spell_class_mask_a = crate::util::read_array_i32::<3>(chunk)?;
291
292            // effect_spell_class_mask_b: int32[3]
293            let effect_spell_class_mask_b = crate::util::read_array_i32::<3>(chunk)?;
294
295            // effect_spell_class_mask_c: int32[3]
296            let effect_spell_class_mask_c = crate::util::read_array_i32::<3>(chunk)?;
297
298            // spell_visual_id: int32[2]
299            let spell_visual_id = crate::util::read_array_i32::<2>(chunk)?;
300
301            // spell_icon_id: foreign_key (SpellIcon) int32
302            let spell_icon_id = SpellIconKey::new(crate::util::read_i32_le(chunk)?.into());
303
304            // active_icon_id: foreign_key (SpellIcon) int32
305            let active_icon_id = SpellIconKey::new(crate::util::read_i32_le(chunk)?.into());
306
307            // spell_priority: int32
308            let spell_priority = crate::util::read_i32_le(chunk)?;
309
310            // name_lang: string_ref_loc (Extended)
311            let name_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
312
313            // name_subtext_lang: string_ref_loc (Extended)
314            let name_subtext_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
315
316            // description_lang: string_ref_loc (Extended)
317            let description_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
318
319            // aura_description_lang: string_ref_loc (Extended)
320            let aura_description_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
321
322            // mana_cost_pct: int32
323            let mana_cost_pct = crate::util::read_i32_le(chunk)?;
324
325            // start_recovery_category: int32
326            let start_recovery_category = crate::util::read_i32_le(chunk)?;
327
328            // start_recovery_time: int32
329            let start_recovery_time = crate::util::read_i32_le(chunk)?;
330
331            // max_target_level: int32
332            let max_target_level = crate::util::read_i32_le(chunk)?;
333
334            // spell_class_set: int32
335            let spell_class_set = crate::util::read_i32_le(chunk)?;
336
337            // spell_class_mask: int32[3]
338            let spell_class_mask = crate::util::read_array_i32::<3>(chunk)?;
339
340            // max_targets: int32
341            let max_targets = crate::util::read_i32_le(chunk)?;
342
343            // defense_type: int32
344            let defense_type = crate::util::read_i32_le(chunk)?;
345
346            // prevention_type: int32
347            let prevention_type = crate::util::read_i32_le(chunk)?;
348
349            // stance_bar_order: int32
350            let stance_bar_order = crate::util::read_i32_le(chunk)?;
351
352            // effect_chain_amplitude: float[3]
353            let effect_chain_amplitude = crate::util::read_array_f32::<3>(chunk)?;
354
355            // min_faction_id: foreign_key (Faction) int32
356            let min_faction_id = FactionKey::new(crate::util::read_i32_le(chunk)?.into());
357
358            // min_reputation: int32
359            let min_reputation = crate::util::read_i32_le(chunk)?;
360
361            // required_aura_vision: int32
362            let required_aura_vision = crate::util::read_i32_le(chunk)?;
363
364            // required_totem_category_id: int32[2]
365            let required_totem_category_id = crate::util::read_array_i32::<2>(chunk)?;
366
367            // required_areas_id: foreign_key (AreaGroup) int32
368            let required_areas_id = AreaGroupKey::new(crate::util::read_i32_le(chunk)?.into());
369
370            // school_mask: int32
371            let school_mask = crate::util::read_i32_le(chunk)?;
372
373            // rune_cost_id: foreign_key (SpellRuneCost) int32
374            let rune_cost_id = SpellRuneCostKey::new(crate::util::read_i32_le(chunk)?.into());
375
376            // spell_missile_id: foreign_key (SpellMissile) int32
377            let spell_missile_id = SpellMissileKey::new(crate::util::read_i32_le(chunk)?.into());
378
379            // power_display_id: foreign_key (PowerDisplay) int32
380            let power_display_id = PowerDisplayKey::new(crate::util::read_i32_le(chunk)?.into());
381
382            // effect_bonus_coefficient: float[3]
383            let effect_bonus_coefficient = crate::util::read_array_f32::<3>(chunk)?;
384
385            // description_variables_id: foreign_key (SpellDescriptionVariables) int32
386            let description_variables_id = SpellDescriptionVariablesKey::new(crate::util::read_i32_le(chunk)?.into());
387
388            // difficulty: int32
389            let difficulty = crate::util::read_i32_le(chunk)?;
390
391
392            rows.push(SpellRow {
393                id,
394                category,
395                dispel_type,
396                mechanic,
397                attributes,
398                attributes_ex,
399                attributes_ex_b,
400                attributes_ex_c,
401                attributes_ex_d,
402                attributes_ex_e,
403                attributes_ex_f,
404                attributes_ex_g,
405                shapeshift_mask,
406                shapeshift_exclude,
407                targets,
408                target_creature_type,
409                requires_spell_focus,
410                facing_caster_flags,
411                caster_aura_state,
412                target_aura_state,
413                exclude_caster_aura_state,
414                exclude_target_aura_state,
415                caster_aura_spell,
416                target_aura_spell,
417                exclude_caster_aura_spell,
418                exclude_target_aura_spell,
419                casting_time_index,
420                recovery_time,
421                category_recovery_time,
422                interrupt_flags,
423                aura_interrupt_flags,
424                channel_interrupt_flags,
425                proc_type_mask,
426                proc_chance,
427                proc_charges,
428                max_level,
429                base_level,
430                spell_level,
431                duration_index,
432                power_type,
433                mana_cost,
434                mana_cost_per_level,
435                mana_per_second,
436                mana_per_second_per_level,
437                range_index,
438                speed,
439                modal_next_spell,
440                cumulative_aura,
441                totem,
442                reagent,
443                reagent_count,
444                equipped_item_class,
445                equipped_item_subclass,
446                equipped_item_inv_types,
447                effect,
448                effect_die_sides,
449                effect_real_points_per_level,
450                effect_base_points,
451                effect_mechanic,
452                implicit_target_a,
453                implicit_target_b,
454                effect_radius_index,
455                effect_aura,
456                effect_aura_period,
457                effect_amplitude,
458                effect_chain_targets,
459                effect_item_type,
460                effect_misc_value,
461                effect_misc_value_b,
462                effect_trigger_spell,
463                effect_points_per_combo,
464                effect_spell_class_mask_a,
465                effect_spell_class_mask_b,
466                effect_spell_class_mask_c,
467                spell_visual_id,
468                spell_icon_id,
469                active_icon_id,
470                spell_priority,
471                name_lang,
472                name_subtext_lang,
473                description_lang,
474                aura_description_lang,
475                mana_cost_pct,
476                start_recovery_category,
477                start_recovery_time,
478                max_target_level,
479                spell_class_set,
480                spell_class_mask,
481                max_targets,
482                defense_type,
483                prevention_type,
484                stance_bar_order,
485                effect_chain_amplitude,
486                min_faction_id,
487                min_reputation,
488                required_aura_vision,
489                required_totem_category_id,
490                required_areas_id,
491                school_mask,
492                rune_cost_id,
493                spell_missile_id,
494                power_display_id,
495                effect_bonus_coefficient,
496                description_variables_id,
497                difficulty,
498            });
499        }
500
501        Ok(Spell { rows, })
502    }
503
504    fn write(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
505        let header = DbcHeader {
506            record_count: self.rows.len() as u32,
507            field_count: 234,
508            record_size: 936,
509            string_block_size: self.string_block_size(),
510        };
511
512        b.write_all(&header.write_header())?;
513
514        let mut string_index = 1;
515        for row in &self.rows {
516            // id: primary_key (Spell) int32
517            b.write_all(&row.id.id.to_le_bytes())?;
518
519            // category: foreign_key (SpellCategory) int32
520            b.write_all(&(row.category.id as i32).to_le_bytes())?;
521
522            // dispel_type: foreign_key (SpellDispelType) int32
523            b.write_all(&(row.dispel_type.id as i32).to_le_bytes())?;
524
525            // mechanic: foreign_key (SpellMechanic) int32
526            b.write_all(&(row.mechanic.id as i32).to_le_bytes())?;
527
528            // attributes: int32
529            b.write_all(&row.attributes.to_le_bytes())?;
530
531            // attributes_ex: int32
532            b.write_all(&row.attributes_ex.to_le_bytes())?;
533
534            // attributes_ex_b: int32
535            b.write_all(&row.attributes_ex_b.to_le_bytes())?;
536
537            // attributes_ex_c: int32
538            b.write_all(&row.attributes_ex_c.to_le_bytes())?;
539
540            // attributes_ex_d: int32
541            b.write_all(&row.attributes_ex_d.to_le_bytes())?;
542
543            // attributes_ex_e: int32
544            b.write_all(&row.attributes_ex_e.to_le_bytes())?;
545
546            // attributes_ex_f: int32
547            b.write_all(&row.attributes_ex_f.to_le_bytes())?;
548
549            // attributes_ex_g: int32
550            b.write_all(&row.attributes_ex_g.to_le_bytes())?;
551
552            // shapeshift_mask: int32[2]
553            for i in row.shapeshift_mask {
554                b.write_all(&i.to_le_bytes())?;
555            }
556
557
558            // shapeshift_exclude: int32[2]
559            for i in row.shapeshift_exclude {
560                b.write_all(&i.to_le_bytes())?;
561            }
562
563
564            // targets: int32
565            b.write_all(&row.targets.to_le_bytes())?;
566
567            // target_creature_type: int32
568            b.write_all(&row.target_creature_type.to_le_bytes())?;
569
570            // requires_spell_focus: foreign_key (SpellFocusObject) int32
571            b.write_all(&(row.requires_spell_focus.id as i32).to_le_bytes())?;
572
573            // facing_caster_flags: int32
574            b.write_all(&row.facing_caster_flags.to_le_bytes())?;
575
576            // caster_aura_state: int32
577            b.write_all(&row.caster_aura_state.to_le_bytes())?;
578
579            // target_aura_state: int32
580            b.write_all(&row.target_aura_state.to_le_bytes())?;
581
582            // exclude_caster_aura_state: int32
583            b.write_all(&row.exclude_caster_aura_state.to_le_bytes())?;
584
585            // exclude_target_aura_state: int32
586            b.write_all(&row.exclude_target_aura_state.to_le_bytes())?;
587
588            // caster_aura_spell: int32
589            b.write_all(&row.caster_aura_spell.to_le_bytes())?;
590
591            // target_aura_spell: int32
592            b.write_all(&row.target_aura_spell.to_le_bytes())?;
593
594            // exclude_caster_aura_spell: int32
595            b.write_all(&row.exclude_caster_aura_spell.to_le_bytes())?;
596
597            // exclude_target_aura_spell: int32
598            b.write_all(&row.exclude_target_aura_spell.to_le_bytes())?;
599
600            // casting_time_index: foreign_key (SpellCastTimes) int32
601            b.write_all(&(row.casting_time_index.id as i32).to_le_bytes())?;
602
603            // recovery_time: int32
604            b.write_all(&row.recovery_time.to_le_bytes())?;
605
606            // category_recovery_time: int32
607            b.write_all(&row.category_recovery_time.to_le_bytes())?;
608
609            // interrupt_flags: int32
610            b.write_all(&row.interrupt_flags.to_le_bytes())?;
611
612            // aura_interrupt_flags: int32
613            b.write_all(&row.aura_interrupt_flags.to_le_bytes())?;
614
615            // channel_interrupt_flags: int32
616            b.write_all(&row.channel_interrupt_flags.to_le_bytes())?;
617
618            // proc_type_mask: int32
619            b.write_all(&row.proc_type_mask.to_le_bytes())?;
620
621            // proc_chance: int32
622            b.write_all(&row.proc_chance.to_le_bytes())?;
623
624            // proc_charges: int32
625            b.write_all(&row.proc_charges.to_le_bytes())?;
626
627            // max_level: int32
628            b.write_all(&row.max_level.to_le_bytes())?;
629
630            // base_level: int32
631            b.write_all(&row.base_level.to_le_bytes())?;
632
633            // spell_level: int32
634            b.write_all(&row.spell_level.to_le_bytes())?;
635
636            // duration_index: foreign_key (SpellDuration) int32
637            b.write_all(&(row.duration_index.id as i32).to_le_bytes())?;
638
639            // power_type: int32
640            b.write_all(&row.power_type.to_le_bytes())?;
641
642            // mana_cost: int32
643            b.write_all(&row.mana_cost.to_le_bytes())?;
644
645            // mana_cost_per_level: int32
646            b.write_all(&row.mana_cost_per_level.to_le_bytes())?;
647
648            // mana_per_second: int32
649            b.write_all(&row.mana_per_second.to_le_bytes())?;
650
651            // mana_per_second_per_level: int32
652            b.write_all(&row.mana_per_second_per_level.to_le_bytes())?;
653
654            // range_index: int32
655            b.write_all(&row.range_index.to_le_bytes())?;
656
657            // speed: float
658            b.write_all(&row.speed.to_le_bytes())?;
659
660            // modal_next_spell: int32
661            b.write_all(&row.modal_next_spell.to_le_bytes())?;
662
663            // cumulative_aura: int32
664            b.write_all(&row.cumulative_aura.to_le_bytes())?;
665
666            // totem: int32[2]
667            for i in row.totem {
668                b.write_all(&i.to_le_bytes())?;
669            }
670
671
672            // reagent: int32[8]
673            for i in row.reagent {
674                b.write_all(&i.to_le_bytes())?;
675            }
676
677
678            // reagent_count: int32[8]
679            for i in row.reagent_count {
680                b.write_all(&i.to_le_bytes())?;
681            }
682
683
684            // equipped_item_class: int32
685            b.write_all(&row.equipped_item_class.to_le_bytes())?;
686
687            // equipped_item_subclass: int32
688            b.write_all(&row.equipped_item_subclass.to_le_bytes())?;
689
690            // equipped_item_inv_types: int32
691            b.write_all(&row.equipped_item_inv_types.to_le_bytes())?;
692
693            // effect: int32[3]
694            for i in row.effect {
695                b.write_all(&i.to_le_bytes())?;
696            }
697
698
699            // effect_die_sides: int32[3]
700            for i in row.effect_die_sides {
701                b.write_all(&i.to_le_bytes())?;
702            }
703
704
705            // effect_real_points_per_level: float[3]
706            for i in row.effect_real_points_per_level {
707                b.write_all(&i.to_le_bytes())?;
708            }
709
710
711            // effect_base_points: int32[3]
712            for i in row.effect_base_points {
713                b.write_all(&i.to_le_bytes())?;
714            }
715
716
717            // effect_mechanic: int32[3]
718            for i in row.effect_mechanic {
719                b.write_all(&i.to_le_bytes())?;
720            }
721
722
723            // implicit_target_a: int32[3]
724            for i in row.implicit_target_a {
725                b.write_all(&i.to_le_bytes())?;
726            }
727
728
729            // implicit_target_b: int32[3]
730            for i in row.implicit_target_b {
731                b.write_all(&i.to_le_bytes())?;
732            }
733
734
735            // effect_radius_index: int32[3]
736            for i in row.effect_radius_index {
737                b.write_all(&i.to_le_bytes())?;
738            }
739
740
741            // effect_aura: AuraMod[3]
742            for i in row.effect_aura {
743                b.write_all(&(i.as_int() as i32).to_le_bytes())?;
744            }
745
746
747            // effect_aura_period: int32[3]
748            for i in row.effect_aura_period {
749                b.write_all(&i.to_le_bytes())?;
750            }
751
752
753            // effect_amplitude: float[3]
754            for i in row.effect_amplitude {
755                b.write_all(&i.to_le_bytes())?;
756            }
757
758
759            // effect_chain_targets: int32[3]
760            for i in row.effect_chain_targets {
761                b.write_all(&i.to_le_bytes())?;
762            }
763
764
765            // effect_item_type: int32[3]
766            for i in row.effect_item_type {
767                b.write_all(&i.to_le_bytes())?;
768            }
769
770
771            // effect_misc_value: int32[3]
772            for i in row.effect_misc_value {
773                b.write_all(&i.to_le_bytes())?;
774            }
775
776
777            // effect_misc_value_b: int32[3]
778            for i in row.effect_misc_value_b {
779                b.write_all(&i.to_le_bytes())?;
780            }
781
782
783            // effect_trigger_spell: int32[3]
784            for i in row.effect_trigger_spell {
785                b.write_all(&i.to_le_bytes())?;
786            }
787
788
789            // effect_points_per_combo: float[3]
790            for i in row.effect_points_per_combo {
791                b.write_all(&i.to_le_bytes())?;
792            }
793
794
795            // effect_spell_class_mask_a: int32[3]
796            for i in row.effect_spell_class_mask_a {
797                b.write_all(&i.to_le_bytes())?;
798            }
799
800
801            // effect_spell_class_mask_b: int32[3]
802            for i in row.effect_spell_class_mask_b {
803                b.write_all(&i.to_le_bytes())?;
804            }
805
806
807            // effect_spell_class_mask_c: int32[3]
808            for i in row.effect_spell_class_mask_c {
809                b.write_all(&i.to_le_bytes())?;
810            }
811
812
813            // spell_visual_id: int32[2]
814            for i in row.spell_visual_id {
815                b.write_all(&i.to_le_bytes())?;
816            }
817
818
819            // spell_icon_id: foreign_key (SpellIcon) int32
820            b.write_all(&(row.spell_icon_id.id as i32).to_le_bytes())?;
821
822            // active_icon_id: foreign_key (SpellIcon) int32
823            b.write_all(&(row.active_icon_id.id as i32).to_le_bytes())?;
824
825            // spell_priority: int32
826            b.write_all(&row.spell_priority.to_le_bytes())?;
827
828            // name_lang: string_ref_loc (Extended)
829            b.write_all(&row.name_lang.string_indices_as_array(&mut string_index))?;
830
831            // name_subtext_lang: string_ref_loc (Extended)
832            b.write_all(&row.name_subtext_lang.string_indices_as_array(&mut string_index))?;
833
834            // description_lang: string_ref_loc (Extended)
835            b.write_all(&row.description_lang.string_indices_as_array(&mut string_index))?;
836
837            // aura_description_lang: string_ref_loc (Extended)
838            b.write_all(&row.aura_description_lang.string_indices_as_array(&mut string_index))?;
839
840            // mana_cost_pct: int32
841            b.write_all(&row.mana_cost_pct.to_le_bytes())?;
842
843            // start_recovery_category: int32
844            b.write_all(&row.start_recovery_category.to_le_bytes())?;
845
846            // start_recovery_time: int32
847            b.write_all(&row.start_recovery_time.to_le_bytes())?;
848
849            // max_target_level: int32
850            b.write_all(&row.max_target_level.to_le_bytes())?;
851
852            // spell_class_set: int32
853            b.write_all(&row.spell_class_set.to_le_bytes())?;
854
855            // spell_class_mask: int32[3]
856            for i in row.spell_class_mask {
857                b.write_all(&i.to_le_bytes())?;
858            }
859
860
861            // max_targets: int32
862            b.write_all(&row.max_targets.to_le_bytes())?;
863
864            // defense_type: int32
865            b.write_all(&row.defense_type.to_le_bytes())?;
866
867            // prevention_type: int32
868            b.write_all(&row.prevention_type.to_le_bytes())?;
869
870            // stance_bar_order: int32
871            b.write_all(&row.stance_bar_order.to_le_bytes())?;
872
873            // effect_chain_amplitude: float[3]
874            for i in row.effect_chain_amplitude {
875                b.write_all(&i.to_le_bytes())?;
876            }
877
878
879            // min_faction_id: foreign_key (Faction) int32
880            b.write_all(&(row.min_faction_id.id as i32).to_le_bytes())?;
881
882            // min_reputation: int32
883            b.write_all(&row.min_reputation.to_le_bytes())?;
884
885            // required_aura_vision: int32
886            b.write_all(&row.required_aura_vision.to_le_bytes())?;
887
888            // required_totem_category_id: int32[2]
889            for i in row.required_totem_category_id {
890                b.write_all(&i.to_le_bytes())?;
891            }
892
893
894            // required_areas_id: foreign_key (AreaGroup) int32
895            b.write_all(&(row.required_areas_id.id as i32).to_le_bytes())?;
896
897            // school_mask: int32
898            b.write_all(&row.school_mask.to_le_bytes())?;
899
900            // rune_cost_id: foreign_key (SpellRuneCost) int32
901            b.write_all(&(row.rune_cost_id.id as i32).to_le_bytes())?;
902
903            // spell_missile_id: foreign_key (SpellMissile) int32
904            b.write_all(&(row.spell_missile_id.id as i32).to_le_bytes())?;
905
906            // power_display_id: foreign_key (PowerDisplay) int32
907            b.write_all(&(row.power_display_id.id as i32).to_le_bytes())?;
908
909            // effect_bonus_coefficient: float[3]
910            for i in row.effect_bonus_coefficient {
911                b.write_all(&i.to_le_bytes())?;
912            }
913
914
915            // description_variables_id: foreign_key (SpellDescriptionVariables) int32
916            b.write_all(&(row.description_variables_id.id as i32).to_le_bytes())?;
917
918            // difficulty: int32
919            b.write_all(&row.difficulty.to_le_bytes())?;
920
921        }
922
923        self.write_string_block(b)?;
924
925        Ok(())
926    }
927
928}
929
930impl Indexable for Spell {
931    type PrimaryKey = SpellKey;
932    fn get(&self, key: impl TryInto<Self::PrimaryKey>) -> Option<&Self::Row> {
933        let key = key.try_into().ok()?;
934        self.rows.iter().find(|a| a.id.id == key.id)
935    }
936
937    fn get_mut(&mut self, key: impl TryInto<Self::PrimaryKey>) -> Option<&mut Self::Row> {
938        let key = key.try_into().ok()?;
939        self.rows.iter_mut().find(|a| a.id.id == key.id)
940    }
941}
942
943impl Spell {
944    fn write_string_block(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
945        b.write_all(&[0])?;
946
947        for row in &self.rows {
948            row.name_lang.string_block_as_array(b)?;
949            row.name_subtext_lang.string_block_as_array(b)?;
950            row.description_lang.string_block_as_array(b)?;
951            row.aura_description_lang.string_block_as_array(b)?;
952        }
953
954        Ok(())
955    }
956
957    fn string_block_size(&self) -> u32 {
958        let mut sum = 1;
959        for row in &self.rows {
960            sum += row.name_lang.string_block_size();
961            sum += row.name_subtext_lang.string_block_size();
962            sum += row.description_lang.string_block_size();
963            sum += row.aura_description_lang.string_block_size();
964        }
965
966        sum as u32
967    }
968
969}
970
971#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
972pub struct SpellKey {
973    pub id: i32
974}
975
976impl SpellKey {
977    pub const fn new(id: i32) -> Self {
978        Self { id }
979    }
980
981}
982
983impl From<u8> for SpellKey {
984    fn from(v: u8) -> Self {
985        Self::new(v.into())
986    }
987}
988
989impl From<u16> for SpellKey {
990    fn from(v: u16) -> Self {
991        Self::new(v.into())
992    }
993}
994
995impl From<i8> for SpellKey {
996    fn from(v: i8) -> Self {
997        Self::new(v.into())
998    }
999}
1000
1001impl From<i16> for SpellKey {
1002    fn from(v: i16) -> Self {
1003        Self::new(v.into())
1004    }
1005}
1006
1007impl From<i32> for SpellKey {
1008    fn from(v: i32) -> Self {
1009        Self::new(v)
1010    }
1011}
1012
1013impl TryFrom<u32> for SpellKey {
1014    type Error = u32;
1015    fn try_from(v: u32) -> Result<Self, Self::Error> {
1016        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
1017    }
1018}
1019
1020impl TryFrom<usize> for SpellKey {
1021    type Error = usize;
1022    fn try_from(v: usize) -> Result<Self, Self::Error> {
1023        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
1024    }
1025}
1026
1027impl TryFrom<u64> for SpellKey {
1028    type Error = u64;
1029    fn try_from(v: u64) -> Result<Self, Self::Error> {
1030        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
1031    }
1032}
1033
1034impl TryFrom<i64> for SpellKey {
1035    type Error = i64;
1036    fn try_from(v: i64) -> Result<Self, Self::Error> {
1037        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
1038    }
1039}
1040
1041impl TryFrom<isize> for SpellKey {
1042    type Error = isize;
1043    fn try_from(v: isize) -> Result<Self, Self::Error> {
1044        Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
1045    }
1046}
1047
1048#[derive(Debug, Clone, PartialEq, PartialOrd)]
1049pub struct SpellRow {
1050    pub id: SpellKey,
1051    pub category: SpellCategoryKey,
1052    pub dispel_type: SpellDispelTypeKey,
1053    pub mechanic: SpellMechanicKey,
1054    pub attributes: i32,
1055    pub attributes_ex: i32,
1056    pub attributes_ex_b: i32,
1057    pub attributes_ex_c: i32,
1058    pub attributes_ex_d: i32,
1059    pub attributes_ex_e: i32,
1060    pub attributes_ex_f: i32,
1061    pub attributes_ex_g: i32,
1062    pub shapeshift_mask: [i32; 2],
1063    pub shapeshift_exclude: [i32; 2],
1064    pub targets: i32,
1065    pub target_creature_type: i32,
1066    pub requires_spell_focus: SpellFocusObjectKey,
1067    pub facing_caster_flags: i32,
1068    pub caster_aura_state: i32,
1069    pub target_aura_state: i32,
1070    pub exclude_caster_aura_state: i32,
1071    pub exclude_target_aura_state: i32,
1072    pub caster_aura_spell: i32,
1073    pub target_aura_spell: i32,
1074    pub exclude_caster_aura_spell: i32,
1075    pub exclude_target_aura_spell: i32,
1076    pub casting_time_index: SpellCastTimesKey,
1077    pub recovery_time: i32,
1078    pub category_recovery_time: i32,
1079    pub interrupt_flags: i32,
1080    pub aura_interrupt_flags: i32,
1081    pub channel_interrupt_flags: i32,
1082    pub proc_type_mask: i32,
1083    pub proc_chance: i32,
1084    pub proc_charges: i32,
1085    pub max_level: i32,
1086    pub base_level: i32,
1087    pub spell_level: i32,
1088    pub duration_index: SpellDurationKey,
1089    pub power_type: i32,
1090    pub mana_cost: i32,
1091    pub mana_cost_per_level: i32,
1092    pub mana_per_second: i32,
1093    pub mana_per_second_per_level: i32,
1094    pub range_index: i32,
1095    pub speed: f32,
1096    pub modal_next_spell: i32,
1097    pub cumulative_aura: i32,
1098    pub totem: [i32; 2],
1099    pub reagent: [i32; 8],
1100    pub reagent_count: [i32; 8],
1101    pub equipped_item_class: i32,
1102    pub equipped_item_subclass: i32,
1103    pub equipped_item_inv_types: i32,
1104    pub effect: [i32; 3],
1105    pub effect_die_sides: [i32; 3],
1106    pub effect_real_points_per_level: [f32; 3],
1107    pub effect_base_points: [i32; 3],
1108    pub effect_mechanic: [i32; 3],
1109    pub implicit_target_a: [i32; 3],
1110    pub implicit_target_b: [i32; 3],
1111    pub effect_radius_index: [i32; 3],
1112    pub effect_aura: [AuraMod; 3],
1113    pub effect_aura_period: [i32; 3],
1114    pub effect_amplitude: [f32; 3],
1115    pub effect_chain_targets: [i32; 3],
1116    pub effect_item_type: [i32; 3],
1117    pub effect_misc_value: [i32; 3],
1118    pub effect_misc_value_b: [i32; 3],
1119    pub effect_trigger_spell: [i32; 3],
1120    pub effect_points_per_combo: [f32; 3],
1121    pub effect_spell_class_mask_a: [i32; 3],
1122    pub effect_spell_class_mask_b: [i32; 3],
1123    pub effect_spell_class_mask_c: [i32; 3],
1124    pub spell_visual_id: [i32; 2],
1125    pub spell_icon_id: SpellIconKey,
1126    pub active_icon_id: SpellIconKey,
1127    pub spell_priority: i32,
1128    pub name_lang: ExtendedLocalizedString,
1129    pub name_subtext_lang: ExtendedLocalizedString,
1130    pub description_lang: ExtendedLocalizedString,
1131    pub aura_description_lang: ExtendedLocalizedString,
1132    pub mana_cost_pct: i32,
1133    pub start_recovery_category: i32,
1134    pub start_recovery_time: i32,
1135    pub max_target_level: i32,
1136    pub spell_class_set: i32,
1137    pub spell_class_mask: [i32; 3],
1138    pub max_targets: i32,
1139    pub defense_type: i32,
1140    pub prevention_type: i32,
1141    pub stance_bar_order: i32,
1142    pub effect_chain_amplitude: [f32; 3],
1143    pub min_faction_id: FactionKey,
1144    pub min_reputation: i32,
1145    pub required_aura_vision: i32,
1146    pub required_totem_category_id: [i32; 2],
1147    pub required_areas_id: AreaGroupKey,
1148    pub school_mask: i32,
1149    pub rune_cost_id: SpellRuneCostKey,
1150    pub spell_missile_id: SpellMissileKey,
1151    pub power_display_id: PowerDisplayKey,
1152    pub effect_bonus_coefficient: [f32; 3],
1153    pub description_variables_id: SpellDescriptionVariablesKey,
1154    pub difficulty: i32,
1155}
1156