Game/2D/MusicManager.cs
using Sandbox;
public sealed class MusicManager : Component
{
public static MusicManager Instance { get; private set; }
SoundHandle _menuMusic;
SoundHandle _windMusic;
SoundHandle _gameMusic;
// Tracked explicitly rather than inferred from SoundHandle.IsValid(), because
// a handle stopped with a fade is not reliably invalid straight away — and
// guessing wrong here means the menu comes back silent.
bool _menuPlaying;
protected override void OnStart()
{
Instance = this;
// Subscribe to game events
if (ChainReactionGame.Instance != null)
{
ChainReactionGame.Instance.OnGameStarted += OnGameStarted;
ChainReactionGame.Instance.OnGameReturned += OnGameReturned;
}
StartMenuLoops(.25f);
}
void StartMenuLoops(float volume)
{
_menuMusic = Sound.Play("phonk_menu_music", volume);
_windMusic = Sound.Play("wind_blowing_loop", volume);
_menuPlaying = true;
}
void StopMenuLoops(float fade)
{
if (_menuMusic.IsValid()) _menuMusic.Stop(fade);
if (_windMusic.IsValid()) _windMusic.Stop(fade);
_menuPlaying = false;
}
void OnGameStarted()
{
// Reactor mode is meant to be left running for a long time — the combat
// track would grate after ten minutes, so it keeps the calmer menu loop.
if (ChainReactionGame.Instance?.Mode == GameMode.Idle)
{
if (_gameMusic.IsValid()) _gameMusic.Stop(.5f);
if (!_menuPlaying) StartMenuLoops(.18f);
else if (_menuMusic.IsValid()) _menuMusic.Volume = .18f;
return;
}
StopMenuLoops(.5f);
// Only start game music if not already playing
if (!_gameMusic.IsValid())
_gameMusic = Sound.Play("abydos_game");
}
public void StopMenuMusic() => StopMenuLoops(0f);
public void PlayMenuMusic() => StartMenuLoops(.25f);
void OnGameReturned()
{
// Reactor mode never starts the combat track, so this handle can still be
// default-constructed here — calling Stop() on that throws.
if (_gameMusic.IsValid()) _gameMusic.Stop(.5f);
// Coming back from Reactor mode the menu loop never stopped — restore
// its volume instead of stacking a second copy on top of it.
if (_menuPlaying)
{
if (_menuMusic.IsValid()) _menuMusic.Volume = .3f;
return;
}
StartMenuLoops(.3f);
}
}