From daa9ed7cbc1a2d8aa6db64c2dc6e753fd5e50668 Mon Sep 17 00:00:00 2001 From: chexit Date: Wed, 4 Nov 2026 15:59:12 +0300 Subject: [PATCH] Use catalog sound identifiers throughout runtime Co-Authored-By: Codex --- airdef-mod/src/cinema.rs | 26 +++++---- airdef-mod/src/engines.rs | 14 +++-- airdef-mod/src/replay.rs | 14 +++-- airdef-mod/src/sim/catalog_sound_ids.rs | 14 +++++ airdef-mod/src/sim/mod.rs | 73 +++++++++++++------------ tools/gen_catalog.py | 2 + 6 files changed, 83 insertions(+), 60 deletions(-) diff --git a/airdef-mod/src/cinema.rs b/airdef-mod/src/cinema.rs index 7c731ed..bdc7eec 100644 --- a/airdef-mod/src/cinema.rs +++ b/airdef-mod/src/cinema.rs @@ -2,15 +2,17 @@ //! tail; from afar the muffled report and a late boom), and the camera's reaction (a brief //! exposure and bloom punch). Everything is a function of the blast, its distance and its age, so //! a replay hears and sees the same as the live raid did, from the replay's camera. +use crate::sim::catalog::sound; + /// The power (0 air burst .. 4 ballistic) of a blast sound event, if it is one. pub fn blast_power(event: &str) -> Option { Some(match event { - "airdef:blast.air" => 0, - "airdef:blast.medium" => 1, - "airdef:blast.big" => 2, - "airdef:blast.heavy" => 3, - "airdef:blast.huge" => 4, + sound::BLAST_AIR => 0, + sound::BLAST_MEDIUM => 1, + sound::BLAST_BIG => 2, + sound::BLAST_HEAVY => 3, + sound::BLAST_HUGE => 4, _ => return None, }) } @@ -34,7 +36,7 @@ pub const FULL: usize = 3; /// nearest of its tick. pub fn layers(power: usize, dist: f64, far: f64, gain: f32, pitch: f32, rank: usize) -> Vec { let g = gain.clamp(0.3, 2.0); - let own = ["airdef:blast.air", "airdef:blast.medium", "airdef:blast.big", "airdef:blast.heavy", "airdef:blast.huge"][power.min(4)]; + let own = [sound::BLAST_AIR, sound::BLAST_MEDIUM, sound::BLAST_BIG, sound::BLAST_HEAVY, sound::BLAST_HUGE][power.min(4)]; let layer = |name: &str, volume: f32, pitch: f32, delay: u64| Layer { name: name.to_string(), volume, pitch, delay }; let far_away = dist > far; let suffix = if far_away { "_far" } else { "" }; @@ -45,22 +47,22 @@ pub fn layers(power: usize, dist: f64, far: f64, gain: f32, pitch: f32, rank: us // The muffled report, then a deep boom that arrives late. return vec![ layer(&format!("{own}_far"), g, pitch, 0), - layer("airdef:blast.big_far", 0.7 * g, pitch * 0.6, 10 + 2 * power as u64), + layer(sound::BLAST_BIG_FAR, 0.7 * g, pitch * 0.6, 10 + 2 * power as u64), ]; } let tail = (0.45 + 0.08 * power as f32) * g; if power == 0 { // An air burst has no body of its own: the crack, the thump, the roll. vec![ - layer("airdef:blast.air", g, pitch * 1.12, 0), - layer("airdef:blast.big", 0.85 * g, pitch * 0.66, 2), - layer("airdef:blast.huge", tail, pitch * 0.5, 7), + layer(sound::BLAST_AIR, g, pitch * 1.12, 0), + layer(sound::BLAST_BIG, 0.85 * g, pitch * 0.66, 2), + layer(sound::BLAST_HUGE, tail, pitch * 0.5, 7), ] } else { vec![ layer(own, g, pitch, 0), - layer("airdef:blast.air", 0.7 * g, pitch * 1.15, 0), - layer("airdef:blast.huge", tail, pitch * 0.5, 7), + layer(sound::BLAST_AIR, 0.7 * g, pitch * 1.15, 0), + layer(sound::BLAST_HUGE, tail, pitch * 0.5, 7), ] } } diff --git a/airdef-mod/src/engines.rs b/airdef-mod/src/engines.rs index 8093a59..4a5121b 100644 --- a/airdef-mod/src/engines.rs +++ b/airdef-mod/src/engines.rs @@ -9,6 +9,8 @@ //! for a tick or two (a step the simulation skipped) does not stop the sound; a *cut* (a replay //! seek, a new shot) stops every engine and starts them again under new ids, so nothing glides //! across the jump. +use crate::sim::catalog::sound; + use glam::DVec3; use std::collections::{BTreeMap, BTreeSet}; @@ -52,12 +54,12 @@ pub enum Op { /// engine_sounds_has_no_hole` finds them (after the fade-in, before the sound begins to die). pub fn steady_part(event: &str) -> (f32, f32) { match event { - "airdef:drone.shahed" => (0.2, 2.2), - "airdef:drone.geran3" => (0.2, 2.0), - "airdef:drone.lancet" => (0.2, 1.4), - "airdef:drone.cruise" => (0.2, 2.6), - "airdef:drone.rocket" => (0.2, 2.6), - "airdef:missile.flight" => (0.2, 2.2), + sound::DRONE_SHAHED => (0.2, 2.2), + sound::DRONE_GERAN3 => (0.2, 2.0), + sound::DRONE_LANCET => (0.2, 1.4), + sound::DRONE_CRUISE => (0.2, 2.6), + sound::DRONE_ROCKET => (0.2, 2.6), + sound::MISSILE_FLIGHT => (0.2, 2.2), _ => (0.0, 0.0), } } diff --git a/airdef-mod/src/replay.rs b/airdef-mod/src/replay.rs index c707558..6575438 100644 --- a/airdef-mod/src/replay.rs +++ b/airdef-mod/src/replay.rs @@ -4,6 +4,8 @@ //! world and a director's camera (a full-screen camera view) follows them — //! behind the drone, then behind the interceptor or from the side — slowing //! time round the moment itself. +use crate::sim::catalog::sound; + use crate::film::{self, Film}; use crate::panel::distance; use crate::sim::Ground; @@ -526,11 +528,11 @@ impl Player { for e in rec.events.iter().filter(|e| (self.heard..self.t).contains(&(e.at as f64))) { let event = match e.kind { EventKind::Kill { kind, outcome, .. } => crate::sim::outcome::look(kind, outcome).3, - EventKind::Hit { power, .. } | EventKind::Crash { power, .. } => ["airdef:blast.air", "airdef:blast.medium", "airdef:blast.big", "airdef:blast.heavy", "airdef:blast.huge"][(power as usize).min(4)], - EventKind::SamLost { .. } => "airdef:blast.big", - EventKind::Split { .. } => "airdef:boom.sonic", + EventKind::Hit { power, .. } | EventKind::Crash { power, .. } => [sound::BLAST_AIR, sound::BLAST_MEDIUM, sound::BLAST_BIG, sound::BLAST_HEAVY, sound::BLAST_HUGE][(power as usize).min(4)], + EventKind::SamLost { .. } => sound::BLAST_BIG, + EventKind::Split { .. } => sound::BOOM_SONIC, EventKind::Strike { result: StrikeResult::Halted, .. } => continue, - EventKind::Strike { result, .. } => ["airdef:blast.air", "airdef:blast.medium", "airdef:blast.big", "airdef:blast.heavy", "airdef:blast.huge"][match result { + EventKind::Strike { result, .. } => [sound::BLAST_AIR, sound::BLAST_MEDIUM, sound::BLAST_BIG, sound::BLAST_HEAVY, sound::BLAST_HUGE][match result { StrikeResult::Destroyed => 4, StrikeResult::Intercepted => 0, _ => 3, @@ -539,7 +541,7 @@ impl Player { let gain = if let EventKind::Kill { kind, outcome, .. } = e.kind { crate::sim::outcome::look(kind, outcome).2 } else { 1.0 }; out.sound(event, heard(e.pos), gain, 1.0); if let EventKind::Kill { outcome: crate::sim::outcome::Outcome::AirDetonation, .. } = e.kind { - out.sound("airdef:boom.sonic", heard(e.pos), 0.8, 1.2); + out.sound(sound::BOOM_SONIC, heard(e.pos), 0.8, 1.2); } } // New recordings carry the exact launch and ignition sounds and their actual positions. @@ -570,7 +572,7 @@ impl Player { for tr in rec.tracks.iter().filter(|tr| matches!(tr.what, What::StrikeCarrier(_))) { let at = tr.first as f64 + crate::sim::strike::EJECT_TICKS as f64; if (self.heard..self.t).contains(&at) && let Some(p) = tr.at(rec.origin, at) { - out.sound("airdef:launch.s400", heard(p), 1.0, 1.0); + out.sound(sound::LAUNCH_S400, heard(p), 1.0, 1.0); } } self.heard = self.t; diff --git a/airdef-mod/src/sim/catalog_sound_ids.rs b/airdef-mod/src/sim/catalog_sound_ids.rs index b0e2cd6..b2715a5 100644 --- a/airdef-mod/src/sim/catalog_sound_ids.rs +++ b/airdef-mod/src/sim/catalog_sound_ids.rs @@ -7,16 +7,30 @@ pub const DRONE_ROCKET: &str = "airdef:drone.rocket"; pub const MISSILE_FLIGHT: &str = "airdef:missile.flight"; pub const DRONE_BALLISTIC: &str = "airdef:drone.ballistic"; pub const BOOM_SONIC: &str = "airdef:boom.sonic"; +pub const BOOM_SONIC_FAR: &str = "airdef:boom.sonic_far"; pub const LAUNCH_PATRIOT: &str = "airdef:launch.patriot"; +pub const LAUNCH_PATRIOT_FAR: &str = "airdef:launch.patriot_far"; pub const LAUNCH_S400_EJECT: &str = "airdef:launch.s400_eject"; +pub const LAUNCH_S400_EJECT_FAR: &str = "airdef:launch.s400_eject_far"; pub const LAUNCH_S400: &str = "airdef:launch.s400"; +pub const LAUNCH_S400_FAR: &str = "airdef:launch.s400_far"; pub const LAUNCH_S500_EJECT: &str = "airdef:launch.s500_eject"; +pub const LAUNCH_S500_EJECT_FAR: &str = "airdef:launch.s500_eject_far"; pub const LAUNCH_S500: &str = "airdef:launch.s500"; +pub const LAUNCH_S500_FAR: &str = "airdef:launch.s500_far"; pub const LAUNCH_PANTSIR: &str = "airdef:launch.pantsir"; +pub const LAUNCH_PANTSIR_FAR: &str = "airdef:launch.pantsir_far"; pub const GUN_GEPARD: &str = "airdef:gun.gepard"; +pub const GUN_GEPARD_FAR: &str = "airdef:gun.gepard_far"; pub const GUN_PANTSIR: &str = "airdef:gun.pantsir"; +pub const GUN_PANTSIR_FAR: &str = "airdef:gun.pantsir_far"; pub const BLAST_BIG: &str = "airdef:blast.big"; +pub const BLAST_BIG_FAR: &str = "airdef:blast.big_far"; pub const BLAST_HEAVY: &str = "airdef:blast.heavy"; +pub const BLAST_HEAVY_FAR: &str = "airdef:blast.heavy_far"; pub const BLAST_HUGE: &str = "airdef:blast.huge"; +pub const BLAST_HUGE_FAR: &str = "airdef:blast.huge_far"; pub const BLAST_MEDIUM: &str = "airdef:blast.medium"; +pub const BLAST_MEDIUM_FAR: &str = "airdef:blast.medium_far"; pub const BLAST_AIR: &str = "airdef:blast.air"; +pub const BLAST_AIR_FAR: &str = "airdef:blast.air_far"; diff --git a/airdef-mod/src/sim/mod.rs b/airdef-mod/src/sim/mod.rs index 7acc781..4914126 100644 --- a/airdef-mod/src/sim/mod.rs +++ b/airdef-mod/src/sim/mod.rs @@ -12,6 +12,7 @@ use std::collections::HashMap; pub mod battery; pub mod launch; pub mod catalog; +use catalog::sound; mod generated_bounds; mod damage; pub mod doctrine; @@ -680,11 +681,11 @@ impl DroneKind { /// The sound of a launch from the ground: a light catapult shot, a rocket booster, a heavy ballistic launch. pub fn launch_sound(self) -> &'static str { match self { - DroneKind::Shahed | DroneKind::Geran3 | DroneKind::Lancet | DroneKind::Gerbera => "airdef:launch.s400_eject", - DroneKind::Kh101 | DroneKind::Kalibr | DroneKind::Kh22 => "airdef:launch.patriot", - DroneKind::Zircon => "airdef:launch.s400", + DroneKind::Shahed | DroneKind::Geran3 | DroneKind::Lancet | DroneKind::Gerbera => sound::LAUNCH_S400_EJECT, + DroneKind::Kh101 | DroneKind::Kalibr | DroneKind::Kh22 => sound::LAUNCH_PATRIOT, + DroneKind::Zircon => sound::LAUNCH_S400, DroneKind::Iskander | DroneKind::Kinzhal | DroneKind::Oreshnik | DroneKind::OreshnikBlock | DroneKind::OreshnikSub => { - "airdef:launch.s500" + sound::LAUNCH_S500 } } } @@ -704,7 +705,7 @@ impl DroneKind { engine: Engine::Prop(1.34, 1.0), decoy: false, stealth: 1.0, - sound: ("airdef:drone.shahed", 1.0, 48), + sound: (sound::DRONE_SHAHED, 1.0, 48), class: Class::Drone, ballistic: None, }, @@ -722,7 +723,7 @@ impl DroneKind { engine: Engine::Jet(0.34, 1.55, 1.0), decoy: false, stealth: 1.1, - sound: ("airdef:drone.geran3", 1.0, 40), + sound: (sound::DRONE_GERAN3, 1.0, 40), class: Class::Jet, ballistic: None, }, @@ -740,7 +741,7 @@ impl DroneKind { engine: Engine::Prop(0.93, 0.55), decoy: false, stealth: 1.4, - sound: ("airdef:drone.lancet", 1.0, 32), + sound: (sound::DRONE_LANCET, 1.0, 32), class: Class::Drone, ballistic: None, }, @@ -758,7 +759,7 @@ impl DroneKind { engine: Engine::Prop(1.03, 0.9), decoy: true, stealth: 0.9, - sound: ("airdef:drone.shahed", 1.3, 40), + sound: (sound::DRONE_SHAHED, 1.3, 40), class: Class::Drone, ballistic: None, }, @@ -776,7 +777,7 @@ impl DroneKind { engine: Engine::Jet(-0.27, 1.4, 0.6), decoy: false, stealth: 1.5, - sound: ("airdef:drone.cruise", 1.0, 50), + sound: (sound::DRONE_CRUISE, 1.0, 50), class: Class::Cruise, ballistic: None, }, @@ -794,7 +795,7 @@ impl DroneKind { engine: Engine::Jet(-0.2, 1.5, 0.6), decoy: false, stealth: 1.3, - sound: ("airdef:drone.cruise", 1.2, 50), + sound: (sound::DRONE_CRUISE, 1.2, 50), class: Class::Cruise, ballistic: None, }, @@ -812,7 +813,7 @@ impl DroneKind { engine: Engine::Rocket(1.5, 1.3), decoy: false, stealth: 1.4, - sound: ("airdef:drone.rocket", 0.8, 46), + sound: (sound::DRONE_ROCKET, 0.8, 46), class: Class::Supersonic, ballistic: None, }, @@ -830,7 +831,7 @@ impl DroneKind { engine: Engine::Rocket(1.5, 1.1), decoy: false, stealth: 2.0, - sound: ("airdef:drone.rocket", 1.35, 46), + sound: (sound::DRONE_ROCKET, 1.35, 46), class: Class::Supersonic, ballistic: None, }, @@ -848,7 +849,7 @@ impl DroneKind { engine: Engine::Rocket(1.5, 1.6), decoy: false, stealth: 1.6, - sound: ("airdef:drone.rocket", 0.7, 46), + sound: (sound::DRONE_ROCKET, 0.7, 46), class: Class::Ballistic, ballistic: Some(1000.0), }, @@ -866,7 +867,7 @@ impl DroneKind { engine: Engine::Rocket(1.5, 1.5), decoy: false, stealth: 2.2, - sound: ("airdef:drone.rocket", 0.6, 46), + sound: (sound::DRONE_ROCKET, 0.6, 46), class: Class::Ballistic, ballistic: Some(1500.0), }, @@ -884,7 +885,7 @@ impl DroneKind { engine: Engine::Rocket(1.5, 2.4), decoy: false, stealth: 3.0, - sound: ("airdef:drone.rocket", 0.5, 46), + sound: (sound::DRONE_ROCKET, 0.5, 46), class: Class::Ballistic, ballistic: Some(2600.0), }, @@ -902,7 +903,7 @@ impl DroneKind { engine: Engine::Rocket(1.0, 1.0), decoy: false, stealth: 3.5, - sound: ("airdef:drone.ballistic", 0.8, 9999), + sound: (sound::DRONE_BALLISTIC, 0.8, 9999), class: Class::Ballistic, ballistic: None, }, @@ -920,7 +921,7 @@ impl DroneKind { engine: Engine::Rocket(1.0, 1.0), decoy: false, stealth: 4.0, - sound: ("airdef:drone.ballistic", 1.0, 9999), + sound: (sound::DRONE_BALLISTIC, 1.0, 9999), class: Class::Ballistic, ballistic: None, }, @@ -1106,13 +1107,13 @@ impl MissileKind { /// The sound of its launch. pub fn launch_sound(self) -> &'static str { match self { - MissileKind::Pac3 => "airdef:launch.patriot", - MissileKind::M57e6 => "airdef:launch.pantsir", - MissileKind::M48n6 => "airdef:launch.s400_eject", - MissileKind::M77n6 => "airdef:launch.s500_eject", - MissileKind::IrisT | MissileKind::M9m338 => "airdef:launch.s400_eject", - MissileKind::Amraam | MissileKind::M9m317 => "airdef:launch.patriot", - MissileKind::P1sun => "airdef:drone.lancet", + MissileKind::Pac3 => sound::LAUNCH_PATRIOT, + MissileKind::M57e6 => sound::LAUNCH_PANTSIR, + MissileKind::M48n6 => sound::LAUNCH_S400_EJECT, + MissileKind::M77n6 => sound::LAUNCH_S500_EJECT, + MissileKind::IrisT | MissileKind::M9m338 => sound::LAUNCH_S400_EJECT, + MissileKind::Amraam | MissileKind::M9m317 => sound::LAUNCH_PATRIOT, + MissileKind::P1sun => sound::DRONE_LANCET, } } fn spec(self) -> &'static MissileSpec { @@ -2075,13 +2076,13 @@ impl Sim { let v = (aim - d.pos).normalize_or(DVec3::NEG_Y) * 3.0; released.push((piece, d.pos + v.normalize_or_zero() * (i as f64 * 0.3), v, aim, d.sector)); } - out.sound("airdef:boom.sonic", d.pos, 1.0, 0.7); + out.sound(sound::BOOM_SONIC, d.pos, 1.0, 0.7); splits.push((d.id, d.pos)); // Its pieces count as launched instead of it. self.launched += 5; out.particles("minecraft:firework", d.pos, 1.5, DVec3::ZERO, 0.3, 40); if d.kind == DroneKind::OreshnikBlock && self.rng.chance(0.5) { - out.sound("airdef:drone.ballistic", d.pos, 1.0, 1.1); + out.sound(sound::DRONE_BALLISTIC, d.pos, 1.0, 1.1); } removed.push(d.id); continue; @@ -2106,8 +2107,8 @@ impl Sim { if d.vel.y < -1.0 && d.spin == 0.0 && d.pos.distance(d.target) < d.vel.length() * 80.0 { d.spin = 1.0; let p = if d.kind == DroneKind::Kinzhal { 0.85 } else { 1.0 }; - out.sound("airdef:drone.ballistic", d.pos, 1.0, p); - out.sound("airdef:boom.sonic", d.pos, 1.0, p); + out.sound(sound::DRONE_BALLISTIC, d.pos, 1.0, p); + out.sound(sound::BOOM_SONIC, d.pos, 1.0, p); } continue; } @@ -2401,7 +2402,7 @@ impl Sim { out.particles("minecraft:lava", pos, 1.0, DVec3::ZERO, 0.0, 16); out.particles("minecraft:campfire_signal_smoke", pos, 1.2, DVec3::new(0.0, 0.04, 0.0), 0.01, if big { 30 } else { 10 }); let pitch = 0.9 + self.vis.f() as f32 * 0.2; - let event = ["airdef:blast.air", "airdef:blast.medium", "airdef:blast.big", "airdef:blast.heavy", "airdef:blast.huge"][power]; + let event = [sound::BLAST_AIR, sound::BLAST_MEDIUM, sound::BLAST_BIG, sound::BLAST_HEAVY, sound::BLAST_HUGE][power]; out.sound(event, pos, 1.0, if small { pitch * 1.15 } else { pitch }); if power >= 3 { // A heavy warhead throws a column of dirt and a ring of dust. @@ -2518,7 +2519,7 @@ impl Sim { out.particles("minecraft:large_smoke", pos, size * 0.3, DVec3::new(0.0, 0.05, 0.0), 0.07, if self.shader { 20 } else { 40 }); out.particles("minecraft:firework", pos, 0.6, DVec3::ZERO, 0.5, 50); // The shock arrives after the flash (`boom` sounds travel); the warhead's blast hurts what is near. - out.sound("airdef:boom.sonic", pos, 0.8, 1.2); + out.sound(sound::BOOM_SONIC, pos, 0.8, 1.2); self.blast_damage(pos, 0, ground, out); } } @@ -2828,7 +2829,7 @@ impl Sim { } // A gun sound holds a few shots: one every other burst. if sam.bursts % 2 == 0 { - let event = if sam.kind == SamKind::Pantsir { "airdef:gun.pantsir" } else { "airdef:gun.gepard" }; + let event = if sam.kind == SamKind::Pantsir { sound::GUN_PANTSIR } else { sound::GUN_GEPARD }; out.sound(event, mount, 1.0, 0.95 + self.vis.f() as f32 * 0.1); } // A fresh working own-radar fire-control track does not depend on seeing the target. @@ -2937,7 +2938,7 @@ impl Sim { if spec.cold > 0 { // Thrown out by gas: a puff, a thump; the motor lights later. out.particles("minecraft:cloud", muzzle, 0.6, dir * 0.05, 0.05, 30); - let event = if kind == MissileKind::M77n6 { "airdef:launch.s500_eject" } else { "airdef:launch.s400_eject" }; + let event = if kind == MissileKind::M77n6 { sound::LAUNCH_S500_EJECT } else { sound::LAUNCH_S400_EJECT }; out.sound(event, muzzle, 1.0, 1.0); self.scene_event(muzzle, record::SceneKind::MissileLaunch { missile: id, sam, target, kind, sound: event, pitch: 1.0 }); } else { @@ -2946,7 +2947,7 @@ impl Sim { out.particles("minecraft:cloud", muzzle - dir * 2.0, 1.4, DVec3::new(0.0, 0.02, 0.0), 0.06, 70); out.particles("minecraft:campfire_cosy_smoke", muzzle - dir * 3.0, 1.2, DVec3::ZERO, 0.02, 20); } - let event = if kind == MissileKind::M57e6 { "airdef:launch.pantsir" } else { "airdef:launch.patriot" }; + let event = if kind == MissileKind::M57e6 { sound::LAUNCH_PANTSIR } else { sound::LAUNCH_PATRIOT }; let pitch = 0.95 + self.vis.f() as f32 * 0.1; out.sound(event, muzzle, 1.0, pitch); self.scene_event(muzzle, record::SceneKind::MissileLaunch { missile: id, sam, target, kind, sound: event, pitch }); @@ -3142,7 +3143,7 @@ impl Sim { continue; } if lit && m.age == spec.cold + 1 { - let sound = (spec.cold > 0 && spec.flame > 0.0).then_some(if m.kind == MissileKind::M77n6 { "airdef:launch.s500" } else { "airdef:launch.s400" }); + let sound = (spec.cold > 0 && spec.flame > 0.0).then_some(if m.kind == MissileKind::M77n6 { sound::LAUNCH_S500 } else { sound::LAUNCH_S400 }); ignitions.push((m.pos, m.id, m.kind, sound)); } if lit { @@ -3157,7 +3158,7 @@ impl Sim { out.particles("minecraft:cloud", back - new * 0.5, 0.12 * spec.scale as f32, DVec3::ZERO, 0.005, if m.age < 30 { 3 } else { 1 }); } if m.age == spec.cold + 1 && spec.cold > 0 { - let event = if m.kind == MissileKind::M77n6 { "airdef:launch.s500" } else { "airdef:launch.s400" }; + let event = if m.kind == MissileKind::M77n6 { sound::LAUNCH_S500 } else { sound::LAUNCH_S400 }; out.sound(event, m.pos, 1.0, 1.0); out.particles("minecraft:cloud", m.pos, 1.0, DVec3::ZERO, 0.08, 40); } @@ -3187,7 +3188,7 @@ impl Sim { let m = self.missiles.swap_remove(i); self.fireball(m.pos, 2.5 * m.kind.spec().scale, 7); out.particles("minecraft:explosion", m.pos, 0.4, DVec3::ZERO, 0.0, 3); - out.sound("airdef:blast.air", m.pos, 1.0, 1.25); + out.sound(sound::BLAST_AIR, m.pos, 1.0, 1.25); if let Some(t) = target.and_then(|t| self.drones.iter().position(|d| d.id == t)) { self.drones[t].engaged = self.drones[t].engaged.saturating_sub(1); if kill { diff --git a/tools/gen_catalog.py b/tools/gen_catalog.py index 22434cd..655e962 100644 --- a/tools/gen_catalog.py +++ b/tools/gen_catalog.py @@ -35,6 +35,8 @@ def generate_sound_ids(entries): event = entry["event"] name = event.replace(".", "_").upper() lines.append(f'pub const {name}: &str = "airdef:{event}";') + if entry["far"]: + lines.append(f'pub const {name}_FAR: &str = "airdef:{event}_far";') return "\n".join(lines + [""])