GameLogic/crowd/CrowdAudioController.cs
using Sandbox;
public sealed class CrowdAudioController : Component
{
[Property, Group( "Ambiance Arène" )] public SoundEvent ArenaAmbientLoop { get; set; }
[Property, Group( "Ambiance Arène" )] public float BaseAmbientVolume { get; set; } = 0.4f;
[Property, Group( "Événements de Manche" ), Title( "Clameur Début de Manche" )]
public SoundEvent RoundStartCheerSound { get; set; }
[Property, Group( "Réactions Bot" )] public SoundEvent BotKillReactionSound { get; set; }
private SoundHandle _ambientHandle;
private RealTimeSince _timeSinceLastReaction = 10f;
private float _minReactionInterval = 1.3f; // Évite la cacophonie
protected override void OnEnabled()
{
GameManager.OnPhaseChanged += HandlePhaseChanged;
}
protected override void OnDisabled()
{
GameManager.OnPhaseChanged -= HandlePhaseChanged;
}
protected override void OnStart()
{
if ( ArenaAmbientLoop != null )
{
_ambientHandle = Sound.Play( ArenaAmbientLoop );
if ( _ambientHandle != null )
_ambientHandle.Volume = BaseAmbientVolume;
}
}
protected override void OnDestroy()
{
_ambientHandle?.Stop( 0.5f );
}
private void HandlePhaseChanged( GamePhase newPhase )
{
// Déclenchement à l'entrée
if ( newPhase == GamePhase.RoundIntro )
{
PlayRoundStartReaction();
}
}
public void PlayRoundStartReaction()
{
if ( RoundStartCheerSound == null ) return;
// Force la lecture sans tenir compte du cooldown anti-spam
_timeSinceLastReaction = 0f;
Sound.Play( RoundStartCheerSound );
}
public void PlayReaction( SoundEvent sound, bool isPositive )
{
if ( sound == null ) return;
if ( _timeSinceLastReaction < _minReactionInterval )
return;
_timeSinceLastReaction = 0f;
Sound.Play( sound );
}
public void PlayBotHighlightReaction()
{
if ( BotKillReactionSound != null && _timeSinceLastReaction > 2.0f )
{
_timeSinceLastReaction = 0f;
Sound.Play( BotKillReactionSound );
}
}
}