use crate::{
DbcTable, ExtendedLocalizedString, Indexable,
};
use crate::header::{
DbcHeader, HEADER_SIZE, parse_header,
};
use crate::wrath_tables::area_group::AreaGroupKey;
use crate::wrath_tables::faction::FactionKey;
use crate::wrath_tables::power_display::PowerDisplayKey;
use crate::wrath_tables::spell_cast_times::SpellCastTimesKey;
use crate::wrath_tables::spell_category::SpellCategoryKey;
use crate::wrath_tables::spell_description_variables::SpellDescriptionVariablesKey;
use crate::wrath_tables::spell_dispel_type::SpellDispelTypeKey;
use crate::wrath_tables::spell_duration::SpellDurationKey;
use crate::wrath_tables::spell_focus_object::SpellFocusObjectKey;
use crate::wrath_tables::spell_icon::SpellIconKey;
use crate::wrath_tables::spell_mechanic::SpellMechanicKey;
use crate::wrath_tables::spell_missile::SpellMissileKey;
use crate::wrath_tables::spell_rune_cost::SpellRuneCostKey;
use std::io::Write;
use wow_world_base::wrath::AuraMod;
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Spell {
pub rows: Vec<SpellRow>,
}
impl DbcTable for Spell {
type Row = SpellRow;
const FILENAME: &'static str = "Spell.dbc";
fn rows(&self) -> &[Self::Row] { &self.rows }
fn rows_mut(&mut self) -> &mut [Self::Row] { &mut self.rows }
fn read(b: &mut impl std::io::Read) -> Result<Self, crate::DbcError> {
let mut header = [0_u8; HEADER_SIZE];
b.read_exact(&mut header)?;
let header = parse_header(&header)?;
if header.record_size != 936 {
return Err(crate::DbcError::InvalidHeader(
crate::InvalidHeaderError::RecordSize {
expected: 936,
actual: header.record_size,
},
));
}
if header.field_count != 234 {
return Err(crate::DbcError::InvalidHeader(
crate::InvalidHeaderError::FieldCount {
expected: 234,
actual: header.field_count,
},
));
}
let mut r = vec![0_u8; (header.record_count * header.record_size) as usize];
b.read_exact(&mut r)?;
let mut string_block = vec![0_u8; header.string_block_size as usize];
b.read_exact(&mut string_block)?;
let mut rows = Vec::with_capacity(header.record_count as usize);
for mut chunk in r.chunks(header.record_size as usize) {
let chunk = &mut chunk;
let id = SpellKey::new(crate::util::read_i32_le(chunk)?);
let category = SpellCategoryKey::new(crate::util::read_i32_le(chunk)?.into());
let dispel_type = SpellDispelTypeKey::new(crate::util::read_i32_le(chunk)?.into());
let mechanic = SpellMechanicKey::new(crate::util::read_i32_le(chunk)?.into());
let attributes = crate::util::read_i32_le(chunk)?;
let attributes_ex = crate::util::read_i32_le(chunk)?;
let attributes_ex_b = crate::util::read_i32_le(chunk)?;
let attributes_ex_c = crate::util::read_i32_le(chunk)?;
let attributes_ex_d = crate::util::read_i32_le(chunk)?;
let attributes_ex_e = crate::util::read_i32_le(chunk)?;
let attributes_ex_f = crate::util::read_i32_le(chunk)?;
let attributes_ex_g = crate::util::read_i32_le(chunk)?;
let shapeshift_mask = crate::util::read_array_i32::<2>(chunk)?;
let shapeshift_exclude = crate::util::read_array_i32::<2>(chunk)?;
let targets = crate::util::read_i32_le(chunk)?;
let target_creature_type = crate::util::read_i32_le(chunk)?;
let requires_spell_focus = SpellFocusObjectKey::new(crate::util::read_i32_le(chunk)?.into());
let facing_caster_flags = crate::util::read_i32_le(chunk)?;
let caster_aura_state = crate::util::read_i32_le(chunk)?;
let target_aura_state = crate::util::read_i32_le(chunk)?;
let exclude_caster_aura_state = crate::util::read_i32_le(chunk)?;
let exclude_target_aura_state = crate::util::read_i32_le(chunk)?;
let caster_aura_spell = crate::util::read_i32_le(chunk)?;
let target_aura_spell = crate::util::read_i32_le(chunk)?;
let exclude_caster_aura_spell = crate::util::read_i32_le(chunk)?;
let exclude_target_aura_spell = crate::util::read_i32_le(chunk)?;
let casting_time_index = SpellCastTimesKey::new(crate::util::read_i32_le(chunk)?.into());
let recovery_time = crate::util::read_i32_le(chunk)?;
let category_recovery_time = crate::util::read_i32_le(chunk)?;
let interrupt_flags = crate::util::read_i32_le(chunk)?;
let aura_interrupt_flags = crate::util::read_i32_le(chunk)?;
let channel_interrupt_flags = crate::util::read_i32_le(chunk)?;
let proc_type_mask = crate::util::read_i32_le(chunk)?;
let proc_chance = crate::util::read_i32_le(chunk)?;
let proc_charges = crate::util::read_i32_le(chunk)?;
let max_level = crate::util::read_i32_le(chunk)?;
let base_level = crate::util::read_i32_le(chunk)?;
let spell_level = crate::util::read_i32_le(chunk)?;
let duration_index = SpellDurationKey::new(crate::util::read_i32_le(chunk)?.into());
let power_type = crate::util::read_i32_le(chunk)?;
let mana_cost = crate::util::read_i32_le(chunk)?;
let mana_cost_per_level = crate::util::read_i32_le(chunk)?;
let mana_per_second = crate::util::read_i32_le(chunk)?;
let mana_per_second_per_level = crate::util::read_i32_le(chunk)?;
let range_index = crate::util::read_i32_le(chunk)?;
let speed = crate::util::read_f32_le(chunk)?;
let modal_next_spell = crate::util::read_i32_le(chunk)?;
let cumulative_aura = crate::util::read_i32_le(chunk)?;
let totem = crate::util::read_array_i32::<2>(chunk)?;
let reagent = crate::util::read_array_i32::<8>(chunk)?;
let reagent_count = crate::util::read_array_i32::<8>(chunk)?;
let equipped_item_class = crate::util::read_i32_le(chunk)?;
let equipped_item_subclass = crate::util::read_i32_le(chunk)?;
let equipped_item_inv_types = crate::util::read_i32_le(chunk)?;
let effect = crate::util::read_array_i32::<3>(chunk)?;
let effect_die_sides = crate::util::read_array_i32::<3>(chunk)?;
let effect_real_points_per_level = crate::util::read_array_f32::<3>(chunk)?;
let effect_base_points = crate::util::read_array_i32::<3>(chunk)?;
let effect_mechanic = crate::util::read_array_i32::<3>(chunk)?;
let implicit_target_a = crate::util::read_array_i32::<3>(chunk)?;
let implicit_target_b = crate::util::read_array_i32::<3>(chunk)?;
let effect_radius_index = crate::util::read_array_i32::<3>(chunk)?;
let effect_aura = {
let mut arr = [AuraMod::default(); 3];
for i in arr.iter_mut() {
*i = crate::util::read_i32_le(chunk)?.try_into()?;
}
arr
};
let effect_aura_period = crate::util::read_array_i32::<3>(chunk)?;
let effect_amplitude = crate::util::read_array_f32::<3>(chunk)?;
let effect_chain_targets = crate::util::read_array_i32::<3>(chunk)?;
let effect_item_type = crate::util::read_array_i32::<3>(chunk)?;
let effect_misc_value = crate::util::read_array_i32::<3>(chunk)?;
let effect_misc_value_b = crate::util::read_array_i32::<3>(chunk)?;
let effect_trigger_spell = crate::util::read_array_i32::<3>(chunk)?;
let effect_points_per_combo = crate::util::read_array_f32::<3>(chunk)?;
let effect_spell_class_mask_a = crate::util::read_array_i32::<3>(chunk)?;
let effect_spell_class_mask_b = crate::util::read_array_i32::<3>(chunk)?;
let effect_spell_class_mask_c = crate::util::read_array_i32::<3>(chunk)?;
let spell_visual_id = crate::util::read_array_i32::<2>(chunk)?;
let spell_icon_id = SpellIconKey::new(crate::util::read_i32_le(chunk)?.into());
let active_icon_id = SpellIconKey::new(crate::util::read_i32_le(chunk)?.into());
let spell_priority = crate::util::read_i32_le(chunk)?;
let name_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
let name_subtext_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
let description_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
let aura_description_lang = crate::util::read_extended_localized_string(chunk, &string_block)?;
let mana_cost_pct = crate::util::read_i32_le(chunk)?;
let start_recovery_category = crate::util::read_i32_le(chunk)?;
let start_recovery_time = crate::util::read_i32_le(chunk)?;
let max_target_level = crate::util::read_i32_le(chunk)?;
let spell_class_set = crate::util::read_i32_le(chunk)?;
let spell_class_mask = crate::util::read_array_i32::<3>(chunk)?;
let max_targets = crate::util::read_i32_le(chunk)?;
let defense_type = crate::util::read_i32_le(chunk)?;
let prevention_type = crate::util::read_i32_le(chunk)?;
let stance_bar_order = crate::util::read_i32_le(chunk)?;
let effect_chain_amplitude = crate::util::read_array_f32::<3>(chunk)?;
let min_faction_id = FactionKey::new(crate::util::read_i32_le(chunk)?.into());
let min_reputation = crate::util::read_i32_le(chunk)?;
let required_aura_vision = crate::util::read_i32_le(chunk)?;
let required_totem_category_id = crate::util::read_array_i32::<2>(chunk)?;
let required_areas_id = AreaGroupKey::new(crate::util::read_i32_le(chunk)?.into());
let school_mask = crate::util::read_i32_le(chunk)?;
let rune_cost_id = SpellRuneCostKey::new(crate::util::read_i32_le(chunk)?.into());
let spell_missile_id = SpellMissileKey::new(crate::util::read_i32_le(chunk)?.into());
let power_display_id = PowerDisplayKey::new(crate::util::read_i32_le(chunk)?.into());
let effect_bonus_coefficient = crate::util::read_array_f32::<3>(chunk)?;
let description_variables_id = SpellDescriptionVariablesKey::new(crate::util::read_i32_le(chunk)?.into());
let difficulty = crate::util::read_i32_le(chunk)?;
rows.push(SpellRow {
id,
category,
dispel_type,
mechanic,
attributes,
attributes_ex,
attributes_ex_b,
attributes_ex_c,
attributes_ex_d,
attributes_ex_e,
attributes_ex_f,
attributes_ex_g,
shapeshift_mask,
shapeshift_exclude,
targets,
target_creature_type,
requires_spell_focus,
facing_caster_flags,
caster_aura_state,
target_aura_state,
exclude_caster_aura_state,
exclude_target_aura_state,
caster_aura_spell,
target_aura_spell,
exclude_caster_aura_spell,
exclude_target_aura_spell,
casting_time_index,
recovery_time,
category_recovery_time,
interrupt_flags,
aura_interrupt_flags,
channel_interrupt_flags,
proc_type_mask,
proc_chance,
proc_charges,
max_level,
base_level,
spell_level,
duration_index,
power_type,
mana_cost,
mana_cost_per_level,
mana_per_second,
mana_per_second_per_level,
range_index,
speed,
modal_next_spell,
cumulative_aura,
totem,
reagent,
reagent_count,
equipped_item_class,
equipped_item_subclass,
equipped_item_inv_types,
effect,
effect_die_sides,
effect_real_points_per_level,
effect_base_points,
effect_mechanic,
implicit_target_a,
implicit_target_b,
effect_radius_index,
effect_aura,
effect_aura_period,
effect_amplitude,
effect_chain_targets,
effect_item_type,
effect_misc_value,
effect_misc_value_b,
effect_trigger_spell,
effect_points_per_combo,
effect_spell_class_mask_a,
effect_spell_class_mask_b,
effect_spell_class_mask_c,
spell_visual_id,
spell_icon_id,
active_icon_id,
spell_priority,
name_lang,
name_subtext_lang,
description_lang,
aura_description_lang,
mana_cost_pct,
start_recovery_category,
start_recovery_time,
max_target_level,
spell_class_set,
spell_class_mask,
max_targets,
defense_type,
prevention_type,
stance_bar_order,
effect_chain_amplitude,
min_faction_id,
min_reputation,
required_aura_vision,
required_totem_category_id,
required_areas_id,
school_mask,
rune_cost_id,
spell_missile_id,
power_display_id,
effect_bonus_coefficient,
description_variables_id,
difficulty,
});
}
Ok(Spell { rows, })
}
fn write(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
let header = DbcHeader {
record_count: self.rows.len() as u32,
field_count: 234,
record_size: 936,
string_block_size: self.string_block_size(),
};
b.write_all(&header.write_header())?;
let mut string_index = 1;
for row in &self.rows {
b.write_all(&row.id.id.to_le_bytes())?;
b.write_all(&(row.category.id as i32).to_le_bytes())?;
b.write_all(&(row.dispel_type.id as i32).to_le_bytes())?;
b.write_all(&(row.mechanic.id as i32).to_le_bytes())?;
b.write_all(&row.attributes.to_le_bytes())?;
b.write_all(&row.attributes_ex.to_le_bytes())?;
b.write_all(&row.attributes_ex_b.to_le_bytes())?;
b.write_all(&row.attributes_ex_c.to_le_bytes())?;
b.write_all(&row.attributes_ex_d.to_le_bytes())?;
b.write_all(&row.attributes_ex_e.to_le_bytes())?;
b.write_all(&row.attributes_ex_f.to_le_bytes())?;
b.write_all(&row.attributes_ex_g.to_le_bytes())?;
for i in row.shapeshift_mask {
b.write_all(&i.to_le_bytes())?;
}
for i in row.shapeshift_exclude {
b.write_all(&i.to_le_bytes())?;
}
b.write_all(&row.targets.to_le_bytes())?;
b.write_all(&row.target_creature_type.to_le_bytes())?;
b.write_all(&(row.requires_spell_focus.id as i32).to_le_bytes())?;
b.write_all(&row.facing_caster_flags.to_le_bytes())?;
b.write_all(&row.caster_aura_state.to_le_bytes())?;
b.write_all(&row.target_aura_state.to_le_bytes())?;
b.write_all(&row.exclude_caster_aura_state.to_le_bytes())?;
b.write_all(&row.exclude_target_aura_state.to_le_bytes())?;
b.write_all(&row.caster_aura_spell.to_le_bytes())?;
b.write_all(&row.target_aura_spell.to_le_bytes())?;
b.write_all(&row.exclude_caster_aura_spell.to_le_bytes())?;
b.write_all(&row.exclude_target_aura_spell.to_le_bytes())?;
b.write_all(&(row.casting_time_index.id as i32).to_le_bytes())?;
b.write_all(&row.recovery_time.to_le_bytes())?;
b.write_all(&row.category_recovery_time.to_le_bytes())?;
b.write_all(&row.interrupt_flags.to_le_bytes())?;
b.write_all(&row.aura_interrupt_flags.to_le_bytes())?;
b.write_all(&row.channel_interrupt_flags.to_le_bytes())?;
b.write_all(&row.proc_type_mask.to_le_bytes())?;
b.write_all(&row.proc_chance.to_le_bytes())?;
b.write_all(&row.proc_charges.to_le_bytes())?;
b.write_all(&row.max_level.to_le_bytes())?;
b.write_all(&row.base_level.to_le_bytes())?;
b.write_all(&row.spell_level.to_le_bytes())?;
b.write_all(&(row.duration_index.id as i32).to_le_bytes())?;
b.write_all(&row.power_type.to_le_bytes())?;
b.write_all(&row.mana_cost.to_le_bytes())?;
b.write_all(&row.mana_cost_per_level.to_le_bytes())?;
b.write_all(&row.mana_per_second.to_le_bytes())?;
b.write_all(&row.mana_per_second_per_level.to_le_bytes())?;
b.write_all(&row.range_index.to_le_bytes())?;
b.write_all(&row.speed.to_le_bytes())?;
b.write_all(&row.modal_next_spell.to_le_bytes())?;
b.write_all(&row.cumulative_aura.to_le_bytes())?;
for i in row.totem {
b.write_all(&i.to_le_bytes())?;
}
for i in row.reagent {
b.write_all(&i.to_le_bytes())?;
}
for i in row.reagent_count {
b.write_all(&i.to_le_bytes())?;
}
b.write_all(&row.equipped_item_class.to_le_bytes())?;
b.write_all(&row.equipped_item_subclass.to_le_bytes())?;
b.write_all(&row.equipped_item_inv_types.to_le_bytes())?;
for i in row.effect {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_die_sides {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_real_points_per_level {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_base_points {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_mechanic {
b.write_all(&i.to_le_bytes())?;
}
for i in row.implicit_target_a {
b.write_all(&i.to_le_bytes())?;
}
for i in row.implicit_target_b {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_radius_index {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_aura {
b.write_all(&(i.as_int() as i32).to_le_bytes())?;
}
for i in row.effect_aura_period {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_amplitude {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_chain_targets {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_item_type {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_misc_value {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_misc_value_b {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_trigger_spell {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_points_per_combo {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_spell_class_mask_a {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_spell_class_mask_b {
b.write_all(&i.to_le_bytes())?;
}
for i in row.effect_spell_class_mask_c {
b.write_all(&i.to_le_bytes())?;
}
for i in row.spell_visual_id {
b.write_all(&i.to_le_bytes())?;
}
b.write_all(&(row.spell_icon_id.id as i32).to_le_bytes())?;
b.write_all(&(row.active_icon_id.id as i32).to_le_bytes())?;
b.write_all(&row.spell_priority.to_le_bytes())?;
b.write_all(&row.name_lang.string_indices_as_array(&mut string_index))?;
b.write_all(&row.name_subtext_lang.string_indices_as_array(&mut string_index))?;
b.write_all(&row.description_lang.string_indices_as_array(&mut string_index))?;
b.write_all(&row.aura_description_lang.string_indices_as_array(&mut string_index))?;
b.write_all(&row.mana_cost_pct.to_le_bytes())?;
b.write_all(&row.start_recovery_category.to_le_bytes())?;
b.write_all(&row.start_recovery_time.to_le_bytes())?;
b.write_all(&row.max_target_level.to_le_bytes())?;
b.write_all(&row.spell_class_set.to_le_bytes())?;
for i in row.spell_class_mask {
b.write_all(&i.to_le_bytes())?;
}
b.write_all(&row.max_targets.to_le_bytes())?;
b.write_all(&row.defense_type.to_le_bytes())?;
b.write_all(&row.prevention_type.to_le_bytes())?;
b.write_all(&row.stance_bar_order.to_le_bytes())?;
for i in row.effect_chain_amplitude {
b.write_all(&i.to_le_bytes())?;
}
b.write_all(&(row.min_faction_id.id as i32).to_le_bytes())?;
b.write_all(&row.min_reputation.to_le_bytes())?;
b.write_all(&row.required_aura_vision.to_le_bytes())?;
for i in row.required_totem_category_id {
b.write_all(&i.to_le_bytes())?;
}
b.write_all(&(row.required_areas_id.id as i32).to_le_bytes())?;
b.write_all(&row.school_mask.to_le_bytes())?;
b.write_all(&(row.rune_cost_id.id as i32).to_le_bytes())?;
b.write_all(&(row.spell_missile_id.id as i32).to_le_bytes())?;
b.write_all(&(row.power_display_id.id as i32).to_le_bytes())?;
for i in row.effect_bonus_coefficient {
b.write_all(&i.to_le_bytes())?;
}
b.write_all(&(row.description_variables_id.id as i32).to_le_bytes())?;
b.write_all(&row.difficulty.to_le_bytes())?;
}
self.write_string_block(b)?;
Ok(())
}
}
impl Indexable for Spell {
type PrimaryKey = SpellKey;
fn get(&self, key: impl TryInto<Self::PrimaryKey>) -> Option<&Self::Row> {
let key = key.try_into().ok()?;
self.rows.iter().find(|a| a.id.id == key.id)
}
fn get_mut(&mut self, key: impl TryInto<Self::PrimaryKey>) -> Option<&mut Self::Row> {
let key = key.try_into().ok()?;
self.rows.iter_mut().find(|a| a.id.id == key.id)
}
}
impl Spell {
fn write_string_block(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
b.write_all(&[0])?;
for row in &self.rows {
row.name_lang.string_block_as_array(b)?;
row.name_subtext_lang.string_block_as_array(b)?;
row.description_lang.string_block_as_array(b)?;
row.aura_description_lang.string_block_as_array(b)?;
}
Ok(())
}
fn string_block_size(&self) -> u32 {
let mut sum = 1;
for row in &self.rows {
sum += row.name_lang.string_block_size();
sum += row.name_subtext_lang.string_block_size();
sum += row.description_lang.string_block_size();
sum += row.aura_description_lang.string_block_size();
}
sum as u32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
pub struct SpellKey {
pub id: i32
}
impl SpellKey {
pub const fn new(id: i32) -> Self {
Self { id }
}
}
impl From<u8> for SpellKey {
fn from(v: u8) -> Self {
Self::new(v.into())
}
}
impl From<u16> for SpellKey {
fn from(v: u16) -> Self {
Self::new(v.into())
}
}
impl From<i8> for SpellKey {
fn from(v: i8) -> Self {
Self::new(v.into())
}
}
impl From<i16> for SpellKey {
fn from(v: i16) -> Self {
Self::new(v.into())
}
}
impl From<i32> for SpellKey {
fn from(v: i32) -> Self {
Self::new(v)
}
}
impl TryFrom<u32> for SpellKey {
type Error = u32;
fn try_from(v: u32) -> Result<Self, Self::Error> {
Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
}
}
impl TryFrom<usize> for SpellKey {
type Error = usize;
fn try_from(v: usize) -> Result<Self, Self::Error> {
Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
}
}
impl TryFrom<u64> for SpellKey {
type Error = u64;
fn try_from(v: u64) -> Result<Self, Self::Error> {
Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
}
}
impl TryFrom<i64> for SpellKey {
type Error = i64;
fn try_from(v: i64) -> Result<Self, Self::Error> {
Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
}
}
impl TryFrom<isize> for SpellKey {
type Error = isize;
fn try_from(v: isize) -> Result<Self, Self::Error> {
Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct SpellRow {
pub id: SpellKey,
pub category: SpellCategoryKey,
pub dispel_type: SpellDispelTypeKey,
pub mechanic: SpellMechanicKey,
pub attributes: i32,
pub attributes_ex: i32,
pub attributes_ex_b: i32,
pub attributes_ex_c: i32,
pub attributes_ex_d: i32,
pub attributes_ex_e: i32,
pub attributes_ex_f: i32,
pub attributes_ex_g: i32,
pub shapeshift_mask: [i32; 2],
pub shapeshift_exclude: [i32; 2],
pub targets: i32,
pub target_creature_type: i32,
pub requires_spell_focus: SpellFocusObjectKey,
pub facing_caster_flags: i32,
pub caster_aura_state: i32,
pub target_aura_state: i32,
pub exclude_caster_aura_state: i32,
pub exclude_target_aura_state: i32,
pub caster_aura_spell: i32,
pub target_aura_spell: i32,
pub exclude_caster_aura_spell: i32,
pub exclude_target_aura_spell: i32,
pub casting_time_index: SpellCastTimesKey,
pub recovery_time: i32,
pub category_recovery_time: i32,
pub interrupt_flags: i32,
pub aura_interrupt_flags: i32,
pub channel_interrupt_flags: i32,
pub proc_type_mask: i32,
pub proc_chance: i32,
pub proc_charges: i32,
pub max_level: i32,
pub base_level: i32,
pub spell_level: i32,
pub duration_index: SpellDurationKey,
pub power_type: i32,
pub mana_cost: i32,
pub mana_cost_per_level: i32,
pub mana_per_second: i32,
pub mana_per_second_per_level: i32,
pub range_index: i32,
pub speed: f32,
pub modal_next_spell: i32,
pub cumulative_aura: i32,
pub totem: [i32; 2],
pub reagent: [i32; 8],
pub reagent_count: [i32; 8],
pub equipped_item_class: i32,
pub equipped_item_subclass: i32,
pub equipped_item_inv_types: i32,
pub effect: [i32; 3],
pub effect_die_sides: [i32; 3],
pub effect_real_points_per_level: [f32; 3],
pub effect_base_points: [i32; 3],
pub effect_mechanic: [i32; 3],
pub implicit_target_a: [i32; 3],
pub implicit_target_b: [i32; 3],
pub effect_radius_index: [i32; 3],
pub effect_aura: [AuraMod; 3],
pub effect_aura_period: [i32; 3],
pub effect_amplitude: [f32; 3],
pub effect_chain_targets: [i32; 3],
pub effect_item_type: [i32; 3],
pub effect_misc_value: [i32; 3],
pub effect_misc_value_b: [i32; 3],
pub effect_trigger_spell: [i32; 3],
pub effect_points_per_combo: [f32; 3],
pub effect_spell_class_mask_a: [i32; 3],
pub effect_spell_class_mask_b: [i32; 3],
pub effect_spell_class_mask_c: [i32; 3],
pub spell_visual_id: [i32; 2],
pub spell_icon_id: SpellIconKey,
pub active_icon_id: SpellIconKey,
pub spell_priority: i32,
pub name_lang: ExtendedLocalizedString,
pub name_subtext_lang: ExtendedLocalizedString,
pub description_lang: ExtendedLocalizedString,
pub aura_description_lang: ExtendedLocalizedString,
pub mana_cost_pct: i32,
pub start_recovery_category: i32,
pub start_recovery_time: i32,
pub max_target_level: i32,
pub spell_class_set: i32,
pub spell_class_mask: [i32; 3],
pub max_targets: i32,
pub defense_type: i32,
pub prevention_type: i32,
pub stance_bar_order: i32,
pub effect_chain_amplitude: [f32; 3],
pub min_faction_id: FactionKey,
pub min_reputation: i32,
pub required_aura_vision: i32,
pub required_totem_category_id: [i32; 2],
pub required_areas_id: AreaGroupKey,
pub school_mask: i32,
pub rune_cost_id: SpellRuneCostKey,
pub spell_missile_id: SpellMissileKey,
pub power_display_id: PowerDisplayKey,
pub effect_bonus_coefficient: [f32; 3],
pub description_variables_id: SpellDescriptionVariablesKey,
pub difficulty: i32,
}