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 let id = SpellKey::new(crate::util::read_i32_le(chunk)?);
66
67 let category = SpellCategoryKey::new(crate::util::read_i32_le(chunk)?.into());
69
70 let cast_u_i = crate::util::read_i32_le(chunk)?;
72
73 let dispel_type = SpellDispelTypeKey::new(crate::util::read_i32_le(chunk)?.into());
75
76 let mechanic = SpellMechanicKey::new(crate::util::read_i32_le(chunk)?.into());
78
79 let attributes = crate::util::read_i32_le(chunk)?;
81
82 let attributes_ex = crate::util::read_i32_le(chunk)?;
84
85 let attributes_ex_b = crate::util::read_i32_le(chunk)?;
87
88 let attributes_ex_c = crate::util::read_i32_le(chunk)?;
90
91 let attributes_ex_d = crate::util::read_i32_le(chunk)?;
93
94 let attributes_ex_e = crate::util::read_i32_le(chunk)?;
96
97 let attributes_ex_f = crate::util::read_i32_le(chunk)?;
99
100 let shapeshift_mask = crate::util::read_i32_le(chunk)?;
102
103 let shapeshift_exclude = crate::util::read_i32_le(chunk)?;
105
106 let targets = crate::util::read_i32_le(chunk)?;
108
109 let target_creature_type = crate::util::read_i32_le(chunk)?;
111
112 let requires_spell_focus = SpellFocusObjectKey::new(crate::util::read_i32_le(chunk)?.into());
114
115 let facing_caster_flags = crate::util::read_i32_le(chunk)?;
117
118 let caster_aura_state = crate::util::read_i32_le(chunk)?;
120
121 let target_aura_state = crate::util::read_i32_le(chunk)?;
123
124 let exclude_caster_aura_state = crate::util::read_i32_le(chunk)?;
126
127 let exclude_target_aura_state = crate::util::read_i32_le(chunk)?;
129
130 let casting_time_index = SpellCastTimesKey::new(crate::util::read_i32_le(chunk)?.into());
132
133 let recovery_time = crate::util::read_i32_le(chunk)?;
135
136 let category_recovery_time = crate::util::read_i32_le(chunk)?;
138
139 let interrupt_flags = crate::util::read_i32_le(chunk)?;
141
142 let aura_interrupt_flags = crate::util::read_i32_le(chunk)?;
144
145 let channel_interrupt_flags = crate::util::read_i32_le(chunk)?;
147
148 let proc_type_mask = crate::util::read_i32_le(chunk)?;
150
151 let proc_chance = crate::util::read_i32_le(chunk)?;
153
154 let proc_charges = crate::util::read_i32_le(chunk)?;
156
157 let max_level = crate::util::read_i32_le(chunk)?;
159
160 let base_level = crate::util::read_i32_le(chunk)?;
162
163 let spell_level = crate::util::read_i32_le(chunk)?;
165
166 let duration_index = SpellDurationKey::new(crate::util::read_i32_le(chunk)?.into());
168
169 let power_type = crate::util::read_i32_le(chunk)?;
171
172 let mana_cost = crate::util::read_i32_le(chunk)?;
174
175 let mana_cost_per_level = crate::util::read_i32_le(chunk)?;
177
178 let mana_per_second = crate::util::read_i32_le(chunk)?;
180
181 let mana_per_second_per_level = crate::util::read_i32_le(chunk)?;
183
184 let range_index = crate::util::read_i32_le(chunk)?;
186
187 let speed = crate::util::read_f32_le(chunk)?;
189
190 let modal_next_spell = crate::util::read_i32_le(chunk)?;
192
193 let cumulative_aura = crate::util::read_i32_le(chunk)?;
195
196 let totem = crate::util::read_array_i32::<2>(chunk)?;
198
199 let reagent = crate::util::read_array_i32::<8>(chunk)?;
201
202 let reagent_count = crate::util::read_array_i32::<8>(chunk)?;
204
205 let equipped_item_class = crate::util::read_i32_le(chunk)?;
207
208 let equipped_item_subclass = crate::util::read_i32_le(chunk)?;
210
211 let equipped_item_inv_types = crate::util::read_i32_le(chunk)?;
213
214 let effect = crate::util::read_array_i32::<3>(chunk)?;
216
217 let effect_die_sides = crate::util::read_array_i32::<3>(chunk)?;
219
220 let effect_base_dice = crate::util::read_array_i32::<3>(chunk)?;
222
223 let effect_dice_per_level = crate::util::read_array_i32::<3>(chunk)?;
225
226 let effect_real_points_per_level = crate::util::read_array_f32::<3>(chunk)?;
228
229 let effect_base_points = crate::util::read_array_i32::<3>(chunk)?;
231
232 let effect_mechanic = crate::util::read_array_i32::<3>(chunk)?;
234
235 let implicit_target_a = crate::util::read_array_i32::<3>(chunk)?;
237
238 let implicit_target_b = crate::util::read_array_i32::<3>(chunk)?;
240
241 let effect_radius_index = crate::util::read_array_i32::<3>(chunk)?;
243
244 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 let effect_aura_period = crate::util::read_array_i32::<3>(chunk)?;
256
257 let effect_amplitude = crate::util::read_array_f32::<3>(chunk)?;
259
260 let effect_chain_targets = crate::util::read_array_i32::<3>(chunk)?;
262
263 let effect_item_type = crate::util::read_array_i32::<3>(chunk)?;
265
266 let effect_misc_value = crate::util::read_array_i32::<3>(chunk)?;
268
269 let effect_misc_value_b = crate::util::read_array_i32::<3>(chunk)?;
271
272 let effect_trigger_spell = crate::util::read_array_i32::<3>(chunk)?;
274
275 let effect_points_per_combo = crate::util::read_array_f32::<3>(chunk)?;
277
278 let spell_visual_id = crate::util::read_array_i32::<2>(chunk)?;
280
281 let spell_icon_id = SpellIconKey::new(crate::util::read_i32_le(chunk)?.into());
283
284 let active_icon_id = SpellIconKey::new(crate::util::read_i32_le(chunk)?.into());
286
287 let spell_priority = crate::util::read_i32_le(chunk)?;
289
290 let name_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
292
293 let name_subtext_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
295
296 let description_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
298
299 let aura_description_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
301
302 let mana_cost_pct = crate::util::read_i32_le(chunk)?;
304
305 let start_recovery_category = crate::util::read_i32_le(chunk)?;
307
308 let start_recovery_time = crate::util::read_i32_le(chunk)?;
310
311 let max_target_level = crate::util::read_i32_le(chunk)?;
313
314 let spell_class_set = crate::util::read_i32_le(chunk)?;
316
317 let spell_class_mask = crate::util::read_array_i32::<2>(chunk)?;
319
320 let max_targets = crate::util::read_i32_le(chunk)?;
322
323 let defense_type = crate::util::read_i32_le(chunk)?;
325
326 let prevention_type = crate::util::read_i32_le(chunk)?;
328
329 let stance_bar_order = crate::util::read_i32_le(chunk)?;
331
332 let effect_chain_amplitude = crate::util::read_array_f32::<3>(chunk)?;
334
335 let min_faction_id = FactionKey::new(crate::util::read_i32_le(chunk)?.into());
337
338 let min_reputation = crate::util::read_i32_le(chunk)?;
340
341 let required_aura_vision = crate::util::read_i32_le(chunk)?;
343
344 let required_totem_category_id = crate::util::read_array_i32::<2>(chunk)?;
346
347 let required_areas_id = crate::util::read_i32_le(chunk)?;
349
350 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 b.write_all(&row.id.id.to_le_bytes())?;
469
470 b.write_all(&(row.category.id as i32).to_le_bytes())?;
472
473 b.write_all(&row.cast_u_i.to_le_bytes())?;
475
476 b.write_all(&(row.dispel_type.id as i32).to_le_bytes())?;
478
479 b.write_all(&(row.mechanic.id as i32).to_le_bytes())?;
481
482 b.write_all(&row.attributes.to_le_bytes())?;
484
485 b.write_all(&row.attributes_ex.to_le_bytes())?;
487
488 b.write_all(&row.attributes_ex_b.to_le_bytes())?;
490
491 b.write_all(&row.attributes_ex_c.to_le_bytes())?;
493
494 b.write_all(&row.attributes_ex_d.to_le_bytes())?;
496
497 b.write_all(&row.attributes_ex_e.to_le_bytes())?;
499
500 b.write_all(&row.attributes_ex_f.to_le_bytes())?;
502
503 b.write_all(&row.shapeshift_mask.to_le_bytes())?;
505
506 b.write_all(&row.shapeshift_exclude.to_le_bytes())?;
508
509 b.write_all(&row.targets.to_le_bytes())?;
511
512 b.write_all(&row.target_creature_type.to_le_bytes())?;
514
515 b.write_all(&(row.requires_spell_focus.id as i32).to_le_bytes())?;
517
518 b.write_all(&row.facing_caster_flags.to_le_bytes())?;
520
521 b.write_all(&row.caster_aura_state.to_le_bytes())?;
523
524 b.write_all(&row.target_aura_state.to_le_bytes())?;
526
527 b.write_all(&row.exclude_caster_aura_state.to_le_bytes())?;
529
530 b.write_all(&row.exclude_target_aura_state.to_le_bytes())?;
532
533 b.write_all(&(row.casting_time_index.id as i32).to_le_bytes())?;
535
536 b.write_all(&row.recovery_time.to_le_bytes())?;
538
539 b.write_all(&row.category_recovery_time.to_le_bytes())?;
541
542 b.write_all(&row.interrupt_flags.to_le_bytes())?;
544
545 b.write_all(&row.aura_interrupt_flags.to_le_bytes())?;
547
548 b.write_all(&row.channel_interrupt_flags.to_le_bytes())?;
550
551 b.write_all(&row.proc_type_mask.to_le_bytes())?;
553
554 b.write_all(&row.proc_chance.to_le_bytes())?;
556
557 b.write_all(&row.proc_charges.to_le_bytes())?;
559
560 b.write_all(&row.max_level.to_le_bytes())?;
562
563 b.write_all(&row.base_level.to_le_bytes())?;
565
566 b.write_all(&row.spell_level.to_le_bytes())?;
568
569 b.write_all(&(row.duration_index.id as i32).to_le_bytes())?;
571
572 b.write_all(&row.power_type.to_le_bytes())?;
574
575 b.write_all(&row.mana_cost.to_le_bytes())?;
577
578 b.write_all(&row.mana_cost_per_level.to_le_bytes())?;
580
581 b.write_all(&row.mana_per_second.to_le_bytes())?;
583
584 b.write_all(&row.mana_per_second_per_level.to_le_bytes())?;
586
587 b.write_all(&row.range_index.to_le_bytes())?;
589
590 b.write_all(&row.speed.to_le_bytes())?;
592
593 b.write_all(&row.modal_next_spell.to_le_bytes())?;
595
596 b.write_all(&row.cumulative_aura.to_le_bytes())?;
598
599 for i in row.totem {
601 b.write_all(&i.to_le_bytes())?;
602 }
603
604
605 for i in row.reagent {
607 b.write_all(&i.to_le_bytes())?;
608 }
609
610
611 for i in row.reagent_count {
613 b.write_all(&i.to_le_bytes())?;
614 }
615
616
617 b.write_all(&row.equipped_item_class.to_le_bytes())?;
619
620 b.write_all(&row.equipped_item_subclass.to_le_bytes())?;
622
623 b.write_all(&row.equipped_item_inv_types.to_le_bytes())?;
625
626 for i in row.effect {
628 b.write_all(&i.to_le_bytes())?;
629 }
630
631
632 for i in row.effect_die_sides {
634 b.write_all(&i.to_le_bytes())?;
635 }
636
637
638 for i in row.effect_base_dice {
640 b.write_all(&i.to_le_bytes())?;
641 }
642
643
644 for i in row.effect_dice_per_level {
646 b.write_all(&i.to_le_bytes())?;
647 }
648
649
650 for i in row.effect_real_points_per_level {
652 b.write_all(&i.to_le_bytes())?;
653 }
654
655
656 for i in row.effect_base_points {
658 b.write_all(&i.to_le_bytes())?;
659 }
660
661
662 for i in row.effect_mechanic {
664 b.write_all(&i.to_le_bytes())?;
665 }
666
667
668 for i in row.implicit_target_a {
670 b.write_all(&i.to_le_bytes())?;
671 }
672
673
674 for i in row.implicit_target_b {
676 b.write_all(&i.to_le_bytes())?;
677 }
678
679
680 for i in row.effect_radius_index {
682 b.write_all(&i.to_le_bytes())?;
683 }
684
685
686 for i in row.effect_aura {
688 b.write_all(&(i.as_int() as i32).to_le_bytes())?;
689 }
690
691
692 for i in row.effect_aura_period {
694 b.write_all(&i.to_le_bytes())?;
695 }
696
697
698 for i in row.effect_amplitude {
700 b.write_all(&i.to_le_bytes())?;
701 }
702
703
704 for i in row.effect_chain_targets {
706 b.write_all(&i.to_le_bytes())?;
707 }
708
709
710 for i in row.effect_item_type {
712 b.write_all(&i.to_le_bytes())?;
713 }
714
715
716 for i in row.effect_misc_value {
718 b.write_all(&i.to_le_bytes())?;
719 }
720
721
722 for i in row.effect_misc_value_b {
724 b.write_all(&i.to_le_bytes())?;
725 }
726
727
728 for i in row.effect_trigger_spell {
730 b.write_all(&i.to_le_bytes())?;
731 }
732
733
734 for i in row.effect_points_per_combo {
736 b.write_all(&i.to_le_bytes())?;
737 }
738
739
740 for i in row.spell_visual_id {
742 b.write_all(&i.to_le_bytes())?;
743 }
744
745
746 b.write_all(&(row.spell_icon_id.id as i32).to_le_bytes())?;
748
749 b.write_all(&(row.active_icon_id.id as i32).to_le_bytes())?;
751
752 b.write_all(&row.spell_priority.to_le_bytes())?;
754
755 b.write_all(&row.name_lang.string_indices_as_array(&mut string_index))?;
757
758 b.write_all(&row.name_subtext_lang.string_indices_as_array(&mut string_index))?;
760
761 b.write_all(&row.description_lang.string_indices_as_array(&mut string_index))?;
763
764 b.write_all(&row.aura_description_lang.string_indices_as_array(&mut string_index))?;
766
767 b.write_all(&row.mana_cost_pct.to_le_bytes())?;
769
770 b.write_all(&row.start_recovery_category.to_le_bytes())?;
772
773 b.write_all(&row.start_recovery_time.to_le_bytes())?;
775
776 b.write_all(&row.max_target_level.to_le_bytes())?;
778
779 b.write_all(&row.spell_class_set.to_le_bytes())?;
781
782 for i in row.spell_class_mask {
784 b.write_all(&i.to_le_bytes())?;
785 }
786
787
788 b.write_all(&row.max_targets.to_le_bytes())?;
790
791 b.write_all(&row.defense_type.to_le_bytes())?;
793
794 b.write_all(&row.prevention_type.to_le_bytes())?;
796
797 b.write_all(&row.stance_bar_order.to_le_bytes())?;
799
800 for i in row.effect_chain_amplitude {
802 b.write_all(&i.to_le_bytes())?;
803 }
804
805
806 b.write_all(&(row.min_faction_id.id as i32).to_le_bytes())?;
808
809 b.write_all(&row.min_reputation.to_le_bytes())?;
811
812 b.write_all(&row.required_aura_vision.to_le_bytes())?;
814
815 for i in row.required_totem_category_id {
817 b.write_all(&i.to_le_bytes())?;
818 }
819
820
821 b.write_all(&row.required_areas_id.to_le_bytes())?;
823
824 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