Add ambient music (#16829)
This commit is contained in:
@@ -11,6 +11,7 @@ using Robust.Shared.Random;
|
|||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
namespace Content.Client.Audio
|
namespace Content.Client.Audio
|
||||||
{
|
{
|
||||||
@@ -106,7 +107,19 @@ namespace Content.Client.Audio
|
|||||||
_playingCount.Remove(sound.Sound);
|
_playingCount.Remove(sound.Sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAmbienceVolume(float value) => _ambienceVolume = value;
|
private void SetAmbienceVolume(float value)
|
||||||
|
{
|
||||||
|
_ambienceVolume = value;
|
||||||
|
|
||||||
|
foreach (var (comp, values) in _playingSounds)
|
||||||
|
{
|
||||||
|
if (values.Stream == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var stream = (AudioSystem.PlayingStream) values.Stream;
|
||||||
|
stream.Volume = _params.Volume + comp.Volume + _ambienceVolume;
|
||||||
|
}
|
||||||
|
}
|
||||||
private void SetCooldown(float value) => _cooldown = value;
|
private void SetCooldown(float value) => _cooldown = value;
|
||||||
private void SetAmbientCount(int value) => _maxAmbientCount = value;
|
private void SetAmbientCount(int value) => _maxAmbientCount = value;
|
||||||
private void SetAmbientRange(float value) => _maxAmbientRange = value;
|
private void SetAmbientRange(float value) => _maxAmbientRange = value;
|
||||||
|
|||||||
@@ -1,21 +1,12 @@
|
|||||||
using System.Threading;
|
|
||||||
using Content.Client.Gameplay;
|
|
||||||
using Content.Client.GameTicking.Managers;
|
using Content.Client.GameTicking.Managers;
|
||||||
using Content.Client.Lobby;
|
using Content.Client.Lobby;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client;
|
using Robust.Client;
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.Player;
|
|
||||||
using Robust.Client.ResourceManagement;
|
|
||||||
using Robust.Client.State;
|
using Robust.Client.State;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Timer = Robust.Shared.Timing.Timer;
|
|
||||||
|
|
||||||
namespace Content.Client.Audio;
|
namespace Content.Client.Audio;
|
||||||
|
|
||||||
@@ -26,57 +17,18 @@ public sealed class BackgroundAudioSystem : EntitySystem
|
|||||||
[Dependency] private readonly IBaseClient _client = default!;
|
[Dependency] private readonly IBaseClient _client = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
||||||
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
|
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playMan = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
|
||||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
|
|
||||||
private readonly AudioParams _ambientParams = new(-10f, 1, "Master", 0, 0, 0, true, 0f);
|
|
||||||
private readonly AudioParams _lobbyParams = new(-5f, 1, "Master", 0, 0, 0, true, 0f);
|
private readonly AudioParams _lobbyParams = new(-5f, 1, "Master", 0, 0, 0, true, 0f);
|
||||||
|
|
||||||
private IPlayingAudioStream? _ambientStream;
|
|
||||||
private IPlayingAudioStream? _lobbyStream;
|
private IPlayingAudioStream? _lobbyStream;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What is currently playing.
|
|
||||||
/// </summary>
|
|
||||||
private SoundCollectionPrototype? _playingCollection;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What the ambience has been set to.
|
|
||||||
/// </summary>
|
|
||||||
private SoundCollectionPrototype? _currentCollection;
|
|
||||||
private CancellationTokenSource _timerCancelTokenSource = new();
|
|
||||||
|
|
||||||
private SoundCollectionPrototype _spaceAmbience = default!;
|
|
||||||
private SoundCollectionPrototype _stationAmbience = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_stationAmbience = _prototypeManager.Index<SoundCollectionPrototype>("StationAmbienceBase");
|
|
||||||
_spaceAmbience = _prototypeManager.Index<SoundCollectionPrototype>("SpaceAmbienceBase");
|
|
||||||
_currentCollection = _stationAmbience;
|
|
||||||
|
|
||||||
// TODO: Ideally audio loading streamed better / we have more robust audio but this is quite annoying
|
|
||||||
var cache = IoCManager.Resolve<IResourceCache>();
|
|
||||||
|
|
||||||
foreach (var audio in _spaceAmbience.PickFiles)
|
|
||||||
{
|
|
||||||
cache.GetResource<AudioResource>(audio.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
_configManager.OnValueChanged(CCVars.AmbienceVolume, AmbienceCVarChanged);
|
|
||||||
_configManager.OnValueChanged(CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
|
_configManager.OnValueChanged(CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
|
||||||
_configManager.OnValueChanged(CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
|
_configManager.OnValueChanged(CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
|
||||||
_configManager.OnValueChanged(CCVars.StationAmbienceEnabled, StationAmbienceCVarChanged);
|
|
||||||
_configManager.OnValueChanged(CCVars.SpaceAmbienceEnabled, SpaceAmbienceCVarChanged);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
|
|
||||||
SubscribeLocalEvent<EntParentChangedMessage>(EntParentChanged);
|
|
||||||
SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetached);
|
|
||||||
|
|
||||||
_stateManager.OnStateChanged += StateManagerOnStateChanged;
|
_stateManager.OnStateChanged += StateManagerOnStateChanged;
|
||||||
|
|
||||||
@@ -85,28 +37,12 @@ public sealed class BackgroundAudioSystem : EntitySystem
|
|||||||
_gameTicker.LobbyStatusUpdated += LobbySongReceived;
|
_gameTicker.LobbyStatusUpdated += LobbySongReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerAttached(PlayerAttachedEvent ev)
|
|
||||||
{
|
|
||||||
if (!TryComp<TransformComponent>(ev.Entity, out var xform))
|
|
||||||
return;
|
|
||||||
|
|
||||||
CheckAmbience(xform);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayerDetached(PlayerDetachedEvent ev)
|
|
||||||
{
|
|
||||||
EndAmbience();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
{
|
{
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
|
|
||||||
_configManager.UnsubValueChanged(CCVars.AmbienceVolume, AmbienceCVarChanged);
|
|
||||||
_configManager.UnsubValueChanged(CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
|
_configManager.UnsubValueChanged(CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
|
||||||
_configManager.UnsubValueChanged(CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
|
_configManager.UnsubValueChanged(CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
|
||||||
_configManager.UnsubValueChanged(CCVars.StationAmbienceEnabled, StationAmbienceCVarChanged);
|
|
||||||
_configManager.UnsubValueChanged(CCVars.SpaceAmbienceEnabled, SpaceAmbienceCVarChanged);
|
|
||||||
|
|
||||||
_stateManager.OnStateChanged -= StateManagerOnStateChanged;
|
_stateManager.OnStateChanged -= StateManagerOnStateChanged;
|
||||||
|
|
||||||
@@ -114,61 +50,17 @@ public sealed class BackgroundAudioSystem : EntitySystem
|
|||||||
|
|
||||||
_gameTicker.LobbyStatusUpdated -= LobbySongReceived;
|
_gameTicker.LobbyStatusUpdated -= LobbySongReceived;
|
||||||
|
|
||||||
EndAmbience();
|
|
||||||
EndLobbyMusic();
|
EndLobbyMusic();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckAmbience(TransformComponent xform)
|
|
||||||
{
|
|
||||||
if (xform.GridUid != null)
|
|
||||||
ChangeAmbience(_stationAmbience);
|
|
||||||
else
|
|
||||||
ChangeAmbience(_spaceAmbience);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EntParentChanged(ref EntParentChangedMessage message)
|
|
||||||
{
|
|
||||||
if (_playMan.LocalPlayer is null
|
|
||||||
|| _playMan.LocalPlayer.ControlledEntity != message.Entity
|
|
||||||
|| !(_timing.IsFirstTimePredicted || _timing.ApplyingState))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Check if we traversed to grid.
|
|
||||||
CheckAmbience(message.Transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ChangeAmbience(SoundCollectionPrototype newAmbience)
|
|
||||||
{
|
|
||||||
if (_currentCollection == newAmbience)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_timerCancelTokenSource.Cancel();
|
|
||||||
_currentCollection = newAmbience;
|
|
||||||
_timerCancelTokenSource = new CancellationTokenSource();
|
|
||||||
Timer.Spawn(1500, () =>
|
|
||||||
{
|
|
||||||
// If we traverse a few times then don't interrupt an existing song.
|
|
||||||
// If we are not in gameplay, don't call StartAmbience because of player movement
|
|
||||||
if (_playingCollection == _currentCollection || _stateManager.CurrentState is not GameplayState)
|
|
||||||
return;
|
|
||||||
StartAmbience();
|
|
||||||
}, _timerCancelTokenSource.Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StateManagerOnStateChanged(StateChangedEventArgs args)
|
private void StateManagerOnStateChanged(StateChangedEventArgs args)
|
||||||
{
|
{
|
||||||
switch (args.NewState)
|
switch (args.NewState)
|
||||||
{
|
{
|
||||||
case LobbyState:
|
case LobbyState:
|
||||||
EndAmbience();
|
|
||||||
StartLobbyMusic();
|
StartLobbyMusic();
|
||||||
break;
|
break;
|
||||||
case GameplayState:
|
|
||||||
EndLobbyMusic();
|
|
||||||
StartAmbience();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
EndAmbience();
|
|
||||||
EndLobbyMusic();
|
EndLobbyMusic();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -176,80 +68,9 @@ public sealed class BackgroundAudioSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnLeave(object? sender, PlayerEventArgs args)
|
private void OnLeave(object? sender, PlayerEventArgs args)
|
||||||
{
|
{
|
||||||
EndAmbience();
|
|
||||||
EndLobbyMusic();
|
EndLobbyMusic();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AmbienceCVarChanged(float volume)
|
|
||||||
{
|
|
||||||
if (_stateManager.CurrentState is GameplayState)
|
|
||||||
{
|
|
||||||
StartAmbience();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EndAmbience();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartAmbience()
|
|
||||||
{
|
|
||||||
EndAmbience();
|
|
||||||
if (_currentCollection == null || !CanPlayCollection(_currentCollection))
|
|
||||||
return;
|
|
||||||
_playingCollection = _currentCollection;
|
|
||||||
var file = _robustRandom.Pick(_currentCollection.PickFiles).ToString();
|
|
||||||
_ambientStream = _audio.PlayGlobal(file, Filter.Local(), false,
|
|
||||||
_ambientParams.WithVolume(_ambientParams.Volume + _configManager.GetCVar(CCVars.AmbienceVolume)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EndAmbience()
|
|
||||||
{
|
|
||||||
_playingCollection = null;
|
|
||||||
_ambientStream?.Stop();
|
|
||||||
_ambientStream = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CanPlayCollection(SoundCollectionPrototype collection)
|
|
||||||
{
|
|
||||||
if (collection.ID == _spaceAmbience.ID)
|
|
||||||
return _configManager.GetCVar(CCVars.SpaceAmbienceEnabled);
|
|
||||||
if (collection.ID == _stationAmbience.ID)
|
|
||||||
return _configManager.GetCVar(CCVars.StationAmbienceEnabled);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StationAmbienceCVarChanged(bool enabled)
|
|
||||||
{
|
|
||||||
if (_currentCollection == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (enabled && _stateManager.CurrentState is GameplayState && _currentCollection.ID == _stationAmbience.ID)
|
|
||||||
{
|
|
||||||
StartAmbience();
|
|
||||||
}
|
|
||||||
else if (_currentCollection.ID == _stationAmbience.ID)
|
|
||||||
{
|
|
||||||
EndAmbience();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SpaceAmbienceCVarChanged(bool enabled)
|
|
||||||
{
|
|
||||||
if (_currentCollection == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (enabled && _stateManager.CurrentState is GameplayState && _currentCollection.ID == _spaceAmbience.ID)
|
|
||||||
{
|
|
||||||
StartAmbience();
|
|
||||||
}
|
|
||||||
else if (_currentCollection.ID == _spaceAmbience.ID)
|
|
||||||
{
|
|
||||||
EndAmbience();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LobbyMusicVolumeCVarChanged(float volume)
|
private void LobbyMusicVolumeCVarChanged(float volume)
|
||||||
{
|
{
|
||||||
if (_stateManager.CurrentState is LobbyState)
|
if (_stateManager.CurrentState is LobbyState)
|
||||||
|
|||||||
262
Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs
Normal file
262
Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Client.Gameplay;
|
||||||
|
using Content.Shared.Audio;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.Random;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
using Robust.Client.ResourceManagement;
|
||||||
|
using Robust.Client.State;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client.Audio;
|
||||||
|
|
||||||
|
public sealed partial class ContentAudioSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
|
[Dependency] private readonly IResourceCache _resource = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly IStateManager _state = default!;
|
||||||
|
[Dependency] private readonly RulesSystem _rules = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
|
||||||
|
private readonly TimeSpan _minAmbienceTime = TimeSpan.FromSeconds(30);
|
||||||
|
private readonly TimeSpan _maxAmbienceTime = TimeSpan.FromSeconds(60);
|
||||||
|
|
||||||
|
private const float AmbientMusicFadeTime = 10f;
|
||||||
|
private static float _volumeSlider;
|
||||||
|
|
||||||
|
// Don't need to worry about this being serializable or pauseable as it doesn't affect the sim.
|
||||||
|
private TimeSpan _nextAudio;
|
||||||
|
|
||||||
|
private AudioSystem.PlayingStream? _ambientMusicStream;
|
||||||
|
private AmbientMusicPrototype? _musicProto;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If we find a better ambient music proto can we interrupt this one.
|
||||||
|
/// </summary>
|
||||||
|
private bool _interruptable;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Track what ambient sounds we've played. This is so they all get played an even
|
||||||
|
/// number of times.
|
||||||
|
/// When we get to the end of the list we'll re-shuffle
|
||||||
|
/// </summary>
|
||||||
|
private readonly Dictionary<string, List<ResPath>> _ambientSounds = new();
|
||||||
|
|
||||||
|
private ISawmill _sawmill = default!;
|
||||||
|
|
||||||
|
private void InitializeAmbientMusic()
|
||||||
|
{
|
||||||
|
// TODO: Shitty preload
|
||||||
|
foreach (var audio in _proto.Index<SoundCollectionPrototype>("AmbienceSpace").PickFiles)
|
||||||
|
{
|
||||||
|
_resource.GetResource<AudioResource>(audio.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
_configManager.OnValueChanged(CCVars.AmbientMusicVolume, AmbienceCVarChanged, true);
|
||||||
|
_sawmill = IoCManager.Resolve<ILogManager>().GetSawmill("audio.ambience");
|
||||||
|
|
||||||
|
// Reset audio
|
||||||
|
_nextAudio = TimeSpan.MaxValue;
|
||||||
|
|
||||||
|
SetupAmbientSounds();
|
||||||
|
_proto.PrototypesReloaded += OnProtoReload;
|
||||||
|
_state.OnStateChanged += OnStateChange;
|
||||||
|
// On round end summary OR lobby cut audio.
|
||||||
|
SubscribeNetworkEvent<RoundEndMessageEvent>(OnRoundEndMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AmbienceCVarChanged(float obj)
|
||||||
|
{
|
||||||
|
_volumeSlider = obj;
|
||||||
|
|
||||||
|
if (_ambientMusicStream != null && _musicProto != null)
|
||||||
|
{
|
||||||
|
_ambientMusicStream.Volume = _musicProto.Sound.Params.Volume + _volumeSlider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShutdownAmbientMusic()
|
||||||
|
{
|
||||||
|
_configManager.UnsubValueChanged(CCVars.AmbientMusicVolume, AmbienceCVarChanged);
|
||||||
|
_proto.PrototypesReloaded -= OnProtoReload;
|
||||||
|
_state.OnStateChanged -= OnStateChange;
|
||||||
|
_ambientMusicStream?.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnProtoReload(PrototypesReloadedEventArgs obj)
|
||||||
|
{
|
||||||
|
if (!obj.ByType.ContainsKey(typeof(AmbientMusicPrototype)) &&
|
||||||
|
!obj.ByType.ContainsKey(typeof(RulesPrototype)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ambientSounds.Clear();
|
||||||
|
SetupAmbientSounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStateChange(StateChangedEventArgs obj)
|
||||||
|
{
|
||||||
|
if (obj.NewState is not GameplayState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If they go to game then reset the ambience timer.
|
||||||
|
_nextAudio = _timing.CurTime + _random.Next(_minAmbienceTime, _maxAmbienceTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupAmbientSounds()
|
||||||
|
{
|
||||||
|
foreach (var ambience in _proto.EnumeratePrototypes<AmbientMusicPrototype>())
|
||||||
|
{
|
||||||
|
var tracks = _ambientSounds.GetOrNew(ambience.ID);
|
||||||
|
RefreshTracks(ambience.Sound, tracks, null);
|
||||||
|
_random.Shuffle(tracks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRoundEndMessage(RoundEndMessageEvent ev)
|
||||||
|
{
|
||||||
|
// If scoreboard shows then just stop the music
|
||||||
|
_ambientMusicStream?.Stop();
|
||||||
|
_ambientMusicStream = null;
|
||||||
|
_nextAudio = TimeSpan.FromMinutes(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshTracks(SoundSpecifier sound, List<ResPath> tracks, ResPath? lastPlayed)
|
||||||
|
{
|
||||||
|
DebugTools.Assert(tracks.Count == 0);
|
||||||
|
|
||||||
|
switch (sound)
|
||||||
|
{
|
||||||
|
case SoundCollectionSpecifier collection:
|
||||||
|
if (collection.Collection == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var slothCud = _proto.Index<SoundCollectionPrototype>(collection.Collection);
|
||||||
|
tracks.AddRange(slothCud.PickFiles);
|
||||||
|
break;
|
||||||
|
case SoundPathSpecifier path:
|
||||||
|
tracks.Add(path.Path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just so the same track doesn't play twice
|
||||||
|
if (tracks.Count > 1 && tracks[^1] == lastPlayed)
|
||||||
|
{
|
||||||
|
(tracks[0], tracks[^1]) = (tracks[^1], tracks[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAmbientMusic()
|
||||||
|
{
|
||||||
|
// Update still runs in lobby so just ignore it.
|
||||||
|
if (_state.CurrentState is not GameplayState)
|
||||||
|
{
|
||||||
|
FadeOut(_ambientMusicStream);
|
||||||
|
_ambientMusicStream = null;
|
||||||
|
_musicProto = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDone = _ambientMusicStream?.Done;
|
||||||
|
|
||||||
|
if (_interruptable)
|
||||||
|
{
|
||||||
|
var player = _player.LocalPlayer?.ControlledEntity;
|
||||||
|
|
||||||
|
if (player == null || _musicProto == null || !_rules.IsTrue(player.Value, _proto.Index<RulesPrototype>(_musicProto.Rules)))
|
||||||
|
{
|
||||||
|
FadeOut(_ambientMusicStream, AmbientMusicFadeTime);
|
||||||
|
_musicProto = null;
|
||||||
|
_interruptable = false;
|
||||||
|
isDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Still running existing ambience
|
||||||
|
if (isDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If ambience finished reset the CD (this also means if we have long ambience it won't clip)
|
||||||
|
if (isDone == true)
|
||||||
|
{
|
||||||
|
// Also don't need to worry about rounding here as it doesn't affect the sim
|
||||||
|
_nextAudio = _timing.CurTime + _random.Next(_minAmbienceTime, _maxAmbienceTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ambientMusicStream = null;
|
||||||
|
|
||||||
|
if (_nextAudio > _timing.CurTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_musicProto = GetAmbience();
|
||||||
|
|
||||||
|
if (_musicProto == null)
|
||||||
|
{
|
||||||
|
_interruptable = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_interruptable = _musicProto.Interruptable;
|
||||||
|
var tracks = _ambientSounds[_musicProto.ID];
|
||||||
|
|
||||||
|
var track = tracks[^1];
|
||||||
|
tracks.RemoveAt(tracks.Count - 1);
|
||||||
|
|
||||||
|
var strim = _audio.PlayGlobal(
|
||||||
|
track.ToString(),
|
||||||
|
Filter.Local(),
|
||||||
|
false,
|
||||||
|
AudioParams.Default.WithVolume(_musicProto.Sound.Params.Volume + _volumeSlider));
|
||||||
|
|
||||||
|
if (strim != null)
|
||||||
|
{
|
||||||
|
_ambientMusicStream = (AudioSystem.PlayingStream) strim;
|
||||||
|
|
||||||
|
if (_musicProto.FadeIn)
|
||||||
|
{
|
||||||
|
FadeIn(_ambientMusicStream, AmbientMusicFadeTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh the list
|
||||||
|
if (tracks.Count == 0)
|
||||||
|
{
|
||||||
|
RefreshTracks(_musicProto.Sound, tracks, track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AmbientMusicPrototype? GetAmbience()
|
||||||
|
{
|
||||||
|
var player = _player.LocalPlayer?.ControlledEntity;
|
||||||
|
|
||||||
|
if (player == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var ambiences = _proto.EnumeratePrototypes<AmbientMusicPrototype>().ToList();
|
||||||
|
ambiences.Sort((x, y) => y.Priority.CompareTo(x.Priority));
|
||||||
|
|
||||||
|
foreach (var amb in ambiences)
|
||||||
|
{
|
||||||
|
if (!_rules.IsTrue(player.Value, _proto.Index<RulesPrototype>(amb.Rules)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return amb;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sawmill.Warning($"Unable to find fallback ambience track");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,124 @@
|
|||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
namespace Content.Client.Audio;
|
namespace Content.Client.Audio;
|
||||||
|
|
||||||
public sealed class ContentAudioSystem : SharedContentAudioSystem
|
public sealed partial class ContentAudioSystem : SharedContentAudioSystem
|
||||||
{
|
{
|
||||||
|
// Need how much volume to change per tick and just remove it when it drops below "0"
|
||||||
|
private readonly Dictionary<AudioSystem.PlayingStream, float> _fadingOut = new();
|
||||||
|
|
||||||
|
// Need volume change per tick + target volume.
|
||||||
|
private readonly Dictionary<AudioSystem.PlayingStream, (float VolumeChange, float TargetVolume)> _fadingIn = new();
|
||||||
|
|
||||||
|
private readonly List<AudioSystem.PlayingStream> _fadeToRemove = new();
|
||||||
|
|
||||||
|
private const float MinVolume = -32f;
|
||||||
|
private const float DefaultDuration = 2f;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
UpdatesOutsidePrediction = true;
|
||||||
|
InitializeAmbientMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
ShutdownAmbientMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
if (!_timing.IsFirstTimePredicted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdateAmbientMusic();
|
||||||
|
UpdateFades(frameTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Fades
|
||||||
|
|
||||||
|
public void FadeOut(AudioSystem.PlayingStream? stream, float duration = DefaultDuration)
|
||||||
|
{
|
||||||
|
if (stream == null || duration <= 0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Just in case
|
||||||
|
// TODO: Maybe handle the removals by making it seamless?
|
||||||
|
_fadingIn.Remove(stream);
|
||||||
|
var diff = stream.Volume - MinVolume;
|
||||||
|
_fadingOut.Add(stream, diff / duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FadeIn(AudioSystem.PlayingStream? stream, float duration = DefaultDuration)
|
||||||
|
{
|
||||||
|
if (stream == null || duration <= 0f || stream.Volume < MinVolume)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fadingOut.Remove(stream);
|
||||||
|
var curVolume = stream.Volume;
|
||||||
|
var change = (curVolume - MinVolume) / duration;
|
||||||
|
_fadingIn.Add(stream, (change, stream.Volume));
|
||||||
|
stream.Volume = MinVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFades(float frameTime)
|
||||||
|
{
|
||||||
|
_fadeToRemove.Clear();
|
||||||
|
|
||||||
|
foreach (var (stream, change) in _fadingOut)
|
||||||
|
{
|
||||||
|
// Cancelled elsewhere
|
||||||
|
if (stream.Done)
|
||||||
|
{
|
||||||
|
_fadeToRemove.Add(stream);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var volume = stream.Volume - change * frameTime;
|
||||||
|
stream.Volume = MathF.Max(MinVolume, volume);
|
||||||
|
|
||||||
|
if (stream.Volume.Equals(MinVolume))
|
||||||
|
{
|
||||||
|
stream.Stop();
|
||||||
|
_fadeToRemove.Add(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var stream in _fadeToRemove)
|
||||||
|
{
|
||||||
|
_fadingOut.Remove(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
_fadeToRemove.Clear();
|
||||||
|
|
||||||
|
foreach (var (stream, (change, target)) in _fadingIn)
|
||||||
|
{
|
||||||
|
// Cancelled elsewhere
|
||||||
|
if (stream.Done)
|
||||||
|
{
|
||||||
|
_fadeToRemove.Add(stream);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var volume = stream.Volume + change * frameTime;
|
||||||
|
stream.Volume = MathF.Min(target, volume);
|
||||||
|
|
||||||
|
if (stream.Volume.Equals(target))
|
||||||
|
{
|
||||||
|
_fadeToRemove.Add(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var stream in _fadeToRemove)
|
||||||
|
{
|
||||||
|
_fadingIn.Remove(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<Control MinSize="8 0" />
|
<Control MinSize="8 0" />
|
||||||
<Slider Name="MidiVolumeSlider"
|
<Slider Name="MidiVolumeSlider"
|
||||||
MinValue="0"
|
MinValue="0"
|
||||||
MaxValue="200"
|
MaxValue="100"
|
||||||
HorizontalExpand="True"
|
HorizontalExpand="True"
|
||||||
MinSize="80 0"
|
MinSize="80 0"
|
||||||
Rounded="True" />
|
Rounded="True" />
|
||||||
@@ -35,12 +35,25 @@
|
|||||||
<Label Name="MidiVolumeLabel" MinSize="48 0" Align="Right" />
|
<Label Name="MidiVolumeLabel" MinSize="48 0" Align="Right" />
|
||||||
<Control MinSize="4 0"/>
|
<Control MinSize="4 0"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||||
|
<Label Text="{Loc 'ui-options-ambient-music-volume'}" HorizontalExpand="True" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Slider Name="AmbientMusicVolumeSlider"
|
||||||
|
MinValue="0"
|
||||||
|
MaxValue="100"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
MinSize="80 0"
|
||||||
|
Rounded="True" />
|
||||||
|
<Control MinSize="8 0" />
|
||||||
|
<Label Name="AmbientMusicVolumeLabel" MinSize="48 0" Align="Right" />
|
||||||
|
<Control MinSize="4 0"/>
|
||||||
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
<BoxContainer Orientation="Horizontal" Margin="5 0 0 0">
|
||||||
<Label Text="{Loc 'ui-options-ambience-volume'}" HorizontalExpand="True" />
|
<Label Text="{Loc 'ui-options-ambience-volume'}" HorizontalExpand="True" />
|
||||||
<Control MinSize="8 0" />
|
<Control MinSize="8 0" />
|
||||||
<Slider Name="AmbienceVolumeSlider"
|
<Slider Name="AmbienceVolumeSlider"
|
||||||
MinValue="0"
|
MinValue="0"
|
||||||
MaxValue="300"
|
MaxValue="100"
|
||||||
HorizontalExpand="True"
|
HorizontalExpand="True"
|
||||||
MinSize="80 0"
|
MinSize="80 0"
|
||||||
Rounded="True" />
|
Rounded="True" />
|
||||||
@@ -53,7 +66,7 @@
|
|||||||
<Control MinSize="8 0" />
|
<Control MinSize="8 0" />
|
||||||
<Slider Name="LobbyVolumeSlider"
|
<Slider Name="LobbyVolumeSlider"
|
||||||
MinValue="0"
|
MinValue="0"
|
||||||
MaxValue="200"
|
MaxValue="100"
|
||||||
HorizontalExpand="True"
|
HorizontalExpand="True"
|
||||||
MinSize="80 0"
|
MinSize="80 0"
|
||||||
Rounded="True" />
|
Rounded="True" />
|
||||||
@@ -79,8 +92,6 @@
|
|||||||
<CheckBox Name="RestartSoundsCheckBox" Text="{Loc 'ui-options-restart-sounds'}" />
|
<CheckBox Name="RestartSoundsCheckBox" Text="{Loc 'ui-options-restart-sounds'}" />
|
||||||
<CheckBox Name="EventMusicCheckBox" Text="{Loc 'ui-options-event-music'}" />
|
<CheckBox Name="EventMusicCheckBox" Text="{Loc 'ui-options-event-music'}" />
|
||||||
<CheckBox Name="AdminSoundsCheckBox" Text="{Loc 'ui-options-admin-sounds'}" />
|
<CheckBox Name="AdminSoundsCheckBox" Text="{Loc 'ui-options-admin-sounds'}" />
|
||||||
<CheckBox Name="StationAmbienceCheckBox" Text="{Loc 'ui-options-station-ambience'}" />
|
|
||||||
<CheckBox Name="SpaceAmbienceCheckBox" Text="{Loc 'ui-options-space-ambience'}" />
|
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
|
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
|
||||||
|
|||||||
@@ -25,13 +25,12 @@ namespace Content.Client.Options.UI.Tabs
|
|||||||
RestartSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
RestartSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
||||||
EventMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.EventMusicEnabled);
|
EventMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.EventMusicEnabled);
|
||||||
AdminSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.AdminSoundsEnabled);
|
AdminSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.AdminSoundsEnabled);
|
||||||
StationAmbienceCheckBox.Pressed = _cfg.GetCVar(CCVars.StationAmbienceEnabled);
|
|
||||||
SpaceAmbienceCheckBox.Pressed = _cfg.GetCVar(CCVars.SpaceAmbienceEnabled);
|
|
||||||
|
|
||||||
ApplyButton.OnPressed += OnApplyButtonPressed;
|
ApplyButton.OnPressed += OnApplyButtonPressed;
|
||||||
ResetButton.OnPressed += OnResetButtonPressed;
|
ResetButton.OnPressed += OnResetButtonPressed;
|
||||||
MasterVolumeSlider.OnValueChanged += OnMasterVolumeSliderChanged;
|
MasterVolumeSlider.OnValueChanged += OnMasterVolumeSliderChanged;
|
||||||
MidiVolumeSlider.OnValueChanged += OnMidiVolumeSliderChanged;
|
MidiVolumeSlider.OnValueChanged += OnMidiVolumeSliderChanged;
|
||||||
|
AmbientMusicVolumeSlider.OnValueChanged += OnAmbientMusicVolumeSliderChanged;
|
||||||
AmbienceVolumeSlider.OnValueChanged += OnAmbienceVolumeSliderChanged;
|
AmbienceVolumeSlider.OnValueChanged += OnAmbienceVolumeSliderChanged;
|
||||||
AmbienceSoundsSlider.OnValueChanged += OnAmbienceSoundsSliderChanged;
|
AmbienceSoundsSlider.OnValueChanged += OnAmbienceSoundsSliderChanged;
|
||||||
LobbyVolumeSlider.OnValueChanged += OnLobbyVolumeSliderChanged;
|
LobbyVolumeSlider.OnValueChanged += OnLobbyVolumeSliderChanged;
|
||||||
@@ -39,8 +38,6 @@ namespace Content.Client.Options.UI.Tabs
|
|||||||
RestartSoundsCheckBox.OnToggled += OnRestartSoundsCheckToggled;
|
RestartSoundsCheckBox.OnToggled += OnRestartSoundsCheckToggled;
|
||||||
EventMusicCheckBox.OnToggled += OnEventMusicCheckToggled;
|
EventMusicCheckBox.OnToggled += OnEventMusicCheckToggled;
|
||||||
AdminSoundsCheckBox.OnToggled += OnAdminSoundsCheckToggled;
|
AdminSoundsCheckBox.OnToggled += OnAdminSoundsCheckToggled;
|
||||||
StationAmbienceCheckBox.OnToggled += OnStationAmbienceCheckToggled;
|
|
||||||
SpaceAmbienceCheckBox.OnToggled += OnSpaceAmbienceCheckToggled;
|
|
||||||
|
|
||||||
AmbienceSoundsSlider.MinValue = _cfg.GetCVar(CCVars.MinMaxAmbientSourcesConfigured);
|
AmbienceSoundsSlider.MinValue = _cfg.GetCVar(CCVars.MinMaxAmbientSourcesConfigured);
|
||||||
AmbienceSoundsSlider.MaxValue = _cfg.GetCVar(CCVars.MaxMaxAmbientSourcesConfigured);
|
AmbienceSoundsSlider.MaxValue = _cfg.GetCVar(CCVars.MaxMaxAmbientSourcesConfigured);
|
||||||
@@ -54,6 +51,7 @@ namespace Content.Client.Options.UI.Tabs
|
|||||||
ResetButton.OnPressed -= OnResetButtonPressed;
|
ResetButton.OnPressed -= OnResetButtonPressed;
|
||||||
MasterVolumeSlider.OnValueChanged -= OnMasterVolumeSliderChanged;
|
MasterVolumeSlider.OnValueChanged -= OnMasterVolumeSliderChanged;
|
||||||
MidiVolumeSlider.OnValueChanged -= OnMidiVolumeSliderChanged;
|
MidiVolumeSlider.OnValueChanged -= OnMidiVolumeSliderChanged;
|
||||||
|
AmbientMusicVolumeSlider.OnValueChanged -= OnAmbientMusicVolumeSliderChanged;
|
||||||
AmbienceVolumeSlider.OnValueChanged -= OnAmbienceVolumeSliderChanged;
|
AmbienceVolumeSlider.OnValueChanged -= OnAmbienceVolumeSliderChanged;
|
||||||
LobbyVolumeSlider.OnValueChanged -= OnLobbyVolumeSliderChanged;
|
LobbyVolumeSlider.OnValueChanged -= OnLobbyVolumeSliderChanged;
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
@@ -64,6 +62,11 @@ namespace Content.Client.Options.UI.Tabs
|
|||||||
UpdateChanges();
|
UpdateChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnAmbientMusicVolumeSliderChanged(Range obj)
|
||||||
|
{
|
||||||
|
UpdateChanges();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnAmbienceVolumeSliderChanged(Range obj)
|
private void OnAmbienceVolumeSliderChanged(Range obj)
|
||||||
{
|
{
|
||||||
UpdateChanges();
|
UpdateChanges();
|
||||||
@@ -103,29 +106,21 @@ namespace Content.Client.Options.UI.Tabs
|
|||||||
UpdateChanges();
|
UpdateChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStationAmbienceCheckToggled(BaseButton.ButtonEventArgs args)
|
|
||||||
{
|
|
||||||
UpdateChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSpaceAmbienceCheckToggled(BaseButton.ButtonEventArgs args)
|
|
||||||
{
|
|
||||||
UpdateChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
|
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
|
||||||
{
|
{
|
||||||
_cfg.SetCVar(CVars.AudioMasterVolume, MasterVolumeSlider.Value / 100);
|
_cfg.SetCVar(CVars.AudioMasterVolume, MasterVolumeSlider.Value / 100);
|
||||||
_cfg.SetCVar(CVars.MidiVolume, LV100ToDB(MidiVolumeSlider.Value));
|
// Want the CVar updated values to have the multiplier applied
|
||||||
_cfg.SetCVar(CCVars.AmbienceVolume, LV100ToDB(AmbienceVolumeSlider.Value));
|
// For the UI we just display 0-100 still elsewhere
|
||||||
|
_cfg.SetCVar(CVars.MidiVolume, LV100ToDB(MidiVolumeSlider.Value, CCVars.MidiMultiplier));
|
||||||
|
_cfg.SetCVar(CCVars.AmbienceVolume, LV100ToDB(AmbienceVolumeSlider.Value, CCVars.AmbienceMultiplier));
|
||||||
|
_cfg.SetCVar(CCVars.AmbientMusicVolume, LV100ToDB(AmbientMusicVolumeSlider.Value, CCVars.AmbientMusicMultiplier));
|
||||||
|
|
||||||
_cfg.SetCVar(CCVars.LobbyMusicVolume, LV100ToDB(LobbyVolumeSlider.Value));
|
_cfg.SetCVar(CCVars.LobbyMusicVolume, LV100ToDB(LobbyVolumeSlider.Value));
|
||||||
_cfg.SetCVar(CCVars.MaxAmbientSources, (int)AmbienceSoundsSlider.Value);
|
_cfg.SetCVar(CCVars.MaxAmbientSources, (int)AmbienceSoundsSlider.Value);
|
||||||
_cfg.SetCVar(CCVars.LobbyMusicEnabled, LobbyMusicCheckBox.Pressed);
|
_cfg.SetCVar(CCVars.LobbyMusicEnabled, LobbyMusicCheckBox.Pressed);
|
||||||
_cfg.SetCVar(CCVars.RestartSoundsEnabled, RestartSoundsCheckBox.Pressed);
|
_cfg.SetCVar(CCVars.RestartSoundsEnabled, RestartSoundsCheckBox.Pressed);
|
||||||
_cfg.SetCVar(CCVars.EventMusicEnabled, EventMusicCheckBox.Pressed);
|
_cfg.SetCVar(CCVars.EventMusicEnabled, EventMusicCheckBox.Pressed);
|
||||||
_cfg.SetCVar(CCVars.AdminSoundsEnabled, AdminSoundsCheckBox.Pressed);
|
_cfg.SetCVar(CCVars.AdminSoundsEnabled, AdminSoundsCheckBox.Pressed);
|
||||||
_cfg.SetCVar(CCVars.StationAmbienceEnabled, StationAmbienceCheckBox.Pressed);
|
|
||||||
_cfg.SetCVar(CCVars.SpaceAmbienceEnabled, SpaceAmbienceCheckBox.Pressed);
|
|
||||||
_cfg.SaveToFile();
|
_cfg.SaveToFile();
|
||||||
UpdateChanges();
|
UpdateChanges();
|
||||||
}
|
}
|
||||||
@@ -138,30 +133,32 @@ namespace Content.Client.Options.UI.Tabs
|
|||||||
private void Reset()
|
private void Reset()
|
||||||
{
|
{
|
||||||
MasterVolumeSlider.Value = _cfg.GetCVar(CVars.AudioMasterVolume) * 100;
|
MasterVolumeSlider.Value = _cfg.GetCVar(CVars.AudioMasterVolume) * 100;
|
||||||
MidiVolumeSlider.Value = DBToLV100(_cfg.GetCVar(CVars.MidiVolume));
|
MidiVolumeSlider.Value = DBToLV100(_cfg.GetCVar(CVars.MidiVolume), CCVars.MidiMultiplier);
|
||||||
AmbienceVolumeSlider.Value = DBToLV100(_cfg.GetCVar(CCVars.AmbienceVolume));
|
AmbienceVolumeSlider.Value = DBToLV100(_cfg.GetCVar(CCVars.AmbienceVolume), CCVars.AmbienceMultiplier);
|
||||||
|
AmbientMusicVolumeSlider.Value =
|
||||||
|
DBToLV100(_cfg.GetCVar(CCVars.AmbientMusicVolume), CCVars.AmbientMusicMultiplier);
|
||||||
LobbyVolumeSlider.Value = DBToLV100(_cfg.GetCVar(CCVars.LobbyMusicVolume));
|
LobbyVolumeSlider.Value = DBToLV100(_cfg.GetCVar(CCVars.LobbyMusicVolume));
|
||||||
AmbienceSoundsSlider.Value = _cfg.GetCVar(CCVars.MaxAmbientSources);
|
AmbienceSoundsSlider.Value = _cfg.GetCVar(CCVars.MaxAmbientSources);
|
||||||
LobbyMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.LobbyMusicEnabled);
|
LobbyMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.LobbyMusicEnabled);
|
||||||
RestartSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
RestartSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
||||||
EventMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.EventMusicEnabled);
|
EventMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.EventMusicEnabled);
|
||||||
AdminSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.AdminSoundsEnabled);
|
AdminSoundsCheckBox.Pressed = _cfg.GetCVar(CCVars.AdminSoundsEnabled);
|
||||||
StationAmbienceCheckBox.Pressed = _cfg.GetCVar(CCVars.StationAmbienceEnabled);
|
|
||||||
SpaceAmbienceCheckBox.Pressed = _cfg.GetCVar(CCVars.SpaceAmbienceEnabled);
|
|
||||||
UpdateChanges();
|
UpdateChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Rather than moving these functions somewhere, instead switch MidiManager to using linear units rather than dB
|
// Note: Rather than moving these functions somewhere, instead switch MidiManager to using linear units rather than dB
|
||||||
// Do be sure to rename the setting though
|
// Do be sure to rename the setting though
|
||||||
private float DBToLV100(float db)
|
private float DBToLV100(float db, float multiplier = 1f)
|
||||||
{
|
{
|
||||||
return (MathF.Pow(10, (db / 10)) * 100);
|
var weh = (float) (Math.Pow(10, db / 10) * 100 / multiplier);
|
||||||
|
return weh;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float LV100ToDB(float lv100)
|
private float LV100ToDB(float lv100, float multiplier = 1f)
|
||||||
{
|
{
|
||||||
// Saving negative infinity doesn't work, so use -10000000 instead (MidiManager does it)
|
// Saving negative infinity doesn't work, so use -10000000 instead (MidiManager does it)
|
||||||
return MathF.Max(-10000000, MathF.Log(lv100 / 100, 10) * 10);
|
var weh = MathF.Max(-10000000, (float) (Math.Log(lv100 * multiplier / 100, 10) * 10));
|
||||||
|
return weh;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateChanges()
|
private void UpdateChanges()
|
||||||
@@ -169,9 +166,11 @@ namespace Content.Client.Options.UI.Tabs
|
|||||||
var isMasterVolumeSame =
|
var isMasterVolumeSame =
|
||||||
Math.Abs(MasterVolumeSlider.Value - _cfg.GetCVar(CVars.AudioMasterVolume) * 100) < 0.01f;
|
Math.Abs(MasterVolumeSlider.Value - _cfg.GetCVar(CVars.AudioMasterVolume) * 100) < 0.01f;
|
||||||
var isMidiVolumeSame =
|
var isMidiVolumeSame =
|
||||||
Math.Abs(MidiVolumeSlider.Value - DBToLV100(_cfg.GetCVar(CVars.MidiVolume))) < 0.01f;
|
Math.Abs(MidiVolumeSlider.Value - DBToLV100(_cfg.GetCVar(CVars.MidiVolume), CCVars.MidiMultiplier)) < 0.01f;
|
||||||
var isAmbientVolumeSame =
|
var isAmbientVolumeSame =
|
||||||
Math.Abs(AmbienceVolumeSlider.Value - DBToLV100(_cfg.GetCVar(CCVars.AmbienceVolume))) < 0.01f;
|
Math.Abs(AmbienceVolumeSlider.Value - DBToLV100(_cfg.GetCVar(CCVars.AmbienceVolume), CCVars.AmbienceMultiplier)) < 0.01f;
|
||||||
|
var isAmbientMusicVolumeSame =
|
||||||
|
Math.Abs(AmbientMusicVolumeSlider.Value - DBToLV100(_cfg.GetCVar(CCVars.AmbientMusicVolume), CCVars.AmbientMusicMultiplier)) < 0.01f;
|
||||||
var isLobbyVolumeSame =
|
var isLobbyVolumeSame =
|
||||||
Math.Abs(LobbyVolumeSlider.Value - DBToLV100(_cfg.GetCVar(CCVars.LobbyMusicVolume))) < 0.01f;
|
Math.Abs(LobbyVolumeSlider.Value - DBToLV100(_cfg.GetCVar(CCVars.LobbyMusicVolume))) < 0.01f;
|
||||||
var isAmbientSoundsSame = (int)AmbienceSoundsSlider.Value == _cfg.GetCVar(CCVars.MaxAmbientSources);
|
var isAmbientSoundsSame = (int)AmbienceSoundsSlider.Value == _cfg.GetCVar(CCVars.MaxAmbientSources);
|
||||||
@@ -179,16 +178,16 @@ namespace Content.Client.Options.UI.Tabs
|
|||||||
var isRestartSoundsSame = RestartSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
var isRestartSoundsSame = RestartSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.RestartSoundsEnabled);
|
||||||
var isEventSame = EventMusicCheckBox.Pressed == _cfg.GetCVar(CCVars.EventMusicEnabled);
|
var isEventSame = EventMusicCheckBox.Pressed == _cfg.GetCVar(CCVars.EventMusicEnabled);
|
||||||
var isAdminSoundsSame = AdminSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.AdminSoundsEnabled);
|
var isAdminSoundsSame = AdminSoundsCheckBox.Pressed == _cfg.GetCVar(CCVars.AdminSoundsEnabled);
|
||||||
var isStationAmbienceSame = StationAmbienceCheckBox.Pressed == _cfg.GetCVar(CCVars.StationAmbienceEnabled);
|
var isEverythingSame = isMasterVolumeSame && isMidiVolumeSame && isAmbientVolumeSame && isAmbientMusicVolumeSame && isAmbientSoundsSame && isLobbySame && isRestartSoundsSame && isEventSame
|
||||||
var isSpaceAmbienceSame = SpaceAmbienceCheckBox.Pressed == _cfg.GetCVar(CCVars.SpaceAmbienceEnabled);
|
&& isAdminSoundsSame && isLobbyVolumeSame;
|
||||||
var isEverythingSame = isMasterVolumeSame && isMidiVolumeSame && isAmbientVolumeSame && isAmbientSoundsSame && isLobbySame && isRestartSoundsSame && isEventSame
|
|
||||||
&& isAdminSoundsSame && isStationAmbienceSame && isSpaceAmbienceSame && isLobbyVolumeSame;
|
|
||||||
ApplyButton.Disabled = isEverythingSame;
|
ApplyButton.Disabled = isEverythingSame;
|
||||||
ResetButton.Disabled = isEverythingSame;
|
ResetButton.Disabled = isEverythingSame;
|
||||||
MasterVolumeLabel.Text =
|
MasterVolumeLabel.Text =
|
||||||
Loc.GetString("ui-options-volume-percent", ("volume", MasterVolumeSlider.Value / 100));
|
Loc.GetString("ui-options-volume-percent", ("volume", MasterVolumeSlider.Value / 100));
|
||||||
MidiVolumeLabel.Text =
|
MidiVolumeLabel.Text =
|
||||||
Loc.GetString("ui-options-volume-percent", ("volume", MidiVolumeSlider.Value / 100));
|
Loc.GetString("ui-options-volume-percent", ("volume", MidiVolumeSlider.Value / 100));
|
||||||
|
AmbientMusicVolumeLabel.Text =
|
||||||
|
Loc.GetString("ui-options-volume-percent", ("volume", AmbientMusicVolumeSlider.Value / 100));
|
||||||
AmbienceVolumeLabel.Text =
|
AmbienceVolumeLabel.Text =
|
||||||
Loc.GetString("ui-options-volume-percent", ("volume", AmbienceVolumeSlider.Value / 100));
|
Loc.GetString("ui-options-volume-percent", ("volume", AmbienceVolumeSlider.Value / 100));
|
||||||
LobbyVolumeLabel.Text =
|
LobbyVolumeLabel.Text =
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server.Storage.Components;
|
|||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Morgue;
|
using Content.Shared.Morgue;
|
||||||
|
using Content.Shared.Morgue.Components;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
|
|
||||||
namespace Content.Server.Morgue;
|
namespace Content.Server.Morgue;
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Server.Prayer
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Allows an entity to be prayed on in the context menu
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed class PrayableComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// If bible users are only allowed to use this prayable entity
|
|
||||||
/// </summary>
|
|
||||||
[DataField("bibleUserOnly")]
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public bool BibleUserOnly;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Message given to user to notify them a message was sent
|
|
||||||
/// </summary>
|
|
||||||
[DataField("sentMessage")]
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public string SentMessage = "prayer-popup-notify-pray-sent";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prefix used in the notification to admins
|
|
||||||
/// </summary>
|
|
||||||
[DataField("notifiactionPrefix")]
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public string NotifiactionPrefix = "prayer-chat-notify-pray";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used in window title and context menu
|
|
||||||
/// </summary>
|
|
||||||
[DataField("verb")]
|
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
|
||||||
public string Verb = "prayer-verbs-pray";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Context menu image
|
|
||||||
/// </summary>
|
|
||||||
[DataField("verbImage")]
|
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
|
||||||
public SpriteSpecifier? VerbImage = new SpriteSpecifier.Texture(new ("/Textures/Interface/pray.svg.png"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -8,6 +8,7 @@ using Content.Shared.Popups;
|
|||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
|
using Content.Shared.Prayer;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
|
|
||||||
@@ -100,10 +101,9 @@ public sealed class PrayerSystem : EntitySystem
|
|||||||
if (sender.AttachedEntity == null)
|
if (sender.AttachedEntity == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString(comp.SentMessage), sender.AttachedEntity.Value, sender, PopupType.Medium);
|
_popupSystem.PopupEntity(Loc.GetString(comp.SentMessage), sender.AttachedEntity.Value, sender, PopupType.Medium);
|
||||||
|
|
||||||
_chatManager.SendAdminAnnouncement($"{Loc.GetString(comp.NotifiactionPrefix)} <{sender.Name}>: {message}");
|
_chatManager.SendAdminAnnouncement($"{Loc.GetString(comp.NotificationPrefix)} <{sender.Name}>: {message}");
|
||||||
_adminLogger.Add(LogType.AdminMessage, LogImpact.Low, $"{ToPrettyString(sender.AttachedEntity.Value):player} sent prayer ({Loc.GetString(comp.NotifiactionPrefix)}): {message}");
|
_adminLogger.Add(LogType.AdminMessage, LogImpact.Low, $"{ToPrettyString(sender.AttachedEntity.Value):player} sent prayer ({Loc.GetString(comp.NotificationPrefix)}): {message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
Content.Shared/Audio/AmbientMusicPrototype.cs
Normal file
39
Content.Shared/Audio/AmbientMusicPrototype.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using Content.Shared.Random;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Shared.Audio;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attaches a rules prototype to sound files to play ambience.
|
||||||
|
/// </summary>
|
||||||
|
[Prototype("ambientMusic")]
|
||||||
|
public sealed class AmbientMusicPrototype : IPrototype
|
||||||
|
{
|
||||||
|
[IdDataField] public string ID { get; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Traditionally you'd prioritise most rules to least as priority but in our case we'll just be explicit.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("priority")]
|
||||||
|
public int Priority = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Can we interrupt this ambience for a better prototype if possible?
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("interruptable")]
|
||||||
|
public bool Interruptable = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Do we fade-in. Useful for songs.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("fadeIn")]
|
||||||
|
public bool FadeIn;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("sound", required: true)]
|
||||||
|
public SoundSpecifier Sound = default!;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("rules", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<RulesPrototype>))]
|
||||||
|
public string Rules = string.Empty;
|
||||||
|
}
|
||||||
@@ -4,8 +4,8 @@ using Robust.Shared.GameStates;
|
|||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.Audio
|
namespace Content.Shared.Audio;
|
||||||
{
|
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[NetworkedComponent]
|
[NetworkedComponent]
|
||||||
[Access(typeof(SharedAmbientSoundSystem))]
|
[Access(typeof(SharedAmbientSoundSystem))]
|
||||||
@@ -48,4 +48,3 @@ namespace Content.Shared.Audio
|
|||||||
public float Range { get; init; }
|
public float Range { get; init; }
|
||||||
public float Volume { get; init; }
|
public float Volume { get; init; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -33,10 +33,6 @@ namespace Content.Shared.CCVar
|
|||||||
/*
|
/*
|
||||||
* Ambience
|
* Ambience
|
||||||
*/
|
*/
|
||||||
//TODO: This is so that this compiles, yell at me if this is still in
|
|
||||||
public static readonly CVarDef<bool> AmbienceBasicEnabled =
|
|
||||||
CVarDef.Create("ambiance.basic_enabled", true, CVar.CLIENTONLY | CVar.ARCHIVE);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How long we'll wait until re-sampling nearby objects for ambience. Should be pretty fast, but doesn't have to match the tick rate.
|
/// How long we'll wait until re-sampling nearby objects for ambience. Should be pretty fast, but doesn't have to match the tick rate.
|
||||||
@@ -74,24 +70,25 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<float> AmbienceVolume =
|
public static readonly CVarDef<float> AmbienceVolume =
|
||||||
CVarDef.Create("ambience.volume", 0.0f, CVar.ARCHIVE | CVar.CLIENTONLY);
|
CVarDef.Create("ambience.volume", 0.0f, CVar.ARCHIVE | CVar.CLIENTONLY);
|
||||||
|
|
||||||
|
// Midi is on engine so deal
|
||||||
|
public const float MidiMultiplier = 3f;
|
||||||
|
|
||||||
|
public const float AmbienceMultiplier = 2f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ambience music volume.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<float> AmbientMusicVolume =
|
||||||
|
CVarDef.Create("ambience.music_volume", 0.0f, CVar.ARCHIVE | CVar.CLIENTONLY);
|
||||||
|
|
||||||
|
public const float AmbientMusicMultiplier = 2f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lobby / round end music volume.
|
/// Lobby / round end music volume.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly CVarDef<float> LobbyMusicVolume =
|
public static readonly CVarDef<float> LobbyMusicVolume =
|
||||||
CVarDef.Create("ambience.lobby_music_volume", 0.0f, CVar.ARCHIVE | CVar.CLIENTONLY);
|
CVarDef.Create("ambience.lobby_music_volume", 0.0f, CVar.ARCHIVE | CVar.CLIENTONLY);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether to play the station ambience (humming) sound
|
|
||||||
/// </summary>
|
|
||||||
public static readonly CVarDef<bool> StationAmbienceEnabled =
|
|
||||||
CVarDef.Create("ambience.station_ambience", true, CVar.ARCHIVE | CVar.CLIENTONLY);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether to play the space ambience
|
|
||||||
/// </summary>
|
|
||||||
public static readonly CVarDef<bool> SpaceAmbienceEnabled =
|
|
||||||
CVarDef.Create("ambience.space_ambience", true, CVar.ARCHIVE | CVar.CLIENTONLY);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Status
|
* Status
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
namespace Content.Server.Morgue.Components;
|
namespace Content.Shared.Morgue.Components;
|
||||||
|
|
||||||
[RegisterComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
public sealed class MorgueComponent : Component
|
public sealed class MorgueComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -253,10 +253,10 @@ namespace Content.Shared.Movement.Systems
|
|||||||
if (!weightless && mobMoverQuery.TryGetComponent(uid, out var mobMover) &&
|
if (!weightless && mobMoverQuery.TryGetComponent(uid, out var mobMover) &&
|
||||||
TryGetSound(weightless, uid, mover, mobMover, xform, out var sound))
|
TryGetSound(weightless, uid, mover, mobMover, xform, out var sound))
|
||||||
{
|
{
|
||||||
var soundModifier = mover.Sprinting ? 1.5f : 1f;
|
var soundModifier = mover.Sprinting ? 3.5f : 1.5f;
|
||||||
|
|
||||||
var audioParams = sound.Params
|
var audioParams = sound.Params
|
||||||
.WithVolume(sound.Params.Volume * soundModifier)
|
.WithVolume(sound.Params.Volume + soundModifier)
|
||||||
.WithVariation(sound.Params.Variation ?? FootstepVariation);
|
.WithVariation(sound.Params.Variation ?? FootstepVariation);
|
||||||
|
|
||||||
// If we're a relay target then predict the sound for all relays.
|
// If we're a relay target then predict the sound for all relays.
|
||||||
|
|||||||
46
Content.Shared/Prayer/PrayableComponent.cs
Normal file
46
Content.Shared/Prayer/PrayableComponent.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Prayer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allows an entity to be prayed on in the context menu
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed class PrayableComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// If bible users are only allowed to use this prayable entity
|
||||||
|
/// </summary>
|
||||||
|
[DataField("bibleUserOnly")]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public bool BibleUserOnly;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message given to user to notify them a message was sent
|
||||||
|
/// </summary>
|
||||||
|
[DataField("sentMessage")]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public string SentMessage = "prayer-popup-notify-pray-sent";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prefix used in the notification to admins
|
||||||
|
/// </summary>
|
||||||
|
[DataField("notifiactionPrefix")]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public string NotificationPrefix = "prayer-chat-notify-pray";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used in window title and context menu
|
||||||
|
/// </summary>
|
||||||
|
[DataField("verb")]
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
public string Verb = "prayer-verbs-pray";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Context menu image
|
||||||
|
/// </summary>
|
||||||
|
[DataField("verbImage")]
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
public SpriteSpecifier? VerbImage = new SpriteSpecifier.Texture(new ("/Textures/Interface/pray.svg.png"));
|
||||||
|
}
|
||||||
130
Content.Shared/Random/RulesPrototype.cs
Normal file
130
Content.Shared/Random/RulesPrototype.cs
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
using Content.Shared.Access;
|
||||||
|
using Content.Shared.Maps;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||||
|
|
||||||
|
namespace Content.Shared.Random;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rules-based item selection. Can be used for any sort of conditional selection
|
||||||
|
/// Every single condition needs to be true for this to be selected.
|
||||||
|
/// e.g. "choose maintenance audio if 90% of tiles nearby are maintenance tiles"
|
||||||
|
/// </summary>
|
||||||
|
[Prototype("rules")]
|
||||||
|
public sealed class RulesPrototype : IPrototype
|
||||||
|
{
|
||||||
|
[IdDataField] public string ID { get; } = string.Empty;
|
||||||
|
|
||||||
|
[DataField("rules", required: true)]
|
||||||
|
public List<RulesRule> Rules = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
[ImplicitDataDefinitionForInheritors]
|
||||||
|
public abstract class RulesRule
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the attached entity is in space.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class InSpaceRule : RulesRule
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for entities matching the whitelist in range.
|
||||||
|
/// This is more expensive than <see cref="NearbyComponentsRule"/> so prefer that!
|
||||||
|
/// </summary>
|
||||||
|
public sealed class NearbyEntitiesRule : RulesRule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// How many of the entity need to be nearby.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("count")]
|
||||||
|
public int Count = 1;
|
||||||
|
|
||||||
|
[DataField("whitelist", required: true)]
|
||||||
|
public EntityWhitelist Whitelist = new();
|
||||||
|
|
||||||
|
[DataField("range")]
|
||||||
|
public float Range = 10f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class NearbyTilesPercentRule : RulesRule
|
||||||
|
{
|
||||||
|
[DataField("percent", required: true)]
|
||||||
|
public float Percent;
|
||||||
|
|
||||||
|
[DataField("tiles", required: true, customTypeSerializer:typeof(PrototypeIdListSerializer<ContentTileDefinition>))]
|
||||||
|
public List<string> Tiles = new();
|
||||||
|
|
||||||
|
[DataField("range")]
|
||||||
|
public float Range = 10f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Always returns true. Used for fallbacks.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class AlwaysTrueRule : RulesRule
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if on a grid or in range of one.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class GridInRangeRule : RulesRule
|
||||||
|
{
|
||||||
|
[DataField("range")]
|
||||||
|
public float Range = 10f;
|
||||||
|
|
||||||
|
[DataField("inverted")]
|
||||||
|
public bool Inverted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if griduid and mapuid match (AKA on 'planet').
|
||||||
|
/// </summary>
|
||||||
|
public sealed class OnMapGridRule : RulesRule
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for an entity nearby with the specified access.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class NearbyAccessRule : RulesRule
|
||||||
|
{
|
||||||
|
// This exists because of doorelectronics contained inside doors.
|
||||||
|
/// <summary>
|
||||||
|
/// Does the access entity need to be anchored.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("anchored")]
|
||||||
|
public bool Anchored = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Count of entities that need to be nearby.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("count")]
|
||||||
|
public int Count = 1;
|
||||||
|
|
||||||
|
[DataField("access", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<AccessLevelPrototype>))]
|
||||||
|
public List<string> Access = new();
|
||||||
|
|
||||||
|
[DataField("range")]
|
||||||
|
public float Range = 10f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class NearbyComponentsRule : RulesRule
|
||||||
|
{
|
||||||
|
[DataField("count")] public int Count;
|
||||||
|
|
||||||
|
[DataField("components", required: true)]
|
||||||
|
public ComponentRegistry Components = default!;
|
||||||
|
|
||||||
|
[DataField("range")]
|
||||||
|
public float Range = 10f;
|
||||||
|
}
|
||||||
207
Content.Shared/Random/RulesSystem.cs
Normal file
207
Content.Shared/Random/RulesSystem.cs
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
using Content.Shared.Access.Components;
|
||||||
|
using Content.Shared.Access.Systems;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Map.Components;
|
||||||
|
|
||||||
|
namespace Content.Shared.Random;
|
||||||
|
|
||||||
|
public sealed class RulesSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
|
[Dependency] private readonly ITileDefinitionManager _tileDef = default!;
|
||||||
|
[Dependency] private readonly AccessReaderSystem _reader = default!;
|
||||||
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
|
||||||
|
public bool IsTrue(EntityUid uid, RulesPrototype rules)
|
||||||
|
{
|
||||||
|
foreach (var rule in rules.Rules)
|
||||||
|
{
|
||||||
|
switch (rule)
|
||||||
|
{
|
||||||
|
case AlwaysTrueRule:
|
||||||
|
break;
|
||||||
|
case GridInRangeRule griddy:
|
||||||
|
{
|
||||||
|
if (!TryComp<TransformComponent>(uid, out var xform))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xform.GridUid != null)
|
||||||
|
{
|
||||||
|
return !griddy.Inverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
var worldPos = _transform.GetWorldPosition(xform);
|
||||||
|
|
||||||
|
foreach (var _ in _mapManager.FindGridsIntersecting(
|
||||||
|
xform.MapID,
|
||||||
|
new Box2(worldPos - griddy.Range, worldPos + griddy.Range)))
|
||||||
|
{
|
||||||
|
return !griddy.Inverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InSpaceRule:
|
||||||
|
{
|
||||||
|
if (!TryComp<TransformComponent>(uid, out var xform) ||
|
||||||
|
xform.GridUid != null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NearbyAccessRule access:
|
||||||
|
{
|
||||||
|
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
|
|
||||||
|
if (!xformQuery.TryGetComponent(uid, out var xform) ||
|
||||||
|
xform.MapUid == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var found = false;
|
||||||
|
var worldPos = _transform.GetWorldPosition(xform, xformQuery);
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
// TODO: Update this when we get the callback version
|
||||||
|
foreach (var comp in _lookup.GetComponentsInRange<AccessReaderComponent>(xform.MapID,
|
||||||
|
worldPos, access.Range))
|
||||||
|
{
|
||||||
|
if (access.Anchored && !xformQuery.GetComponent(comp.Owner).Anchored ||
|
||||||
|
!_reader.AreAccessTagsAllowed(access.Access, comp))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count < access.Count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NearbyComponentsRule nearbyComps:
|
||||||
|
{
|
||||||
|
if (!TryComp<TransformComponent>(uid, out var xform) ||
|
||||||
|
xform.MapUid == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var found = false;
|
||||||
|
var worldPos = _transform.GetWorldPosition(xform);
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
foreach (var comp in nearbyComps.Components.Values)
|
||||||
|
{
|
||||||
|
// TODO: Update this when we get the callback version
|
||||||
|
foreach (var _ in _lookup.GetComponentsInRange(comp.Component.GetType(), xform.MapID,
|
||||||
|
worldPos, nearbyComps.Range))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count >= nearbyComps.Count)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NearbyEntitiesRule entity:
|
||||||
|
{
|
||||||
|
if (!TryComp<TransformComponent>(uid, out var xform) ||
|
||||||
|
xform.MapUid == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var found = false;
|
||||||
|
var worldPos = _transform.GetWorldPosition(xform);
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
foreach (var ent in _lookup.GetEntitiesInRange(xform.MapID, worldPos, entity.Range))
|
||||||
|
{
|
||||||
|
if (!entity.Whitelist.IsValid(ent, EntityManager))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count < entity.Count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NearbyTilesPercentRule tiles:
|
||||||
|
{
|
||||||
|
if (!TryComp<TransformComponent>(uid, out var xform) ||
|
||||||
|
!TryComp<MapGridComponent>(xform.GridUid, out var grid))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tileCount = 0;
|
||||||
|
var matchingTileCount = 0;
|
||||||
|
|
||||||
|
foreach (var tile in grid.GetTilesIntersecting(new Circle(_transform.GetWorldPosition(xform),
|
||||||
|
tiles.Range)))
|
||||||
|
{
|
||||||
|
tileCount++;
|
||||||
|
|
||||||
|
if (!tiles.Tiles.Contains(_tileDef[tile.Tile.TypeId].ID))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
matchingTileCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchingTileCount / (float) tileCount < tiles.Percent)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OnMapGridRule:
|
||||||
|
{
|
||||||
|
if (!TryComp<TransformComponent>(uid, out var xform) ||
|
||||||
|
xform.GridUid != xform.MapUid ||
|
||||||
|
xform.MapUid == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Resources/Audio/Ambience/ambiatmos.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiatmos.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiatmos2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiatmos2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambicave.ogg
Normal file
BIN
Resources/Audio/Ambience/ambicave.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambicha1.ogg
Normal file
BIN
Resources/Audio/Ambience/ambicha1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambicha2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambicha2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambicha3.ogg
Normal file
BIN
Resources/Audio/Ambience/ambicha3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambicha4.ogg
Normal file
BIN
Resources/Audio/Ambience/ambicha4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambidanger.ogg
Normal file
BIN
Resources/Audio/Ambience/ambidanger.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambidanger2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambidanger2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen1.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen10.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen10.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen11.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen11.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen12.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen12.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen13.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen13.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen14.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen14.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen15.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen15.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen3.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen4.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen5.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen5.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen6.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen6.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen7.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen7.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen8.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen8.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambigen9.ogg
Normal file
BIN
Resources/Audio/Ambience/ambigen9.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiholy.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiholy.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiholy2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiholy2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiholy3.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiholy3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambilava1.ogg
Normal file
BIN
Resources/Audio/Ambience/ambilava1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambilava2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambilava2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambilava3.ogg
Normal file
BIN
Resources/Audio/Ambience/ambilava3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambimaint1.ogg
Normal file
BIN
Resources/Audio/Ambience/ambimaint1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambimaint2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambimaint2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambimaint3.ogg
Normal file
BIN
Resources/Audio/Ambience/ambimaint3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambimaint4.ogg
Normal file
BIN
Resources/Audio/Ambience/ambimaint4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambimaint5.ogg
Normal file
BIN
Resources/Audio/Ambience/ambimaint5.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambimine.ogg
Normal file
BIN
Resources/Audio/Ambience/ambimine.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambimo1.ogg
Normal file
BIN
Resources/Audio/Ambience/ambimo1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambimo2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambimo2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambimystery.ogg
Normal file
BIN
Resources/Audio/Ambience/ambimystery.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambinice.ogg
Normal file
BIN
Resources/Audio/Ambience/ambinice.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiodd.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiodd.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambireebe1.ogg
Normal file
BIN
Resources/Audio/Ambience/ambireebe1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambireebe3.ogg
Normal file
BIN
Resources/Audio/Ambience/ambireebe3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiruin.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiruin.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiruin2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiruin2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiruin3.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiruin3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiruin4.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiruin4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiruin5.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiruin5.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiruin6.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiruin6.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambiruin7.ogg
Normal file
BIN
Resources/Audio/Ambience/ambiruin7.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambisin1.ogg
Normal file
BIN
Resources/Audio/Ambience/ambisin1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambisin2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambisin2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambisin3.ogg
Normal file
BIN
Resources/Audio/Ambience/ambisin3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambisin4.ogg
Normal file
BIN
Resources/Audio/Ambience/ambisin4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambitech.ogg
Normal file
BIN
Resources/Audio/Ambience/ambitech.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambitech2.ogg
Normal file
BIN
Resources/Audio/Ambience/ambitech2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/ambitech3.ogg
Normal file
BIN
Resources/Audio/Ambience/ambitech3.ogg
Normal file
Binary file not shown.
@@ -2,3 +2,64 @@
|
|||||||
license: "CC0-1.0"
|
license: "CC0-1.0"
|
||||||
copyright: "Created by Joao_Janz, edited and converted to Mono by EmoGarbage"
|
copyright: "Created by Joao_Janz, edited and converted to Mono by EmoGarbage"
|
||||||
source: "https://freesound.org/people/Joao_Janz/sounds/478472/"
|
source: "https://freesound.org/people/Joao_Janz/sounds/478472/"
|
||||||
|
|
||||||
|
- files:
|
||||||
|
- "ambiatmos.ogg"
|
||||||
|
- "ambiatmos2.ogg"
|
||||||
|
- "ambicave.ogg"
|
||||||
|
- "ambicha1.ogg"
|
||||||
|
- "ambicha2.ogg"
|
||||||
|
- "ambicha3.ogg"
|
||||||
|
- "ambicha4.ogg"
|
||||||
|
- "ambidanger.ogg"
|
||||||
|
- "ambidanger2.ogg"
|
||||||
|
- "ambigen1.ogg"
|
||||||
|
- "ambigen2.ogg"
|
||||||
|
- "ambigen3.ogg"
|
||||||
|
- "ambigen4.ogg"
|
||||||
|
- "ambigen5.ogg"
|
||||||
|
- "ambigen6.ogg"
|
||||||
|
- "ambigen7.ogg"
|
||||||
|
- "ambigen8.ogg"
|
||||||
|
- "ambigen9.ogg"
|
||||||
|
- "ambigen10.ogg"
|
||||||
|
- "ambigen11.ogg"
|
||||||
|
- "ambigen12.ogg"
|
||||||
|
- "ambigen13.ogg"
|
||||||
|
- "ambigen14.ogg"
|
||||||
|
- "ambigen15.ogg"
|
||||||
|
- "ambiholy.ogg"
|
||||||
|
- "ambiholy2.ogg"
|
||||||
|
- "ambiholy3.ogg"
|
||||||
|
- "ambilava1.ogg"
|
||||||
|
- "ambilava2.ogg"
|
||||||
|
- "ambilava3.ogg"
|
||||||
|
- "ambimaint1.ogg"
|
||||||
|
- "ambimaint2.ogg"
|
||||||
|
- "ambimaint3.ogg"
|
||||||
|
- "ambimaint4.ogg"
|
||||||
|
- "ambimaint5.ogg"
|
||||||
|
- "ambimine.ogg"
|
||||||
|
- "ambimo1.ogg"
|
||||||
|
- "ambimo2.ogg"
|
||||||
|
- "ambimystery.ogg"
|
||||||
|
- "ambinice.ogg"
|
||||||
|
- "ambiodd.ogg"
|
||||||
|
- "ambiruin.ogg"
|
||||||
|
- "ambiruin2.ogg"
|
||||||
|
- "ambiruin3.ogg"
|
||||||
|
- "ambiruin4.ogg"
|
||||||
|
- "ambiruin5.ogg"
|
||||||
|
- "ambiruin6.ogg"
|
||||||
|
- "ambiruin7.ogg"
|
||||||
|
- "ambisin1.ogg"
|
||||||
|
- "ambisin2.ogg"
|
||||||
|
- "ambisin3.ogg"
|
||||||
|
- "ambisin4.ogg"
|
||||||
|
- "ambitech.ogg"
|
||||||
|
- "ambitech2.ogg"
|
||||||
|
- "ambitech3.ogg"
|
||||||
|
- "maintambience.ogg"
|
||||||
|
license: "CC-BY-SA-3.0"
|
||||||
|
copyright: "Taken from tgstation"
|
||||||
|
source: "https://github.com/tgstation/tgstation/tree/ae9767664701396501af5dcef8e34c4b5add3d47/sound/ambience"
|
||||||
BIN
Resources/Audio/Ambience/maintambience.ogg
Normal file
BIN
Resources/Audio/Ambience/maintambience.ogg
Normal file
Binary file not shown.
8
Resources/Audio/Voice/Misc/attributions.yml
Normal file
8
Resources/Audio/Voice/Misc/attributions.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
- files:
|
||||||
|
- "lowHiss1.ogg"
|
||||||
|
- "lowHiss2.ogg"
|
||||||
|
- "lowHiss3.ogg"
|
||||||
|
- "lowHiss4.ogg"
|
||||||
|
license: "CC-BY-SA-3.0"
|
||||||
|
copyright: "Taken from tgstation"
|
||||||
|
source: "https://github.com/tgstation/tgstation/tree/ae9767664701396501af5dcef8e34c4b5add3d47/sound/ambience"
|
||||||
BIN
Resources/Audio/Voice/Misc/lowHiss1.ogg
Normal file
BIN
Resources/Audio/Voice/Misc/lowHiss1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Voice/Misc/lowHiss2.ogg
Normal file
BIN
Resources/Audio/Voice/Misc/lowHiss2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Voice/Misc/lowHiss3.ogg
Normal file
BIN
Resources/Audio/Voice/Misc/lowHiss3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Voice/Misc/lowHiss4.ogg
Normal file
BIN
Resources/Audio/Voice/Misc/lowHiss4.ogg
Normal file
Binary file not shown.
@@ -14,6 +14,7 @@ ui-options-default = Default
|
|||||||
|
|
||||||
ui-options-master-volume = Master Volume:
|
ui-options-master-volume = Master Volume:
|
||||||
ui-options-midi-volume = MIDI (Instrument) Volume:
|
ui-options-midi-volume = MIDI (Instrument) Volume:
|
||||||
|
ui-options-ambient-music-volume = Ambient music volume:
|
||||||
ui-options-ambience-volume = Ambience volume:
|
ui-options-ambience-volume = Ambience volume:
|
||||||
ui-options-lobby-volume = Lobby & Round-end volume:
|
ui-options-lobby-volume = Lobby & Round-end volume:
|
||||||
ui-options-ambience-max-sounds = Ambience simultaneous sounds:
|
ui-options-ambience-max-sounds = Ambience simultaneous sounds:
|
||||||
@@ -21,8 +22,6 @@ ui-options-lobby-music = Lobby & Round-end Music
|
|||||||
ui-options-restart-sounds = Round Restart Sounds
|
ui-options-restart-sounds = Round Restart Sounds
|
||||||
ui-options-event-music = Event Music
|
ui-options-event-music = Event Music
|
||||||
ui-options-admin-sounds = Play Admin Sounds
|
ui-options-admin-sounds = Play Admin Sounds
|
||||||
ui-options-station-ambience = Station Ambience
|
|
||||||
ui-options-space-ambience = Space Ambience
|
|
||||||
ui-options-volume-label = Volume
|
ui-options-volume-label = Volume
|
||||||
ui-options-volume-percent = { TOSTRING($volume, "P0") }
|
ui-options-volume-percent = { TOSTRING($volume, "P0") }
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
- type: soundCollection
|
|
||||||
id: StationAmbienceBase
|
|
||||||
files:
|
|
||||||
- /Audio/Ambience/shipambience.ogg
|
|
||||||
|
|
||||||
- type: soundCollection
|
|
||||||
id: SpaceAmbienceBase
|
|
||||||
files:
|
|
||||||
- /Audio/Ambience/starlight.ogg
|
|
||||||
- /Audio/Ambience/constellations.ogg
|
|
||||||
- /Audio/Ambience/drifting.ogg
|
|
||||||
262
Resources/Prototypes/audio.yml
Normal file
262
Resources/Prototypes/audio.yml
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
- type: ambientMusic
|
||||||
|
id: Morgue
|
||||||
|
sound:
|
||||||
|
params:
|
||||||
|
volume: -12
|
||||||
|
collection: AmbienceSpooky
|
||||||
|
rules: NearMorgue
|
||||||
|
priority: 4
|
||||||
|
|
||||||
|
- type: ambientMusic
|
||||||
|
id: Holy
|
||||||
|
sound:
|
||||||
|
params:
|
||||||
|
volume: -12
|
||||||
|
collection: AmbienceHoly
|
||||||
|
rules: NearPrayable
|
||||||
|
priority: 4
|
||||||
|
|
||||||
|
# Departments
|
||||||
|
- type: ambientMusic
|
||||||
|
id: Medical
|
||||||
|
sound:
|
||||||
|
params:
|
||||||
|
volume: -12
|
||||||
|
collection: AmbienceMedical
|
||||||
|
rules: NearMedical
|
||||||
|
priority: 3
|
||||||
|
|
||||||
|
- type: ambientMusic
|
||||||
|
id: Engineering
|
||||||
|
sound:
|
||||||
|
params:
|
||||||
|
volume: -12
|
||||||
|
collection: AmbienceEngineering
|
||||||
|
rules: NearEngineering
|
||||||
|
priority: 3
|
||||||
|
|
||||||
|
# General areas
|
||||||
|
- type: ambientMusic
|
||||||
|
id: Maintenance
|
||||||
|
sound:
|
||||||
|
params:
|
||||||
|
volume: -12
|
||||||
|
collection: AmbienceMaintenance
|
||||||
|
rules: NearMaintenance
|
||||||
|
priority: 2
|
||||||
|
|
||||||
|
- type: ambientMusic
|
||||||
|
id: Space
|
||||||
|
sound:
|
||||||
|
params:
|
||||||
|
volume: -10
|
||||||
|
collection: AmbienceSpace
|
||||||
|
fadeIn: true
|
||||||
|
interruptable: true
|
||||||
|
rules: InSpace
|
||||||
|
priority: 1
|
||||||
|
|
||||||
|
- type: ambientMusic
|
||||||
|
id: Mining
|
||||||
|
sound:
|
||||||
|
params:
|
||||||
|
volume: -12
|
||||||
|
collection: AmbienceMining
|
||||||
|
rules: OnMapGrid
|
||||||
|
fadeIn: true
|
||||||
|
interruptable: true
|
||||||
|
priority: 1
|
||||||
|
|
||||||
|
## Fallback if nothing else found
|
||||||
|
- type: ambientMusic
|
||||||
|
id: General
|
||||||
|
sound:
|
||||||
|
params:
|
||||||
|
volume: -12
|
||||||
|
collection: AmbienceGeneral
|
||||||
|
rules: AlwaysTrue
|
||||||
|
|
||||||
|
# Sound collections
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceEngineering
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/ambiatmos.ogg
|
||||||
|
- /Audio/Ambience/ambiatmos2.ogg
|
||||||
|
- /Audio/Ambience/ambisin1.ogg
|
||||||
|
- /Audio/Ambience/ambisin2.ogg
|
||||||
|
- /Audio/Ambience/ambisin3.ogg
|
||||||
|
- /Audio/Ambience/ambisin4.ogg
|
||||||
|
- /Audio/Ambience/ambitech.ogg
|
||||||
|
- /Audio/Ambience/ambitech2.ogg
|
||||||
|
- /Audio/Ambience/ambitech3.ogg
|
||||||
|
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceGeneral
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/ambigen1.ogg
|
||||||
|
- /Audio/Ambience/ambigen3.ogg
|
||||||
|
- /Audio/Ambience/ambigen4.ogg
|
||||||
|
- /Audio/Ambience/ambigen5.ogg
|
||||||
|
- /Audio/Ambience/ambigen6.ogg
|
||||||
|
- /Audio/Ambience/ambigen7.ogg
|
||||||
|
- /Audio/Ambience/ambigen8.ogg
|
||||||
|
- /Audio/Ambience/ambigen9.ogg
|
||||||
|
- /Audio/Ambience/ambigen10.ogg
|
||||||
|
- /Audio/Ambience/ambigen11.ogg
|
||||||
|
- /Audio/Ambience/ambigen12.ogg
|
||||||
|
- /Audio/Ambience/ambigen14.ogg
|
||||||
|
- /Audio/Ambience/ambigen15.ogg
|
||||||
|
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceHoly
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/ambicha1.ogg
|
||||||
|
- /Audio/Ambience/ambicha2.ogg
|
||||||
|
- /Audio/Ambience/ambicha3.ogg
|
||||||
|
- /Audio/Ambience/ambicha4.ogg
|
||||||
|
- /Audio/Ambience/ambiholy.ogg
|
||||||
|
- /Audio/Ambience/ambiholy2.ogg
|
||||||
|
- /Audio/Ambience/ambiholy3.ogg
|
||||||
|
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceMaintenance
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/ambimaint1.ogg
|
||||||
|
- /Audio/Ambience/ambimaint2.ogg
|
||||||
|
- /Audio/Ambience/ambimaint3.ogg
|
||||||
|
- /Audio/Ambience/ambimaint4.ogg
|
||||||
|
- /Audio/Ambience/ambimaint5.ogg
|
||||||
|
- /Audio/Ambience/ambitech2.ogg
|
||||||
|
- /Audio/Voice/Misc/lowHiss1.ogg
|
||||||
|
- /Audio/Voice/Misc/lowHiss2.ogg
|
||||||
|
- /Audio/Voice/Misc/lowHiss3.ogg
|
||||||
|
- /Audio/Voice/Misc/lowHiss4.ogg
|
||||||
|
- /Audio/Ambience/maintambience.ogg
|
||||||
|
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceMedical
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/ambinice.ogg
|
||||||
|
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceMining
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/ambicave.ogg
|
||||||
|
- /Audio/Ambience/ambidanger.ogg
|
||||||
|
- /Audio/Ambience/ambidanger2.ogg
|
||||||
|
- /Audio/Ambience/ambilava1.ogg
|
||||||
|
- /Audio/Ambience/ambilava2.ogg
|
||||||
|
- /Audio/Ambience/ambilava3.ogg
|
||||||
|
- /Audio/Ambience/ambimaint1.ogg
|
||||||
|
- /Audio/Ambience/ambimine.ogg
|
||||||
|
- /Audio/Ambience/ambiruin.ogg
|
||||||
|
- /Audio/Ambience/ambiruin2.ogg
|
||||||
|
- /Audio/Ambience/ambiruin3.ogg
|
||||||
|
- /Audio/Ambience/ambiruin4.ogg
|
||||||
|
- /Audio/Ambience/ambiruin5.ogg
|
||||||
|
- /Audio/Ambience/ambiruin6.ogg
|
||||||
|
- /Audio/Ambience/ambiruin7.ogg
|
||||||
|
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceRuins
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/ambicave.ogg
|
||||||
|
- /Audio/Ambience/ambidanger.ogg
|
||||||
|
- /Audio/Ambience/ambidanger2.ogg
|
||||||
|
- /Audio/Ambience/ambimaint1.ogg
|
||||||
|
- /Audio/Ambience/ambimine.ogg
|
||||||
|
- /Audio/Ambience/ambimystery.ogg
|
||||||
|
- /Audio/Ambience/ambiruin.ogg
|
||||||
|
- /Audio/Ambience/ambiruin2.ogg
|
||||||
|
- /Audio/Ambience/ambiruin3.ogg
|
||||||
|
- /Audio/Ambience/ambiruin4.ogg
|
||||||
|
- /Audio/Ambience/ambiruin5.ogg
|
||||||
|
- /Audio/Ambience/ambiruin6.ogg
|
||||||
|
- /Audio/Ambience/ambiruin7.ogg
|
||||||
|
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceSpace
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/starlight.ogg
|
||||||
|
- /Audio/Ambience/constellations.ogg
|
||||||
|
- /Audio/Ambience/drifting.ogg
|
||||||
|
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceSpooky
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/ambimo1.ogg
|
||||||
|
- /Audio/Ambience/ambimo2.ogg
|
||||||
|
- /Audio/Ambience/ambimystery.ogg
|
||||||
|
- /Audio/Ambience/ambiodd.ogg
|
||||||
|
- /Audio/Ambience/ambiruin6.ogg
|
||||||
|
- /Audio/Ambience/ambiruin7.ogg
|
||||||
|
|
||||||
|
## Background noise on station, separate to ambient music.
|
||||||
|
- type: soundCollection
|
||||||
|
id: AmbienceStation
|
||||||
|
files:
|
||||||
|
- /Audio/Ambience/shipambience.ogg
|
||||||
|
|
||||||
|
# Rules
|
||||||
|
- type: rules
|
||||||
|
id: AlwaysTrue
|
||||||
|
rules:
|
||||||
|
- !type:AlwaysTrueRule
|
||||||
|
|
||||||
|
# TODO: Need to make sure no grids nearby
|
||||||
|
- type: rules
|
||||||
|
id: InSpace
|
||||||
|
rules:
|
||||||
|
- !type:InSpaceRule
|
||||||
|
- !type:GridInRangeRule
|
||||||
|
inverted: true
|
||||||
|
range: 10
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
- type: rules
|
||||||
|
id: NearEngineering
|
||||||
|
rules:
|
||||||
|
- !type:NearbyAccessRule
|
||||||
|
access:
|
||||||
|
- Engineering
|
||||||
|
range: 3
|
||||||
|
|
||||||
|
- type: rules
|
||||||
|
id: NearMaintenance
|
||||||
|
rules:
|
||||||
|
- !type:NearbyTilesPercentRule
|
||||||
|
percent: 0.25
|
||||||
|
tiles:
|
||||||
|
- Plating
|
||||||
|
range: 3
|
||||||
|
|
||||||
|
- type: rules
|
||||||
|
id: NearMedical
|
||||||
|
rules:
|
||||||
|
- !type:NearbyTilesPercentRule
|
||||||
|
percent: 0.5
|
||||||
|
tiles:
|
||||||
|
- FloorWhite
|
||||||
|
range: 5
|
||||||
|
|
||||||
|
- type: rules
|
||||||
|
id: NearPrayable
|
||||||
|
rules:
|
||||||
|
- !type:NearbyComponentsRule
|
||||||
|
components:
|
||||||
|
- type: Prayable
|
||||||
|
range: 5
|
||||||
|
|
||||||
|
- type: rules
|
||||||
|
id: NearMorgue
|
||||||
|
rules:
|
||||||
|
- !type:NearbyComponentsRule
|
||||||
|
count: 2
|
||||||
|
components:
|
||||||
|
- type: Morgue
|
||||||
|
range: 3
|
||||||
|
|
||||||
|
- type: rules
|
||||||
|
id: OnMapGrid
|
||||||
|
rules:
|
||||||
|
- !type:OnMapGridRule
|
||||||
Reference in New Issue
Block a user