wow_dbc/tbc_tables/
spell.rs

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