1use crate::{
2 DbcTable, Indexable,
3};
4use crate::header::{
5 DbcHeader, HEADER_SIZE, parse_header,
6};
7use crate::wrath_tables::footstep_terrain_lookup::FootstepTerrainLookupKey;
8use crate::wrath_tables::sound_entries::SoundEntriesKey;
9use std::io::Write;
10
11#[derive(Debug, Clone, PartialEq, PartialOrd)]
12pub struct CreatureSoundData {
13 pub rows: Vec<CreatureSoundDataRow>,
14}
15
16impl DbcTable for CreatureSoundData {
17 type Row = CreatureSoundDataRow;
18
19 const FILENAME: &'static str = "CreatureSoundData.dbc";
20
21 fn rows(&self) -> &[Self::Row] { &self.rows }
22 fn rows_mut(&mut self) -> &mut [Self::Row] { &mut self.rows }
23
24 fn read(b: &mut impl std::io::Read) -> Result<Self, crate::DbcError> {
25 let mut header = [0_u8; HEADER_SIZE];
26 b.read_exact(&mut header)?;
27 let header = parse_header(&header)?;
28
29 if header.record_size != 152 {
30 return Err(crate::DbcError::InvalidHeader(
31 crate::InvalidHeaderError::RecordSize {
32 expected: 152,
33 actual: header.record_size,
34 },
35 ));
36 }
37
38 if header.field_count != 38 {
39 return Err(crate::DbcError::InvalidHeader(
40 crate::InvalidHeaderError::FieldCount {
41 expected: 38,
42 actual: header.field_count,
43 },
44 ));
45 }
46
47 let mut r = vec![0_u8; (header.record_count * header.record_size) as usize];
48 b.read_exact(&mut r)?;
49
50 let mut rows = Vec::with_capacity(header.record_count as usize);
51
52 for mut chunk in r.chunks(header.record_size as usize) {
53 let chunk = &mut chunk;
54
55 let id = CreatureSoundDataKey::new(crate::util::read_i32_le(chunk)?);
57
58 let sound_exertion_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
60
61 let sound_exertion_critical_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
63
64 let sound_injury_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
66
67 let sound_injury_critical_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
69
70 let sound_injury_crushing_blow_id = crate::util::read_i32_le(chunk)?;
72
73 let sound_death_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
75
76 let sound_stun_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
78
79 let sound_stand_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
81
82 let sound_footstep_id = FootstepTerrainLookupKey::new(crate::util::read_i32_le(chunk)?.into());
84
85 let sound_aggro_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
87
88 let sound_wing_flap_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
90
91 let sound_wing_glide_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
93
94 let sound_alert_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
96
97 let sound_fidget = crate::util::read_array_i32::<5>(chunk)?;
99
100 let custom_attack = crate::util::read_array_i32::<4>(chunk)?;
102
103 let n_p_c_sound_id = crate::util::read_i32_le(chunk)?;
105
106 let loop_sound_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
108
109 let creature_impact_type = crate::util::read_i32_le(chunk)?;
111
112 let sound_jump_start_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
114
115 let sound_jump_end_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
117
118 let sound_pet_attack_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
120
121 let sound_pet_order_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
123
124 let sound_pet_dismiss_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
126
127 let fidget_delay_seconds_min = crate::util::read_f32_le(chunk)?;
129
130 let fidget_delay_seconds_max = crate::util::read_f32_le(chunk)?;
132
133 let birth_sound_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
135
136 let spell_cast_directed_sound_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
138
139 let submerge_sound_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
141
142 let submerged_sound_id = SoundEntriesKey::new(crate::util::read_i32_le(chunk)?.into());
144
145 let creature_sound_data_id_pet = CreatureSoundDataKey::new(crate::util::read_i32_le(chunk)?.into());
147
148
149 rows.push(CreatureSoundDataRow {
150 id,
151 sound_exertion_id,
152 sound_exertion_critical_id,
153 sound_injury_id,
154 sound_injury_critical_id,
155 sound_injury_crushing_blow_id,
156 sound_death_id,
157 sound_stun_id,
158 sound_stand_id,
159 sound_footstep_id,
160 sound_aggro_id,
161 sound_wing_flap_id,
162 sound_wing_glide_id,
163 sound_alert_id,
164 sound_fidget,
165 custom_attack,
166 n_p_c_sound_id,
167 loop_sound_id,
168 creature_impact_type,
169 sound_jump_start_id,
170 sound_jump_end_id,
171 sound_pet_attack_id,
172 sound_pet_order_id,
173 sound_pet_dismiss_id,
174 fidget_delay_seconds_min,
175 fidget_delay_seconds_max,
176 birth_sound_id,
177 spell_cast_directed_sound_id,
178 submerge_sound_id,
179 submerged_sound_id,
180 creature_sound_data_id_pet,
181 });
182 }
183
184 Ok(CreatureSoundData { rows, })
185 }
186
187 fn write(&self, b: &mut impl Write) -> Result<(), std::io::Error> {
188 let header = DbcHeader {
189 record_count: self.rows.len() as u32,
190 field_count: 38,
191 record_size: 152,
192 string_block_size: 1,
193 };
194
195 b.write_all(&header.write_header())?;
196
197 for row in &self.rows {
198 b.write_all(&row.id.id.to_le_bytes())?;
200
201 b.write_all(&(row.sound_exertion_id.id as i32).to_le_bytes())?;
203
204 b.write_all(&(row.sound_exertion_critical_id.id as i32).to_le_bytes())?;
206
207 b.write_all(&(row.sound_injury_id.id as i32).to_le_bytes())?;
209
210 b.write_all(&(row.sound_injury_critical_id.id as i32).to_le_bytes())?;
212
213 b.write_all(&row.sound_injury_crushing_blow_id.to_le_bytes())?;
215
216 b.write_all(&(row.sound_death_id.id as i32).to_le_bytes())?;
218
219 b.write_all(&(row.sound_stun_id.id as i32).to_le_bytes())?;
221
222 b.write_all(&(row.sound_stand_id.id as i32).to_le_bytes())?;
224
225 b.write_all(&(row.sound_footstep_id.id as i32).to_le_bytes())?;
227
228 b.write_all(&(row.sound_aggro_id.id as i32).to_le_bytes())?;
230
231 b.write_all(&(row.sound_wing_flap_id.id as i32).to_le_bytes())?;
233
234 b.write_all(&(row.sound_wing_glide_id.id as i32).to_le_bytes())?;
236
237 b.write_all(&(row.sound_alert_id.id as i32).to_le_bytes())?;
239
240 for i in row.sound_fidget {
242 b.write_all(&i.to_le_bytes())?;
243 }
244
245
246 for i in row.custom_attack {
248 b.write_all(&i.to_le_bytes())?;
249 }
250
251
252 b.write_all(&row.n_p_c_sound_id.to_le_bytes())?;
254
255 b.write_all(&(row.loop_sound_id.id as i32).to_le_bytes())?;
257
258 b.write_all(&row.creature_impact_type.to_le_bytes())?;
260
261 b.write_all(&(row.sound_jump_start_id.id as i32).to_le_bytes())?;
263
264 b.write_all(&(row.sound_jump_end_id.id as i32).to_le_bytes())?;
266
267 b.write_all(&(row.sound_pet_attack_id.id as i32).to_le_bytes())?;
269
270 b.write_all(&(row.sound_pet_order_id.id as i32).to_le_bytes())?;
272
273 b.write_all(&(row.sound_pet_dismiss_id.id as i32).to_le_bytes())?;
275
276 b.write_all(&row.fidget_delay_seconds_min.to_le_bytes())?;
278
279 b.write_all(&row.fidget_delay_seconds_max.to_le_bytes())?;
281
282 b.write_all(&(row.birth_sound_id.id as i32).to_le_bytes())?;
284
285 b.write_all(&(row.spell_cast_directed_sound_id.id as i32).to_le_bytes())?;
287
288 b.write_all(&(row.submerge_sound_id.id as i32).to_le_bytes())?;
290
291 b.write_all(&(row.submerged_sound_id.id as i32).to_le_bytes())?;
293
294 b.write_all(&(row.creature_sound_data_id_pet.id as i32).to_le_bytes())?;
296
297 }
298
299 b.write_all(&[0_u8])?;
300
301 Ok(())
302 }
303
304}
305
306impl Indexable for CreatureSoundData {
307 type PrimaryKey = CreatureSoundDataKey;
308 fn get(&self, key: impl TryInto<Self::PrimaryKey>) -> Option<&Self::Row> {
309 let key = key.try_into().ok()?;
310 self.rows.iter().find(|a| a.id.id == key.id)
311 }
312
313 fn get_mut(&mut self, key: impl TryInto<Self::PrimaryKey>) -> Option<&mut Self::Row> {
314 let key = key.try_into().ok()?;
315 self.rows.iter_mut().find(|a| a.id.id == key.id)
316 }
317}
318
319#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default)]
320pub struct CreatureSoundDataKey {
321 pub id: i32
322}
323
324impl CreatureSoundDataKey {
325 pub const fn new(id: i32) -> Self {
326 Self { id }
327 }
328
329}
330
331impl From<u8> for CreatureSoundDataKey {
332 fn from(v: u8) -> Self {
333 Self::new(v.into())
334 }
335}
336
337impl From<u16> for CreatureSoundDataKey {
338 fn from(v: u16) -> Self {
339 Self::new(v.into())
340 }
341}
342
343impl From<i8> for CreatureSoundDataKey {
344 fn from(v: i8) -> Self {
345 Self::new(v.into())
346 }
347}
348
349impl From<i16> for CreatureSoundDataKey {
350 fn from(v: i16) -> Self {
351 Self::new(v.into())
352 }
353}
354
355impl From<i32> for CreatureSoundDataKey {
356 fn from(v: i32) -> Self {
357 Self::new(v)
358 }
359}
360
361impl TryFrom<u32> for CreatureSoundDataKey {
362 type Error = u32;
363 fn try_from(v: u32) -> Result<Self, Self::Error> {
364 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
365 }
366}
367
368impl TryFrom<usize> for CreatureSoundDataKey {
369 type Error = usize;
370 fn try_from(v: usize) -> Result<Self, Self::Error> {
371 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
372 }
373}
374
375impl TryFrom<u64> for CreatureSoundDataKey {
376 type Error = u64;
377 fn try_from(v: u64) -> Result<Self, Self::Error> {
378 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
379 }
380}
381
382impl TryFrom<i64> for CreatureSoundDataKey {
383 type Error = i64;
384 fn try_from(v: i64) -> Result<Self, Self::Error> {
385 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
386 }
387}
388
389impl TryFrom<isize> for CreatureSoundDataKey {
390 type Error = isize;
391 fn try_from(v: isize) -> Result<Self, Self::Error> {
392 Ok(TryInto::<i32>::try_into(v).ok().ok_or(v)?.into())
393 }
394}
395
396#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
397pub struct CreatureSoundDataRow {
398 pub id: CreatureSoundDataKey,
399 pub sound_exertion_id: SoundEntriesKey,
400 pub sound_exertion_critical_id: SoundEntriesKey,
401 pub sound_injury_id: SoundEntriesKey,
402 pub sound_injury_critical_id: SoundEntriesKey,
403 pub sound_injury_crushing_blow_id: i32,
404 pub sound_death_id: SoundEntriesKey,
405 pub sound_stun_id: SoundEntriesKey,
406 pub sound_stand_id: SoundEntriesKey,
407 pub sound_footstep_id: FootstepTerrainLookupKey,
408 pub sound_aggro_id: SoundEntriesKey,
409 pub sound_wing_flap_id: SoundEntriesKey,
410 pub sound_wing_glide_id: SoundEntriesKey,
411 pub sound_alert_id: SoundEntriesKey,
412 pub sound_fidget: [i32; 5],
413 pub custom_attack: [i32; 4],
414 pub n_p_c_sound_id: i32,
415 pub loop_sound_id: SoundEntriesKey,
416 pub creature_impact_type: i32,
417 pub sound_jump_start_id: SoundEntriesKey,
418 pub sound_jump_end_id: SoundEntriesKey,
419 pub sound_pet_attack_id: SoundEntriesKey,
420 pub sound_pet_order_id: SoundEntriesKey,
421 pub sound_pet_dismiss_id: SoundEntriesKey,
422 pub fidget_delay_seconds_min: f32,
423 pub fidget_delay_seconds_max: f32,
424 pub birth_sound_id: SoundEntriesKey,
425 pub spell_cast_directed_sound_id: SoundEntriesKey,
426 pub submerge_sound_id: SoundEntriesKey,
427 pub submerged_sound_id: SoundEntriesKey,
428 pub creature_sound_data_id_pet: CreatureSoundDataKey,
429}
430