SausageAudio.cs
using Sandbox;
namespace PaintballBaddies;
// Short spatial cues with varied takes and bounded overlap. Existing master SFX
// volume still applies; none of these cues plays as an unattenuated UI sound.
public static class SausageAudio
{
private sealed class Bank
{
public readonly SoundEvent[] Events;
public int Previous=-1;
public readonly float Volume;
public Bank(string name,float volume)
{
Volume=volume;
Events=Enumerable.Range(0,4).Select(i=>new SoundEvent
{
Sounds=[SoundFile.Load($"sounds/sausage/{name}_{i}.vsnd")],Volume=1,Pitch=1,
Distance=1100,DistanceAttenuation=true,OcclusionEnabled=false,AirAbsorption=false,ReverbEnabled=false
}).ToArray();
}
}
private static readonly Dictionary<string,Bank> banks=new()
{
["plate"]=new("plate",.82f),["burst"]=new("burst",.76f),
["hit"]=new("hit",.6f),["limb"]=new("limb",.72f),
["landing"]=new("landing",.68f),["sputter"]=new("stumble",.7f)
};
private static readonly List<SoundHandle> active=new();
public static int Plays {get;private set;}
public static int BodyHits {get;private set;}
public static int LastVariation {get;private set;}
public static string LastKind {get;private set;}="";
public static int ActiveVoices=>active.Count(x=>x.IsPlaying);
public static SoundHandle Play(string kind,Vector3 point)
{
if(!banks.TryGetValue(kind,out var bank))return null;
active.RemoveAll(x=>!x.IsPlaying);
while(active.Count>=14){active[0].Stop();active.RemoveAt(0);}
// Uniformly choose from the other takes, never an immediate repeat.
int take=bank.Previous<0 ? Game.Random.Int(0,3) : (bank.Previous+Game.Random.Int(1,3))%4;
bank.Previous=take;LastVariation=take;LastKind=kind;
var handle=Sound.Play(bank.Events[take],point);
if(handle is not null)
{
handle.Volume=bank.Volume;handle.Pitch=Game.Random.Float(.97f,1.04f);
active.Add(handle);Plays++;if(kind=="hit")BodyHits++;
}
return handle;
}
}