From ea8555480e5e67e877e896971a0e196c7aebd2a3 Mon Sep 17 00:00:00 2001 From: arcattack Date: Wed, 15 Jul 2026 22:29:05 -0500 Subject: [PATCH] Audio: fix stuck MissileLoading loop -- ProjectileWeapon never reached a ready state (task #50) The runaway loop the user heard was MissileLoading01: the ProjectileWeapon (SRM/ballistic) state machine set Firing(0)/Loading(3)/Jammed(5)/NoAmmo(7) but NEVER a ready/Loaded level, so at idle the launcher parked in Loading(3) forever. Its WeaponState audio (weaponAlarm, now StateIndicator-firing) therefore looped MissileLoading indefinitely -- the loop stops only when the alarm LEAVES the loading state. (The laser sibling was fine: the Emitter DOES reach Loaded when its charge tops off, so LaserACharge stopped.) Fix: in ProjectileWeaponSimulation's default (idle/ready) branch, drive the state from readiness -- Loaded(2, charge + ammo up = silent ready) once ReadyToFire, else Loading(3, reloading). SetLevel fires audio only on a real change, so this yields the natural Firing -> Loading(reload) -> Loaded(ready) cycle and the MissileLoading loop now stops when the launcher finishes reloading. Verified: weapon cycles Loading(3, recoil>0)->Loaded(2, recoil<=0); the only remaining continuous loop is EnginePower (correct). Fire path unchanged. Also: master volume default kept; richer BT_AUDIO_LOG StopNote/SetupPatch traces. Co-Authored-By: Claude Opus 4.8 (1M context) --- engine/MUNGA_L4/L4AUDLVL.cpp | 2 +- game/reconstructed/projweap.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/engine/MUNGA_L4/L4AUDLVL.cpp b/engine/MUNGA_L4/L4AUDLVL.cpp index 53c5c3d..ee4116e 100644 --- a/engine/MUNGA_L4/L4AUDLVL.cpp +++ b/engine/MUNGA_L4/L4AUDLVL.cpp @@ -205,7 +205,7 @@ void PatchLevelOfDetail::PlayNote(SourceSet sourceSet) void PatchLevelOfDetail::StopNote(SourceSet sourceSet) { - { static int s_s=0; if (getenv("BT_AUDIO_LOG") && s_s++<30) DEBUG_STREAM << "[audio] StopNote count=" << sourceSet.count << " src0=" << (sourceSet.count>0?sourceSet.sources[0]:0) << "\n" << std::flush; } + if (getenv("BT_AUDIO_LOG")) { static int s_s=0; if (s_s++<400) { DEBUG_STREAM << "[audio] StopNote"; for (int _i=0;_i0 && sourceSet.sources != NULL) { alSourceStopv(sourceSet.count, sourceSet.sources); diff --git a/game/reconstructed/projweap.cpp b/game/reconstructed/projweap.cpp index 032adeb..2a3dc96 100644 --- a/game/reconstructed/projweap.cpp +++ b/game/reconstructed/projweap.cpp @@ -673,6 +673,18 @@ void if (weaponAlarm.GetState() != NoAmmoState && weaponAlarm.GetState() != JammedState) weaponAlarm.SetLevel(0); // Firing } + else + { + // Idle/reload: drive the ready state so the WeaponState audio is correct. + // The recon set Firing(0)/Loading(3)/Jammed/NoAmmo but NEVER a ready level, + // so at idle the launcher sat in Loading(3) forever and its WeaponState + // audio looped MissileLoading indefinitely (the loop stops only when the + // alarm LEAVES the loading state). Reflect readiness: Loaded(2, charge + + // ammo up = silent ready) once ReadyToFire, else Loading(3, reloading) -- + // SetLevel fires audio only on a real change, so this just yields the + // natural Firing -> Loading(reload) -> Loaded(ready) cycle. [T2] + weaponAlarm.SetLevel(ReadyToFire() ? 2 : 3); + } break; }