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 let id = SpellKey::new(crate::util::read_i32_le(chunk)?);
71
72 let category = SpellCategoryKey::new(crate::util::read_i32_le(chunk)?.into());
74
75 let dispel_type = SpellDispelTypeKey::new(crate::util::read_i32_le(chunk)?.into());
77
78 let mechanic = SpellMechanicKey::new(crate::util::read_i32_le(chunk)?.into());
80
81 let attributes = crate::util::read_i32_le(chunk)?;
83
84 let attributes_ex = crate::util::read_i32_le(chunk)?;
86
87 let attributes_ex_b = crate::util::read_i32_le(chunk)?;
89
90 let attributes_ex_c = crate::util::read_i32_le(chunk)?;
92
93 let attributes_ex_d = crate::util::read_i32_le(chunk)?;
95
96 let attributes_ex_e = crate::util::read_i32_le(chunk)?;
98
99 let attributes_ex_f = crate::util::read_i32_le(chunk)?;
101
102 let attributes_ex_g = crate::util::read_i32_le(chunk)?;
104
105 let shapeshift_mask = crate::util::read_array_i32::<2>(chunk)?;
107
108 let shapeshift_exclude = crate::util::read_array_i32::<2>(chunk)?;
110
111 let targets = crate::util::read_i32_le(chunk)?;
113
114 let target_creature_type = crate::util::read_i32_le(chunk)?;
116
117 let requires_spell_focus = SpellFocusObjectKey::new(crate::util::read_i32_le(chunk)?.into());
119
120 let facing_caster_flags = crate::util::read_i32_le(chunk)?;
122
123 let caster_aura_state = crate::util::read_i32_le(chunk)?;
125
126 let target_aura_state = crate::util::read_i32_le(chunk)?;
128
129 let exclude_caster_aura_state = crate::util::read_i32_le(chunk)?;
131
132 let exclude_target_aura_state = crate::util::read_i32_le(chunk)?;
134
135 let caster_aura_spell = crate::util::read_i32_le(chunk)?;
137
138 let target_aura_spell = crate::util::read_i32_le(chunk)?;
140
141 let exclude_caster_aura_spell = crate::util::read_i32_le(chunk)?;
143
144 let exclude_target_aura_spell = crate::util::read_i32_le(chunk)?;
146
147 let casting_time_index = SpellCastTimesKey::new(crate::util::read_i32_le(chunk)?.into());
149
150 let recovery_time = crate::util::read_i32_le(chunk)?;
152
153 let category_recovery_time = crate::util::read_i32_le(chunk)?;
155
156 let interrupt_flags = crate::util::read_i32_le(chunk)?;
158
159 let aura_interrupt_flags = crate::util::read_i32_le(chunk)?;
161
162 let channel_interrupt_flags = crate::util::read_i32_le(chunk)?;
164
165 let proc_type_mask = crate::util::read_i32_le(chunk)?;
167
168 let proc_chance = crate::util::read_i32_le(chunk)?;
170
171 let proc_charges = crate::util::read_i32_le(chunk)?;
173
174 let max_level = crate::util::read_i32_le(chunk)?;
176
177 let base_level = crate::util::read_i32_le(chunk)?;
179
180 let spell_level = crate::util::read_i32_le(chunk)?;
182
183 let duration_index = SpellDurationKey::new(crate::util::read_i32_le(chunk)?.into());
185
186 let power_type = crate::util::read_i32_le(chunk)?;
188
189 let mana_cost = crate::util::read_i32_le(chunk)?;
191
192 let mana_cost_per_level = crate::util::read_i32_le(chunk)?;
194
195 let mana_per_second = crate::util::read_i32_le(chunk)?;
197
198 let mana_per_second_per_level = crate::util::read_i32_le(chunk)?;
200
201 let range_index = crate::util::read_i32_le(chunk)?;
203
204 let speed = crate::util::read_f32_le(chunk)?;
206
207 let modal_next_spell = crate::util::read_i32_le(chunk)?;
209
210 let cumulative_aura = crate::util::read_i32_le(chunk)?;
212
213 let totem = crate::util::read_array_i32::<2>(chunk)?;
215
216 let reagent = crate::util::read_array_i32::<8>(chunk)?;
218
219 let reagent_count = crate::util::read_array_i32::<8>(chunk)?;
221
222 let equipped_item_class = crate::util::read_i32_le(chunk)?;
224
225 let equipped_item_subclass = crate::util::read_i32_le(chunk)?;
227
228 let equipped_item_inv_types = crate::util::read_i32_le(chunk)?;
230
231 let effect = crate::util::read_array_i32::<3>(chunk)?;
233
234 let effect_die_sides = crate::util::read_array_i32::<3>(chunk)?;
236
237 let effect_real_points_per_level = crate::util::read_array_f32::<3>(chunk)?;
239
240 let effect_base_points = crate::util::read_array_i32::<3>(chunk)?;
242
243 let effect_mechanic = crate::util::read_array_i32::<3>(chunk)?;
245
246 let implicit_target_a = crate::util::read_array_i32::<3>(chunk)?;
248
249 let implicit_target_b = crate::util::read_array_i32::<3>(chunk)?;
251
252 let effect_radius_index = crate::util::read_array_i32::<3>(chunk)?;
254
255 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 let effect_aura_period = crate::util::read_array_i32::<3>(chunk)?;
267
268 let effect_amplitude = crate::util::read_array_f32::<3>(chunk)?;
270
271 let effect_chain_targets = crate::util::read_array_i32::<3>(chunk)?;
273
274 let effect_item_type = crate::util::read_array_i32::<3>(chunk)?;
276
277 let effect_misc_value = crate::util::read_array_i32::<3>(chunk)?;
279
280 let effect_misc_value_b = crate::util::read_array_i32::<3>(chunk)?;
282
283 let effect_trigger_spell = crate::util::read_array_i32::<3>(chunk)?;
285
286 let effect_points_per_combo = crate::util::read_array_f32::<3>(chunk)?;
288
289 let effect_spell_class_mask_a = crate::util::read_array_i32::<3>(chunk)?;
291
292 let effect_spell_class_mask_b = crate::util::read_array_i32::<3>(chunk)?;
294
295 let effect_spell_class_mask_c = crate::util::read_array_i32::<3>(chunk)?;
297
298 let spell_visual_id = crate::util::read_array_i32::<2>(chunk)?;
300
301 let spell_icon_id = SpellIconKey::new(crate::util::read_i32_le(chunk)?.into());
303
304 let active_icon_id = SpellIconKey::new(crate::util::read_i32_le(chunk)?.into());
306
307 let spell_priority = crate::util::read_i32_le(chunk)?;
309
310 let name_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
312
313 let name_subtext_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
315
316 let description_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
318
319 let aura_description_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
321
322 let mana_cost_pct = crate::util::read_i32_le(chunk)?;
324
325 let start_recovery_category = crate::util::read_i32_le(chunk)?;
327
328 let start_recovery_time = crate::util::read_i32_le(chunk)?;
330
331 let max_target_level = crate::util::read_i32_le(chunk)?;
333
334 let spell_class_set = crate::util::read_i32_le(chunk)?;
336
337 let spell_class_mask = crate::util::read_array_i32::<3>(chunk)?;
339
340 let max_targets = crate::util::read_i32_le(chunk)?;
342
343 let defense_type = crate::util::read_i32_le(chunk)?;
345
346 let prevention_type = crate::util::read_i32_le(chunk)?;
348
349 let stance_bar_order = crate::util::read_i32_le(chunk)?;
351
352 let effect_chain_amplitude = crate::util::read_array_f32::<3>(chunk)?;
354
355 let min_faction_id = FactionKey::new(crate::util::read_i32_le(chunk)?.into());
357
358 let min_reputation = crate::util::read_i32_le(chunk)?;
360
361 let required_aura_vision = crate::util::read_i32_le(chunk)?;
363
364 let required_totem_category_id = crate::util::read_array_i32::<2>(chunk)?;
366
367 let required_areas_id = AreaGroupKey::new(crate::util::read_i32_le(chunk)?.into());
369
370 let school_mask = crate::util::read_i32_le(chunk)?;
372
373 let rune_cost_id = SpellRuneCostKey::new(crate::util::read_i32_le(chunk)?.into());
375
376 let spell_missile_id = SpellMissileKey::new(crate::util::read_i32_le(chunk)?.into());
378
379 let power_display_id = PowerDisplayKey::new(crate::util::read_i32_le(chunk)?.into());
381
382 let effect_bonus_coefficient = crate::util::read_array_f32::<3>(chunk)?;
384
385 let description_variables_id = SpellDescriptionVariablesKey::new(crate::util::read_i32_le(chunk)?.into());
387
388 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 b.write_all(&row.id.id.to_le_bytes())?;
518
519 b.write_all(&(row.category.id as i32).to_le_bytes())?;
521
522 b.write_all(&(row.dispel_type.id as i32).to_le_bytes())?;
524
525 b.write_all(&(row.mechanic.id as i32).to_le_bytes())?;
527
528 b.write_all(&row.attributes.to_le_bytes())?;
530
531 b.write_all(&row.attributes_ex.to_le_bytes())?;
533
534 b.write_all(&row.attributes_ex_b.to_le_bytes())?;
536
537 b.write_all(&row.attributes_ex_c.to_le_bytes())?;
539
540 b.write_all(&row.attributes_ex_d.to_le_bytes())?;
542
543 b.write_all(&row.attributes_ex_e.to_le_bytes())?;
545
546 b.write_all(&row.attributes_ex_f.to_le_bytes())?;
548
549 b.write_all(&row.attributes_ex_g.to_le_bytes())?;
551
552 for i in row.shapeshift_mask {
554 b.write_all(&i.to_le_bytes())?;
555 }
556
557
558 for i in row.shapeshift_exclude {
560 b.write_all(&i.to_le_bytes())?;
561 }
562
563
564 b.write_all(&row.targets.to_le_bytes())?;
566
567 b.write_all(&row.target_creature_type.to_le_bytes())?;
569
570 b.write_all(&(row.requires_spell_focus.id as i32).to_le_bytes())?;
572
573 b.write_all(&row.facing_caster_flags.to_le_bytes())?;
575
576 b.write_all(&row.caster_aura_state.to_le_bytes())?;
578
579 b.write_all(&row.target_aura_state.to_le_bytes())?;
581
582 b.write_all(&row.exclude_caster_aura_state.to_le_bytes())?;
584
585 b.write_all(&row.exclude_target_aura_state.to_le_bytes())?;
587
588 b.write_all(&row.caster_aura_spell.to_le_bytes())?;
590
591 b.write_all(&row.target_aura_spell.to_le_bytes())?;
593
594 b.write_all(&row.exclude_caster_aura_spell.to_le_bytes())?;
596
597 b.write_all(&row.exclude_target_aura_spell.to_le_bytes())?;
599
600 b.write_all(&(row.casting_time_index.id as i32).to_le_bytes())?;
602
603 b.write_all(&row.recovery_time.to_le_bytes())?;
605
606 b.write_all(&row.category_recovery_time.to_le_bytes())?;
608
609 b.write_all(&row.interrupt_flags.to_le_bytes())?;
611
612 b.write_all(&row.aura_interrupt_flags.to_le_bytes())?;
614
615 b.write_all(&row.channel_interrupt_flags.to_le_bytes())?;
617
618 b.write_all(&row.proc_type_mask.to_le_bytes())?;
620
621 b.write_all(&row.proc_chance.to_le_bytes())?;
623
624 b.write_all(&row.proc_charges.to_le_bytes())?;
626
627 b.write_all(&row.max_level.to_le_bytes())?;
629
630 b.write_all(&row.base_level.to_le_bytes())?;
632
633 b.write_all(&row.spell_level.to_le_bytes())?;
635
636 b.write_all(&(row.duration_index.id as i32).to_le_bytes())?;
638
639 b.write_all(&row.power_type.to_le_bytes())?;
641
642 b.write_all(&row.mana_cost.to_le_bytes())?;
644
645 b.write_all(&row.mana_cost_per_level.to_le_bytes())?;
647
648 b.write_all(&row.mana_per_second.to_le_bytes())?;
650
651 b.write_all(&row.mana_per_second_per_level.to_le_bytes())?;
653
654 b.write_all(&row.range_index.to_le_bytes())?;
656
657 b.write_all(&row.speed.to_le_bytes())?;
659
660 b.write_all(&row.modal_next_spell.to_le_bytes())?;
662
663 b.write_all(&row.cumulative_aura.to_le_bytes())?;
665
666 for i in row.totem {
668 b.write_all(&i.to_le_bytes())?;
669 }
670
671
672 for i in row.reagent {
674 b.write_all(&i.to_le_bytes())?;
675 }
676
677
678 for i in row.reagent_count {
680 b.write_all(&i.to_le_bytes())?;
681 }
682
683
684 b.write_all(&row.equipped_item_class.to_le_bytes())?;
686
687 b.write_all(&row.equipped_item_subclass.to_le_bytes())?;
689
690 b.write_all(&row.equipped_item_inv_types.to_le_bytes())?;
692
693 for i in row.effect {
695 b.write_all(&i.to_le_bytes())?;
696 }
697
698
699 for i in row.effect_die_sides {
701 b.write_all(&i.to_le_bytes())?;
702 }
703
704
705 for i in row.effect_real_points_per_level {
707 b.write_all(&i.to_le_bytes())?;
708 }
709
710
711 for i in row.effect_base_points {
713 b.write_all(&i.to_le_bytes())?;
714 }
715
716
717 for i in row.effect_mechanic {
719 b.write_all(&i.to_le_bytes())?;
720 }
721
722
723 for i in row.implicit_target_a {
725 b.write_all(&i.to_le_bytes())?;
726 }
727
728
729 for i in row.implicit_target_b {
731 b.write_all(&i.to_le_bytes())?;
732 }
733
734
735 for i in row.effect_radius_index {
737 b.write_all(&i.to_le_bytes())?;
738 }
739
740
741 for i in row.effect_aura {
743 b.write_all(&(i.as_int() as i32).to_le_bytes())?;
744 }
745
746
747 for i in row.effect_aura_period {
749 b.write_all(&i.to_le_bytes())?;
750 }
751
752
753 for i in row.effect_amplitude {
755 b.write_all(&i.to_le_bytes())?;
756 }
757
758
759 for i in row.effect_chain_targets {
761 b.write_all(&i.to_le_bytes())?;
762 }
763
764
765 for i in row.effect_item_type {
767 b.write_all(&i.to_le_bytes())?;
768 }
769
770
771 for i in row.effect_misc_value {
773 b.write_all(&i.to_le_bytes())?;
774 }
775
776
777 for i in row.effect_misc_value_b {
779 b.write_all(&i.to_le_bytes())?;
780 }
781
782
783 for i in row.effect_trigger_spell {
785 b.write_all(&i.to_le_bytes())?;
786 }
787
788
789 for i in row.effect_points_per_combo {
791 b.write_all(&i.to_le_bytes())?;
792 }
793
794
795 for i in row.effect_spell_class_mask_a {
797 b.write_all(&i.to_le_bytes())?;
798 }
799
800
801 for i in row.effect_spell_class_mask_b {
803 b.write_all(&i.to_le_bytes())?;
804 }
805
806
807 for i in row.effect_spell_class_mask_c {
809 b.write_all(&i.to_le_bytes())?;
810 }
811
812
813 for i in row.spell_visual_id {
815 b.write_all(&i.to_le_bytes())?;
816 }
817
818
819 b.write_all(&(row.spell_icon_id.id as i32).to_le_bytes())?;
821
822 b.write_all(&(row.active_icon_id.id as i32).to_le_bytes())?;
824
825 b.write_all(&row.spell_priority.to_le_bytes())?;
827
828 b.write_all(&row.name_lang.string_indices_as_array(&mut string_index))?;
830
831 b.write_all(&row.name_subtext_lang.string_indices_as_array(&mut string_index))?;
833
834 b.write_all(&row.description_lang.string_indices_as_array(&mut string_index))?;
836
837 b.write_all(&row.aura_description_lang.string_indices_as_array(&mut string_index))?;
839
840 b.write_all(&row.mana_cost_pct.to_le_bytes())?;
842
843 b.write_all(&row.start_recovery_category.to_le_bytes())?;
845
846 b.write_all(&row.start_recovery_time.to_le_bytes())?;
848
849 b.write_all(&row.max_target_level.to_le_bytes())?;
851
852 b.write_all(&row.spell_class_set.to_le_bytes())?;
854
855 for i in row.spell_class_mask {
857 b.write_all(&i.to_le_bytes())?;
858 }
859
860
861 b.write_all(&row.max_targets.to_le_bytes())?;
863
864 b.write_all(&row.defense_type.to_le_bytes())?;
866
867 b.write_all(&row.prevention_type.to_le_bytes())?;
869
870 b.write_all(&row.stance_bar_order.to_le_bytes())?;
872
873 for i in row.effect_chain_amplitude {
875 b.write_all(&i.to_le_bytes())?;
876 }
877
878
879 b.write_all(&(row.min_faction_id.id as i32).to_le_bytes())?;
881
882 b.write_all(&row.min_reputation.to_le_bytes())?;
884
885 b.write_all(&row.required_aura_vision.to_le_bytes())?;
887
888 for i in row.required_totem_category_id {
890 b.write_all(&i.to_le_bytes())?;
891 }
892
893
894 b.write_all(&(row.required_areas_id.id as i32).to_le_bytes())?;
896
897 b.write_all(&row.school_mask.to_le_bytes())?;
899
900 b.write_all(&(row.rune_cost_id.id as i32).to_le_bytes())?;
902
903 b.write_all(&(row.spell_missile_id.id as i32).to_le_bytes())?;
905
906 b.write_all(&(row.power_display_id.id as i32).to_le_bytes())?;
908
909 for i in row.effect_bonus_coefficient {
911 b.write_all(&i.to_le_bytes())?;
912 }
913
914
915 b.write_all(&(row.description_variables_id.id as i32).to_le_bytes())?;
917
918 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